Skip to content

Commit a5a15b2

Browse files
committed
fix(time): make struct_time type immutable
1 parent 053f101 commit a5a15b2

6 files changed

Lines changed: 11 additions & 18 deletions

File tree

‎Doc/c-api/tuple.rst‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,6 @@ type.
232232
Creates an instance of *type*, which must have been created with
233233
:c:func:`PyStructSequence_NewType`.
234234
235-
The returned instance is not tracked by the garbage collector. If the
236-
instance can contain objects that participate in reference cycles, call
237-
:c:func:`PyObject_GC_Track` after populating its fields.
238-
239235
Return ``NULL`` with an exception set on failure.
240236
241237

‎Lib/test/test_structseq.py‎

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,9 @@ def test_reference_cycle(self):
351351
# was cleared first, the structseq instance would crash in the
352352
# destructor.
353353
script_helper.assert_python_ok("-c", textwrap.dedent(r"""
354-
import time
355-
t = time.gmtime()
356-
type(t).refcyle = t
354+
import os
355+
t = os.stat('.')
356+
type(t).refcycle = t
357357
"""))
358358

359359
def test_replace_gc_tracked(self):
@@ -365,12 +365,10 @@ def test_replace_gc_tracked(self):
365365

366366
self.assertTrue(gc.is_tracked(replaced_struct))
367367

368-
def test_gc_tracked(self):
369-
# Instances created via Python or stdlib callers that may participate
370-
# in cycles are GC-tracked; simple instances like os.stat_result are not.
371-
self.assertTrue(gc.is_tracked(time.gmtime()))
372-
self.assertTrue(gc.is_tracked(time.struct_time((2020, 1, 1, 0, 0, 0, 0, 1, 0))))
373-
self.assertFalse(gc.is_tracked(os.stat(__file__)))
368+
def test_struct_time_type_immutable(self):
369+
t = time.gmtime()
370+
with self.assertRaisesRegex(TypeError, "immutable type"):
371+
type(t).refcycle = t
374372

375373
if __name__ == "__main__":
376374
unittest.main()

‎Lib/test/test_sys.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1969,7 +1969,6 @@ def test_asyncgen_hooks(self):
19691969

19701970
sys.set_asyncgen_hooks(firstiter=firstiter)
19711971
hooks = sys.get_asyncgen_hooks()
1972-
self.assertTrue(gc.is_tracked(hooks))
19731972
self.assertIs(hooks.firstiter, firstiter)
19741973
self.assertIs(hooks[0], firstiter)
19751974
self.assertIs(hooks.finalizer, None)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Track :func:`time.struct_time` and :func:`sys.get_asyncgen_hooks` objects in the garbage collector to prevent reference cycle leaks. Patch by Shamil Abdulaev.
1+
Make the :class:`time.struct_time` type immutable to prevent reference cycles between the type and its instances. Patch by Shamil Abdulaev.

‎Modules/timemodule.c‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "pycore_moduleobject.h" // _PyModule_GetState()
66
#include "pycore_namespace.h" // _PyNamespace_New()
77
#include "pycore_runtime.h" // _Py_ID()
8+
#include "pycore_structseq.h" // _PyStructSequence_NewType()
89
#include "pycore_time.h" // _PyTimeFraction
910

1011
#include <time.h> // clock()
@@ -497,7 +498,6 @@ tmtotuple(time_module_state *state, struct tm *p
497498
#undef SET
498499
#undef SET_ITEM
499500

500-
PyObject_GC_Track(v);
501501
return v;
502502
}
503503

@@ -2111,7 +2111,8 @@ time_exec(PyObject *module)
21112111
}
21122112

21132113
// struct_time type
2114-
state->struct_time_type = PyStructSequence_NewType(&struct_time_type_desc);
2114+
state->struct_time_type = _PyStructSequence_NewType(
2115+
&struct_time_type_desc, Py_TPFLAGS_IMMUTABLETYPE);
21152116
if (state->struct_time_type == NULL) {
21162117
return -1;
21172118
}

‎Python/sysmodule.c‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,6 @@ sys_get_asyncgen_hooks_impl(PyObject *module)
15311531
PyStructSequence_SET_ITEM(res, 0, Py_NewRef(firstiter));
15321532
PyStructSequence_SET_ITEM(res, 1, Py_NewRef(finalizer));
15331533

1534-
PyObject_GC_Track(res);
15351534
return res;
15361535
}
15371536

0 commit comments

Comments
 (0)