8000 gh-66410: Do not stringify arguments of Tkinter callback by serhiy-storchaka · Pull Request #98592 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-66410: Do not stringify arguments of Tkinter callback #98592

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

Merged
merged 5 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'main' into tkinter-obj-cmd
  • Loading branch information
serhiy-storchaka committed May 7, 2024
commit 24165e29f4094ac27f291723e0b8c88bc1ee34e5
89 changes: 80 additions & 9 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2179,15 +2179,86 @@ Porting to Python 3.12
:class:`bytes` type is accepted for bytes strings.
(Contributed by Victor Stinner in :gh:`98393`.)

* Callbacks registered in the :mod:`tkinter` module now take arguments as
various Python objects (``int``, ``float``, ``bytes``, ``tuple``),
not just ``str``.
To restore the previous behavior set :mod:`!tkinter` module global
:data:`~tkinter.wantobject` to ``1`` before creating the
:class:`~tkinter.Tk` object or call the :meth:`~tkinter.Tk.wantobject`
method of the :class:`!Tk` object with argument ``1``.
Calling it with argument ``2`` restores the current default behavior.
(Contributed by Serhiy Storchaka in :gh:`66410`.)
* The :c:macro:`Py_CLEAR`, :c:macro:`Py_SETREF` and :c:macro:`Py_XSETREF`
macros now only evaluate their arguments once. If an argument has side
effects, these side effects are no longer duplicated.
(Contributed by Victor Stinner in :gh:`98724`.)

* The interpreter's error indicator is now always normalized. This means
that :c:func:`PyErr_SetObject`, :c:func:`PyErr_SetString` and the other
functions that set the error indicator now normalize the exception
before storing it. (Contributed by Mark Shannon in :gh:`101578`.)

* ``_Py_RefTotal`` is no longer authoritative and only kept around
for ABI compatibility. Note that it is an internal global and only
available on debug builds. If you happen to be using it then you'll
need to start using ``_Py_GetGlobalRefTotal()``.

* The following functions now select an appropriate metaclass for the newly
created type:

* :c:func:`PyType_FromSpec`
* :c:func:`PyType_FromSpecWithBases`
* :c:func:`PyType_FromModuleAndSpec`

Creating classes whose metaclass overrides :c:member:`~PyTypeObject.tp_new`
is deprecated, and in Python 3.14+ it will be disallowed.
Note that these functions ignore ``tp_new`` of the metaclass, possibly
allowing incomplete initialization.

Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12)
already disallows creating classes whose metaclass overrides ``tp_new``
(:meth:`~object.__new__` in Python).

Since ``tp_new`` overrides almost everything ``PyType_From*`` functions do,
the two are incompatible with each other.
The existing behavior -- ignoring the metaclass for several steps
of type creation -- is unsafe in general, since (meta)classes assume that
``tp_new`` was called.
There is no simple general workaround. One of the following may work for you:

- If you control the metaclass, avoid using ``tp_new`` in it:

- If initialization can be skipped, it can be done in
:c:member:`~PyTypeObject.tp_init` instead.
- If the metaclass doesn't need to be instantiated from Python,
set its ``tp_new`` to ``NULL`` using
the :c:macro:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag.
This makes it acceptable for ``PyType_From*`` functions.

- Avoid ``PyType_From*`` functions: if you don't need C-specific features
(slots or setting the instance size), create types by :ref:`calling <call>`
the metaclass.

- If you *know* the ``tp_new`` can be skipped safely, filter the deprecation
warning out using :func:`warnings.catch_warnings` from Python.

* :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no
longer called in :ref:`subinterpreters <sub-interpreter-support>`. This is
because clients generally rely on process-wide global state (since these
callbacks have no way of recovering extension module state).

This also avoids situations where extensions may find themselves running in a
subinterpreter that they don't support (or haven't yet been loaded in). See
:gh:`104668` for more info.

* :c:struct:`PyLongObject` has had its internals changed for better performance.
Although the internals of :c:struct:`PyLongObject` are private, they are used
by some extension modules.
The internal fields should no longer be accessed directly, instead the API
functions beginning ``PyLong_...`` should be used instead.
Two new *unstable* API functions are provided for efficient access to the
value of :c:struct:`PyLongObject`\s which fit into a single machine word:

* :c:func:`PyUnstable_Long_IsCompact`
* :c:func:`PyUnstable_Long_CompactValue`

* Custom allocators, set via :c:func:`PyMem_SetAllocator`, are now
required to be thread-safe, regardless of memory domain. Allocators
that don't have their own state, including "hooks", are not affected.
If your custom allocator is not already thread-safe and you need
guidance then please create a new GitHub issue
and CC ``@ericsnowcurrently``.

Deprecated
----------
Expand Down
10 changes: 10 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1855,6 +1855,16 @@ Changes in the Python API
to :c:func:`PyUnstable_Code_GetFirstFree`.
(Contributed by Bogdan Romanyuk in :gh:`115781`.)

* Callbacks registered in the :mod:`tkinter` module now take arguments as
various Python objects (``int``, ``float``, ``bytes``, ``tuple``),
not just ``str``.
To restore the previous behavior set :mod:`!tkinter` module global
:data:`!wantobject` to ``1`` before creating the
:class:`!Tk` object or call the :meth:`!wantobject`
method of the :class:`!Tk` object with argument ``1``.
Calling it with argument ``2`` restores the current default behavior.
(Contributed by Serhiy Storchaka in :gh:`66410`.)


Build Changes
=============
Expand Down
3 changes: 2 additions & 1 deletion Lib/idlelib/redirector.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ def dispatch(self, operation, *args):
to *args to accomplish that. For an example, see colorizer.py.

'''
m = self._operations.get(str(operation))
operation = str(operation) # can be a Tcl_Obj
m = self._operations.get(operation)
try:
if m:
return m(*args)
Expand Down
3 changes: 2 additions & 1 deletion Lib/tkinter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import re

wantobjects = 2
_debug = False # set to True to print executed Tcl/Tk commands

TkVersion = float(_tkinter.TK_VERSION)
TclVersion = float(_tkinter.TCL_VERSION)
Expand Down Expand Up @@ -1762,7 +1763,7 @@ def getint_event(s):
e.type = EventType(T)
except ValueError:
try:
e.type = EventType(str(T))
e.type = EventType(str(T)) # can be int
except ValueError:
e.type = T
try:
Expand Down
9 changes: 4 additions & 5 deletions Modules/_tkinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -2386,9 +2386,8 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name,
if (!data)
return PyErr_NoMemory();
Py_INCREF(self);
Py_INCREF(func);
data->self = self;
data->func = func;
data->func = Py_NewRef(func);
if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
Tcl_Condition cond = NULL;
CommandEvent *ev = (CommandEvent*)attemptckalloc(sizeof(CommandEvent));
Expand Down Expand Up @@ -2901,7 +2900,7 @@ Tkapp_WantObjects(PyObject *self, PyObject *args)
{

int wantobjects = -1;
if (!PyArg_ParseTuple(args, "|p:wantobjects", &wantobjects))
if (!PyArg_ParseTuple(args, "|i:wantobjects", &wantobjects))
return NULL;
if (wantobjects == -1)
return PyLong_FromLong(((TkappObject*)self)->wantobjects);
Expand Down Expand Up @@ -3090,7 +3089,7 @@ _tkinter.create
baseName: str = ""
className: str = "Tk"
interactive: bool = False
wantobjects: bool = False
wantobjects: int = 0
wantTk: bool = True
if false, then Tk_Init() doesn't get called
sync: bool = False
Expand All @@ -3106,7 +3105,7 @@ _tkinter_create_impl(PyObject *module, const char *screenName,
const char *baseName, const char *className,
int interactive, int wantobjects, int wantTk, int sync,
const char *use)
/*[clinic end generated code: output=e3315607648e6bb4 input=09afef9adea70a19]*/
/*[clinic end generated code: output=e3315607648e6bb4 input=7e382ba431bed537]*/
{
/* XXX baseName is not used anymore;
* try getting rid of it. */
Expand Down
8 changes: 4 additions & 4 deletions Modules/clinic/_tkinter.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.
0