How to make Forpy use non-default python?

I want to specify to Forpy which python to use but I can’t figure it out. The only hack I found is to make a python virtual environment so that the default python is changed inside of the environment but this is not good enough for my case.

PS: I also asked the question in the Forpy repo. I’m asking it here too so that I can reach more people.

In Python you either have to use an environment, or you install manually into a given Python. You change the default Python by putting the correct python in your $PATH. The first line in the script:

Looks up the python in your $PATH and uses that. So just put python version 3.9 (that you need) in your $PATH and that should do it. Alternatively you can specify a full (absolute) path to it on that first line.

1 Like

I tried that out but afaik that file is not really necessary. FORPY’s author writes in the readme that you only really need the file forpy_mod.F90. I could pinpoint my issue a bit more. Here is a Fortran program that starts the Python interpreter, imports sys and prints the Python executable aswell as the Python version it is using.

program print_python_version
  use forpy_mod
  implicit none

  integer :: ierror
  type(module_py) :: sys
  type(object) :: version, executable
  character(len=:), allocatable :: version_str, executable_str

  ierror = forpy_initialize()
  ierror = import_py(sys, "sys")
  ierror = sys%getattribute(version, "version")
  ierror = sys%getattribute(executable, "executable")
  ierror = cast(version_str, version)
  ierror = cast(executable_str, executable)
  call forpy_finalize()

  print *, "Python VERSION is ", version_str
  print *, "Python EXECUTABLE is ", executable_str
end program

In order to compile and run it, you can do:

wget https://raw.githubusercontent.com/ylikx/forpy/refs/heads/master/forpy_mod.F90# gets forpy
gfortran -c forpy_mod.F90
gfortran main.f90 forpy_mod.o `python3-config --ldflags --embed` -o main
./main

The output in this case is:

 Python VERSION is 3.8.10 (default, Sep 11 2024, 16:02:53)
[GCC 9.4.0]
 Python EXECUTABLE is /usr/bin/python3

If I link with python3.9 libraries instead by changing to python3.9-config I get the following output:

 Python VERSION is 3.9.10 (main, May 16 2022, 19:45:25)
[GCC 9.4.0]
 Python EXECUTABLE is /usr/bin/python3

What I think is happening is it does manage to import the sys module of my python3.9 but it is using the wrong python executable. I am stuck here for now.

I made a Docker image with two pythons (3.8 and 3.9) where you can try out and see the issue for yourself if anyone wants to give it a shot. If you have docker and you are on a Unix machine you can do:

docker pull ordinaryslim/forpy-multiple-pythons-test
docker run -ti --network=host -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --rm --shm-size=512m ordinaryslim/forpy-multiple-pythons-test

Once in the docker container you can run:

gfortran -c forpy_mod.F90
gfortran main.f90 forpy_mod.o `python3.9-config --ldflags --embed` -o main
./main

and you’ll see the issue.

If you run

python3.9-config --ldflags --embed

On it’s own in a terminal what is the output?

-L/usr/lib/python3.9/config-3.9-x86_64-linux-gnu -L/usr/lib/x86_64-linux-gnu -lpython3.9 -lcrypt -lpthread -ldl -lutil -lm -lm

and python3-config --ldflags --embed:

-L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -L/usr/lib -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -lm

What about if you run the different versions of python themselves? I.e.
python3 check_version.py vs python3.9 check_version.py where

import sys
print(sys.version)
print(sys.executable)

python3 check_version.py:

3.8.10 (default, Sep 11 2024, 16:02:53) 
[GCC 9.4.0]
/usr/bin/python3

python3.9 check_version.py:

3.9.5 (default, Nov 23 2021, 15:27:38) 
[GCC 9.3.0]
/usr/bin/python3.9

The only solution I found so far is to make a virutal environment so that inside the virtual environment the default python is changed. This way Forpy uses the python of the venv, and even if the python3.9-config script is not in the virtual environment folder, it seems to work fine.

You could also consider using one of the various flavors of conda (anaconda, miniconda, I’ve heard mamba is popular lately) to grab specific versions of Python other than your system install, since going off the name, your script is tailored to a specific Python version that you also coincidentally happen to have on your system.

I’m generally not wild about conda because I’ve had its excessive environment pollution screw me over more than once, but I haven’t found anything better to deal with how “foamy” the Python ecosystem is. (It’s one of my biggest annoyances using a bleeding edge Linux distro as my daily driver, it’s a miracle whenever any Python script longer than “Hello World” actually works.)