Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 287f8b0

Browse files
committed
Merge branch 'main' into copy-replace-structseq
2 parents d90e5ae + fc2cb86 commit 287f8b0

26 files changed

+204
-67
lines changed

Doc/c-api/object.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,3 +489,21 @@ Object Protocol
489489
:c:macro:`Py_TPFLAGS_ITEMS_AT_END` set.
490490
491491
.. versionadded:: 3.12
492+
493+
.. c:function:: int PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
494+
495+
Visit the managed dictionary of *obj*.
496+
497+
This function must only be called in a traverse function of the type which
498+
has the :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag set.
499+
500+
.. versionadded:: 3.13
501+
502+
.. c:function:: void PyObject_ClearManagedDict(PyObject *obj)
503+
504+
Clear the managed dictionary of *obj*.
505+
506+
This function must only be called in a traverse function of the type which
507+
has the :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag set.
508+
509+
.. versionadded:: 3.13

Doc/c-api/typeobj.rst

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,9 @@ and :c:data:`PyType_Type` effectively act as defaults.)
11311131

11321132
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
11331133

1134+
The type traverse function must call :c:func:`PyObject_VisitManagedDict`
1135+
and its clear function must call :c:func:`PyObject_ClearManagedDict`.
1136+
11341137
.. versionadded:: 3.12
11351138

11361139
**Inheritance:**
@@ -1368,6 +1371,23 @@ and :c:data:`PyType_Type` effectively act as defaults.)
13681371
debugging aid you may want to visit it anyway just so the :mod:`gc` module's
13691372
:func:`~gc.get_referents` function will include it.
13701373

1374+
Heap types (:c:macro:`Py_TPFLAGS_HEAPTYPE`) must visit their type with::
1375+
1376+
Py_VISIT(Py_TYPE(self));
1377+
1378+
It is only needed since Python 3.9. To support Python 3.8 and older, this
1379+
line must be conditionnal::
1380+
1381+
#if PY_VERSION_HEX >= 0x03090000
1382+
Py_VISIT(Py_TYPE(self));
1383+
#endif
1384+
1385+
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
1386+
:c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
1387+
:c:func:`PyObject_VisitManagedDict` like this::
1388+
1389+
PyObject_VisitManagedDict((PyObject*)self, visit, arg);
1390+
13711391
.. warning::
13721392
When implementing :c:member:`~PyTypeObject.tp_traverse`, only the
13731393
members that the instance *owns* (by having :term:`strong references
@@ -1451,6 +1471,12 @@ and :c:data:`PyType_Type` effectively act as defaults.)
14511471
so that *self* knows the contained object can no longer be used. The
14521472
:c:func:`Py_CLEAR` macro performs the operations in a safe order.
14531473

1474+
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
1475+
:c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
1476+
:c:func:`PyObject_ClearManagedDict` like this::
1477+
1478+
PyObject_ClearManagedDict((PyObject*)self);
1479+
14541480
Note that :c:member:`~PyTypeObject.tp_clear` is not *always* called
14551481
before an instance is deallocated. For example, when reference counting
14561482
is enough to determine that an object is no longer used, the cyclic garbage
@@ -1801,7 +1827,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
18011827
field is ``NULL`` then no :attr:`~object.__dict__` gets created for instances.
18021828

18031829
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
1804-
:c:member:`~PyTypeObject.tp_dict` field, then
1830+
:c:member:`~PyTypeObject.tp_flags` field, then
18051831
:c:member:`~PyTypeObject.tp_dictoffset` will be set to ``-1``, to indicate
18061832
that it is unsafe to use this field.
18071833

Doc/data/stable_abi.dat

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Doc/using/windows.rst

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -867,17 +867,18 @@ For example, if the first line of your script starts with
867867
868868
#! /usr/bin/python
869869
870-
The default Python will be located and used. As many Python scripts written
871-
to work on Unix will already have this line, you should find these scripts can
872-
be used by the launcher without modification. If you are writing a new script
873-
on Windows which you hope will be useful on Unix, you should use one of the
874-
shebang lines starting with ``/usr``.
870+
The default Python or an active virtual environment will be located and used.
871+
As many Python scripts written to work on Unix will already have this line,
872+
you should find these scripts can be used by the launcher without modification.
873+
If you are writing a new script on Windows which you hope will be useful on
874+
Unix, you should use one of the shebang lines starting with ``/usr``.
875875

876876
Any of the above virtual commands can be suffixed with an explicit version
877877
(either just the major version, or the major and minor version).
878878
Furthermore the 32-bit version can be requested by adding "-32" after the
879879
minor version. I.e. ``/usr/bin/python3.7-32`` will request usage of the
880-
32-bit python 3.7.
880+
32-bit Python 3.7. If a virtual environment is active, the version will be
881+
ignored and the environment will be used.
881882

882883
.. versionadded:: 3.7
883884

@@ -891,6 +892,13 @@ minor version. I.e. ``/usr/bin/python3.7-32`` will request usage of the
891892
not provably i386/32-bit". To request a specific environment, use the new
892893
:samp:`-V:{TAG}` argument with the complete tag.
893894

895+
.. versionchanged:: 3.13
896+
897+
Virtual commands referencing ``python`` now prefer an active virtual
898+
environment rather than searching :envvar:`PATH`. This handles cases where
899+
the shebang specifies ``/usr/bin/env python3`` but :file:`python3.exe` is
900+
not present in the active environment.
901+
894902
The ``/usr/bin/env`` form of shebang line has one further special property.
895903
Before looking for installed Python interpreters, this form will search the
896904
executable :envvar:`PATH` for a Python executable matching the name provided

Doc/whatsnew/3.12.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ Significant improvements in the standard library:
121121
* A :ref:`command-line interface <uuid-cli>` has been added to the
122122
:mod:`uuid` module
123123
* Due to the changes in :ref:`PEP 701 <whatsnew312-pep701>`,
124-
producing tokens via the :mod:`tokenize` module is up to up to 64% faster.
124+
producing tokens via the :mod:`tokenize` module is up to 64% faster.
125125

126126
Security improvements:
127127

@@ -2123,7 +2123,7 @@ Porting to Python 3.12
21232123
The use of ``tp_dictoffset`` and ``tp_weaklistoffset`` is still
21242124
supported, but does not fully support multiple inheritance
21252125
(:gh:`95589`), and performance may be worse.
2126-
Classes declaring :c:macro:`Py_TPFLAGS_MANAGED_DICT` should call
2126+
Classes declaring :c:macro:`Py_TPFLAGS_MANAGED_DICT` must call
21272127
:c:func:`!_PyObject_VisitManagedDict` and :c:func:`!_PyObject_ClearManagedDict`
21282128
to traverse and clear their instance's dictionaries.
21292129
To clear weakrefs, call :c:func:`PyObject_ClearWeakRefs`, as before.

Doc/whatsnew/3.13.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,12 @@ New Features
995995
references) now supports the :ref:`Limited API <limited-c-api>`.
996996
(Contributed by Victor Stinner in :gh:`108634`.)
997997

998+
* Add :c:func:`PyObject_VisitManagedDict` and
999+
:c:func:`PyObject_ClearManagedDict` functions which must be called by the
1000+
traverse and clear functions of a type using
1001+
:c:macro:`Py_TPFLAGS_MANAGED_DICT` flag.
1002+
(Contributed by Victor Stinner in :gh:`107073`.)
1003+
9981004
Porting to Python 3.13
9991005
----------------------
10001006

@@ -1290,3 +1296,6 @@ removed, although there is currently no date scheduled for their removal.
12901296
* :c:func:`PyThread_get_key_value`: use :c:func:`PyThread_tss_get`.
12911297
* :c:func:`PyThread_delete_key_value`: use :c:func:`PyThread_tss_delete`.
12921298
* :c:func:`PyThread_ReInitTLS`: no longer needed.
1299+
1300+
* Remove undocumented ``PY_TIMEOUT_MAX`` constant from the limited C API.
1301+
(Contributed by Victor Stinner in :gh:`110014`.)

Include/cpython/object.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,8 @@ PyAPI_FUNC(int) _PyTrash_cond(PyObject *op, destructor dealloc);
444444

445445
PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);
446446

447-
PyAPI_FUNC(int) _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
448-
PyAPI_FUNC(void) _PyObject_ClearManagedDict(PyObject *obj);
447+
PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
448+
PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj);
449449

450450
#define TYPE_MAX_WATCHERS 8
451451

Include/cpython/pythread.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
# error "this header file must not be included directly"
33
#endif
44

5+
// PY_TIMEOUT_MAX is the highest usable value (in microseconds) of PY_TIMEOUT_T
6+
// type, and depends on the system threading API.
7+
//
8+
// NOTE: this isn't the same value as `_thread.TIMEOUT_MAX`. The _thread module
9+
// exposes a higher-level API, with timeouts expressed in seconds and
10+
// floating-point numbers allowed.
11+
PyAPI_DATA(const long long) PY_TIMEOUT_MAX;
12+
513
#define PYTHREAD_INVALID_THREAD_ID ((unsigned long)-1)
614

715
#ifdef HAVE_PTHREAD_H

Include/pythread.h

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,18 @@ PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int);
3333
#define WAIT_LOCK 1
3434
#define NOWAIT_LOCK 0
3535

36-
/* PY_TIMEOUT_T is the integral type used to specify timeouts when waiting
37-
on a lock (see PyThread_acquire_lock_timed() below).
38-
PY_TIMEOUT_MAX is the highest usable value (in microseconds) of that
39-
type, and depends on the system threading API.
40-
41-
NOTE: this isn't the same value as `_thread.TIMEOUT_MAX`. The _thread
42-
module exposes a higher-level API, with timeouts expressed in seconds
43-
and floating-point numbers allowed.
44-
*/
36+
// PY_TIMEOUT_T is the integral type used to specify timeouts when waiting
37+
// on a lock (see PyThread_acquire_lock_timed() below).
4538
#define PY_TIMEOUT_T long long
4639

47-
PyAPI_DATA(const long long) PY_TIMEOUT_MAX;
48-
4940

5041
/* If microseconds == 0, the call is non-blocking: it returns immediately
5142
even when the lock can't be acquired.
5243
If microseconds > 0, the call waits up to the specified duration.
5344
If microseconds < 0, the call waits until success (or abnormal failure)
5445
55-
microseconds must be less than PY_TIMEOUT_MAX. Behaviour otherwise is
56-
undefined.
46+
If *microseconds* is greater than PY_TIMEOUT_MAX, clamp the timeout to
47+
PY_TIMEOUT_MAX microseconds.
5748
5849
If intr_flag is true and the acquire is interrupted by a signal, then the
5950
call will return PY_LOCK_INTR. The caller may reattempt to acquire the

Lib/test/test_launcher.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,3 +717,25 @@ def test_literal_shebang_invalid_template(self):
717717
f"{expect} arg1 {script}",
718718
data["stdout"].strip(),
719719
)
720+
721+
def test_shebang_command_in_venv(self):
722+
stem = "python-that-is-not-on-path"
723+
724+
# First ensure that our test name doesn't exist, and the launcher does
725+
# not match any installed env
726+
with self.script(f'#! /usr/bin/env {stem} arg1') as script:
727+
data = self.run_py([script], expect_returncode=103)
728+
729+
with self.fake_venv() as (venv_exe, env):
730+
# Put a real Python (ourselves) on PATH as a distraction.
731+
# The active VIRTUAL_ENV should be preferred when the name isn't an
732+
# exact match.
733+
env["PATH"] = f"{Path(sys.executable).parent};{os.environ['PATH']}"
734+
735+
with self.script(f'#! /usr/bin/env {stem} arg1') as script:
736+
data = self.run_py([script], env=env)
737+
self.assertEqual(data["stdout"].strip(), f"{venv_exe} arg1 {script}")
738+
739+
with self.script(f'#! /usr/bin/env {Path(sys.executable).stem} arg1') as script:
740+
data = self.run_py([script], env=env)
741+
self.assertEqual(data["stdout"].strip(), f"{sys.executable} arg1 {script}")

Lib/test/test_stable_abi_ctypes.py

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_typing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ def test_many_weakrefs(self):
550550
with self.subTest(cls=cls):
551551
vals = weakref.WeakValueDictionary()
552552

553-
for x in range(100000):
553+
for x in range(10):
554554
vals[x] = cls(str(x))
555555
del vals
556556

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add :c:func:`PyObject_VisitManagedDict` and :c:func:`PyObject_ClearManagedDict`
2+
functions which must be called by the traverse and clear functions of a type
3+
using :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag. Patch by Victor Stinner.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Remove undocumented ``PY_TIMEOUT_MAX`` constant from the limited C API.
2+
Patch by Victor Stinner.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Changes the :ref:`launcher` to prefer an active virtual environment when the
2+
launched script has a shebang line using a Unix-like virtual command, even
3+
if the command requests a specific version of Python.

Misc/stable_abi.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,10 +1843,6 @@
18431843
[function.PyThread_start_new_thread]
18441844
added = '3.2'
18451845

1846-
# Not mentioned in PEP 384, was implemented as a macro in Python <= 3.12
1847-
[data.PY_TIMEOUT_MAX]
1848-
added = '3.2'
1849-
18501846
# The following were added in PC/python3.def in Python 3.3:
18511847
# 7800f75827b1be557be16f3b18f5170fbf9fae08
18521848
# 9c56409d3353b8cd4cfc19e0467bbe23fd34fc92

Modules/_asynciomodule.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ FutureObj_clear(FutureObj *fut)
816816
Py_CLEAR(fut->fut_source_tb);
817817
Py_CLEAR(fut->fut_cancel_msg);
818818
Py_CLEAR(fut->fut_cancelled_exc);
819-
_PyObject_ClearManagedDict((PyObject *)fut);
819+
PyObject_ClearManagedDict((PyObject *)fut);
820820
return 0;
821821
}
822822

@@ -834,7 +834,7 @@ FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
834834
Py_VISIT(fut->fut_source_tb);
835835
Py_VISIT(fut->fut_cancel_msg);
836836
Py_VISIT(fut->fut_cancelled_exc);
837-
_PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
837+
PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
838838
return 0;
839839
}
840840

@@ -2181,7 +2181,7 @@ TaskObj_traverse(TaskObj *task, visitproc visit, void *arg)
21812181
Py_VISIT(fut->fut_source_tb);
21822182
Py_VISIT(fut->fut_cancel_msg);
21832183
Py_VISIT(fut->fut_cancelled_exc);
2184-
_PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
2184+
PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
21852185
return 0;
21862186
}
21872187

Modules/_testcapi/heaptype.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -805,21 +805,21 @@ static int
805805
heapmanaged_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
806806
{
807807
Py_VISIT(Py_TYPE(self));
808-
return _PyObject_VisitManagedDict((PyObject *)self, visit, arg);
808+
return PyObject_VisitManagedDict((PyObject *)self, visit, arg);
809809
}
810810

811811
static int
812812
heapmanaged_clear(HeapCTypeObject *self)
813813
{
814-
_PyObject_ClearManagedDict((PyObject *)self);
814+
PyObject_ClearManagedDict((PyObject *)self);
815815
return 0;
816816
}
817817

818818
static void
819819
heapmanaged_dealloc(HeapCTypeObject *self)
820820
{
821821
PyTypeObject *tp = Py_TYPE(self);
822-
_PyObject_ClearManagedDict((PyObject *)self);
822+
PyObject_ClearManagedDict((PyObject *)self);
823823
PyObject_GC_UnTrack(self);
824824
PyObject_GC_Del(self);
825825
Py_DECREF(tp);

Modules/_testcapimodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2923,7 +2923,7 @@ settrace_to_error(PyObject *self, PyObject *list)
29232923
static PyObject *
29242924
clear_managed_dict(PyObject *self, PyObject *obj)
29252925
{
2926-
_PyObject_ClearManagedDict(obj);
2926+
PyObject_ClearManagedDict(obj);
29272927
Py_RETURN_NONE;
29282928
}
29292929

Objects/dictobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5649,7 +5649,7 @@ _PyObject_FreeInstanceAttributes(PyObject *self)
56495649
}
56505650

56515651
int
5652-
_PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
5652+
PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
56535653
{
56545654
PyTypeObject *tp = Py_TYPE(obj);
56555655
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
@@ -5672,7 +5672,7 @@ _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
56725672
}
56735673

56745674
void
5675-
_PyObject_ClearManagedDict(PyObject *obj)
5675+
PyObject_ClearManagedDict(PyObject *obj)
56765676
{
56775677
PyTypeObject *tp = Py_TYPE(obj);
56785678
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {

Objects/typeobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,7 +1835,7 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
18351835
assert(base->tp_dictoffset == 0);
18361836
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
18371837
assert(type->tp_dictoffset == -1);
1838-
int err = _PyObject_VisitManagedDict(self, visit, arg);
1838+
int err = PyObject_VisitManagedDict(self, visit, arg);
18391839
if (err) {
18401840
return err;
18411841
}
@@ -1905,7 +1905,7 @@ subtype_clear(PyObject *self)
19051905
__dict__ slots (as in the case 'self.__dict__ is self'). */
19061906
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
19071907
if ((base->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
1908-
_PyObject_ClearManagedDict(self);
1908+
PyObject_ClearManagedDict(self);
19091909
}
19101910
}
19111911
else if (type->tp_dictoffset != base->tp_dictoffset) {

0 commit comments

Comments
 (0)