Skip to content

ENH: Make f2py use multiphase init#31578

Open
da-woods wants to merge 3 commits into
numpy:mainfrom
da-woods:f2py-multiphase-init
Open

ENH: Make f2py use multiphase init#31578
da-woods wants to merge 3 commits into
numpy:mainfrom
da-woods:f2py-multiphase-init

Conversation

@da-woods

@da-woods da-woods commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

PR summary

Adapt f2py to use multiphase init (and on Python 3.15+, to use PEP 793 and 820 init). This is mainly useful for future Limited API support (although mutliphase init is generally "preferred" and so arguably better anyway).

The main complication was the usercode that gets injected into the module init function. This wasn't tested (so I added a test) but user code with error handling requires return NULL to be valid, so I moved it to a separate function that keeps that interface.

One potential issue to flag is if people are doing embedding type things and manually calling the PyInit_ function. This isn't recommended and isn't an insurmountable problem, but will break that case.

AI Disclosure

No AI tools used

Adapt f2py to use multiphase init (and on Python 3.15+, to
use PEP 793 and 820 init). This is mainly useful for future
Limited API support (although mutliphase init is generally
considered the more modern system).

The main complication was the usercode that gets injected into
the module init function. This wasn't tested (so I added a test)
but user code with error handling requires `return NULL` to be
valid, so I moved it to a separate function that keeps that
interface.

One potential issue to flag is if people are doing embedding
type things and manually calling the `PyInit_` function.
This isn't recommended and isn't an insurmountable problem,
but will break that case.
Comment thread numpy/f2py/rules.py
NULL,
NULL
};
static PyObject *f2py_module_interface_usercode(PyObject *m, PyObject *d) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've assumed here that m and d are the function-level variables that people might reasonably use. And that there's no reason for them to use tmp, i and s from the init function.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, sounds fine to me, wrapping it into it's own function is saner anyway. However, I would lean towards adding/keeping the:

#modulename#_module = m;

alias here, which is a nice name. (#modulename#_error seems rather unnecessary to me, though, and I doubt there is a point to f2py_routine_defs or so.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I would lean towards adding/keeping the:

#modulename#_module = m;

I think that's a global so should be available generally. I'll check properly later though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh, right. Nvm, I missed that it is a global (but it also means that it'll keep working either way).

@seberg seberg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM, modulo that one nit that maybe we should include the ..._module alias.

Do you care for this being backported to 2.5, or are f2py extensions a bit "out there" and we don't mind to wait for 2.6 for supporting Py_TARGET_ABI3T for them?

(It seems fine to backport generally, but f2py is a bit annoying and the rc is already out for 2.5.)

Comment thread numpy/f2py/rules.py
NULL,
NULL
};
static PyObject *f2py_module_interface_usercode(PyObject *m, PyObject *d) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, sounds fine to me, wrapping it into it's own function is saner anyway. However, I would lean towards adding/keeping the:

#modulename#_module = m;

alias here, which is a nice name. (#modulename#_error seems rather unnecessary to me, though, and I doubt there is a point to f2py_routine_defs or so.)

Comment thread numpy/f2py/rules.py
@da-woods

da-woods commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Do you care for this being backported to 2.5, [...]

There's a bunch of other stuff to be done to make it work in abi3t. This is essentially just one independent step. If you've got a release candidate already then I'd save this for 2.6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants