Gfort2py v3.0.0 release

I’m happy to announce the release of gfort2py version 3 (https://github.com/rjfarmer/gfort2py).

Gfort2py is a Python to Fortran interface library designed to make it easy to call modern Fortran from Python. Features including getting/setting module variables and calling procedures inside a module with both scalars and array (explicit, assumed shape, assumed size, allocatable, and assumed rank) as arguments and return values. It does this by using Gfortran’s .mod file to provide details of your codes API, meaning as a user you don’t need make any changes to your Fortran code or have to have any deep knowledge of how to convert something between Python and Fortran, as long as your code sits in a Fortran module.

New features include:

  • Support for gfortran 15 and above
  • Support for allocatable arrays of derived types
  • Support assumed rank arrays
  • Support unicode ‘ISO_10646’ (scalars and arrays)
  • Support quad precision arrays (scalars already supported)
  • Support type bound procedures (both PASS and NOPASS)
  • Support unsigned (scalars and arrays)
  • Returning arrays of characters

Package is available from both Github ( https://github.com/rjfarmer/gfort2py) and PyPi
(python -m pip install --upgrade gfort2py).

Note for quad precision support you require an extra package, pyQuadP (python -m pip install --upgrade pyquadp). As part of this version I also extracted the Gfortran module handling code into a separate library gfModParser (https://github.com/rjfarmer/gfModParser) which can be used standalone to explore Gfortran’s module files.

Bug reports and feature requests are welcome as Github issues.

13 Likes

Can it call fortran type-bound-procedure?

Good job!

Yes it can call fortran type bound methods. Assuming you have a type(x) with type bound methods then you can just do x.method(arg1,arg2…) and it handles passing the type where needed.

2 Likes

Like pybind11

pip install gfort2py

python -c “import gfort2py; print(gfort2py._version_)”

ModuleNotFoundError: No module named ‘gfort2py’

Did pip say which version it installed?

If you run it as python -m pip, so that pip is installing to the same place as your python is running from, does that work?

! circle_mod.f90
module circle_mod
    implicit none
    ! 定义 circle 类型
    type::circle
        real::radius !实例变量
    contains
        procedure,pass(this) :: create_circle  !实例方法:构造方法
        procedure,pass(this) :: calculate_area !实例方法:计算面积方法
        procedure,nopass :: print_name !静态方法: 打印类名
    end type circle

    type(circle)::a !实例对象
contains
    !实例方法:构造方法
    subroutine create_circle(this,radius)
        class(circle) :: this
        real,intent(in)::radius
        this%radius = radius
    end subroutine create_circle
    !实例方法:计算面积
    function calculate_area(this)
        class(circle), intent(in) :: this
        real::calculate_area
        calculate_area = 3.141592653589793 * this%radius**2
    end function calculate_area
    !静态方法: 打印类名  同时也是模块方法
    subroutine print_name()
        write(*,*)"Circle!"
    end subroutine print_name
end module circle_mod

Is line13 “type(circle)::a” necessary?

import gfort2py as gf
mod = gf.fFort(f"./circle_mod.{gf.lib_ext()}","./circle_mod.mod") 

mod.a.create_circle(2.0) #实例方法
z=mod.a.calculate_area() #实例方法
print(z.result)
print("Module Method:")
mod.print_name() #模块方法
print("NoPass Method:")
mod.a.print_name() #静态方法 
print(mod.a['radius']) #读实例变量
mod.a={'radius':1.0} #写实例变量
print(mod.a['radius']) #读实例变量
z=mod.a.calculate_area() #实例方法
print(z.result)
1 Like

A program that uses this module is allowed to reference and modify that variable. So even if it is unused within the module, there is the possibility that it could be used elsewhere, so there are no compiler warnings printed for this variable declaration. If you were to add the private attribute to that variable, so that it can no longer be accessed from outside the module, then a compiler can see that the declaration is unnecessary:

$ gfortran -c -Wall circle.f90 
circle.f90:13:30:

   13 |     type(circle), private :: a !实例对象
      |                              1
Warning: Unused PRIVATE module variable 'a' declared at (1) [-Wunused-value]

if i comment line 13 “!type(circle)::a” in fortran , how to create a object in python?

At the moment there’s no simple way. Either don’t comment out the module level variable or you could write a Fortran subroutine that has a type(circle),intent(out) argument. Then call the subroutine with an empty dict and you’ll get back a fDT object which you can then use in Python.

I did it.

subroutine create_circle(this,radius)
  type(circle), intent(out) :: this
  real,intent(in)::radius
  this%radius = radius
end subroutine create_circle
z=mod.create_circle(None, 2.0) #模块方法
b=z.args['this'] #返回当前实例对象
z=mod.calculate_area(b) #实例方法用模块方法调用
print(z.result)

It’s too complicated.

subroutine create_circle is only module method and not type-bound method(class(circle)).

So, “type(circle)::a” is very necessary.

z=mod.create_circle(None, 2.0) #模块方法
b=z.args['this'] #返回当前实例对象
z=b.calculate_area() #实例方法
print(z.result)

why this is Error?

function class_name()
  character(:),allocatable::class_name
  !character(255)::class_name
  class_name="Circle!"
end function class_name
z=mod.class_name()
print(z.result)

Traceback (most recent call last):
File “F:\wxprogram\python program\oop2\circle_mod.py”, line 31, in
z=mod.class_name()
File “C:\Users\weixi\AppData\Roaming\Python\Python313\site-packages\gfort2py\procedures\procedures.py”, line 95, in call
self.result = self._proc(*all_args)
~~~~~~~~~~^^^^^^^^^^^
OSError: exception: access violation writing 0x0000000000000001

module add_mod
  implicit none
contains
  function add(x) result(res)
    real(kind=8), intent(in) :: x(:)   
    !real(kind=8), intent(in) :: x(*)   
    real(kind=8) :: res
    res = x(1)+x(2)
  end function add
end module add_mod

same error about assumed-shape arrays!

procedure,pass(this)::Create=>BaseReservoir_Create


function BaseReservoir_Create(this,Name,error) result(Create)
!GCC$ ATTRIBUTES DLLEXPORT :: BaseReservoir_Create

gfort2py print Error

ValueError: symbol ‘__basereservoirmodnoclass_MOD___vtab_basereservoirmodnoclass_Basereservoir’ not found

Hi @weixing1531 ,

I am also very interested in Gfort2py (so reading this thread), but I guess it would be useful to add a bit more “self-contained” information about the issue (e.g., like the “minimal working example (MWE)”, so that anyone can try it with their environment). For more detailed descriptions of the code, it might also be useful to use machine translation etc to translate non-English comments to English (using some “auto-translation” feature in the Discourse, if available?), so that anyone can understand them easily (e.g. like “返回当前实例对象”, possibly meaning “returns xxx of an instance”…?)