2626#endif
2727
2828typedef struct {
29+ /* Static types exposed by the datetime C-API. */
2930 PyTypeObject * date_type ;
3031 PyTypeObject * datetime_type ;
3132 PyTypeObject * delta_type ;
32- PyTypeObject * isocalendar_date_type ;
3333 PyTypeObject * time_type ;
3434 PyTypeObject * tzinfo_type ;
35+ /* Exposed indirectly via TimeZone_UTC. */
3536 PyTypeObject * timezone_type ;
3637
38+ /* Other module classes. */
39+ PyTypeObject * isocalendar_date_type ;
40+
3741 /* Conversion factors. */
3842 PyObject * us_per_ms ; // 1_000
3943 PyObject * us_per_second ; // 1_000_000
@@ -3460,17 +3464,40 @@ static PyMethodDef iso_calendar_date_methods[] = {
34603464 {NULL , NULL },
34613465};
34623466
3463- static PyTypeObject PyDateTime_IsoCalendarDateType = {
3464- PyVarObject_HEAD_INIT (NULL , 0 )
3465- .tp_name = "datetime.IsoCalendarDate" ,
3466- .tp_basicsize = sizeof (PyDateTime_IsoCalendarDate ),
3467- .tp_repr = (reprfunc ) iso_calendar_date_repr ,
3468- .tp_flags = Py_TPFLAGS_DEFAULT ,
3469- .tp_doc = iso_calendar_date__doc__ ,
3470- .tp_methods = iso_calendar_date_methods ,
3471- .tp_getset = iso_calendar_date_getset ,
3472- // .tp_base = &PyTuple_Type, // filled in PyInit__datetime
3473- .tp_new = iso_calendar_date_new ,
3467+ static int
3468+ iso_calendar_date_traverse (PyDateTime_IsoCalendarDate * self , visitproc visit ,
3469+ void * arg )
3470+ {
3471+ Py_VISIT (Py_TYPE (self ));
3472+ return PyTuple_Type .tp_traverse ((PyObject * )self , visit , arg );
3473+ }
3474+
3475+ static void
3476+ iso_calendar_date_dealloc (PyDateTime_IsoCalendarDate * self )
3477+ {
3478+ PyTypeObject * tp = Py_TYPE (self );
3479+ PyTuple_Type .tp_dealloc ((PyObject * )self ); // delegate GC-untrack as well
3480+ Py_DECREF (tp );
3481+ }
3482+
3483+ static PyType_Slot isocal_slots [] = {
3484+ {Py_tp_repr , iso_calendar_date_repr },
3485+ {Py_tp_doc , (void * )iso_calendar_date__doc__ },
3486+ {Py_tp_methods , iso_calendar_date_methods },
3487+ {Py_tp_getset , iso_calendar_date_getset },
3488+ {Py_tp_new , iso_calendar_date_new },
3489+ {Py_tp_dealloc , iso_calendar_date_dealloc },
3490+ {Py_tp_traverse , iso_calendar_date_traverse },
3491+ {0 , NULL },
3492+ };
3493+
3494+ static PyType_Spec isocal_spec = {
3495+ .name = "datetime.IsoCalendarDate" ,
3496+ .basicsize = sizeof (PyDateTime_IsoCalendarDate ),
3497+ .flags = (Py_TPFLAGS_DEFAULT |
3498+ Py_TPFLAGS_HAVE_GC |
3499+ Py_TPFLAGS_IMMUTABLETYPE ),
3500+ .slots = isocal_slots ,
34743501};
34753502
34763503/*[clinic input]
@@ -6842,22 +6869,25 @@ create_timezone_from_delta(int days, int sec, int ms, int normalize)
68426869}
68436870
68446871static int
6845- init_state (datetime_state * st )
6872+ init_state (datetime_state * st , PyTypeObject * PyDateTime_IsoCalendarDateType )
68466873{
68476874 // While datetime uses global module "state", we unly initialize it once.
68486875 // The PyLong objects created here (once per process) are not decref'd.
68496876 if (st -> initialized ) {
68506877 return 0 ;
68516878 }
68526879
6880+ /* Static types exposed by the C-API. */
68536881 st -> date_type = & PyDateTime_DateType ;
68546882 st -> datetime_type = & PyDateTime_DateTimeType ;
68556883 st -> delta_type = & PyDateTime_DeltaType ;
6856- st -> isocalendar_date_type = & PyDateTime_IsoCalendarDateType ;
68576884 st -> time_type = & PyDateTime_TimeType ;
68586885 st -> tzinfo_type = & PyDateTime_TZInfoType ;
68596886 st -> timezone_type = & PyDateTime_TimeZoneType ;
68606887
6888+ /* Per-module heap types. */
6889+ st -> isocalendar_date_type = PyDateTime_IsoCalendarDateType ;
6890+
68616891 st -> us_per_ms = PyLong_FromLong (1000 );
68626892 if (st -> us_per_ms == NULL ) {
68636893 return -1 ;
@@ -6914,11 +6944,10 @@ _datetime_exec(PyObject *module)
69146944 // `&...` is not a constant expression according to a strict reading
69156945 // of C standards. Fill tp_base at run-time rather than statically.
69166946 // See https://bugs.python.org/issue40777
6917- PyDateTime_IsoCalendarDateType .tp_base = & PyTuple_Type ;
69186947 PyDateTime_TimeZoneType .tp_base = & PyDateTime_TZInfoType ;
69196948 PyDateTime_DateTimeType .tp_base = & PyDateTime_DateType ;
69206949
6921- PyTypeObject * types [] = {
6950+ PyTypeObject * capi_types [] = {
69226951 & PyDateTime_DateType ,
69236952 & PyDateTime_DateTimeType ,
69246953 & PyDateTime_TimeType ,
@@ -6927,18 +6956,30 @@ _datetime_exec(PyObject *module)
69276956 & PyDateTime_TimeZoneType ,
69286957 };
69296958
6930- for (size_t i = 0 ; i < Py_ARRAY_LENGTH (types ); i ++ ) {
6931- if (PyModule_AddType (module , types [i ]) < 0 ) {
6959+ for (size_t i = 0 ; i < Py_ARRAY_LENGTH (capi_types ); i ++ ) {
6960+ if (PyModule_AddType (module , capi_types [i ]) < 0 ) {
69326961 goto error ;
69336962 }
69346963 }
69356964
6936- if (PyType_Ready (& PyDateTime_IsoCalendarDateType ) < 0 ) {
6937- goto error ;
6938- }
6965+ #define CREATE_TYPE (VAR , SPEC , BASE ) \
6966+ do { \
6967+ VAR = (PyTypeObject *)PyType_FromModuleAndSpec( \
6968+ module, SPEC, (PyObject *)BASE); \
6969+ if (VAR == NULL) { \
6970+ goto error; \
6971+ } \
6972+ } while (0)
69396973
6974+ PyTypeObject * PyDateTime_IsoCalendarDateType = NULL ;
69406975 datetime_state * st = get_datetime_state ();
6941- if (init_state (st ) < 0 ) {
6976+
6977+ if (!st -> initialized ) {
6978+ CREATE_TYPE (PyDateTime_IsoCalendarDateType , & isocal_spec , & PyTuple_Type );
6979+ }
6980+ #undef CREATE_TYPE
6981+
6982+ if (init_state (st , PyDateTime_IsoCalendarDateType ) < 0 ) {
69426983 goto error ;
69436984 }
69446985
0 commit comments