Skip to content

python 3.13 support - #442

Merged
wesgarland merged 47 commits into
mainfrom
Xmader/feat/python-3.13-support
Oct 10, 2024
Merged

python 3.13 support#442
wesgarland merged 47 commits into
mainfrom
Xmader/feat/python-3.13-support

Conversation

@Xmader

@XmaderXmader commented Sep 12, 2024

Copy link
Copy Markdown
Member

In order to make PythonMonkey support the upcoming (October 1, 2024) Python 3.13 release, the following changes/actions need to be made in the codebase:


Closes#441

Comment threadinclude/dictviewShim.hh Outdated
`_Py_IsFinalizing` becomes a stable API in Python 3.13, and is renamed to `Py_IsFinalizing`
https://docs.python.org/3.13/c-api/init.html#c.Py_IsFinalizing
Since Python 3.13, `_PyDictView_New` function became an internal API.
Python 3.13 moved this undocumented function to private API.
See python/cpython#108607
@Xmader
Xmader marked this pull request as ready for review September 20, 2024 08:43
@Xmader
Xmaderforce-pushed the Xmader/feat/python-3.13-support branch from 56aed76 to 46909e3CompareSeptember 23, 2024 21:58
@Xmader
Xmaderforce-pushed the Xmader/feat/python-3.13-support branch from 46909e3 to 623d83eCompareSeptember 23, 2024 22:13
`_PyErr_SetKeyError` is more complex than originally thought, use the provided API when possible
See also python/cpython#101578
@zollqir
zollqir self-requested a review September 24, 2024 14:36

@zollqirzollqir left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I noticed that only on python 3.13, the eval-test.simple test says

"Exception ignored in: <_io.BufferedReader name='/home/runner/work/PythonMonkey/PythonMonkey/tests/js/resources/eval-test.js'>"

I looked into it briefly, looks to be something to do with the file being closed more than once somehow.

zollqir
zollqir previously requested changes Sep 24, 2024

@zollqirzollqir left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Overall looks great, just some minor changes

Comment on lines +85 to 90
# Python 3.13 dramatically changed how the namespace in `exec`/`eval` works
# See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals
_locals = {} # keep the local variables inside `eval`/`exec` to a dict
globalThis.python.eval = lambda x: eval(x, None, _locals)
globalThis.python.exec = lambda x: exec(x, None, _locals)
globalThis.python.getenv = os.getenv

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
# Python 3.13 dramatically changed how the namespace in `exec`/`eval` works
# See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals
_locals= {} # keep the local variables inside `eval`/`exec` to a dict
globalThis.python.eval=lambdax: eval(x, None, _locals)
globalThis.python.exec=lambdax: exec(x, None, _locals)
globalThis.python.getenv=os.getenv
# Python 3.13 dramatically changed how the namespace in `exec`/`eval` works
# See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals
globalThis.python.eval=lambdax: eval(x, None, sys._getframe(1).f_locals)
globalThis.python.exec=lambdax: exec(x, None, sys._getframe(1).f_locals)

Without the above change, pythonmonkey would lose the ability to mutate parent scope variables with pm.eval. On main the following assert passes, but it currently fails on this branch. We should add a test to ensure this behaviour as well.

importpythonmonkeyaspma=42pm.eval("python.exec('a = 43')")
asserta==43

While on the subject, the following currently fails on main, but probably shouldn't. The above change fixes that as well.

importpythonmonkeyaspmdeffoo():
b=42pm.eval("python.exec('b = 43')")
assertb==43foo()

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

https://docs.python.org/3/library/functions.html#exec

In all cases, if the optional parts are omitted, the code is executed in the current scope. If only globals is provided, it must be a dictionary (and not a subclass of dictionary), which will be used for both the global and the local variables. If globals and locals are given, they are used for the global and local variables, respectively. If provided, locals can be any mapping object. Remember that at the module level, globals and locals are the same dictionary.

https://github.com/python/cpython/blob/v3.9.20/Python/bltinmodule.c#L979-L985

if (globals==Py_None) {
globals=PyEval_GetGlobals();
if (locals==Py_None) {
locals=PyEval_GetLocals();
if (locals==NULL)
returnNULL;
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On main

In your first example, a is defined in the global scope, exec can catch it and re-assign it without any problem.

However, in your second example, b is defined in the local scope of the foo() function. Since the exec is executed inside of require.py, it can only see the variables defined in require.py as its "locals".

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

"Without the above change, pythonmonkey would lose the ability to mutate parent scope variables with pm.eval. "

Question: is there a problem with losing that ability?

From a clean design POV, it's probably best to not let the languages mutate each other's scopes, except when those scoping objects are deliberately made available to this, i.e. in the case of globalThis.

The fact that Python modules have a scoping semantic not understand in JS-land underscores this from my POV.

If we made python.eval work more like indirect eval in JS, it would probably be a saner coding environment for our users, even though it might be a breaking change. And since the only code we really care about at this early stage is our test cases and BiFrost2, we control everything, so we can fix API and code in lock-step if necessary.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i.e. to clarify: if we can change PythonMonkey to work with 3.13, and make it work the same in less than 3.13, I think that's probably okay. If a JS developer REALLY needs to mutate a Python scope, that dev can just pass in the scoping object, right?

Comment threadsrc/IntType.cc Outdated
Comment threadinclude/pyshim.hh Outdated
Comment threadsrc/PyEventLoop.cc
Comment threadinclude/pyshim.hh
Comment threadinclude/pyshim.hh
Comment threadinclude/pyshim.hh
Xmaderand others added 11 commits September 25, 2024 17:41
…llOneArg` in all Python versions we support, so no need to do a shim on our own
This commit reverts `bcfcbf35ce5ae10bb3542052cdccadf48e95cdca`
…llObject(func, NULL)`, which is available in all Python versions
…exec`/`eval`
Co-authored-by: Caleb Aikens <caleb@distributive.network>
Python 3.13 was finally released on October 7, 2024.
GitHub Actions' `actions/setup-python` already added support for the final release version.
See https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json
Something is double-free-ed during the final finalization: in a debug build of Python, `./Include/object.h:602: _Py_NegativeRefcount: Assertion failed: object has negative ref count`
In non-debug build of Python, it simply segfaults at the end during finalization.
@wesgarland
wesgarland dismissed zollqir’s stale reviewOctober 10, 2024 16:31

moved to other issue

@wesgarlandwesgarland left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python 3.13 support

5 participants

@Xmader@wesgarland@zollqir@philippedistributive@philippe-distributive