@@ -32,12 +32,10 @@ static PyTypeObject PyDateTime_TimeType;
3232static PyTypeObject PyDateTime_DeltaType ;
3333static PyTypeObject PyDateTime_TZInfoType ;
3434static PyTypeObject PyDateTime_TimeZoneType ;
35+ static PyTypeObject PyDateTime_IsoCalendarDateType ;
3536
3637
3738typedef struct {
38- /* Module heap types. */
39- PyTypeObject * isocalendar_date_type ;
40-
4139 /* Conversion factors. */
4240 PyObject * us_per_ms ; // 1_000
4341 PyObject * us_per_second ; // 1_000_000
@@ -75,7 +73,7 @@ typedef struct {
7573#define DELTA_TYPE (st ) &PyDateTime_DeltaType
7674#define TZINFO_TYPE (st ) &PyDateTime_TZInfoType
7775#define TIMEZONE_TYPE (st ) &PyDateTime_TimeZoneType
78- #define ISOCALENDAR_DATE_TYPE (st ) st->isocalendar_date_type
76+ #define ISOCALENDAR_DATE_TYPE (st ) &PyDateTime_IsoCalendarDateType
7977
8078#define PyDate_CAST (op ) ((PyDateTime_Date *)(op))
8179#define PyDate_Check (op ) PyObject_TypeCheck(op, DATE_TYPE(NO_STATE))
@@ -102,15 +100,52 @@ typedef struct {
102100
103101#define PyIsoCalendarDate_CAST (op ) ((PyDateTime_IsoCalendarDate *)(op))
104102
105- #define CONST_US_PER_MS (st ) st->us_per_ms
106- #define CONST_US_PER_SECOND (st ) st->us_per_second
107- #define CONST_US_PER_MINUTE (st ) st->us_per_minute
108- #define CONST_US_PER_HOUR (st ) st->us_per_hour
109- #define CONST_US_PER_DAY (st ) st->us_per_day
110- #define CONST_US_PER_WEEK (st ) st->us_per_week
111- #define CONST_SEC_PER_DAY (st ) st->seconds_per_day
112- #define CONST_EPOCH (st ) st->epoch
103+ static inline PyObject *
104+ get_const_us_per_ms (datetime_state * st ) {
105+ return st ? st -> us_per_ms : PyLong_FromLong (1000 );
106+ }
107+
108+ static inline PyObject *
109+ get_const_us_per_second (datetime_state * st ) {
110+ return st ? st -> us_per_second : PyLong_FromLong (1000000 );
111+ }
112+
113+ static inline PyObject *
114+ get_const_us_per_minute (datetime_state * st ) {
115+ return st ? st -> us_per_minute : PyLong_FromLong (60000000 );
116+ }
117+
118+ static inline PyObject *
119+ get_const_us_per_hour (datetime_state * st ) {
120+ return st ? st -> us_per_hour : PyLong_FromDouble (3600000000.0 );
121+ }
122+
123+ static inline PyObject *
124+ get_const_us_per_day (datetime_state * st ) {
125+ return st ? st -> us_per_day : PyLong_FromDouble (86400000000.0 );
126+ }
127+
128+ static inline PyObject *
129+ get_const_us_per_week (datetime_state * st ) {
130+ return st ? st -> us_per_week : PyLong_FromDouble (604800000000.0 );
131+ }
132+
133+ static inline PyObject *
134+ get_const_sec_per_day (datetime_state * st ) {
135+ return st ? st -> seconds_per_day : PyLong_FromLong (24 * 3600 );
136+ }
137+
138+ #define CONST_US_PER_MS (st ) get_const_us_per_ms(st)
139+ #define CONST_US_PER_SECOND (st ) get_const_us_per_second(st)
140+ #define CONST_US_PER_MINUTE (st ) get_const_us_per_minute(st)
141+ #define CONST_US_PER_HOUR (st ) get_const_us_per_hour(st)
142+ #define CONST_US_PER_DAY (st ) get_const_us_per_day(st)
143+ #define CONST_US_PER_WEEK (st ) get_const_us_per_week(st)
144+ #define CONST_SEC_PER_DAY (st ) get_const_sec_per_day(st)
113145#define CONST_UTC (st ) ((PyObject *)&utc_timezone)
146+ #define CONST_EPOCH (st ) \
147+ (st ? ((datetime_state *)st)->epoch \
148+ : new_datetime(1970, 1, 1, 0, 0, 0, 0, (PyObject *)&utc_timezone, 0))
114149
115150static datetime_state *
116151get_module_state (PyObject * module )
@@ -173,6 +208,7 @@ _get_current_state(PyObject **p_mod)
173208 * so we must re-import the module. */
174209 mod = PyImport_ImportModule ("_datetime" );
175210 if (mod == NULL ) {
211+ PyErr_Clear ();
176212 return NULL ;
177213 }
178214 }
@@ -184,7 +220,7 @@ _get_current_state(PyObject **p_mod)
184220#define GET_CURRENT_STATE (MOD_VAR ) \
185221 _get_current_state(&MOD_VAR)
186222#define RELEASE_CURRENT_STATE (ST_VAR , MOD_VAR ) \
187- Py_DECREF (MOD_VAR)
223+ Py_XDECREF (MOD_VAR)
188224
189225static int
190226set_current_module (PyInterpreterState * interp , PyObject * mod )
@@ -3691,40 +3727,19 @@ static PyMethodDef iso_calendar_date_methods[] = {
36913727 {NULL , NULL },
36923728};
36933729
3694- static int
3695- iso_calendar_date_traverse (PyObject * self , visitproc visit , void * arg )
3696- {
3697- Py_VISIT (Py_TYPE (self ));
3698- return PyTuple_Type .tp_traverse (self , visit , arg );
3699- }
3700-
3701- static void
3702- iso_calendar_date_dealloc (PyObject * self )
3703- {
3704- PyTypeObject * tp = Py_TYPE (self );
3705- PyTuple_Type .tp_dealloc (self ); // delegate GC-untrack as well
3706- Py_DECREF (tp );
3707- }
3708-
3709- static PyType_Slot isocal_slots [] = {
3710- {Py_tp_repr , iso_calendar_date_repr },
3711- {Py_tp_doc , (void * )iso_calendar_date__doc__ },
3712- {Py_tp_methods , iso_calendar_date_methods },
3713- {Py_tp_getset , iso_calendar_date_getset },
3714- {Py_tp_new , iso_calendar_date_new },
3715- {Py_tp_dealloc , iso_calendar_date_dealloc },
3716- {Py_tp_traverse , iso_calendar_date_traverse },
3717- {0 , NULL },
3730+ static PyTypeObject PyDateTime_IsoCalendarDateType = {
3731+ PyVarObject_HEAD_INIT (NULL , 0 )
3732+ .tp_name = "datetime.IsoCalendarDate" ,
3733+ .tp_basicsize = sizeof (PyDateTime_IsoCalendarDate ),
3734+ .tp_repr = (reprfunc ) iso_calendar_date_repr ,
3735+ .tp_flags = Py_TPFLAGS_DEFAULT ,
3736+ .tp_doc = iso_calendar_date__doc__ ,
3737+ .tp_methods = iso_calendar_date_methods ,
3738+ .tp_getset = iso_calendar_date_getset ,
3739+ // .tp_base = &PyTuple_Type, // filled in PyInit__datetime
3740+ .tp_new = iso_calendar_date_new ,
37183741};
37193742
3720- static PyType_Spec isocal_spec = {
3721- .name = "datetime.IsoCalendarDate" ,
3722- .basicsize = sizeof (PyDateTime_IsoCalendarDate ),
3723- .flags = (Py_TPFLAGS_DEFAULT |
3724- Py_TPFLAGS_HAVE_GC |
3725- Py_TPFLAGS_IMMUTABLETYPE ),
3726- .slots = isocal_slots ,
3727- };
37283743
37293744/*[clinic input]
37303745@classmethod
@@ -3776,7 +3791,7 @@ date_isocalendar(PyObject *self, PyObject *Py_UNUSED(dummy))
37763791 PyObject * current_mod = NULL ;
37773792 datetime_state * st = GET_CURRENT_STATE (current_mod );
37783793
3779- PyObject * v = iso_calendar_date_new_impl (ISOCALENDAR_DATE_TYPE ( st ) ,
3794+ PyObject * v = iso_calendar_date_new_impl (& PyDateTime_IsoCalendarDateType ,
37803795 year , week + 1 , day + 1 );
37813796 RELEASE_CURRENT_STATE (st , current_mod );
37823797 if (v == NULL ) {
@@ -7155,6 +7170,8 @@ static PyTypeObject * const capi_types[] = {
71557170 & PyDateTime_TZInfoType ,
71567171 /* Indirectly, via the utc object. */
71577172 & PyDateTime_TimeZoneType ,
7173+ /* Not exposed */
7174+ & PyDateTime_IsoCalendarDateType ,
71587175};
71597176
71607177/* The C-API is process-global. This violates interpreter isolation
@@ -7214,25 +7231,10 @@ create_timezone_from_delta(int days, int sec, int ms, int normalize)
72147231static int
72157232init_state (datetime_state * st , PyObject * module , PyObject * old_module )
72167233{
7217- /* Each module gets its own heap types. */
7218- #define ADD_TYPE (FIELD , SPEC , BASE ) \
7219- do { \
7220- PyObject *cls = PyType_FromModuleAndSpec( \
7221- module, SPEC, (PyObject *)BASE); \
7222- if (cls == NULL) { \
7223- return -1; \
7224- } \
7225- st->FIELD = (PyTypeObject *)cls; \
7226- } while (0)
7227-
7228- ADD_TYPE (isocalendar_date_type , & isocal_spec , & PyTuple_Type );
7229- #undef ADD_TYPE
7230-
72317234 if (old_module != NULL ) {
72327235 assert (old_module != module );
72337236 datetime_state * st_old = get_module_state (old_module );
72347237 * st = (datetime_state ){
7235- .isocalendar_date_type = st -> isocalendar_date_type ,
72367238 .us_per_ms = Py_NewRef (st_old -> us_per_ms ),
72377239 .us_per_second = Py_NewRef (st_old -> us_per_second ),
72387240 .us_per_minute = Py_NewRef (st_old -> us_per_minute ),
@@ -7245,42 +7247,41 @@ init_state(datetime_state *st, PyObject *module, PyObject *old_module)
72457247 return 0 ;
72467248 }
72477249
7248- st -> us_per_ms = PyLong_FromLong ( 1000 );
7250+ st -> us_per_ms = CONST_US_PER_MS ( NULL );
72497251 if (st -> us_per_ms == NULL ) {
72507252 return -1 ;
72517253 }
7252- st -> us_per_second = PyLong_FromLong ( 1000000 );
7254+ st -> us_per_second = CONST_US_PER_SECOND ( NULL );
72537255 if (st -> us_per_second == NULL ) {
72547256 return -1 ;
72557257 }
7256- st -> us_per_minute = PyLong_FromLong ( 60000000 );
7258+ st -> us_per_minute = CONST_US_PER_MINUTE ( NULL );
72577259 if (st -> us_per_minute == NULL ) {
72587260 return -1 ;
72597261 }
7260- st -> seconds_per_day = PyLong_FromLong ( 24 * 3600 );
7262+ st -> seconds_per_day = CONST_SEC_PER_DAY ( NULL );
72617263 if (st -> seconds_per_day == NULL ) {
72627264 return -1 ;
72637265 }
72647266
72657267 /* The rest are too big for 32-bit ints, but even
72667268 * us_per_week fits in 40 bits, so doubles should be exact.
72677269 */
7268- st -> us_per_hour = PyLong_FromDouble ( 3600000000.0 );
7270+ st -> us_per_hour = CONST_US_PER_HOUR ( NULL );
72697271 if (st -> us_per_hour == NULL ) {
72707272 return -1 ;
72717273 }
7272- st -> us_per_day = PyLong_FromDouble ( 86400000000.0 );
7274+ st -> us_per_day = CONST_US_PER_DAY ( NULL );
72737275 if (st -> us_per_day == NULL ) {
72747276 return -1 ;
72757277 }
7276- st -> us_per_week = PyLong_FromDouble ( 604800000000.0 );
7278+ st -> us_per_week = CONST_US_PER_WEEK ( NULL );
72777279 if (st -> us_per_week == NULL ) {
72787280 return -1 ;
72797281 }
72807282
72817283 /* Init Unix epoch */
7282- st -> epoch = new_datetime (
7283- 1970 , 1 , 1 , 0 , 0 , 0 , 0 , (PyObject * )& utc_timezone , 0 );
7284+ st -> epoch = CONST_EPOCH (NULL );
72847285 if (st -> epoch == NULL ) {
72857286 return -1 ;
72867287 }
@@ -7291,16 +7292,12 @@ init_state(datetime_state *st, PyObject *module, PyObject *old_module)
72917292static int
72927293traverse_state (datetime_state * st , visitproc visit , void * arg )
72937294{
7294- /* heap types */
7295- Py_VISIT (st -> isocalendar_date_type );
7296-
72977295 return 0 ;
72987296}
72997297
73007298static int
73017299clear_state (datetime_state * st )
73027300{
7303- Py_CLEAR (st -> isocalendar_date_type );
73047301 Py_CLEAR (st -> us_per_ms );
73057302 Py_CLEAR (st -> us_per_second );
73067303 Py_CLEAR (st -> us_per_minute );
@@ -7323,6 +7320,7 @@ init_static_types(PyInterpreterState *interp, int reloading)
73237320 // `&...` is not a constant expression according to a strict reading
73247321 // of C standards. Fill tp_base at run-time rather than statically.
73257322 // See https://bugs.python.org/issue40777
7323+ PyDateTime_IsoCalendarDateType .tp_base = & PyTuple_Type ;
73267324 PyDateTime_TimeZoneType .tp_base = & PyDateTime_TZInfoType ;
73277325 PyDateTime_DateTimeType .tp_base = & PyDateTime_DateType ;
73287326
@@ -7369,6 +7367,9 @@ _datetime_exec(PyObject *module)
73697367
73707368 for (size_t i = 0 ; i < Py_ARRAY_LENGTH (capi_types ); i ++ ) {
73717369 PyTypeObject * type = capi_types [i ];
7370+ if (type == & PyDateTime_IsoCalendarDateType ) {
7371+ continue ;
7372+ }
73727373 const char * name = _PyType_Name (type );
73737374 assert (name != NULL );
73747375 if (PyModule_AddObjectRef (module , name , (PyObject * )type ) < 0 ) {
0 commit comments