-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
BUG: Modules from Fortran interface not accessible in Numpy 2.x (current 2.1.2) #27622
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
ping @HaoZeke |
Ran into a similar issue recently, a workaround is to add contains
subroutine has_module_lanedata()
end subroutine has_module_lanedata before the |
@DWesl Thank you. Yes, that this is a workaround for the current behaviour, as I wrote. However,
If it was desired to exclude modules, a f2py directive to hide modules are parts thereof should be introduced. Things I do not want in the interface I compile in external libraries. There used to be f2py commands to include/exclude specific subroutines/symbols on interface creation. Things I put in the interface and for which I use f2py to make the pyf file are there because I explicitly want them in the interface on the first place. |
FWIW I don't think this was an intended change. f2py is complicated, has poor test coverage, and few people understand the internals. We would have left it alone, but the removal of distutils by Python forced us to make some changes and you're seeing the fallout. It's not a perfect situation at all. If you want to help to fix this issue that would be very appreciated. |
Thanks everyone for the discussion here, I've been thinking of how best to resolve this and will have a PR up this weekend most likely. As far as I can remember this (poorly documented) breaking change had to do with the way F2PY was extended to handle derived types. The solution is better docs + an explicit hiding directive to handle declaration only derived type modules. |
@HaoZeke is one of the people who have a lot of knowledge of f2py internals, so I'll defer to them :) |
@HaoZeke You have been always very helpful fixing things swiftly. Thank you so much for that! My recent small patch suggestions to allow the setup for my f2py build framework to continue work with Python 3.12 after the discontinuation of distutils (at least one of them seems a real bug, the other was adding a simple option for backward compatibility that would not have broken anything else or had side effects other than having to "maintain" three extra lines of code), however, were rejected, so I found it futile to suggest further patches myself. What do people do in this case, maybe need to make a branch and rebase every time there is a numpy update? (For |
Thanks, sorry this one took a while to get to.
Sorry could you refresh my memory on this? Generally I'd love to try to get either existing working patchsets in or equivalent changes (i.e. those which pass the original test failure)
There's (IMO terrible) precedent set in the form of For build systems, it is probable that a separate extension module will be used (since NumPy will not vendor any |
@HaoZeke OK, I may try to cast these into real pull requests. It is related to the thread #24874 with items |
I dug into this a bit, and it certainly is an interesting one, thanks for reporting! For starters, it seems to only show up in certain cases, for instance, this works: module types
implicit none
INTEGER, PARAMETER :: int32 = SELECTED_INT_KIND(8)
INTEGER, PARAMETER :: int64 = SELECTED_INT_KIND(16)
INTEGER, PARAMETER :: real64 = SELECTED_REAL_KIND(15)
end module types
module lanedata
use types, only: &
real64, int32
implicit none
save
integer(kind=int32), parameter :: &
maxdata = 2**20-1
real(kind=real64), dimension(:,:), allocatable :: &
theta
integer(kind=int32) :: &
ndata
end module lanedata in In [1]: import ltest
In [2]: dir(ltest)
Out[2]:
['__doc__',
'__f2py_numpy_version__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'__version__',
'_ltest_error',
'lanedata']
In [3]: dir(ltest.lanedata)
Out[3]:
['__call__',
'__class__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'maxdata',
'ndata']
In [4]: ltest.lanedata.ndata
Out[4]: array(0, dtype=int32)
In [5]: ltest.lanedata.maxdata
Out[5]: array(1048575, dtype=int32) However, the bug is reproducible, module types
implicit none
INTEGER, PARAMETER :: int32 = SELECTED_INT_KIND(8)
INTEGER, PARAMETER :: int64 = SELECTED_INT_KIND(16)
INTEGER, PARAMETER :: real64 = SELECTED_REAL_KIND(15)
end module types
module lanedata
use types, only: &
real64, int32
implicit none
save
integer(kind=int32), parameter :: &
maxdata = 2**20-1
real(kind=real64), dimension(:,:), allocatable :: &
theta
integer(kind=int32) :: &
ndata
end module lanedata
subroutine freelanedata()
use lanedata, only: &
ndata, theta
implicit none
if (allocated(theta)) deallocate(theta)
ndata = -1
end subroutine freelanedata Where now, with In [1]: import ltest
In [2]: dir(ltest)
Out[2]:
['__doc__',
'__f2py_numpy_version__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'__version__',
'_ltest_error',
'freelanedata']
In [3]: There are a few things I need to understand conceptually about what the intended behavior is though. The reason this happens is because when there are subroutines they get exported into a module of the same name as requested on the command line ( Bizarrely, I think there's something more specific to the modules reported here by @2sn; since this also works: module datonly
implicit none
integer, parameter :: max_value = 100
real, dimension(:), allocatable :: data_array
end module datonly
module dat
implicit none
integer, parameter :: max_= 1009
end module dat
subroutine simple_subroutine(arg)
integer, intent(inout) :: arg
arg = arg * 5
end subroutine simple_subroutine This also works.. In [1]: import datonly
In [2]: datonly.datonly.max_value
Out[2]: array(100, dtype=int32)
In [3]: datonly.datonly.max_value
Out[3]: array(100, dtype=int32)
In [4]: datonly.dat.max_
Out[4]: array(1009, dtype=int32)
In [5]: dir(datonly)
Out[5]:
['__doc__',
'__f2py_numpy_version__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'__version__',
'_datonly_error',
'dat',
'datonly',
'simple_subroutine'] |
@HaoZeke Thank you very much for looking into this. I am not sure whether your question about the intent/use case is directed at me. What my Python code dies is trying to access the date in module I do not know how access to module data is done internally by Do you plan to have a |
Include all should definitely be the default (and is again after #27695). There are tests for the I'm thinking of adding some examples on using derived types soon, but otherwise, mostly just thinking of bugfixes / docs in the short term. |
Uh oh!
There was an error while loading. Please reload this page.
Describe the issue:
Using Numpy 2.x (tried 2.02, 2.1.2) I can no longer access module data.
After
f2py
I get thepyf
filebut when I try to access the data, as suggested in the online doc (just checking that this is still as it used to be, https://numpy.org/doc/2.1/f2py/python-usage.html#fortran-90-module-data), I get
or
so, not trace of
module lanedata
. This used to work (and still does) in Numpy 1.x.Reproduce the code example:
Here my code,
solver.f90
I use a custom build package that does not work with meson (and sadly, the usually very helpful Numpy developers out of principle refused to include fixes to obvious bugs in the build script to this day and a small patch to make my script continue to work, for both of which I had posted patches) and that are lengthy, so I won't include.
The issue seems to be that there is on interface in module lanedata. If I include an interface into the definition of
module lanedata
so it becomes, e.g.,then the module is included and an interface generated. This behaviour to skip modules w/o interface contents (just adding the
contains
line but an empty section does not suffice).Maybe the Python 1.x behaviour can be restored, as it is common to have plain data modules w/o definition of functions or subroutines.
It is also possible that I missed a flag / behaviour change, my apologies in this case and please advise.
Error message:
Python and NumPy Versions:
2.1.2
3.11.10 (main, Sep 8 2024, 14:25:06) [GCC 14.2.1 20240801 (Red Hat 14.2.1-1)]
Runtime Environment:
[{'numpy_version': '2.1.2',
'python': '3.11.10 (main, Sep 8 2024, 14:25:06) [GCC 14.2.1 20240801 (Red '
'Hat 14.2.1-1)]',
'uname': uname_result(system='Linux', node='w.2sn.net', release='6.11.3-200.fc40.x86_64', version='#1 SMP PREEMPT_DYNAMIC Thu Oct 10 22:31:19 UTC 2024', machine='x86_64')},
{'simd_extensions': {'baseline': ['SSE', 'SSE2', 'SSE3'],
'found': ['SSSE3',
'SSE41',
'POPCNT',
'SSE42',
'AVX',
'F16C',
'FMA3',
'AVX2',
'AVX512F',
'AVX512CD',
'AVX512_SKX'],
'not_found': ['AVX512_KNL',
'AVX512_KNM',
'AVX512_CLX',
'AVX512_CNL',
'AVX512_ICL']}},
{'architecture': 'SkylakeX',
'filepath': '/home/alex/Python_3.11.10/lib/python3.11/site-packages/numpy.libs/libscipy_openblas64_-ff651d7f.so',
'internal_api': 'openblas',
'num_threads': 16,
'prefix': 'libscipy_openblas',
'threading_layer': 'pthreads',
'user_api': 'blas',
'version': '0.3.27'}]
Context for the issue:
breaks code, can no longer access module data that worked in Numpy < 2.0.
The text was updated successfully, but these errors were encountered: