From 4a418cb23b39355fa5c8354b7b94533b00940dcc Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 04:09:15 +0900 Subject: [PATCH 01/50] import poc313a5 diff Co-authored-by: Erlend E. Aasland --- Modules/_datetimemodule.c | 1774 +++++++++++++++++++++---------------- 1 file changed, 987 insertions(+), 787 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 06004e258b2eff..4788a1bbbc165e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -25,22 +25,22 @@ # include /* struct timeval */ #endif -#define PyDate_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateType) -#define PyDate_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateType) +#define PyDate_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DateType) +#define PyDate_CheckExact(st, op) Py_IS_TYPE(op, (st)->PyDateTime_DateType) -#define PyDateTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateTimeType) -#define PyDateTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateTimeType) +#define PyDateTime_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DateTimeType) +#define PyDateTime_CheckExact(st, op) Py_IS_TYPE(op, (st)->PyDateTime_DateTimeType) -#define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType) -#define PyTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TimeType) +#define PyTime_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_TimeType) +#define PyTime_CheckExact(st, op) Py_IS_TYPE(op, (st)->PyDateTime_TimeType) -#define PyDelta_Check(op) PyObject_TypeCheck(op, &PyDateTime_DeltaType) -#define PyDelta_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DeltaType) +#define PyDelta_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DeltaType) +#define PyDelta_CheckExact(st, op) Py_IS_TYPE(op, (st)->PyDateTime_DeltaType) -#define PyTZInfo_Check(op) PyObject_TypeCheck(op, &PyDateTime_TZInfoType) -#define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TZInfoType) +#define PyTZInfo_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_TZInfoType) +#define PyTZInfo_CheckExact(st, op) Py_IS_TYPE(op, (st)->PyDateTime_TZInfoType) -#define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType) +#define PyTimezone_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_TimeZoneType) typedef struct { /* Conversion factors. */ @@ -57,11 +57,57 @@ typedef struct { /* The interned Unix epoch datetime instance */ PyObject *epoch; + + /* _strptime module */ + PyObject *strptime; + + /* Types */ + PyTypeObject *PyDateTime_DateType; + PyTypeObject *PyDateTime_DateTimeType; + PyTypeObject *PyDateTime_DeltaType; + PyTypeObject *PyDateTime_IsoCalendarDateType; + PyTypeObject *PyDateTime_TimeType; + PyTypeObject *PyDateTime_TZInfoType; + PyTypeObject *PyDateTime_TimeZoneType; } datetime_state; -static datetime_state _datetime_global_state; +static inline datetime_state * +get_module_state(PyObject *mod) +{ + void *state = _PyModule_GetState(mod); + assert(state != NULL); + return (datetime_state *)state; +} + +static inline datetime_state * +get_module_state_by_cls(PyTypeObject *cls) +{ + void *state = _PyType_GetModuleState(cls); + assert(state != NULL); + return (datetime_state *)state; +} + +static struct PyModuleDef datetimemodule; + +static inline datetime_state * +find_module_state_by_def(PyTypeObject *type) +{ + PyObject *mod = PyType_GetModuleByDef(type, &datetimemodule); + assert(mod != NULL); + return get_module_state(mod); +} + +static inline datetime_state * +find_state_left_or_right(PyObject *left, PyObject *right) +{ + PyObject *mod = _PyType_GetModuleByDef2(Py_TYPE(left), Py_TYPE(right), + &datetimemodule); + assert(mod != NULL); + return get_module_state(mod); +} + +#define find_module_state_by_def(obj) find_module_state_by_def((PyTypeObject *)(obj)) -#define STATIC_STATE() (&_datetime_global_state) /* We require that C int be at least 32 bits, and use int virtually * everywhere. In just a few cases we use a temp long, where a Python @@ -142,16 +188,7 @@ static datetime_state _datetime_global_state; */ #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12) -/* Forward declarations. */ -static PyTypeObject PyDateTime_DateType; -static PyTypeObject PyDateTime_DateTimeType; -static PyTypeObject PyDateTime_DeltaType; -static PyTypeObject PyDateTime_IsoCalendarDateType; -static PyTypeObject PyDateTime_TimeType; -static PyTypeObject PyDateTime_TZInfoType; -static PyTypeObject PyDateTime_TimeZoneType; - -static int check_tzinfo_subclass(PyObject *p); +static int check_tzinfo_subclass(datetime_state *st, PyObject *p); /*[clinic input] module datetime @@ -671,51 +708,6 @@ normalize_datetime(int *year, int *month, int *day, return normalize_date(year, month, day); } -/* --------------------------------------------------------------------------- - * Basic object allocation: tp_alloc implementations. These allocate - * Python objects of the right size and type, and do the Python object- - * initialization bit. If there's not enough memory, they return NULL after - * setting MemoryError. All data members remain uninitialized trash. - * - * We abuse the tp_alloc "nitems" argument to communicate whether a tzinfo - * member is needed. This is ugly, imprecise, and possibly insecure. - * tp_basicsize for the time and datetime types is set to the size of the - * struct that has room for the tzinfo member, so subclasses in Python will - * allocate enough space for a tzinfo member whether or not one is actually - * needed. That's the "ugly and imprecise" parts. The "possibly insecure" - * part is that PyType_GenericAlloc() (which subclasses in Python end up - * using) just happens today to effectively ignore the nitems argument - * when tp_itemsize is 0, which it is for these type objects. If that - * changes, perhaps the callers of tp_alloc slots in this file should - * be changed to force a 0 nitems argument unless the type being allocated - * is a base type implemented in this file (so that tp_alloc is time_alloc - * or datetime_alloc below, which know about the nitems abuse). - */ - -static PyObject * -time_alloc(PyTypeObject *type, Py_ssize_t aware) -{ - size_t size = aware ? sizeof(PyDateTime_Time) : sizeof(_PyDateTime_BaseTime); - PyObject *self = (PyObject *)PyObject_Malloc(size); - if (self == NULL) { - return PyErr_NoMemory(); - } - _PyObject_Init(self, type); - return self; -} - -static PyObject * -datetime_alloc(PyTypeObject *type, Py_ssize_t aware) -{ - size_t size = aware ? sizeof(PyDateTime_DateTime) : sizeof(_PyDateTime_BaseDateTime); - PyObject *self = (PyObject *)PyObject_Malloc(size); - if (self == NULL) { - return PyErr_NoMemory(); - } - _PyObject_Init(self, type); - return self; -} - /* --------------------------------------------------------------------------- * Helpers for setting object fields. These work on pointers to the * appropriate base class. @@ -978,24 +970,26 @@ new_date_ex(int year, int month, int day, PyTypeObject *type) return (PyObject *)self; } -#define new_date(year, month, day) \ - new_date_ex(year, month, day, &PyDateTime_DateType) +#define new_date(st, year, month, day) \ + new_date_ex(year, month, day, st->PyDateTime_DateType) // Forward declaration static PyObject * -new_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *); +new_datetime_ex(datetime_state *st, + int, int, int, int, int, int, int, PyObject *, PyTypeObject *); /* Create date instance with no range checking, or call subclass constructor */ static PyObject * -new_date_subclass_ex(int year, int month, int day, PyObject *cls) +new_date_subclass_ex(datetime_state *st, + int year, int month, int day, PyObject *cls) { PyObject *result; // We have "fast path" constructors for two subclasses: date and datetime - if ((PyTypeObject *)cls == &PyDateTime_DateType) { + if ((PyTypeObject *)cls == st->PyDateTime_DateType) { result = new_date_ex(year, month, day, (PyTypeObject *)cls); } - else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) { - result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None, + else if ((PyTypeObject *)cls == st->PyDateTime_DateTimeType) { + result = new_datetime_ex(st, year, month, day, 0, 0, 0, 0, Py_None, (PyTypeObject *)cls); } else { @@ -1007,8 +1001,10 @@ new_date_subclass_ex(int year, int month, int day, PyObject *cls) /* Create a datetime instance with no range checking. */ static PyObject * -new_datetime_ex2(int year, int month, int day, int hour, int minute, - int second, int usecond, PyObject *tzinfo, int fold, PyTypeObject *type) +new_datetime_ex2(datetime_state *st, + int year, int month, int day, int hour, int minute, + int second, int usecond, PyObject *tzinfo, int fold, + PyTypeObject *type) { PyDateTime_DateTime *self; char aware = tzinfo != Py_None; @@ -1019,7 +1015,7 @@ new_datetime_ex2(int year, int month, int day, int hour, int minute, if (check_time_args(hour, minute, second, usecond, fold) < 0) { return NULL; } - if (check_tzinfo_subclass(tzinfo) < 0) { + if (check_tzinfo_subclass(st, tzinfo) < 0) { return NULL; } @@ -1040,16 +1036,37 @@ new_datetime_ex2(int year, int month, int day, int hour, int minute, } static PyObject * -new_datetime_ex(int year, int month, int day, int hour, int minute, +new_datetime_ex(datetime_state *st, + int year, int month, int day, int hour, int minute, int second, int usecond, PyObject *tzinfo, PyTypeObject *type) { - return new_datetime_ex2(year, month, day, hour, minute, second, usecond, + return new_datetime_ex2(st, year, month, day, hour, minute, second, usecond, tzinfo, 0, type); } -#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo, fold) \ - new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, \ - &PyDateTime_DateTimeType) +static PyObject * +new_datetime_ex_capi(int year, int month, int day, int hour, int minute, + int second, int usecond, PyObject *tzinfo, + PyTypeObject *type) +{ + datetime_state *st = get_module_state_by_cls(type); + return new_datetime_ex(st, year, month, day, hour, minute, second, + usecond, tzinfo, type); +} + +static PyObject * +new_datetime_ex2_capi(int year, int month, int day, int hour, int minute, + int second, int usecond, PyObject *tzinfo, int fold, + PyTypeObject *type) +{ + datetime_state *st = get_module_state_by_cls(type); + return new_datetime_ex2(st, year, month, day, hour, minute, second, + usecond, tzinfo, fold, type); +} + +#define new_datetime(st, y, m, d, hh, mm, ss, us, tzinfo, fold) \ + new_datetime_ex2(st, y, m, d, hh, mm, ss, us, tzinfo, fold, \ + st->PyDateTime_DateTimeType) static PyObject * call_subclass_fold(PyObject *cls, int fold, const char *format, ...) @@ -1086,13 +1103,14 @@ call_subclass_fold(PyObject *cls, int fold, const char *format, ...) } static PyObject * -new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute, +new_datetime_subclass_fold_ex(datetime_state *st, + int year, int month, int day, int hour, int minute, int second, int usecond, PyObject *tzinfo, int fold, PyObject *cls) { PyObject* dt; - if ((PyTypeObject*)cls == &PyDateTime_DateTimeType) { + if ((PyTypeObject*)cls == st->PyDateTime_DateTimeType) { // Use the fast path constructor - dt = new_datetime(year, month, day, hour, minute, second, usecond, + dt = new_datetime(st, year, month, day, hour, minute, second, usecond, tzinfo, fold); } else { @@ -1105,17 +1123,19 @@ new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute } static PyObject * -new_datetime_subclass_ex(int year, int month, int day, int hour, int minute, +new_datetime_subclass_ex(datetime_state *st, + int year, int month, int day, int hour, int minute, int second, int usecond, PyObject *tzinfo, PyObject *cls) { - return new_datetime_subclass_fold_ex(year, month, day, hour, minute, + return new_datetime_subclass_fold_ex(st, year, month, day, hour, minute, second, usecond, tzinfo, 0, cls); } /* Create a time instance with no range checking. */ static PyObject * -new_time_ex2(int hour, int minute, int second, int usecond, +new_time_ex2(datetime_state *st, + int hour, int minute, int second, int usecond, PyObject *tzinfo, int fold, PyTypeObject *type) { PyDateTime_Time *self; @@ -1124,7 +1144,7 @@ new_time_ex2(int hour, int minute, int second, int usecond, if (check_time_args(hour, minute, second, usecond, fold) < 0) { return NULL; } - if (check_tzinfo_subclass(tzinfo) < 0) { + if (check_tzinfo_subclass(st, tzinfo) < 0) { return NULL; } @@ -1145,23 +1165,33 @@ new_time_ex2(int hour, int minute, int second, int usecond, } static PyObject * -new_time_ex(int hour, int minute, int second, int usecond, +new_time_ex_capi(int hour, int minute, int second, int usecond, PyObject *tzinfo, PyTypeObject *type) { - return new_time_ex2(hour, minute, second, usecond, tzinfo, 0, type); + datetime_state *st = get_module_state_by_cls(type); + return new_time_ex2(st, hour, minute, second, usecond, tzinfo, 0, type); +} + +static PyObject * +new_time_ex2_capi(int hour, int minute, int second, int usecond, + PyObject *tzinfo, int fold, PyTypeObject *type) +{ + datetime_state *st = get_module_state_by_cls(type); + return new_time_ex2(st, hour, minute, second, usecond, tzinfo, fold, type); } -#define new_time(hh, mm, ss, us, tzinfo, fold) \ - new_time_ex2(hh, mm, ss, us, tzinfo, fold, &PyDateTime_TimeType) +#define new_time(st, hh, mm, ss, us, tzinfo, fold) \ + new_time_ex2(st, hh, mm, ss, us, tzinfo, fold, st->PyDateTime_TimeType) static PyObject * -new_time_subclass_fold_ex(int hour, int minute, int second, int usecond, +new_time_subclass_fold_ex(datetime_state *st, + int hour, int minute, int second, int usecond, PyObject *tzinfo, int fold, PyObject *cls) { PyObject *t; - if ((PyTypeObject*)cls == &PyDateTime_TimeType) { + if ((PyTypeObject*)cls == st->PyDateTime_TimeType) { // Use the fast path constructor - t = new_time(hour, minute, second, usecond, tzinfo, fold); + t = new_time(st, hour, minute, second, usecond, tzinfo, fold); } else { // Subclass @@ -1202,8 +1232,8 @@ new_delta_ex(int days, int seconds, int microseconds, int normalize, return (PyObject *) self; } -#define new_delta(d, s, us, normalize) \ - new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType) +#define new_delta(st, d, s, us, normalize) \ + new_delta_ex(d, s, us, normalize, st->PyDateTime_DeltaType) typedef struct @@ -1218,13 +1248,13 @@ typedef struct that offset is a timedelta instance and name is either NULL or a unicode object. */ static PyObject * -create_timezone(PyObject *offset, PyObject *name) +create_timezone(datetime_state *st, PyObject *offset, PyObject *name) { PyDateTime_TimeZone *self; - PyTypeObject *type = &PyDateTime_TimeZoneType; + PyTypeObject *type = st->PyDateTime_TimeZoneType; assert(offset != NULL); - assert(PyDelta_Check(offset)); + assert(PyDelta_Check(st, offset)); assert(name == NULL || PyUnicode_Check(name)); self = (PyDateTime_TimeZone *)(type->tp_alloc(type, 0)); @@ -1239,14 +1269,13 @@ create_timezone(PyObject *offset, PyObject *name) static int delta_bool(PyDateTime_Delta *self); static PyObject * -new_timezone(PyObject *offset, PyObject *name) +new_timezone(datetime_state *st, PyObject *offset, PyObject *name) { assert(offset != NULL); - assert(PyDelta_Check(offset)); + assert(PyDelta_Check(st, offset)); assert(name == NULL || PyUnicode_Check(name)); if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) { - datetime_state *st = STATIC_STATE(); return Py_NewRef(st->utc); } if ((GET_TD_DAYS(offset) == -1 && @@ -1260,7 +1289,14 @@ new_timezone(PyObject *offset, PyObject *name) return NULL; } - return create_timezone(offset, name); + return create_timezone(st, offset, name); +} + +static PyObject * +new_timezone_capi(PyObject *offset, PyObject *name) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(offset)); + return new_timezone(st, offset, name); } /* --------------------------------------------------------------------------- @@ -1271,9 +1307,9 @@ new_timezone(PyObject *offset, PyObject *name) * raise TypeError and return -1. */ static int -check_tzinfo_subclass(PyObject *p) +check_tzinfo_subclass(datetime_state *st, PyObject *p) { - if (p == Py_None || PyTZInfo_Check(p)) + if (p == Py_None || PyTZInfo_Check(st, p)) return 0; PyErr_Format(PyExc_TypeError, "tzinfo argument must be None or of a tzinfo subclass, " @@ -1287,13 +1323,13 @@ check_tzinfo_subclass(PyObject *p) * and the caller must not decref the result. */ static PyObject * -get_tzinfo_member(PyObject *self) +get_tzinfo_member(datetime_state *st, PyObject *self) { PyObject *tzinfo = NULL; - if (PyDateTime_Check(self) && HASTZINFO(self)) + if (PyDateTime_Check(st, self) && HASTZINFO(self)) tzinfo = ((PyDateTime_DateTime *)self)->tzinfo; - else if (PyTime_Check(self) && HASTZINFO(self)) + else if (PyTime_Check(st, self) && HASTZINFO(self)) tzinfo = ((PyDateTime_Time *)self)->tzinfo; return tzinfo; @@ -1307,12 +1343,13 @@ get_tzinfo_member(PyObject *self) * this returns NULL. Else result is returned. */ static PyObject * -call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) +call_tzinfo_method(datetime_state *st, + PyObject *tzinfo, const char *name, PyObject *tzinfoarg) { PyObject *offset; assert(tzinfo != NULL); - assert(PyTZInfo_Check(tzinfo) || tzinfo == Py_None); + assert(PyTZInfo_Check(st, tzinfo) || tzinfo == Py_None); assert(tzinfoarg != NULL); if (tzinfo == Py_None) @@ -1320,7 +1357,7 @@ call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) offset = PyObject_CallMethod(tzinfo, name, "O", tzinfoarg); if (offset == Py_None || offset == NULL) return offset; - if (PyDelta_Check(offset)) { + if (PyDelta_Check(st, offset)) { if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0 && GET_TD_MICROSECONDS(offset) < 1) || @@ -1353,9 +1390,9 @@ call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) * set to 0 and the offset is returned (as timedelta, positive east of UTC). */ static PyObject * -call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg) +call_utcoffset(datetime_state *st, PyObject *tzinfo, PyObject *tzinfoarg) { - return call_tzinfo_method(tzinfo, "utcoffset", tzinfoarg); + return call_tzinfo_method(st, tzinfo, "utcoffset", tzinfoarg); } /* Call tzinfo.dst(tzinfoarg), and extract an integer from the @@ -1367,9 +1404,9 @@ call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg) * the offset is returned (as timedelta, positive east of UTC). */ static PyObject * -call_dst(PyObject *tzinfo, PyObject *tzinfoarg) +call_dst(datetime_state *st, PyObject *tzinfo, PyObject *tzinfoarg) { - return call_tzinfo_method(tzinfo, "dst", tzinfoarg); + return call_tzinfo_method(st, tzinfo, "dst", tzinfoarg); } /* Call tzinfo.tzname(tzinfoarg), and return the result. tzinfo must be @@ -1379,11 +1416,11 @@ call_dst(PyObject *tzinfo, PyObject *tzinfoarg) * string. */ static PyObject * -call_tzname(PyObject *tzinfo, PyObject *tzinfoarg) +call_tzname(datetime_state *st, PyObject *tzinfo, PyObject *tzinfoarg) { PyObject *result; assert(tzinfo != NULL); - assert(check_tzinfo_subclass(tzinfo) >= 0); + assert(check_tzinfo_subclass(st, tzinfo) >= 0); assert(tzinfoarg != NULL); if (tzinfo == Py_None) @@ -1454,21 +1491,21 @@ append_keyword_fold(PyObject *repr, int fold) } static inline PyObject * -tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) +tzinfo_from_isoformat_results(datetime_state *st, + int rv, int tzoffset, int tz_useconds) { PyObject *tzinfo; if (rv == 1) { // Create a timezone from offset in seconds (0 returns UTC) if (tzoffset == 0) { - datetime_state *st = STATIC_STATE(); return Py_NewRef(st->utc); } - PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1); + PyObject *delta = new_delta(st, 0, tzoffset, tz_useconds, 1); if (delta == NULL) { return NULL; } - tzinfo = new_timezone(delta, NULL); + tzinfo = new_timezone(st, delta, NULL); Py_DECREF(delta); } else { @@ -1501,7 +1538,9 @@ format_ctime(PyDateTime_Date *date, int hours, int minutes, int seconds) GET_YEAR(date)); } -static PyObject *delta_negative(PyDateTime_Delta *self); +static inline PyObject * +_delta_negative(datetime_state *st, PyDateTime_Delta *self); + /* Add formatted UTC offset string to buf. buf has no more than * buflen bytes remaining. The UTC offset is gotten by calling @@ -1514,7 +1553,7 @@ static PyObject *delta_negative(PyDateTime_Delta *self); * bogus, an appropriate exception is set and -1 is returned. */ static int -format_utcoffset(char *buf, size_t buflen, const char *sep, +format_utcoffset(datetime_state *st, char *buf, size_t buflen, const char *sep, PyObject *tzinfo, PyObject *tzinfoarg) { PyObject *offset; @@ -1523,7 +1562,7 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, assert(buflen >= 1); - offset = call_utcoffset(tzinfo, tzinfoarg); + offset = call_utcoffset(st, tzinfo, tzinfoarg); if (offset == NULL) return -1; if (offset == Py_None) { @@ -1534,7 +1573,7 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, /* Offset is normalized, so it is negative if days < 0 */ if (GET_TD_DAYS(offset) < 0) { sign = '-'; - Py_SETREF(offset, delta_negative((PyDateTime_Delta *)offset)); + Py_SETREF(offset, _delta_negative(st, (PyDateTime_Delta *)offset)); if (offset == NULL) return -1; } @@ -1562,17 +1601,18 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, } static PyObject * -make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) +make_somezreplacement(datetime_state *st, + PyObject *object, char *sep, PyObject *tzinfoarg) { char buf[100]; - PyObject *tzinfo = get_tzinfo_member(object); + PyObject *tzinfo = get_tzinfo_member(st, object); if (tzinfo == Py_None || tzinfo == NULL) { return PyBytes_FromStringAndSize(NULL, 0); } assert(tzinfoarg != NULL); - if (format_utcoffset(buf, + if (format_utcoffset(st, buf, sizeof(buf), sep, tzinfo, @@ -1583,10 +1623,11 @@ make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) } static PyObject * -make_Zreplacement(PyObject *object, PyObject *tzinfoarg) +make_Zreplacement(datetime_state *st, + PyObject *object, PyObject *tzinfoarg) { PyObject *temp; - PyObject *tzinfo = get_tzinfo_member(object); + PyObject *tzinfo = get_tzinfo_member(st, object); PyObject *Zreplacement = PyUnicode_FromStringAndSize(NULL, 0); if (Zreplacement == NULL) @@ -1595,7 +1636,7 @@ make_Zreplacement(PyObject *object, PyObject *tzinfoarg) return Zreplacement; assert(tzinfoarg != NULL); - temp = call_tzname(tzinfo, tzinfoarg); + temp = call_tzname(st, tzinfo, tzinfoarg); if (temp == NULL) goto Error; if (temp == Py_None) { @@ -1626,12 +1667,12 @@ make_Zreplacement(PyObject *object, PyObject *tzinfoarg) } static PyObject * -make_freplacement(PyObject *object) +make_freplacement(datetime_state *st, PyObject *object) { char freplacement[64]; - if (PyTime_Check(object)) + if (PyTime_Check(st, object)) sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object)); - else if (PyDateTime_Check(object)) + else if (PyDateTime_Check(st, object)) sprintf(freplacement, "%06d", DATE_GET_MICROSECOND(object)); else sprintf(freplacement, "%06d", 0); @@ -1647,7 +1688,8 @@ make_freplacement(PyObject *object) * needed. */ static PyObject * -wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, +wrap_strftime(datetime_state *st, + PyObject *object, PyObject *format, PyObject *timetuple, PyObject *tzinfoarg) { PyObject *result = NULL; /* guilty until proved innocent */ @@ -1710,7 +1752,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, else if (ch == 'z') { /* %z -> +HHMM */ if (zreplacement == NULL) { - zreplacement = make_somezreplacement(object, "", tzinfoarg); + zreplacement = make_somezreplacement(st, object, "", tzinfoarg); if (zreplacement == NULL) goto Done; } @@ -1722,7 +1764,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, else if (ch == ':' && *pin == 'z' && pin++) { /* %:z -> +HH:MM */ if (colonzreplacement == NULL) { - colonzreplacement = make_somezreplacement(object, ":", tzinfoarg); + colonzreplacement = make_somezreplacement(st, object, ":", tzinfoarg); if (colonzreplacement == NULL) goto Done; } @@ -1734,7 +1776,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, else if (ch == 'Z') { /* format tzname */ if (Zreplacement == NULL) { - Zreplacement = make_Zreplacement(object, + Zreplacement = make_Zreplacement(st, object, tzinfoarg); if (Zreplacement == NULL) goto Done; @@ -1749,7 +1791,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, else if (ch == 'f') { /* format microseconds */ if (freplacement == NULL) { - freplacement = make_freplacement(object); + freplacement = make_freplacement(st, object); if (freplacement == NULL) goto Done; } @@ -1883,7 +1925,7 @@ diff_to_bool(int diff, int op) * due to ubiquitous overflow possibilities. */ static PyObject * -delta_to_microseconds(PyDateTime_Delta *self) +delta_to_microseconds(datetime_state *st, PyDateTime_Delta *self) { PyObject *x1 = NULL; PyObject *x2 = NULL; @@ -1893,7 +1935,6 @@ delta_to_microseconds(PyDateTime_Delta *self) x1 = PyLong_FromLong(GET_TD_DAYS(self)); if (x1 == NULL) goto Done; - datetime_state *st = STATIC_STATE(); x2 = PyNumber_Multiply(x1, st->seconds_per_day); /* days in seconds */ if (x2 == NULL) goto Done; @@ -1956,7 +1997,8 @@ checked_divmod(PyObject *a, PyObject *b) /* Convert a number of us (as a Python int) to a timedelta. */ static PyObject * -microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) +microseconds_to_delta_ex(datetime_state *st, + PyObject *pyus, PyTypeObject *type) { int us; int s; @@ -1966,7 +2008,6 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) PyObject *num = NULL; PyObject *result = NULL; - datetime_state *st = STATIC_STATE(); tuple = checked_divmod(pyus, st->us_per_second); if (tuple == NULL) { goto Done; @@ -2018,17 +2059,18 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) goto Done; } -#define microseconds_to_delta(pymicros) \ - microseconds_to_delta_ex(pymicros, &PyDateTime_DeltaType) +#define microseconds_to_delta(st, pymicros) \ + microseconds_to_delta_ex(st, pymicros, (st)->PyDateTime_DeltaType) static PyObject * -multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) +multiply_int_timedelta(datetime_state *st, + PyObject *intobj, PyDateTime_Delta *delta) { PyObject *pyus_in; PyObject *pyus_out; PyObject *result; - pyus_in = delta_to_microseconds(delta); + pyus_in = delta_to_microseconds(st, delta); if (pyus_in == NULL) return NULL; @@ -2037,7 +2079,7 @@ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) if (pyus_out == NULL) return NULL; - result = microseconds_to_delta(pyus_out); + result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; } @@ -2071,13 +2113,15 @@ get_float_as_integer_ratio(PyObject *floatobj) /* op is 0 for multiplication, 1 for division */ static PyObject * -multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, int op) +multiply_truedivide_timedelta_float(datetime_state *st, + PyDateTime_Delta *delta, + PyObject *floatobj, int op) { PyObject *result = NULL; PyObject *pyus_in = NULL, *temp, *pyus_out; PyObject *ratio = NULL; - pyus_in = delta_to_microseconds(delta); + pyus_in = delta_to_microseconds(st, delta); if (pyus_in == NULL) return NULL; ratio = get_float_as_integer_ratio(floatobj); @@ -2092,7 +2136,7 @@ multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, Py_DECREF(temp); if (pyus_out == NULL) goto error; - result = microseconds_to_delta(pyus_out); + result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); error: Py_XDECREF(pyus_in); @@ -2102,13 +2146,14 @@ multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, } static PyObject * -divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj) +divide_timedelta_int(datetime_state *st, + PyDateTime_Delta *delta, PyObject *intobj) { PyObject *pyus_in; PyObject *pyus_out; PyObject *result; - pyus_in = delta_to_microseconds(delta); + pyus_in = delta_to_microseconds(st, delta); if (pyus_in == NULL) return NULL; @@ -2117,23 +2162,24 @@ divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj) if (pyus_out == NULL) return NULL; - result = microseconds_to_delta(pyus_out); + result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; } static PyObject * -divide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right) +divide_timedelta_timedelta(datetime_state *st, + PyDateTime_Delta *left, PyDateTime_Delta *right) { PyObject *pyus_left; PyObject *pyus_right; PyObject *result; - pyus_left = delta_to_microseconds(left); + pyus_left = delta_to_microseconds(st, left); if (pyus_left == NULL) return NULL; - pyus_right = delta_to_microseconds(right); + pyus_right = delta_to_microseconds(st, right); if (pyus_right == NULL) { Py_DECREF(pyus_left); return NULL; @@ -2146,17 +2192,18 @@ divide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right) } static PyObject * -truedivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right) +truedivide_timedelta_timedelta(datetime_state *st, + PyDateTime_Delta *left, PyDateTime_Delta *right) { PyObject *pyus_left; PyObject *pyus_right; PyObject *result; - pyus_left = delta_to_microseconds(left); + pyus_left = delta_to_microseconds(st, left); if (pyus_left == NULL) return NULL; - pyus_right = delta_to_microseconds(right); + pyus_right = delta_to_microseconds(st, right); if (pyus_right == NULL) { Py_DECREF(pyus_left); return NULL; @@ -2169,18 +2216,19 @@ truedivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right) } static PyObject * -truedivide_timedelta_int(PyDateTime_Delta *delta, PyObject *i) +truedivide_timedelta_int(datetime_state *st, + PyDateTime_Delta *delta, PyObject *i) { PyObject *result; PyObject *pyus_in, *pyus_out; - pyus_in = delta_to_microseconds(delta); + pyus_in = delta_to_microseconds(st, delta); if (pyus_in == NULL) return NULL; pyus_out = divide_nearest(pyus_in, i); Py_DECREF(pyus_in); if (pyus_out == NULL) return NULL; - result = microseconds_to_delta(pyus_out); + result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; @@ -2190,8 +2238,9 @@ static PyObject * delta_add(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = find_state_left_or_right(left, right); - if (PyDelta_Check(left) && PyDelta_Check(right)) { + if (PyDelta_Check(st, left) && PyDelta_Check(st, right)) { /* delta + delta */ /* The C-level additions can't overflow because of the * invariant bounds. @@ -2200,7 +2249,7 @@ delta_add(PyObject *left, PyObject *right) int seconds = GET_TD_SECONDS(left) + GET_TD_SECONDS(right); int microseconds = GET_TD_MICROSECONDS(left) + GET_TD_MICROSECONDS(right); - result = new_delta(days, seconds, microseconds, 1); + result = new_delta(st, days, seconds, microseconds, 1); } if (result == Py_NotImplemented) @@ -2208,22 +2257,32 @@ delta_add(PyObject *left, PyObject *right) return result; } -static PyObject * -delta_negative(PyDateTime_Delta *self) +static inline PyObject * +_delta_negative(datetime_state *st, PyDateTime_Delta *self) { - return new_delta(-GET_TD_DAYS(self), + return new_delta(st, + -GET_TD_DAYS(self), -GET_TD_SECONDS(self), -GET_TD_MICROSECONDS(self), 1); } +static PyObject * +delta_negative(PyDateTime_Delta *self) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return _delta_negative(st, self); +} + static PyObject * delta_positive(PyDateTime_Delta *self) { /* Could optimize this (by returning self) if this isn't a * subclass -- but who uses unary + ? Approximately nobody. */ - return new_delta(GET_TD_DAYS(self), + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return new_delta(st, + GET_TD_DAYS(self), GET_TD_SECONDS(self), GET_TD_MICROSECONDS(self), 0); @@ -2237,20 +2296,22 @@ delta_abs(PyDateTime_Delta *self) assert(GET_TD_MICROSECONDS(self) >= 0); assert(GET_TD_SECONDS(self) >= 0); - if (GET_TD_DAYS(self) < 0) - result = delta_negative(self); - else + if (GET_TD_DAYS(self) < 0) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + result = _delta_negative(st, self); + } + else { result = delta_positive(self); - + } return result; } -static PyObject * -delta_subtract(PyObject *left, PyObject *right) +static inline PyObject * +_delta_subtract(datetime_state *st, PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - if (PyDelta_Check(left) && PyDelta_Check(right)) { + if (PyDelta_Check(st, left) && PyDelta_Check(st, right)) { /* delta - delta */ /* The C-level additions can't overflow because of the * invariant bounds. @@ -2259,7 +2320,7 @@ delta_subtract(PyObject *left, PyObject *right) int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right); int microseconds = GET_TD_MICROSECONDS(left) - GET_TD_MICROSECONDS(right); - result = new_delta(days, seconds, microseconds, 1); + result = new_delta(st, days, seconds, microseconds, 1); } if (result == Py_NotImplemented) @@ -2267,6 +2328,13 @@ delta_subtract(PyObject *left, PyObject *right) return result; } +static PyObject * +delta_subtract(PyObject *left, PyObject *right) +{ + datetime_state *st = find_state_left_or_right(left, right); + return _delta_subtract(st, left, right); +} + static int delta_cmp(PyObject *self, PyObject *other) { @@ -2280,10 +2348,10 @@ delta_cmp(PyObject *self, PyObject *other) return diff; } -static PyObject * -delta_richcompare(PyObject *self, PyObject *other, int op) +static inline PyObject * +_delta_richcompare(datetime_state *st, PyObject *self, PyObject *other, int op) { - if (PyDelta_Check(other)) { + if (PyDelta_Check(st, other)) { int diff = delta_cmp(self, other); return diff_to_bool(diff, op); } @@ -2292,6 +2360,13 @@ delta_richcompare(PyObject *self, PyObject *other, int op) } } +static PyObject * +delta_richcompare(PyObject *self, PyObject *other, int op) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return _delta_richcompare(st, self, other, op); +} + static PyObject *delta_getstate(PyDateTime_Delta *self); static Py_hash_t @@ -2311,22 +2386,23 @@ static PyObject * delta_multiply(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = find_state_left_or_right(left, right); - if (PyDelta_Check(left)) { + if (PyDelta_Check(st, left)) { /* delta * ??? */ if (PyLong_Check(right)) - result = multiply_int_timedelta(right, + result = multiply_int_timedelta(st, right, (PyDateTime_Delta *) left); else if (PyFloat_Check(right)) result = multiply_truedivide_timedelta_float( - (PyDateTime_Delta *) left, right, 0); + st, (PyDateTime_Delta *) left, right, 0); } else if (PyLong_Check(left)) - result = multiply_int_timedelta(left, + result = multiply_int_timedelta(st, left, (PyDateTime_Delta *) right); else if (PyFloat_Check(left)) result = multiply_truedivide_timedelta_float( - (PyDateTime_Delta *) right, left, 0); + st, (PyDateTime_Delta *) right, left, 0); if (result == Py_NotImplemented) Py_INCREF(result); @@ -2337,15 +2413,16 @@ static PyObject * delta_divide(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = find_state_left_or_right(left, right); - if (PyDelta_Check(left)) { + if (PyDelta_Check(st, left)) { /* delta * ??? */ if (PyLong_Check(right)) - result = divide_timedelta_int( + result = divide_timedelta_int(st, (PyDateTime_Delta *)left, right); - else if (PyDelta_Check(right)) - result = divide_timedelta_timedelta( + else if (PyDelta_Check(st, right)) + result = divide_timedelta_timedelta(st, (PyDateTime_Delta *)left, (PyDateTime_Delta *)right); } @@ -2359,17 +2436,18 @@ static PyObject * delta_truedivide(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = find_state_left_or_right(left, right); - if (PyDelta_Check(left)) { - if (PyDelta_Check(right)) - result = truedivide_timedelta_timedelta( + if (PyDelta_Check(st, left)) { + if (PyDelta_Check(st, right)) + result = truedivide_timedelta_timedelta(st, (PyDateTime_Delta *)left, (PyDateTime_Delta *)right); else if (PyFloat_Check(right)) result = multiply_truedivide_timedelta_float( - (PyDateTime_Delta *)left, right, 1); + st, (PyDateTime_Delta *)left, right, 1); else if (PyLong_Check(right)) - result = truedivide_timedelta_int( + result = truedivide_timedelta_int(st, (PyDateTime_Delta *)left, right); } @@ -2385,15 +2463,16 @@ delta_remainder(PyObject *left, PyObject *right) PyObject *pyus_right; PyObject *pyus_remainder; PyObject *remainder; + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); - if (!PyDelta_Check(left) || !PyDelta_Check(right)) + if (!PyDelta_Check(st, left) || !PyDelta_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; - pyus_left = delta_to_microseconds((PyDateTime_Delta *)left); + pyus_left = delta_to_microseconds(st, (PyDateTime_Delta *)left); if (pyus_left == NULL) return NULL; - pyus_right = delta_to_microseconds((PyDateTime_Delta *)right); + pyus_right = delta_to_microseconds(st, (PyDateTime_Delta *)right); if (pyus_right == NULL) { Py_DECREF(pyus_left); return NULL; @@ -2405,7 +2484,7 @@ delta_remainder(PyObject *left, PyObject *right) if (pyus_remainder == NULL) return NULL; - remainder = microseconds_to_delta(pyus_remainder); + remainder = microseconds_to_delta(st, pyus_remainder); Py_DECREF(pyus_remainder); if (remainder == NULL) return NULL; @@ -2421,15 +2500,16 @@ delta_divmod(PyObject *left, PyObject *right) PyObject *divmod; PyObject *delta; PyObject *result; + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); - if (!PyDelta_Check(left) || !PyDelta_Check(right)) + if (!PyDelta_Check(st, left) || !PyDelta_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; - pyus_left = delta_to_microseconds((PyDateTime_Delta *)left); + pyus_left = delta_to_microseconds(st, (PyDateTime_Delta *)left); if (pyus_left == NULL) return NULL; - pyus_right = delta_to_microseconds((PyDateTime_Delta *)right); + pyus_right = delta_to_microseconds(st, (PyDateTime_Delta *)right); if (pyus_right == NULL) { Py_DECREF(pyus_left); return NULL; @@ -2441,7 +2521,7 @@ delta_divmod(PyObject *left, PyObject *right) if (divmod == NULL) return NULL; - delta = microseconds_to_delta(PyTuple_GET_ITEM(divmod, 1)); + delta = microseconds_to_delta(st, PyTuple_GET_ITEM(divmod, 1)); if (delta == NULL) { Py_DECREF(divmod); return NULL; @@ -2585,7 +2665,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us); CLEANUP; } - datetime_state *st = STATIC_STATE(); + datetime_state *st = find_module_state_by_def(type); if (ms) { y = accum("milliseconds", x, ms, st->us_per_ms, &leftover_us); CLEANUP; @@ -2647,7 +2727,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) CLEANUP; } - self = microseconds_to_delta_ex(x, type); + self = microseconds_to_delta_ex(st, x, type); Py_DECREF(x); Done: return self; @@ -2752,29 +2832,51 @@ delta_getstate(PyDateTime_Delta *self) GET_TD_MICROSECONDS(self)); } -static PyObject * -delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) +static inline PyObject * +_delta_total_seconds(datetime_state *st, PyObject *self) { PyObject *total_seconds; PyObject *total_microseconds; - total_microseconds = delta_to_microseconds((PyDateTime_Delta *)self); + total_microseconds = delta_to_microseconds(st, (PyDateTime_Delta *)self); if (total_microseconds == NULL) return NULL; - datetime_state *st = STATIC_STATE(); total_seconds = PyNumber_TrueDivide(total_microseconds, st->us_per_second); Py_DECREF(total_microseconds); return total_seconds; } +static PyObject * +delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return _delta_total_seconds(st, self); +} + static PyObject * delta_reduce(PyDateTime_Delta* self, PyObject *Py_UNUSED(ignored)) { return Py_BuildValue("ON", Py_TYPE(self), delta_getstate(self)); } +static int +delta_traverse(PyDateTime_Delta *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +delta_dealloc(PyDateTime_Delta *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); +} + #define OFFSET(field) offsetof(PyDateTime_Delta, field) static PyMemberDef delta_members[] = { @@ -2807,82 +2909,41 @@ PyDoc_STR("Difference between two datetime values.\n\n" "All arguments are optional and default to 0.\n" "Arguments may be integers or floats, and may be positive or negative."); -static PyNumberMethods delta_as_number = { - delta_add, /* nb_add */ - delta_subtract, /* nb_subtract */ - delta_multiply, /* nb_multiply */ - delta_remainder, /* nb_remainder */ - delta_divmod, /* nb_divmod */ - 0, /* nb_power */ - (unaryfunc)delta_negative, /* nb_negative */ - (unaryfunc)delta_positive, /* nb_positive */ - (unaryfunc)delta_abs, /* nb_absolute */ - (inquiry)delta_bool, /* nb_bool */ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_int*/ - 0, /*nb_reserved*/ - 0, /*nb_float*/ - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - delta_divide, /* nb_floor_divide */ - delta_truedivide, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ +static PyType_Slot delta_slots[] = { + {Py_tp_repr, delta_repr}, + {Py_tp_hash, delta_hash}, + {Py_tp_str, delta_str}, + {Py_tp_doc, (void *)delta_doc}, + {Py_tp_richcompare, delta_richcompare}, + {Py_tp_methods, delta_methods}, + {Py_tp_members, delta_members}, + {Py_tp_new, delta_new}, + {Py_tp_traverse, delta_traverse}, + {Py_tp_dealloc, delta_dealloc}, + + // Number protocol + {Py_nb_add, delta_add}, + {Py_nb_subtract, delta_subtract}, + {Py_nb_multiply, delta_multiply}, + {Py_nb_remainder, delta_remainder}, + {Py_nb_divmod, delta_divmod}, + {Py_nb_negative, delta_negative}, + {Py_nb_positive, delta_positive}, + {Py_nb_absolute, delta_abs}, + {Py_nb_bool, delta_bool}, + {Py_nb_floor_divide, delta_divide}, + {Py_nb_true_divide, delta_truedivide}, + {0, NULL}, }; -static PyTypeObject PyDateTime_DeltaType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.timedelta", /* tp_name */ - sizeof(PyDateTime_Delta), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)delta_repr, /* tp_repr */ - &delta_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)delta_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)delta_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - delta_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - delta_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - delta_methods, /* tp_methods */ - delta_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - delta_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec delta_spec = { + .name = "datetime.timedelta", + .basicsize = sizeof(PyDateTime_Delta), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = delta_slots, }; /* @@ -2982,7 +3043,7 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw) } static PyObject * -date_fromtimestamp(PyObject *cls, PyObject *obj) +date_fromtimestamp(datetime_state *st, PyObject *cls, PyObject *obj) { struct tm tm; time_t t; @@ -2993,7 +3054,8 @@ date_fromtimestamp(PyObject *cls, PyObject *obj) if (_PyTime_localtime(t, &tm) != 0) return NULL; - return new_date_subclass_ex(tm.tm_year + 1900, + return new_date_subclass_ex(st, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, cls); @@ -3041,7 +3103,8 @@ static PyObject * datetime_date_fromtimestamp(PyTypeObject *type, PyObject *timestamp) /*[clinic end generated code: output=fd045fda58168869 input=eabb3fe7f40491fe]*/ { - return date_fromtimestamp((PyObject *) type, timestamp); + datetime_state *st = find_module_state_by_def(type); + return date_fromtimestamp(st, (PyObject *) type, timestamp); } /* bpo-36025: This is a wrapper for API compatibility with the public C API, @@ -3055,7 +3118,8 @@ datetime_date_fromtimestamp_capi(PyObject *cls, PyObject *args) PyObject *result = NULL; if (PyArg_UnpackTuple(args, "fromtimestamp", 1, 1, ×tamp)) { - result = date_fromtimestamp(cls, timestamp); + datetime_state *st = get_module_state_by_cls((PyTypeObject *)cls); + result = date_fromtimestamp(st, cls, timestamp); } return result; @@ -3080,7 +3144,8 @@ date_fromordinal(PyObject *cls, PyObject *args) ">= 1"); else { ord_to_ymd(ordinal, &year, &month, &day); - result = new_date_subclass_ex(year, month, day, cls); + datetime_state *st = find_module_state_by_def(cls); + result = new_date_subclass_ex(st, year, month, day, cls); } } return result; @@ -3118,8 +3183,8 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) if (rv < 0) { goto invalid_string_error; } - - return new_date_subclass_ex(year, month, day, cls); + datetime_state *st = find_module_state_by_def(cls); + return new_date_subclass_ex(st, year, month, day, cls); invalid_string_error: PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr); @@ -3164,8 +3229,8 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) day); return NULL; } - - return new_date_subclass_ex(year, month, day, cls); + datetime_state *st = find_module_state_by_def(cls); + return new_date_subclass_ex(st, year, month, day, cls); } @@ -3177,7 +3242,8 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) * instead. */ static PyObject * -add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) +add_date_timedelta(datetime_state *st, + PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) { PyObject *result = NULL; int year = GET_YEAR(date); @@ -3187,7 +3253,7 @@ add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) int day = GET_DAY(date) + (negate ? -deltadays : deltadays); if (normalize_date(&year, &month, &day) >= 0) - result = new_date_subclass_ex(year, month, day, + result = new_date_subclass_ex(st, year, month, day, (PyObject* )Py_TYPE(date)); return result; } @@ -3195,14 +3261,15 @@ add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) static PyObject * date_add(PyObject *left, PyObject *right) { - if (PyDateTime_Check(left) || PyDateTime_Check(right)) + datetime_state *st = find_state_left_or_right(left, right); + if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; - if (PyDate_Check(left)) { + if (PyDate_Check(st, left)) { /* date + ??? */ - if (PyDelta_Check(right)) + if (PyDelta_Check(st, right)) /* date + delta */ - return add_date_timedelta((PyDateTime_Date *) left, + return add_date_timedelta(st, (PyDateTime_Date *) left, (PyDateTime_Delta *) right, 0); } @@ -3210,9 +3277,9 @@ date_add(PyObject *left, PyObject *right) /* ??? + date * 'right' must be one of us, or we wouldn't have been called */ - if (PyDelta_Check(left)) + if (PyDelta_Check(st, left)) /* delta + date */ - return add_date_timedelta((PyDateTime_Date *) right, + return add_date_timedelta(st, (PyDateTime_Date *) right, (PyDateTime_Delta *) left, 0); } @@ -3222,11 +3289,12 @@ date_add(PyObject *left, PyObject *right) static PyObject * date_subtract(PyObject *left, PyObject *right) { - if (PyDateTime_Check(left) || PyDateTime_Check(right)) + datetime_state *st = find_state_left_or_right(left, right); + if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; - if (PyDate_Check(left)) { - if (PyDate_Check(right)) { + if (PyDate_Check(st, left)) { + if (PyDate_Check(st, right)) { /* date - date */ int left_ord = ymd_to_ord(GET_YEAR(left), GET_MONTH(left), @@ -3234,11 +3302,11 @@ date_subtract(PyObject *left, PyObject *right) int right_ord = ymd_to_ord(GET_YEAR(right), GET_MONTH(right), GET_DAY(right)); - return new_delta(left_ord - right_ord, 0, 0, 0); + return new_delta(st, left_ord - right_ord, 0, 0, 0); } - if (PyDelta_Check(right)) { + if (PyDelta_Check(st, right)) { /* date - delta */ - return add_date_timedelta((PyDateTime_Date *) left, + return add_date_timedelta(st, (PyDateTime_Date *) left, (PyDateTime_Delta *) right, 1); } @@ -3296,7 +3364,8 @@ date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw) tuple = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(timetuple)); if (tuple == NULL) return NULL; - result = wrap_strftime((PyObject *)self, format, tuple, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + result = wrap_strftime(st, (PyObject *)self, format, tuple, (PyObject *)self); Py_DECREF(tuple); return result; @@ -3402,6 +3471,22 @@ iso_calendar_date_weekday(PyDateTime_IsoCalendarDate *self, void *unused) return Py_NewRef(weekday); } +static int +iso_calendar_date_traverse(PyDateTime_IsoCalendarDate *self, visitproc visit, + void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return PyTuple_Type.tp_traverse((PyObject *)self, visit, arg); +} + +static void +iso_calendar_date_dealloc(PyDateTime_IsoCalendarDate *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyTuple_Type.tp_dealloc((PyObject *)self); // delegate GC-untrack as well + Py_DECREF(tp); +} + static PyGetSetDef iso_calendar_date_getset[] = { {"year", (getter)iso_calendar_date_year}, {"week", (getter)iso_calendar_date_week}, @@ -3415,17 +3500,24 @@ static PyMethodDef iso_calendar_date_methods[] = { {NULL, NULL}, }; -static PyTypeObject PyDateTime_IsoCalendarDateType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "datetime.IsoCalendarDate", - .tp_basicsize = sizeof(PyDateTime_IsoCalendarDate), - .tp_repr = (reprfunc) iso_calendar_date_repr, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = iso_calendar_date__doc__, - .tp_methods = iso_calendar_date_methods, - .tp_getset = iso_calendar_date_getset, - // .tp_base = &PyTuple_Type, // filled in PyInit__datetime - .tp_new = iso_calendar_date_new, +static PyType_Slot isocal_slots[] = { + {Py_tp_repr, iso_calendar_date_repr}, + {Py_tp_doc, (void *)iso_calendar_date__doc__}, + {Py_tp_methods, iso_calendar_date_methods}, + {Py_tp_getset, iso_calendar_date_getset}, + {Py_tp_new, iso_calendar_date_new}, + {Py_tp_dealloc, iso_calendar_date_dealloc}, + {Py_tp_traverse, iso_calendar_date_traverse}, + {0, NULL}, +}; + +static PyType_Spec isocal_spec = { + .name = "datetime.IsoCalendarDate", + .basicsize = sizeof(PyDateTime_IsoCalendarDate), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = isocal_slots, }; /*[clinic input] @@ -3475,7 +3567,8 @@ date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) week = 0; } - PyObject* v = iso_calendar_date_new_impl(&PyDateTime_IsoCalendarDateType, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + PyObject* v = iso_calendar_date_new_impl(st->PyDateTime_IsoCalendarDateType, year, week + 1, day + 1); if (v == NULL) { return NULL; @@ -3496,7 +3589,8 @@ date_richcompare(PyObject *self, PyObject *other, int op) * The behavior is the same as if Date and DateTime were independent * classes. */ - if (PyDate_Check(other) && !PyDateTime_Check(other)) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (PyDate_Check(st, other) && !PyDateTime_Check(st, other)) { int diff = memcmp(((PyDateTime_Date *)self)->data, ((PyDateTime_Date *)other)->data, _PyDateTime_DATE_DATASIZE); @@ -3530,7 +3624,8 @@ datetime_date_replace_impl(PyDateTime_Date *self, int year, int month, int day) /*[clinic end generated code: output=2a9430d1e6318aeb input=0d1f02685b3e90f6]*/ { - return new_date_subclass_ex(year, month, day, (PyObject *)Py_TYPE(self)); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return new_date_subclass_ex(st, year, month, day, (PyObject *)Py_TYPE(self)); } static Py_hash_t @@ -3586,6 +3681,22 @@ date_reduce(PyDateTime_Date *self, PyObject *arg) return Py_BuildValue("(ON)", Py_TYPE(self), date_getstate(self)); } +static int +date_traverse(PyDateTime_Date *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +date_dealloc(PyDateTime_Date *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); +} + static PyMethodDef date_methods[] = { /* Class methods: */ @@ -3657,59 +3768,32 @@ static PyMethodDef date_methods[] = { static const char date_doc[] = PyDoc_STR("date(year, month, day) --> date object"); -static PyNumberMethods date_as_number = { - date_add, /* nb_add */ - date_subtract, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - 0, /* nb_bool */ +static PyType_Slot date_slots[] = { + {Py_tp_repr, date_repr}, + {Py_tp_hash, date_hash}, + {Py_tp_str, date_str}, + {Py_tp_doc, (void *)date_doc}, + {Py_tp_richcompare, date_richcompare}, + {Py_tp_methods, date_methods}, + {Py_tp_getset, date_getset}, + {Py_tp_new, date_new}, + {Py_tp_traverse, date_traverse}, + {Py_tp_dealloc, date_dealloc}, + + // Number protocol + {Py_nb_add, date_add}, + {Py_nb_subtract, date_subtract}, + {0, NULL}, }; -static PyTypeObject PyDateTime_DateType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.date", /* tp_name */ - sizeof(PyDateTime_Date), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)date_repr, /* tp_repr */ - &date_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)date_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)date_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - date_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - date_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - date_methods, /* tp_methods */ - 0, /* tp_members */ - date_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - date_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec date_spec = { + .name = "datetime.date", + .basicsize = sizeof(PyDateTime_Date), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = date_slots, }; /* @@ -3759,11 +3843,16 @@ tzinfo_dst(PyDateTime_TZInfo *self, PyObject *dt) } -static PyObject *add_datetime_timedelta(PyDateTime_DateTime *date, - PyDateTime_Delta *delta, - int factor); -static PyObject *datetime_utcoffset(PyObject *self, PyObject *); -static PyObject *datetime_dst(PyObject *self, PyObject *); +static inline PyObject * +add_datetime_timedelta(datetime_state *st, PyDateTime_DateTime *date, + PyDateTime_Delta *delta, int factor); + +static inline PyObject * +_datetime_utcoffset(datetime_state *st, PyObject *self); + +static inline PyObject * +_datetime_dst(datetime_state *st, PyObject *self); + static PyObject * tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) @@ -3772,7 +3861,8 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) PyObject *off = NULL, *dst = NULL; PyDateTime_Delta *delta = NULL; - if (!PyDateTime_Check(dt)) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (!PyDateTime_Check(st, dt)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); return NULL; @@ -3783,7 +3873,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) return NULL; } - off = datetime_utcoffset(dt, NULL); + off = _datetime_utcoffset(st, dt); if (off == NULL) return NULL; if (off == Py_None) { @@ -3792,7 +3882,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) goto Fail; } - dst = datetime_dst(dt, NULL); + dst = _datetime_dst(st, dt); if (dst == NULL) goto Fail; if (dst == Py_None) { @@ -3801,21 +3891,21 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) goto Fail; } - delta = (PyDateTime_Delta *)delta_subtract(off, dst); + delta = (PyDateTime_Delta *)_delta_subtract(st, off, dst); if (delta == NULL) goto Fail; - result = add_datetime_timedelta((PyDateTime_DateTime *)dt, delta, 1); + result = add_datetime_timedelta(st, (PyDateTime_DateTime *)dt, delta, 1); if (result == NULL) goto Fail; Py_DECREF(dst); - dst = call_dst(GET_DT_TZINFO(dt), result); + dst = call_dst(st, GET_DT_TZINFO(dt), result); if (dst == NULL) goto Fail; if (dst == Py_None) goto Inconsistent; if (delta_bool((PyDateTime_Delta *)dst) != 0) { - Py_SETREF(result, add_datetime_timedelta((PyDateTime_DateTime *)result, + Py_SETREF(result, add_datetime_timedelta(st, (PyDateTime_DateTime *)result, (PyDateTime_Delta *)dst, 1)); if (result == NULL) goto Fail; @@ -3872,6 +3962,22 @@ tzinfo_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) return Py_BuildValue("(ONN)", Py_TYPE(self), args, state); } +static int +tzinfo_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +tzinfo_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free(self); + Py_DECREF(tp); +} + static PyMethodDef tzinfo_methods[] = { {"tzname", (PyCFunction)tzinfo_tzname, METH_O, @@ -3896,46 +4002,22 @@ static PyMethodDef tzinfo_methods[] = { static const char tzinfo_doc[] = PyDoc_STR("Abstract base class for time zone info objects."); -static PyTypeObject PyDateTime_TZInfoType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.tzinfo", /* tp_name */ - sizeof(PyDateTime_TZInfo), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - tzinfo_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - tzinfo_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - 0, /* tp_free */ +static PyType_Slot tzinfo_slots[] = { + {Py_tp_doc, (void *)tzinfo_doc}, + {Py_tp_methods, tzinfo_methods}, + {Py_tp_dealloc, tzinfo_dealloc}, + {Py_tp_traverse, tzinfo_traverse}, + {0, NULL}, +}; + +static PyType_Spec tzinfo_spec = { + .name = "datetime.tzinfo", + .basicsize = sizeof(PyDateTime_TZInfo), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = tzinfo_slots, }; static char *timezone_kws[] = {"offset", "name", NULL}; @@ -3945,19 +4027,39 @@ timezone_new(PyTypeObject *type, PyObject *args, PyObject *kw) { PyObject *offset; PyObject *name = NULL; + datetime_state *st = find_module_state_by_def(type); if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws, - &PyDateTime_DeltaType, &offset, &name)) - return new_timezone(offset, name); + st->PyDateTime_DeltaType, &offset, &name)) + return new_timezone(st, offset, name); return NULL; } -static void -timezone_dealloc(PyDateTime_TimeZone *self) +static int +timezone_traverse(PyDateTime_TimeZone *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->offset); + Py_VISIT(self->name); + return 0; +} + +static int +timezone_clear(PyDateTime_TimeZone *self) { Py_CLEAR(self->offset); Py_CLEAR(self->name); + return 0; +} + +static void +timezone_dealloc(PyDateTime_TimeZone *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)timezone_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyObject * @@ -3966,10 +4068,11 @@ timezone_richcompare(PyDateTime_TimeZone *self, { if (op != Py_EQ && op != Py_NE) Py_RETURN_NOTIMPLEMENTED; - if (!PyTimezone_Check(other)) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (!PyTimezone_Check(st, other)) { Py_RETURN_NOTIMPLEMENTED; } - return delta_richcompare(self->offset, other->offset, op); + return _delta_richcompare(st, self->offset, other->offset, op); } static Py_hash_t @@ -3983,9 +4086,9 @@ timezone_hash(PyDateTime_TimeZone *self) otherwise. */ static int -_timezone_check_argument(PyObject *dt, const char *meth) +_timezone_check_argument(datetime_state *st, PyObject *dt, const char *meth) { - if (dt == Py_None || PyDateTime_Check(dt)) + if (dt == Py_None || PyDateTime_Check(st, dt)) return 0; PyErr_Format(PyExc_TypeError, "%s(dt) argument must be a datetime instance" " or None, not %.200s", meth, Py_TYPE(dt)->tp_name); @@ -3999,7 +4102,7 @@ timezone_repr(PyDateTime_TimeZone *self) to use Py_TYPE(self)->tp_name here. */ const char *type_name = Py_TYPE(self)->tp_name; - datetime_state *st = STATIC_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (((PyObject *)self) == st->utc) { return PyUnicode_FromFormat("%s.utc", type_name); } @@ -4022,7 +4125,7 @@ timezone_str(PyDateTime_TimeZone *self) if (self->name != NULL) { return Py_NewRef(self->name); } - datetime_state *st = STATIC_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if ((PyObject *)self == st->utc || (GET_TD_DAYS(self->offset) == 0 && GET_TD_SECONDS(self->offset) == 0 && @@ -4033,7 +4136,7 @@ timezone_str(PyDateTime_TimeZone *self) /* Offset is normalized, so it is negative if days < 0 */ if (GET_TD_DAYS(self->offset) < 0) { sign = '-'; - offset = delta_negative((PyDateTime_Delta *)self->offset); + offset = _delta_negative(st, (PyDateTime_Delta *)self->offset); if (offset == NULL) return NULL; } @@ -4062,7 +4165,8 @@ timezone_str(PyDateTime_TimeZone *self) static PyObject * timezone_tzname(PyDateTime_TimeZone *self, PyObject *dt) { - if (_timezone_check_argument(dt, "tzname") == -1) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (_timezone_check_argument(st, dt, "tzname") == -1) return NULL; return timezone_str(self); @@ -4071,7 +4175,8 @@ timezone_tzname(PyDateTime_TimeZone *self, PyObject *dt) static PyObject * timezone_utcoffset(PyDateTime_TimeZone *self, PyObject *dt) { - if (_timezone_check_argument(dt, "utcoffset") == -1) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (_timezone_check_argument(st, dt, "utcoffset") == -1) return NULL; return Py_NewRef(self->offset); @@ -4080,7 +4185,8 @@ timezone_utcoffset(PyDateTime_TimeZone *self, PyObject *dt) static PyObject * timezone_dst(PyObject *self, PyObject *dt) { - if (_timezone_check_argument(dt, "dst") == -1) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (_timezone_check_argument(st, dt, "dst") == -1) return NULL; Py_RETURN_NONE; @@ -4089,7 +4195,8 @@ timezone_dst(PyObject *self, PyObject *dt) static PyObject * timezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt) { - if (!PyDateTime_Check(dt)) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (!PyDateTime_Check(st, dt)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); return NULL; @@ -4100,7 +4207,7 @@ timezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt) return NULL; } - return add_datetime_timedelta(dt, (PyDateTime_Delta *)self->offset, 1); + return add_datetime_timedelta(st, dt, (PyDateTime_Delta *)self->offset, 1); } static PyObject * @@ -4134,45 +4241,27 @@ static PyMethodDef timezone_methods[] = { static const char timezone_doc[] = PyDoc_STR("Fixed offset from UTC implementation of tzinfo."); -static PyTypeObject PyDateTime_TimeZoneType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.timezone", /* tp_name */ - sizeof(PyDateTime_TimeZone), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)timezone_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)timezone_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)timezone_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)timezone_str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - timezone_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)timezone_richcompare,/* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - timezone_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base; filled in PyInit__datetime */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - timezone_new, /* tp_new */ +static PyType_Slot timezone_slots[] = { + {Py_tp_dealloc, timezone_dealloc}, + {Py_tp_traverse, timezone_traverse}, + {Py_tp_clear, timezone_clear}, + {Py_tp_repr, timezone_repr}, + {Py_tp_hash, timezone_hash}, + {Py_tp_str, timezone_str}, + {Py_tp_doc, (void *)timezone_doc}, + {Py_tp_richcompare, timezone_richcompare}, + {Py_tp_methods, timezone_methods}, + {Py_tp_new, timezone_new}, + {0, NULL}, +}; + +static PyType_Spec timezone_spec = { + .name = "datetime.timezone", + .basicsize = sizeof(PyDateTime_TimeZone), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = timezone_slots, }; /* @@ -4240,10 +4329,11 @@ static char *time_kws[] = {"hour", "minute", "second", "microsecond", static PyObject * time_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo) { + datetime_state *st = find_module_state_by_def(type); PyDateTime_Time *me; char aware = (char)(tzinfo != Py_None); - if (aware && check_tzinfo_subclass(tzinfo) < 0) { + if (aware && check_tzinfo_subclass(st, tzinfo) < 0) { PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg"); return NULL; } @@ -4319,12 +4409,28 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw) if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws, &hour, &minute, &second, &usecond, &tzinfo, &fold)) { - self = new_time_ex2(hour, minute, second, usecond, tzinfo, fold, + datetime_state *st = find_module_state_by_def(type); + self = new_time_ex2(st, hour, minute, second, usecond, tzinfo, fold, type); } return self; } +static int +time_traverse(PyDateTime_Time *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->tzinfo); + return 0; +} + +static int +time_clear(PyDateTime_Time *self) +{ + Py_CLEAR(self->tzinfo); + return 0; +} + /* * Destructor. */ @@ -4332,30 +4438,38 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw) static void time_dealloc(PyDateTime_Time *self) { - if (HASTZINFO(self)) { - Py_XDECREF(self->tzinfo); - } - Py_TYPE(self)->tp_free((PyObject *)self); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)time_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } /* * Indirect access to tzinfo methods. */ -/* These are all METH_NOARGS, so don't need to check the arglist. */ +static inline PyObject * +_time_utcoffset(datetime_state *st, PyObject *self) +{ + return call_utcoffset(st, GET_TIME_TZINFO(self), Py_None); +} static PyObject * time_utcoffset(PyObject *self, PyObject *unused) { - return call_utcoffset(GET_TIME_TZINFO(self), Py_None); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return _time_utcoffset(st, (PyObject *)self); } static PyObject * time_dst(PyObject *self, PyObject *unused) { - return call_dst(GET_TIME_TZINFO(self), Py_None); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_dst(st, GET_TIME_TZINFO(self), Py_None); } static PyObject * time_tzname(PyDateTime_Time *self, PyObject *unused) { - return call_tzname(GET_TIME_TZINFO(self), Py_None); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_tzname(st, GET_TIME_TZINFO(self), Py_None); } /* @@ -4450,7 +4564,8 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw) return result; /* We need to append the UTC offset. */ - if (format_utcoffset(buf, sizeof(buf), ":", self->tzinfo, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (format_utcoffset(st, buf, sizeof(buf), ":", self->tzinfo, Py_None) < 0) { Py_DECREF(result); return NULL; @@ -4484,7 +4599,8 @@ time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw) if (tuple == NULL) return NULL; assert(PyTuple_Size(tuple) == 9); - result = wrap_strftime((PyObject *)self, format, tuple, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + result = wrap_strftime(st, (PyObject *)self, format, tuple, Py_None); Py_DECREF(tuple); return result; @@ -4501,7 +4617,8 @@ time_richcompare(PyObject *self, PyObject *other, int op) PyObject *offset1, *offset2; int diff; - if (! PyTime_Check(other)) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (!PyTime_Check(st, other)) Py_RETURN_NOTIMPLEMENTED; if (GET_TIME_TZINFO(self) == GET_TIME_TZINFO(other)) { @@ -4510,10 +4627,10 @@ time_richcompare(PyObject *self, PyObject *other, int op) _PyDateTime_TIME_DATASIZE); return diff_to_bool(diff, op); } - offset1 = time_utcoffset(self, NULL); + offset1 = _time_utcoffset(st, self); if (offset1 == NULL) return NULL; - offset2 = time_utcoffset(other, NULL); + offset2 = _time_utcoffset(st, other); if (offset2 == NULL) goto done; /* If they're both naive, or both aware and have the same offsets, @@ -4521,7 +4638,7 @@ time_richcompare(PyObject *self, PyObject *other, int op) * offset2 == Py_None at this point. */ if ((offset1 == offset2) || - (PyDelta_Check(offset1) && PyDelta_Check(offset2) && + (PyDelta_Check(st, offset1) && PyDelta_Check(st, offset2) && delta_cmp(offset1, offset2) == 0)) { diff = memcmp(((PyDateTime_Time *)self)->data, ((PyDateTime_Time *)other)->data, @@ -4570,8 +4687,10 @@ time_hash(PyDateTime_Time *self) { if (self->hashcode == -1) { PyObject *offset, *self0; + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (TIME_GET_FOLD(self)) { - self0 = new_time_ex2(TIME_GET_HOUR(self), + self0 = new_time_ex2(st, + TIME_GET_HOUR(self), TIME_GET_MINUTE(self), TIME_GET_SECOND(self), TIME_GET_MICROSECOND(self), @@ -4583,7 +4702,7 @@ time_hash(PyDateTime_Time *self) else { self0 = Py_NewRef(self); } - offset = time_utcoffset(self0, NULL); + offset = _time_utcoffset(st, self0); Py_DECREF(self0); if (offset == NULL) @@ -4601,12 +4720,12 @@ time_hash(PyDateTime_Time *self) TIME_GET_MINUTE(self) * 60 + TIME_GET_SECOND(self); microseconds = TIME_GET_MICROSECOND(self); - temp1 = new_delta(0, seconds, microseconds, 1); + temp1 = new_delta(st, 0, seconds, microseconds, 1); if (temp1 == NULL) { Py_DECREF(offset); return -1; } - temp2 = delta_subtract(temp1, offset); + temp2 = _delta_subtract(st, temp1, offset); Py_DECREF(temp1); if (temp2 == NULL) { Py_DECREF(offset); @@ -4640,7 +4759,9 @@ datetime_time_replace_impl(PyDateTime_Time *self, int hour, int minute, int fold) /*[clinic end generated code: output=0b89a44c299e4f80 input=9b6a35b1e704b0ca]*/ { - return new_time_subclass_fold_ex(hour, minute, second, microsecond, tzinfo, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return new_time_subclass_fold_ex(st, + hour, minute, second, microsecond, tzinfo, fold, (PyObject *)Py_TYPE(self)); } @@ -4678,7 +4799,8 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) { goto invalid_string_error; } - PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, + datetime_state *st = find_module_state_by_def(cls); + PyObject *tzinfo = tzinfo_from_isoformat_results(st, rv, tzoffset, tzimicrosecond); if (tzinfo == NULL) { @@ -4686,8 +4808,8 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) { } PyObject *t; - if ( (PyTypeObject *)cls == &PyDateTime_TimeType ) { - t = new_time(hour, minute, second, microsecond, tzinfo, 0); + if ( (PyTypeObject *)cls == st->PyDateTime_TimeType ) { + t = new_time(st, hour, minute, second, microsecond, tzinfo, 0); } else { t = PyObject_CallFunction(cls, "iiiiO", hour, minute, second, microsecond, tzinfo); @@ -4794,46 +4916,29 @@ PyDoc_STR("time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time All arguments are optional. tzinfo may be None, or an instance of\n\ a tzinfo subclass. The remaining arguments may be ints.\n"); -static PyTypeObject PyDateTime_TimeType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.time", /* tp_name */ - sizeof(PyDateTime_Time), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)time_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)time_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)time_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)time_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - time_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - time_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - time_methods, /* tp_methods */ - 0, /* tp_members */ - time_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - time_alloc, /* tp_alloc */ - time_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Slot time_slots[] = { + {Py_tp_dealloc, time_dealloc}, + {Py_tp_traverse, time_traverse}, + {Py_tp_clear, time_clear}, + {Py_tp_repr, time_repr}, + {Py_tp_hash, time_hash}, + {Py_tp_str, time_str}, + {Py_tp_doc, (void *)time_doc}, + {Py_tp_richcompare, time_richcompare}, + {Py_tp_methods, time_methods}, + {Py_tp_getset, time_getset}, + {Py_tp_new, time_new}, + {0, NULL}, +}; + +static PyType_Spec time_spec = { + .name = "datetime.time", + .basicsize = sizeof(PyDateTime_Time), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = time_slots, }; /* @@ -4903,10 +5008,11 @@ static char *datetime_kws[] = { static PyObject * datetime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo) { + datetime_state *st = find_module_state_by_def(type); PyDateTime_DateTime *me; char aware = (char)(tzinfo != Py_None); - if (aware && check_tzinfo_subclass(tzinfo) < 0) { + if (aware && check_tzinfo_subclass(st, tzinfo) < 0) { PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg"); return NULL; } @@ -4985,7 +5091,8 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i", datetime_kws, &year, &month, &day, &hour, &minute, &second, &usecond, &tzinfo, &fold)) { - self = new_datetime_ex2(year, month, day, + datetime_state *st = find_module_state_by_def(type); + self = new_datetime_ex2(st, year, month, day, hour, minute, second, usecond, tzinfo, fold, type); } @@ -5045,7 +5152,8 @@ local(long long u) * Pass localtime or gmtime for f, to control the interpretation of timet. */ static PyObject * -datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, +datetime_from_timet_and_us(datetime_state *st, + PyObject *cls, TM_FUNC f, time_t timet, int us, PyObject *tzinfo) { struct tm tm; @@ -5105,7 +5213,7 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, fold = 1; } } - return new_datetime_subclass_fold_ex(year, month, day, hour, minute, + return new_datetime_subclass_fold_ex(st, year, month, day, hour, minute, second, us, tzinfo, fold, cls); } @@ -5117,7 +5225,8 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, * to get that much precision (e.g., C time() isn't good enough). */ static PyObject * -datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, +datetime_from_timestamp(datetime_state *st, + PyObject *cls, TM_FUNC f, PyObject *timestamp, PyObject *tzinfo) { time_t timet; @@ -5127,7 +5236,7 @@ datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, &timet, &us, _PyTime_ROUND_HALF_EVEN) == -1) return NULL; - return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo); + return datetime_from_timet_and_us(st, cls, f, timet, (int)us, tzinfo); } /* Internal helper. @@ -5135,7 +5244,8 @@ datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, * gmtime for f as appropriate. */ static PyObject * -datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) +datetime_best_possible(datetime_state *st, + PyObject *cls, TM_FUNC f, PyObject *tzinfo) { PyTime_t ts; if (PyTime_Time(&ts) < 0) { @@ -5149,7 +5259,7 @@ datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) return NULL; assert(0 <= us && us <= 999999); - return datetime_from_timet_and_us(cls, f, secs, us, tzinfo); + return datetime_from_timet_and_us(st, cls, f, secs, us, tzinfo); } /*[clinic input] @@ -5174,10 +5284,11 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) /* Return best possible local time -- this isn't constrained by the * precision of a timestamp. */ - if (check_tzinfo_subclass(tz) < 0) + datetime_state *st = find_module_state_by_def(type); + if (check_tzinfo_subclass(st, tz) < 0) return NULL; - self = datetime_best_possible((PyObject *)type, + self = datetime_best_possible(st, (PyObject *)type, tz == Py_None ? _PyTime_localtime : _PyTime_gmtime, tz); @@ -5203,7 +5314,8 @@ datetime_utcnow(PyObject *cls, PyObject *dummy) { return NULL; } - return datetime_best_possible(cls, _PyTime_gmtime, Py_None); + datetime_state *st = find_module_state_by_def(cls); + return datetime_best_possible(st, cls, _PyTime_gmtime, Py_None); } /* Return new local datetime from timestamp (Python timestamp -- a double). */ @@ -5218,10 +5330,11 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", keywords, ×tamp, &tzinfo)) return NULL; - if (check_tzinfo_subclass(tzinfo) < 0) + datetime_state *st = find_module_state_by_def(cls); + if (check_tzinfo_subclass(st, tzinfo) < 0) return NULL; - self = datetime_from_timestamp(cls, + self = datetime_from_timestamp(st, cls, tzinfo == Py_None ? _PyTime_localtime : _PyTime_gmtime, timestamp, @@ -5249,9 +5362,11 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) PyObject *timestamp; PyObject *result = NULL; - if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp)) - result = datetime_from_timestamp(cls, _PyTime_gmtime, timestamp, + if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp)) { + datetime_state *st = find_module_state_by_def(cls); + result = datetime_from_timestamp(st, cls, _PyTime_gmtime, timestamp, Py_None); + } return result; } @@ -5259,19 +5374,21 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) static PyObject * datetime_strptime(PyObject *cls, PyObject *args) { - static PyObject *module = NULL; PyObject *string, *format; if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format)) return NULL; - if (module == NULL) { - module = PyImport_ImportModule("_strptime"); - if (module == NULL) + datetime_state *st = find_module_state_by_def(cls); + if (st->strptime == NULL) { + st->strptime = PyImport_ImportModule("_strptime"); + if (st->strptime == NULL) { return NULL; + } } - return PyObject_CallMethodObjArgs(module, &_Py_ID(_strptime_datetime), - cls, string, format, NULL); + return PyObject_CallMethodObjArgs(st->strptime, + &_Py_ID(_strptime_datetime), + cls, string, format, NULL); } /* Return new datetime from date/datetime and time arguments. */ @@ -5284,16 +5401,18 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw) PyObject *tzinfo = NULL; PyObject *result = NULL; + datetime_state *st = find_module_state_by_def(cls); if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords, - &PyDateTime_DateType, &date, - &PyDateTime_TimeType, &time, &tzinfo)) { + st->PyDateTime_DateType, &date, + st->PyDateTime_TimeType, &time, &tzinfo)) { if (tzinfo == NULL) { if (HASTZINFO(time)) tzinfo = ((PyDateTime_Time *)time)->tzinfo; else tzinfo = Py_None; } - result = new_datetime_subclass_fold_ex(GET_YEAR(date), + result = new_datetime_subclass_fold_ex(st, + GET_YEAR(date), GET_MONTH(date), GET_DAY(date), TIME_GET_HOUR(time), @@ -5537,12 +5656,13 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr) goto invalid_string_error; } - PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, tzusec); + datetime_state *st = find_module_state_by_def(cls); + PyObject *tzinfo = tzinfo_from_isoformat_results(st, rv, tzoffset, tzusec); if (tzinfo == NULL) { goto error; } - PyObject *dt = new_datetime_subclass_ex(year, month, day, hour, minute, + PyObject *dt = new_datetime_subclass_ex(st, year, month, day, hour, minute, second, microsecond, tzinfo, cls); Py_DECREF(tzinfo); @@ -5561,34 +5681,64 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr) /* * Destructor. */ +static int +datetime_traverse(PyDateTime_DateTime *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->tzinfo); + return 0; +} + +static int +datetime_clear(PyDateTime_DateTime *self) +{ + Py_CLEAR(self->tzinfo); + return 0; +} static void datetime_dealloc(PyDateTime_DateTime *self) { - if (HASTZINFO(self)) { - Py_XDECREF(self->tzinfo); - } - Py_TYPE(self)->tp_free((PyObject *)self); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)datetime_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } /* * Indirect access to tzinfo methods. */ -/* These are all METH_NOARGS, so don't need to check the arglist. */ +static inline PyObject * +_datetime_utcoffset(datetime_state *st, PyObject *self) +{ + return call_utcoffset(st, GET_DT_TZINFO(self), self); +} + +static inline PyObject * +_datetime_dst(datetime_state *st, PyObject *self) +{ + return call_dst(st, GET_DT_TZINFO(self), self); +} + static PyObject * -datetime_utcoffset(PyObject *self, PyObject *unused) { - return call_utcoffset(GET_DT_TZINFO(self), self); +datetime_tzname(PyObject *self, PyObject *unused) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_tzname(st, GET_DT_TZINFO(self), self); } + static PyObject * -datetime_dst(PyObject *self, PyObject *unused) { - return call_dst(GET_DT_TZINFO(self), self); +datetime_utcoffset(PyObject *self, PyObject *unused) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return _datetime_utcoffset(st, self); } static PyObject * -datetime_tzname(PyObject *self, PyObject *unused) { - return call_tzname(GET_DT_TZINFO(self), self); +datetime_dst(PyObject *self, PyObject *unused) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return _datetime_dst(st, self); } /* @@ -5599,7 +5749,8 @@ datetime_tzname(PyObject *self, PyObject *unused) { * the tzinfo state of date. */ static PyObject * -add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta, +add_datetime_timedelta(datetime_state *st, + PyDateTime_DateTime *date, PyDateTime_Delta *delta, int factor) { /* Note that the C-level additions can't overflow, because of @@ -5620,7 +5771,7 @@ add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta, return NULL; } - return new_datetime_subclass_ex(year, month, day, + return new_datetime_subclass_ex(st, year, month, day, hour, minute, second, microsecond, HASTZINFO(date) ? date->tzinfo : Py_None, (PyObject *)Py_TYPE(date)); @@ -5629,32 +5780,34 @@ add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta, static PyObject * datetime_add(PyObject *left, PyObject *right) { - if (PyDateTime_Check(left)) { + datetime_state *st = find_state_left_or_right(left, right); + if (PyDateTime_Check(st, left)) { /* datetime + ??? */ - if (PyDelta_Check(right)) + if (PyDelta_Check(st, right)) /* datetime + delta */ return add_datetime_timedelta( + st, (PyDateTime_DateTime *)left, (PyDateTime_Delta *)right, 1); } - else if (PyDelta_Check(left)) { + else if (PyDelta_Check(st, left)) { /* delta + datetime */ - return add_datetime_timedelta((PyDateTime_DateTime *) right, + return add_datetime_timedelta(st, (PyDateTime_DateTime *) right, (PyDateTime_Delta *) left, 1); } Py_RETURN_NOTIMPLEMENTED; } -static PyObject * -datetime_subtract(PyObject *left, PyObject *right) +static inline PyObject * +_datetime_subtract(datetime_state *st, PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - if (PyDateTime_Check(left)) { + if (PyDateTime_Check(st, left)) { /* datetime - ??? */ - if (PyDateTime_Check(right)) { + if (PyDateTime_Check(st, right)) { /* datetime - datetime */ PyObject *offset1, *offset2, *offdiff = NULL; int delta_d, delta_s, delta_us; @@ -5664,10 +5817,10 @@ datetime_subtract(PyObject *left, PyObject *right) offset2 = Py_NewRef(Py_None); } else { - offset1 = datetime_utcoffset(left, NULL); + offset1 = _datetime_utcoffset(st, left); if (offset1 == NULL) return NULL; - offset2 = datetime_utcoffset(right, NULL); + offset2 = _datetime_utcoffset(st, right); if (offset2 == NULL) { Py_DECREF(offset1); return NULL; @@ -5683,7 +5836,7 @@ datetime_subtract(PyObject *left, PyObject *right) } if ((offset1 != offset2) && delta_cmp(offset1, offset2) != 0) { - offdiff = delta_subtract(offset1, offset2); + offdiff = _delta_subtract(st, offset1, offset2); if (offdiff == NULL) { Py_DECREF(offset1); Py_DECREF(offset2); @@ -5710,18 +5863,18 @@ datetime_subtract(PyObject *left, PyObject *right) DATE_GET_SECOND(right)); delta_us = DATE_GET_MICROSECOND(left) - DATE_GET_MICROSECOND(right); - result = new_delta(delta_d, delta_s, delta_us, 1); + result = new_delta(st, delta_d, delta_s, delta_us, 1); if (result == NULL) return NULL; if (offdiff != NULL) { - Py_SETREF(result, delta_subtract(result, offdiff)); + Py_SETREF(result, _delta_subtract(st, result, offdiff)); Py_DECREF(offdiff); } } - else if (PyDelta_Check(right)) { + else if (PyDelta_Check(st, right)) { /* datetime - delta */ - result = add_datetime_timedelta( + result = add_datetime_timedelta(st, (PyDateTime_DateTime *)left, (PyDateTime_Delta *)right, -1); @@ -5733,6 +5886,13 @@ datetime_subtract(PyObject *left, PyObject *right) return result; } +static PyObject * +datetime_subtract(PyObject *left, PyObject *right) +{ + datetime_state *st = find_state_left_or_right(left, right); + return _datetime_subtract(st, left, right); +} + /* Various ways to turn a datetime into a string. */ static PyObject * @@ -5843,7 +6003,8 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) return result; /* We need to append the UTC offset. */ - if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (format_utcoffset(st, buffer, sizeof(buffer), ":", self->tzinfo, (PyObject *)self) < 0) { Py_DECREF(result); return NULL; @@ -5864,9 +6025,10 @@ datetime_ctime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) /* Miscellaneous methods. */ static PyObject * -flip_fold(PyObject *dt) +flip_fold(datetime_state *st, PyObject *dt) { - return new_datetime_ex2(GET_YEAR(dt), + return new_datetime_ex2(st, + GET_YEAR(dt), GET_MONTH(dt), GET_DAY(dt), DATE_GET_HOUR(dt), @@ -5880,14 +6042,14 @@ flip_fold(PyObject *dt) } static PyObject * -get_flip_fold_offset(PyObject *dt) +get_flip_fold_offset(datetime_state *st, PyObject *dt) { PyObject *result, *flip_dt; - flip_dt = flip_fold(dt); + flip_dt = flip_fold(st, dt); if (flip_dt == NULL) return NULL; - result = datetime_utcoffset(flip_dt, NULL); + result = _datetime_utcoffset(st, flip_dt); Py_DECREF(flip_dt); return result; } @@ -5899,13 +6061,13 @@ get_flip_fold_offset(PyObject *dt) * Return 1 if exception applies, 0 if not, and -1 on error. */ static int -pep495_eq_exception(PyObject *self, PyObject *other, +pep495_eq_exception(datetime_state *st, PyObject *self, PyObject *other, PyObject *offset_self, PyObject *offset_other) { int result = 0; PyObject *flip_offset; - flip_offset = get_flip_fold_offset(self); + flip_offset = get_flip_fold_offset(st, self); if (flip_offset == NULL) return -1; if (flip_offset != offset_self && @@ -5916,7 +6078,7 @@ pep495_eq_exception(PyObject *self, PyObject *other, } Py_DECREF(flip_offset); - flip_offset = get_flip_fold_offset(other); + flip_offset = get_flip_fold_offset(st, other); if (flip_offset == NULL) return -1; if (flip_offset != offset_other && @@ -5933,8 +6095,8 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) PyObject *result = NULL; PyObject *offset1, *offset2; int diff; - - if (!PyDateTime_Check(other)) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (!PyDateTime_Check(st, other)) { Py_RETURN_NOTIMPLEMENTED; } @@ -5944,10 +6106,10 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) _PyDateTime_DATETIME_DATASIZE); return diff_to_bool(diff, op); } - offset1 = datetime_utcoffset(self, NULL); + offset1 = _datetime_utcoffset(st, self); if (offset1 == NULL) return NULL; - offset2 = datetime_utcoffset(other, NULL); + offset2 = _datetime_utcoffset(st, other); if (offset2 == NULL) goto done; /* If they're both naive, or both aware and have the same offsets, @@ -5955,13 +6117,13 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) * offset2 == Py_None at this point. */ if ((offset1 == offset2) || - (PyDelta_Check(offset1) && PyDelta_Check(offset2) && + (PyDelta_Check(st, offset1) && PyDelta_Check(st, offset2) && delta_cmp(offset1, offset2) == 0)) { diff = memcmp(((PyDateTime_DateTime *)self)->data, ((PyDateTime_DateTime *)other)->data, _PyDateTime_DATETIME_DATASIZE); if ((op == Py_EQ || op == Py_NE) && diff == 0) { - int ex = pep495_eq_exception(self, other, offset1, offset2); + int ex = pep495_eq_exception(st, self, other, offset1, offset2); if (ex == -1) goto done; if (ex) @@ -5973,7 +6135,7 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) PyDateTime_Delta *delta; assert(offset1 != offset2); /* else last "if" handled it */ - delta = (PyDateTime_Delta *)datetime_subtract((PyObject *)self, + delta = (PyDateTime_Delta *)_datetime_subtract(st, (PyObject *)self, other); if (delta == NULL) goto done; @@ -5983,7 +6145,7 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) GET_TD_MICROSECONDS(delta); Py_DECREF(delta); if ((op == Py_EQ || op == Py_NE) && diff == 0) { - int ex = pep495_eq_exception(self, other, offset1, offset2); + int ex = pep495_eq_exception(st, self, other, offset1, offset2); if (ex == -1) goto done; if (ex) @@ -6011,10 +6173,12 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) static Py_hash_t datetime_hash(PyDateTime_DateTime *self) { + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (self->hashcode == -1) { PyObject *offset, *self0; if (DATE_GET_FOLD(self)) { - self0 = new_datetime_ex2(GET_YEAR(self), + self0 = new_datetime_ex2(st, + GET_YEAR(self), GET_MONTH(self), GET_DAY(self), DATE_GET_HOUR(self), @@ -6029,7 +6193,7 @@ datetime_hash(PyDateTime_DateTime *self) else { self0 = Py_NewRef(self); } - offset = datetime_utcoffset(self0, NULL); + offset = _datetime_utcoffset(st, self0); Py_DECREF(self0); if (offset == NULL) @@ -6050,14 +6214,15 @@ datetime_hash(PyDateTime_DateTime *self) seconds = DATE_GET_HOUR(self) * 3600 + DATE_GET_MINUTE(self) * 60 + DATE_GET_SECOND(self); - temp1 = new_delta(days, seconds, + + temp1 = new_delta(st, days, seconds, DATE_GET_MICROSECOND(self), 1); if (temp1 == NULL) { Py_DECREF(offset); return -1; } - temp2 = delta_subtract(temp1, offset); + temp2 = _delta_subtract(st, temp1, offset); Py_DECREF(temp1); if (temp2 == NULL) { Py_DECREF(offset); @@ -6095,13 +6260,14 @@ datetime_datetime_replace_impl(PyDateTime_DateTime *self, int year, int fold) /*[clinic end generated code: output=00bc96536833fddb input=9b38253d56d9bcad]*/ { - return new_datetime_subclass_fold_ex(year, month, day, hour, minute, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return new_datetime_subclass_fold_ex(st, year, month, day, hour, minute, second, microsecond, tzinfo, fold, (PyObject *)Py_TYPE(self)); } static PyObject * -local_timezone_from_timestamp(time_t timestamp) +local_timezone_from_timestamp(datetime_state *st, time_t timestamp) { PyObject *result = NULL; PyObject *delta; @@ -6113,7 +6279,7 @@ local_timezone_from_timestamp(time_t timestamp) return NULL; #ifdef HAVE_STRUCT_TM_TM_ZONE zone = local_time_tm.tm_zone; - delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1); + delta = new_delta(st, 0, local_time_tm.tm_gmtoff, 0, 1); #else /* HAVE_STRUCT_TM_TM_ZONE */ { PyObject *local_time, *utc_time; @@ -6121,7 +6287,8 @@ local_timezone_from_timestamp(time_t timestamp) char buf[100]; strftime(buf, sizeof(buf), "%Z", &local_time_tm); zone = buf; - local_time = new_datetime(local_time_tm.tm_year + 1900, + local_time = new_datetime(st, + local_time_tm.tm_year + 1900, local_time_tm.tm_mon + 1, local_time_tm.tm_mday, local_time_tm.tm_hour, @@ -6132,7 +6299,8 @@ local_timezone_from_timestamp(time_t timestamp) } if (_PyTime_gmtime(timestamp, &utc_time_tm) != 0) return NULL; - utc_time = new_datetime(utc_time_tm.tm_year + 1900, + utc_time = new_datetime(st, + utc_time_tm.tm_year + 1900, utc_time_tm.tm_mon + 1, utc_time_tm.tm_mday, utc_time_tm.tm_hour, @@ -6142,7 +6310,7 @@ local_timezone_from_timestamp(time_t timestamp) Py_DECREF(local_time); return NULL; } - delta = datetime_subtract(local_time, utc_time); + delta = _datetime_subtract(st, local_time, utc_time); Py_DECREF(local_time); Py_DECREF(utc_time); } @@ -6155,7 +6323,7 @@ local_timezone_from_timestamp(time_t timestamp) if (nameo == NULL) goto error; } - result = new_timezone(delta, nameo); + result = new_timezone(st, delta, nameo); Py_XDECREF(nameo); error: Py_DECREF(delta); @@ -6163,23 +6331,22 @@ local_timezone_from_timestamp(time_t timestamp) } static PyObject * -local_timezone(PyDateTime_DateTime *utc_time) +local_timezone(datetime_state *st, PyDateTime_DateTime *utc_time) { time_t timestamp; PyObject *delta; PyObject *one_second; PyObject *seconds; - datetime_state *st = STATIC_STATE(); - delta = datetime_subtract((PyObject *)utc_time, st->epoch); + delta = _datetime_subtract(st, (PyObject *)utc_time, st->epoch); if (delta == NULL) return NULL; - one_second = new_delta(0, 1, 0, 0); + one_second = new_delta(st, 0, 1, 0, 0); if (one_second == NULL) { Py_DECREF(delta); return NULL; } - seconds = divide_timedelta_timedelta((PyDateTime_Delta *)delta, + seconds = divide_timedelta_timedelta(st, (PyDateTime_Delta *)delta, (PyDateTime_Delta *)one_second); Py_DECREF(one_second); Py_DECREF(delta); @@ -6189,7 +6356,7 @@ local_timezone(PyDateTime_DateTime *utc_time) Py_DECREF(seconds); if (timestamp == -1 && PyErr_Occurred()) return NULL; - return local_timezone_from_timestamp(timestamp); + return local_timezone_from_timestamp(st, timestamp); } static long long @@ -6197,7 +6364,7 @@ local_to_seconds(int year, int month, int day, int hour, int minute, int second, int fold); static PyObject * -local_timezone_from_local(PyDateTime_DateTime *local_dt) +local_timezone_from_local(datetime_state *st, PyDateTime_DateTime *local_dt) { long long seconds, seconds2; time_t timestamp; @@ -6226,7 +6393,7 @@ local_timezone_from_local(PyDateTime_DateTime *local_dt) /* XXX: add bounds check */ timestamp = seconds - epoch; - return local_timezone_from_timestamp(timestamp); + return local_timezone_from_timestamp(st, timestamp); } static PyDateTime_DateTime * @@ -6243,12 +6410,13 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) &tzinfo)) return NULL; - if (check_tzinfo_subclass(tzinfo) == -1) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (check_tzinfo_subclass(st, tzinfo) == -1) return NULL; if (!HASTZINFO(self) || self->tzinfo == Py_None) { naive: - self_tzinfo = local_timezone_from_local(self); + self_tzinfo = local_timezone_from_local(st, self); if (self_tzinfo == NULL) return NULL; } else { @@ -6262,7 +6430,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) } /* Convert self to UTC. */ - offset = call_utcoffset(self_tzinfo, (PyObject *)self); + offset = call_utcoffset(st, self_tzinfo, (PyObject *)self); Py_DECREF(self_tzinfo); if (offset == NULL) return NULL; @@ -6270,25 +6438,25 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) Py_DECREF(offset); goto naive; } - else if (!PyDelta_Check(offset)) { + else if (!PyDelta_Check(st, offset)) { Py_DECREF(offset); PyErr_Format(PyExc_TypeError, "utcoffset() returned %.200s," " expected timedelta or None", Py_TYPE(offset)->tp_name); return NULL; } /* result = self - offset */ - result = (PyDateTime_DateTime *)add_datetime_timedelta(self, + result = (PyDateTime_DateTime *)add_datetime_timedelta(st, self, (PyDateTime_Delta *)offset, -1); Py_DECREF(offset); if (result == NULL) return NULL; - datetime_state *st = STATIC_STATE(); /* Make sure result is aware and UTC. */ if (!HASTZINFO(result)) { temp = (PyObject *)result; result = (PyDateTime_DateTime *) - new_datetime_ex2(GET_YEAR(result), + new_datetime_ex2(st, + GET_YEAR(result), GET_MONTH(result), GET_DAY(result), DATE_GET_HOUR(result), @@ -6309,7 +6477,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) /* Attach new tzinfo and let fromutc() do the rest. */ if (tzinfo == Py_None) { - tzinfo = local_timezone(result); + tzinfo = local_timezone(st, result); if (tzinfo == NULL) { Py_DECREF(result); return NULL; @@ -6335,7 +6503,8 @@ datetime_timetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) if (HASTZINFO(self) && self->tzinfo != Py_None) { PyObject * dst; - dst = call_dst(self->tzinfo, (PyObject *)self); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + dst = call_dst(st, self->tzinfo, (PyObject *)self); if (dst == NULL) return NULL; @@ -6408,12 +6577,12 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) PyObject *result; if (HASTZINFO(self) && self->tzinfo != Py_None) { - datetime_state *st = STATIC_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); PyObject *delta; - delta = datetime_subtract((PyObject *)self, st->epoch); + delta = _datetime_subtract(st, (PyObject *)self, st->epoch); if (delta == NULL) return NULL; - result = delta_total_seconds(delta, NULL); + result = _delta_total_seconds(st, delta); Py_DECREF(delta); } else { @@ -6436,7 +6605,9 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - return new_date(GET_YEAR(self), + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return new_date(st, + GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); } @@ -6444,7 +6615,9 @@ datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - return new_time(DATE_GET_HOUR(self), + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return new_time(st, + DATE_GET_HOUR(self), DATE_GET_MINUTE(self), DATE_GET_SECOND(self), DATE_GET_MICROSECOND(self), @@ -6455,7 +6628,9 @@ datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_gettimetz(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - return new_time(DATE_GET_HOUR(self), + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return new_time(st, + DATE_GET_HOUR(self), DATE_GET_MINUTE(self), DATE_GET_SECOND(self), DATE_GET_MICROSECOND(self), @@ -6476,7 +6651,8 @@ datetime_utctimetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) } else { PyObject *offset; - offset = call_utcoffset(tzinfo, (PyObject *)self); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + offset = call_utcoffset(st, tzinfo, (PyObject *)self); if (offset == NULL) return NULL; if (offset == Py_None) { @@ -6484,7 +6660,7 @@ datetime_utctimetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) utcself = (PyDateTime_DateTime*)Py_NewRef(self); } else { - utcself = (PyDateTime_DateTime *)add_datetime_timedelta(self, + utcself = (PyDateTime_DateTime *)add_datetime_timedelta(st, self, (PyDateTime_Delta *)offset, -1); Py_DECREF(offset); if (utcself == NULL) @@ -6642,60 +6818,33 @@ PyDoc_STR("datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzi The year, month and day arguments are required. tzinfo may be None, or an\n\ instance of a tzinfo subclass. The remaining arguments may be ints.\n"); -static PyNumberMethods datetime_as_number = { - datetime_add, /* nb_add */ - datetime_subtract, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - 0, /* nb_bool */ +static PyType_Slot datetime_slots[] = { + {Py_tp_dealloc, datetime_dealloc}, + {Py_tp_traverse, datetime_traverse}, + {Py_tp_clear, datetime_clear}, + {Py_tp_repr, datetime_repr}, + {Py_tp_hash, datetime_hash}, + {Py_tp_str, datetime_str}, + {Py_tp_doc, (void *)datetime_doc}, + {Py_tp_richcompare, datetime_richcompare}, + {Py_tp_methods, datetime_methods}, + {Py_tp_getset, datetime_getset}, + {Py_tp_new, datetime_new}, + + // Number protocol + {Py_nb_add, datetime_add}, + {Py_nb_subtract, datetime_subtract}, + {0, NULL}, }; -static PyTypeObject PyDateTime_DateTimeType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.datetime", /* tp_name */ - sizeof(PyDateTime_DateTime), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)datetime_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)datetime_repr, /* tp_repr */ - &datetime_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)datetime_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)datetime_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - datetime_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - datetime_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - datetime_methods, /* tp_methods */ - 0, /* tp_members */ - datetime_getset, /* tp_getset */ - 0, /* tp_base; filled in - PyInit__datetime */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - datetime_alloc, /* tp_alloc */ - datetime_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec datetime_spec = { + .name = "datetime.datetime", + .basicsize = sizeof(PyDateTime_DateTime), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = datetime_slots, }; /* --------------------------------------------------------------------------- @@ -6710,30 +6859,29 @@ static PyMethodDef module_methods[] = { * Clients get at C API via PyDateTime_IMPORT, defined in datetime.h. */ static inline PyDateTime_CAPI * -get_datetime_capi(void) +get_datetime_capi(datetime_state *st) { PyDateTime_CAPI *capi = PyMem_Malloc(sizeof(PyDateTime_CAPI)); if (capi == NULL) { PyErr_NoMemory(); return NULL; } - capi->DateType = &PyDateTime_DateType; - capi->DateTimeType = &PyDateTime_DateTimeType; - capi->TimeType = &PyDateTime_TimeType; - capi->DeltaType = &PyDateTime_DeltaType; - capi->TZInfoType = &PyDateTime_TZInfoType; + capi->DateType = st->PyDateTime_DateType; + capi->DateTimeType = st->PyDateTime_DateTimeType; + capi->TimeType = st->PyDateTime_TimeType; + capi->DeltaType = st->PyDateTime_DeltaType; + capi->TZInfoType = st->PyDateTime_TZInfoType; capi->Date_FromDate = new_date_ex; - capi->DateTime_FromDateAndTime = new_datetime_ex; - capi->Time_FromTime = new_time_ex; + capi->DateTime_FromDateAndTime = new_datetime_ex_capi; + capi->Time_FromTime = new_time_ex_capi; capi->Delta_FromDelta = new_delta_ex; - capi->TimeZone_FromTimeZone = new_timezone; + capi->TimeZone_FromTimeZone = new_timezone_capi; capi->DateTime_FromTimestamp = datetime_fromtimestamp; capi->Date_FromTimestamp = datetime_date_fromtimestamp_capi; - capi->DateTime_FromDateAndTimeAndFold = new_datetime_ex2; - capi->Time_FromTimeAndFold = new_time_ex2; + capi->DateTime_FromDateAndTimeAndFold = new_datetime_ex2_capi; + capi->Time_FromTimeAndFold = new_time_ex2_capi; // Make sure this function is called after utc has // been initialized. - datetime_state *st = STATIC_STATE(); assert(st->utc != NULL); capi->TimeZone_UTC = st->utc; // borrowed ref return capi; @@ -6746,31 +6894,15 @@ datetime_destructor(PyObject *op) PyMem_Free(ptr); } -static int -datetime_clear(PyObject *module) -{ - datetime_state *st = STATIC_STATE(); - - Py_CLEAR(st->us_per_ms); - Py_CLEAR(st->us_per_second); - Py_CLEAR(st->us_per_minute); - Py_CLEAR(st->us_per_hour); - Py_CLEAR(st->us_per_day); - Py_CLEAR(st->us_per_week); - Py_CLEAR(st->seconds_per_day); - Py_CLEAR(st->utc); - Py_CLEAR(st->epoch); - return 0; -} - static PyObject * -create_timezone_from_delta(int days, int sec, int ms, int normalize) +create_timezone_from_delta(datetime_state *st, + int days, int sec, int ms, int normalize) { - PyObject *delta = new_delta(days, sec, ms, normalize); + PyObject *delta = new_delta(st, days, sec, ms, normalize); if (delta == NULL) { return NULL; } - PyObject *tz = create_timezone(delta, NULL); + PyObject *tz = create_timezone(st, delta, NULL); Py_DECREF(delta); return tz; } @@ -6812,36 +6944,54 @@ init_state(datetime_state *st) } /* Init UTC timezone */ - st->utc = create_timezone_from_delta(0, 0, 0, 0); + st->utc = create_timezone_from_delta(st, 0, 0, 0, 0); if (st->utc == NULL) { return -1; } /* Init Unix epoch */ - st->epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->utc, 0); + st->epoch = new_datetime(st, 1970, 1, 1, 0, 0, 0, 0, st->utc, 0); if (st->epoch == NULL) { return -1; } return 0; } +static int module_clear(PyObject *module); + static int _datetime_exec(PyObject *module) { - // `&...` is not a constant expression according to a strict reading - // of C standards. Fill tp_base at run-time rather than statically. - // See https://bugs.python.org/issue40777 - PyDateTime_IsoCalendarDateType.tp_base = &PyTuple_Type; - PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType; - PyDateTime_DateTimeType.tp_base = &PyDateTime_DateType; + datetime_state *st = get_module_state(module); + +#define CREATE_TYPE(MOD, VAR, SPEC, BASE) do { \ + PyObject *tp = PyType_FromModuleAndSpec(MOD, SPEC, (PyObject *)BASE); \ + if (tp == NULL) { \ + goto error; \ + } \ + VAR = (PyTypeObject *)tp; \ +} while (0) + + CREATE_TYPE(module, st->PyDateTime_TimeType, &time_spec, NULL); + CREATE_TYPE(module, st->PyDateTime_TZInfoType, &tzinfo_spec, NULL); + CREATE_TYPE(module, st->PyDateTime_TimeZoneType, &timezone_spec, + st->PyDateTime_TZInfoType); + CREATE_TYPE(module, st->PyDateTime_IsoCalendarDateType, &isocal_spec, + &PyTuple_Type); + CREATE_TYPE(module, st->PyDateTime_DeltaType, &delta_spec, NULL); + CREATE_TYPE(module, st->PyDateTime_DateType, &date_spec, NULL); + CREATE_TYPE(module, st->PyDateTime_DateTimeType, &datetime_spec, + st->PyDateTime_DateType); + +#undef CREATE_TYPE PyTypeObject *types[] = { - &PyDateTime_DateType, - &PyDateTime_DateTimeType, - &PyDateTime_TimeType, - &PyDateTime_DeltaType, - &PyDateTime_TZInfoType, - &PyDateTime_TimeZoneType, + st->PyDateTime_DateType, + st->PyDateTime_DateTimeType, + st->PyDateTime_TimeType, + st->PyDateTime_DeltaType, + st->PyDateTime_TZInfoType, + st->PyDateTime_TimeZoneType, }; for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) { @@ -6850,10 +7000,6 @@ _datetime_exec(PyObject *module) } } - if (PyType_Ready(&PyDateTime_IsoCalendarDateType) < 0) { - goto error; - } - #define DATETIME_ADD_MACRO(dict, c, value_expr) \ do { \ PyObject *value = (value_expr); \ @@ -6868,39 +7014,38 @@ _datetime_exec(PyObject *module) } while(0) /* timedelta values */ - PyObject *d = PyDateTime_DeltaType.tp_dict; - DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); - DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0)); + PyObject *d = st->PyDateTime_DeltaType->tp_dict; + DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 0, 0, 1, 0)); + DATETIME_ADD_MACRO(d, "min", new_delta(st, -MAX_DELTA_DAYS, 0, 0, 0)); DATETIME_ADD_MACRO(d, "max", - new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0)); + new_delta(st, MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0)); /* date values */ - d = PyDateTime_DateType.tp_dict; - DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1)); - DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31)); - DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0)); + d = st->PyDateTime_DateType->tp_dict; + DATETIME_ADD_MACRO(d, "min", new_date(st, 1, 1, 1)); + DATETIME_ADD_MACRO(d, "max", new_date(st, MAXYEAR, 12, 31)); + DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 1, 0, 0, 0)); /* time values */ - d = PyDateTime_TimeType.tp_dict; - DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0)); - DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0)); - DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); + d = st->PyDateTime_TimeType->tp_dict; + DATETIME_ADD_MACRO(d, "min", new_time(st, 0, 0, 0, 0, Py_None, 0)); + DATETIME_ADD_MACRO(d, "max", new_time(st, 23, 59, 59, 999999, Py_None, 0)); + DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 0, 0, 1, 0)); /* datetime values */ - d = PyDateTime_DateTimeType.tp_dict; + d = st->PyDateTime_DateTimeType->tp_dict; DATETIME_ADD_MACRO(d, "min", - new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0)); - DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59, + new_datetime(st, 1, 1, 1, 0, 0, 0, 0, Py_None, 0)); + DATETIME_ADD_MACRO(d, "max", new_datetime(st, MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None, 0)); - DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); + DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 0, 0, 1, 0)); - datetime_state *st = STATIC_STATE(); if (init_state(st) < 0) { goto error; } /* timezone values */ - d = PyDateTime_TimeZoneType.tp_dict; + d = st->PyDateTime_TimeZoneType->tp_dict; if (PyDict_SetItemString(d, "utc", st->utc) < 0) { goto error; } @@ -6910,11 +7055,11 @@ _datetime_exec(PyObject *module) * values. This may change in the future.*/ /* -23:59 */ - PyObject *min = create_timezone_from_delta(-1, 60, 0, 1); + PyObject *min = create_timezone_from_delta(st, -1, 60, 0, 1); DATETIME_ADD_MACRO(d, "min", min); /* +23:59 */ - PyObject *max = create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0); + PyObject *max = create_timezone_from_delta(st, 0, (23 * 60 + 59) * 60, 0, 0); DATETIME_ADD_MACRO(d, "max", max); /* Add module level attributes */ @@ -6929,7 +7074,7 @@ _datetime_exec(PyObject *module) } /* At last, set up and add the encapsulated C API */ - PyDateTime_CAPI *capi = get_datetime_capi(); + PyDateTime_CAPI *capi = get_datetime_capi(st); if (capi == NULL) { goto error; } @@ -6965,32 +7110,87 @@ _datetime_exec(PyObject *module) return 0; error: - datetime_clear(module); + module_clear(module); return -1; } #undef DATETIME_ADD_MACRO +static int +module_traverse(PyObject *module, visitproc visit, void *arg) +{ + datetime_state *st = get_module_state(module); + Py_VISIT(st->us_per_ms); + Py_VISIT(st->us_per_second); + Py_VISIT(st->us_per_minute); + Py_VISIT(st->us_per_hour); + Py_VISIT(st->us_per_day); + Py_VISIT(st->us_per_week); + Py_VISIT(st->seconds_per_day); + Py_VISIT(st->utc); + Py_VISIT(st->epoch); + Py_VISIT(st->strptime); + Py_VISIT(st->PyDateTime_DateTimeType); + Py_VISIT(st->PyDateTime_DateType); + Py_VISIT(st->PyDateTime_DeltaType); + Py_VISIT(st->PyDateTime_IsoCalendarDateType); + Py_VISIT(st->PyDateTime_TZInfoType); + Py_VISIT(st->PyDateTime_TimeType); + Py_VISIT(st->PyDateTime_TimeZoneType); + return 0; +} + +static int +module_clear(PyObject *module) +{ + datetime_state *st = get_module_state(module); + Py_CLEAR(st->us_per_ms); + Py_CLEAR(st->us_per_second); + Py_CLEAR(st->us_per_minute); + Py_CLEAR(st->us_per_hour); + Py_CLEAR(st->us_per_day); + Py_CLEAR(st->us_per_week); + Py_CLEAR(st->seconds_per_day); + Py_CLEAR(st->utc); + Py_CLEAR(st->epoch); + Py_CLEAR(st->strptime); + Py_CLEAR(st->PyDateTime_DateTimeType); + Py_CLEAR(st->PyDateTime_DateType); + Py_CLEAR(st->PyDateTime_DeltaType); + Py_CLEAR(st->PyDateTime_IsoCalendarDateType); + Py_CLEAR(st->PyDateTime_TZInfoType); + Py_CLEAR(st->PyDateTime_TimeType); + Py_CLEAR(st->PyDateTime_TimeZoneType); + return 0; +} + +static void +module_free(void *module) +{ + (void)module_clear((PyObject *)module); +} + +static struct PyModuleDef_Slot module_slots[] = { + {Py_mod_exec, _datetime_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL}, +}; + static struct PyModuleDef datetimemodule = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "_datetime", .m_doc = "Fast implementation of the datetime type.", - .m_size = -1, + .m_size = sizeof(datetime_state), .m_methods = module_methods, + .m_slots = module_slots, + .m_traverse = module_traverse, + .m_clear = module_clear, + .m_free = module_free, }; PyMODINIT_FUNC PyInit__datetime(void) { - PyObject *mod = PyModule_Create(&datetimemodule); - if (mod == NULL) - return NULL; - - if (_datetime_exec(mod) < 0) { - Py_DECREF(mod); - return NULL; - } - - return mod; + return PyModuleDef_Init(&datetimemodule); } /* --------------------------------------------------------------------------- From 80084dae6dae07557d7ab8ecd61a95b9aa933ad2 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 04:17:11 +0900 Subject: [PATCH 02/50] import poc313a5 diff --- Include/datetime.h | 22 ++++++-- Lib/test/test_capi/test_misc.py | 16 ++++++ Modules/_testcapi/datetime.c | 16 +----- Modules/_testmultiphase.c | 59 +++++++++++++++++++++ Tools/c-analyzer/cpython/globals-to-fix.tsv | 11 +--- 5 files changed, 97 insertions(+), 27 deletions(-) diff --git a/Include/datetime.h b/Include/datetime.h index b78cc0e8e2e5ac..76544a5ece7267 100644 --- a/Include/datetime.h +++ b/Include/datetime.h @@ -194,10 +194,26 @@ typedef struct { * */ #ifndef _PY_DATETIME_IMPL /* Define global variable for the C API and a macro for setting it. */ -static PyDateTime_CAPI *PyDateTimeAPI = NULL; +static PyDateTime_CAPI *_pydatetimeapi_main = NULL; -#define PyDateTime_IMPORT \ - PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0) +static inline void +_import_pydatetime(void) { + if (PyInterpreterState_Get() == PyInterpreterState_Main()) { + _pydatetimeapi_main = PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0); + } +} +#define PyDateTime_IMPORT _import_pydatetime() + +static inline PyDateTime_CAPI * +_get_pydatetime_api(void) { + if (PyInterpreterState_Get() == PyInterpreterState_Main()) { + return _pydatetimeapi_main; + } + else { + return PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0); + } +} +#define PyDateTimeAPI _get_pydatetime_api() /* Macro for access to the UTC singleton */ #define PyDateTime_TimeZone_UTC PyDateTimeAPI->TimeZone_UTC diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 49d1056f050467..603ad9d2980248 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2282,6 +2282,22 @@ def test_module_state_shared_in_global(self): subinterp_attr_id = os.read(r, 100) self.assertEqual(main_attr_id, subinterp_attr_id) + @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") + def test_datetime_capi_client(self): + script = textwrap.dedent(""" + import importlib.machinery + import importlib.util + fullname = '_test_datetime_capi_client' + origin = importlib.util.find_spec('_testmultiphase').origin + loader = importlib.machinery.ExtensionFileLoader(fullname, origin) + spec = importlib.util.spec_from_loader(fullname, loader) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + """) + exec(script) # run main interp first + ret = support.run_in_subinterp(script) + self.assertEqual(ret, 0) + @requires_subinterpreters class InterpreterConfigTests(unittest.TestCase): diff --git a/Modules/_testcapi/datetime.c b/Modules/_testcapi/datetime.c index b1796039f0d83a..9803a830a25af1 100644 --- a/Modules/_testcapi/datetime.c +++ b/Modules/_testcapi/datetime.c @@ -3,23 +3,11 @@ #include "datetime.h" // PyDateTimeAPI -static int test_run_counter = 0; - static PyObject * test_datetime_capi(PyObject *self, PyObject *args) { - if (PyDateTimeAPI) { - if (test_run_counter) { - /* Probably regrtest.py -R */ - Py_RETURN_NONE; - } - else { - PyErr_SetString(PyExc_AssertionError, - "PyDateTime_CAPI somehow initialized"); - return NULL; - } - } - test_run_counter++; + // PyDateTimeAPI cannot be carried over + // with multi-phase init enabled. PyDateTime_IMPORT; if (PyDateTimeAPI) { diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index 21c5f696a4f2ec..e09de1d5a7b793 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -952,3 +952,62 @@ PyInit__test_shared_gil_only(void) { return PyModuleDef_Init(&shared_gil_only_def); } + + +#include "datetime.h" + +static int +datetime_capi_client_exec(PyObject *m) +{ + int ismain = PyInterpreterState_Get() == PyInterpreterState_Main(); + if (ismain) { + _pydatetimeapi_main = NULL; + } + + PyDateTime_IMPORT; + if (PyDateTimeAPI == NULL) { + return -1; + } + if (PyDateTimeAPI != PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)) { + return -1; + } + if (ismain) { + if (PyDateTimeAPI != _pydatetimeapi_main) { + return -1; + } + } + else { + if (PyDateTimeAPI == _pydatetimeapi_main) { + PyObject *module = PyImport_ImportModule("_datetime"); + if (module == NULL) { + return -1; + } + PyModuleDef *def = PyModule_GetDef(module); + Py_DECREF(module); + if (def) { + // multi-phase init + return -1; + } + else { + // legacy init (shared module) + return 0; + } + } + } + return 0; +} + +static PyModuleDef_Slot datetime_capi_client_slots[] = { + {Py_mod_exec, datetime_capi_client_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL}, +}; + +static PyModuleDef datetime_capi_client_def = TEST_MODULE_DEF( + "_testmultiphase_datetime_capi_client", datetime_capi_client_slots, NULL); + +PyMODINIT_FUNC +PyInit__test_datetime_capi_client(void) +{ + return PyModuleDef_Init(&datetime_capi_client_def); +} diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 79a8f850ec1451..3e4b36ce411d90 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -383,13 +383,6 @@ Modules/_ctypes/ctypes.h - _ctypes_ptrtype_cache - Modules/_ctypes/ctypes.h - basespec_string - Modules/_ctypes/stgdict.c - PyCStgDict_Type - Modules/_cursesmodule.c - PyCursesWindow_Type - -Modules/_datetimemodule.c - PyDateTime_DateTimeType - -Modules/_datetimemodule.c - PyDateTime_DateType - -Modules/_datetimemodule.c - PyDateTime_DeltaType - -Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - -Modules/_datetimemodule.c - PyDateTime_TZInfoType - -Modules/_datetimemodule.c - PyDateTime_TimeType - -Modules/_datetimemodule.c - PyDateTime_TimeZoneType - Modules/xxmodule.c - Null_Type - Modules/xxmodule.c - Str_Type - Modules/xxmodule.c - Xxo_Type - @@ -426,13 +419,11 @@ Modules/_ctypes/_ctypes.c CreateSwappedType swapped_suffix - Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype array_cache - Modules/_cursesmodule.c - ModDict - -Modules/_datetimemodule.c datetime_strptime module - ## state Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache - Modules/_ctypes/_ctypes.c - global_state - Modules/_ctypes/ctypes.h - global_state - -Modules/_datetimemodule.c - _datetime_global_state - Modules/_tkinter.c - tcl_lock - Modules/_tkinter.c - excInCmd - Modules/_tkinter.c - valInCmd - @@ -446,7 +437,7 @@ Modules/_tkinter.c - trbInCmd - ## initialized once ## other -Include/datetime.h - PyDateTimeAPI - +Include/datetime.h - _pydatetimeapi_main - Modules/_ctypes/cfield.c _ctypes_get_fielddesc initialized - Modules/_ctypes/malloc_closure.c - _pagesize - Modules/_cursesmodule.c - initialised - From 23bf9b469ed2b63440e7a2504eba4a444d9ba9e6 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 04:53:56 +0900 Subject: [PATCH 03/50] module, classes --- Modules/_datetimemodule.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 4788a1bbbc165e..7ef95014a95ea1 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -190,17 +190,28 @@ find_state_left_or_right(PyObject *left, PyObject *right) static int check_tzinfo_subclass(datetime_state *st, PyObject *p); +typedef struct +{ + PyObject_HEAD + PyObject *offset; + PyObject *name; +} PyDateTime_TimeZone; + /*[clinic input] module datetime -class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType" -class datetime.date "PyDateTime_Date *" "&PyDateTime_DateType" -class datetime.time "PyDateTime_Time *" "&PyDateTime_TimeType" -class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCalendarDateType" +class datetime.datetime "PyDateTime_DateTime *" "clinic_state()->PyDateTime_DateTimeType" +class datetime.date "PyDateTime_Date *" "clinic_state()->PyDateTime_DateType" +class datetime.timedelta "PyDateTime_Delta *" "clinic_state()->PyDateTime_DeltaType" +class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "clinic_state()->PyDateTime_IsoCalendarDateType" +class datetime.time "PyDateTime_Time *" "clinic_state()->PyDateTime_TimeType" +class datetime.tzinfo "PyDateTime_TZInfo *" "clinic_state()->PyDateTime_TZInfoType" +class datetime.timezone "PyDateTime_TimeZone *" "clinic_state()->PyDateTime_TimeZoneType" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6f65a48dd22fa40f]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c941b310de347082]*/ +#define clinic_state() (get_module_state_by_cls(defcls)) #include "clinic/_datetimemodule.c.h" - +#undef clinic_state /* --------------------------------------------------------------------------- * Math utilities. @@ -1236,13 +1247,6 @@ new_delta_ex(int days, int seconds, int microseconds, int normalize, new_delta_ex(d, s, us, normalize, st->PyDateTime_DeltaType) -typedef struct -{ - PyObject_HEAD - PyObject *offset; - PyObject *name; -} PyDateTime_TimeZone; - /* Create new timezone instance checking offset range. This function does not check the name argument. Caller must assure that offset is a timedelta instance and name is either NULL From 286a28429fa1cb60378bd6eab78d912815e0f244 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 04:57:48 +0900 Subject: [PATCH 04/50] timedelta_total_seconds() --- Modules/_datetimemodule.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 7ef95014a95ea1..b83fef2eaea4a3 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -2852,10 +2852,21 @@ _delta_total_seconds(datetime_state *st, PyObject *self) return total_seconds; } +/*[clinic input] +datetime.timedelta.total_seconds + + self: self(type="PyObject *") + defcls: defining_class + / + +Total seconds in the duration. +[clinic start generated code]*/ + static PyObject * -delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) +datetime_timedelta_total_seconds_impl(PyObject *self, PyTypeObject *defcls) +/*[clinic end generated code: output=d702744694267dbf input=324f72e0d662f3b3]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); return _delta_total_seconds(st, self); } @@ -2897,8 +2908,7 @@ static PyMemberDef delta_members[] = { }; static PyMethodDef delta_methods[] = { - {"total_seconds", delta_total_seconds, METH_NOARGS, - PyDoc_STR("Total seconds in the duration.")}, + DATETIME_TIMEDELTA_TOTAL_SECONDS_METHODDEF {"__reduce__", (PyCFunction)delta_reduce, METH_NOARGS, PyDoc_STR("__reduce__() -> (cls, state)")}, From 8ba2af755017098860eaeeb7ed6e64c4531c3868 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:01:41 +0900 Subject: [PATCH 05/50] date.fromtimestamp() update --- Modules/_datetimemodule.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index b83fef2eaea4a3..b635b50d842521 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3104,6 +3104,7 @@ date_today(PyObject *cls, PyObject *dummy) @classmethod datetime.date.fromtimestamp + defcls: defining_class timestamp: object / @@ -3114,10 +3115,11 @@ as local time. [clinic start generated code]*/ static PyObject * -datetime_date_fromtimestamp(PyTypeObject *type, PyObject *timestamp) -/*[clinic end generated code: output=fd045fda58168869 input=eabb3fe7f40491fe]*/ +datetime_date_fromtimestamp_impl(PyTypeObject *type, PyTypeObject *defcls, + PyObject *timestamp) +/*[clinic end generated code: output=b387674ccfcdead8 input=1b3db9c4244c304e]*/ { - datetime_state *st = find_module_state_by_def(type); + datetime_state *st = get_module_state_by_cls(defcls); return date_fromtimestamp(st, (PyObject *) type, timestamp); } From b21bded5369503cbd36b8c994743b2afa966e662 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:10:19 +0900 Subject: [PATCH 06/50] date.fromordinal() --- Modules/_datetimemodule.c | 78 ++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index b635b50d842521..5bb4013f278432 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3141,35 +3141,60 @@ datetime_date_fromtimestamp_capi(PyObject *cls, PyObject *args) return result; } -/* Return new date from proleptic Gregorian ordinal. Raises ValueError if - * the ordinal is out of range. - */ +/*[clinic input] +@classmethod +datetime.date.fromordinal + + cls: self(type="PyObject *") + defcls: defining_class + ordinal: int + / + +int -> date corresponding to a proleptic Gregorian ordinal. + +Return new date from proleptic Gregorian ordinal. Raises ValueError +if the ordinal is out of range. +[clinic start generated code]*/ + static PyObject * -date_fromordinal(PyObject *cls, PyObject *args) +datetime_date_fromordinal_impl(PyObject *cls, PyTypeObject *defcls, + int ordinal) +/*[clinic end generated code: output=fa7ca4621f1ee8be input=76c85e045fdfbc97]*/ { PyObject *result = NULL; - int ordinal; - - if (PyArg_ParseTuple(args, "i:fromordinal", &ordinal)) { - int year; - int month; - int day; + int year; + int month; + int day; - if (ordinal < 1) - PyErr_SetString(PyExc_ValueError, "ordinal must be " - ">= 1"); - else { - ord_to_ymd(ordinal, &year, &month, &day); - datetime_state *st = find_module_state_by_def(cls); - result = new_date_subclass_ex(st, year, month, day, cls); - } + if (ordinal < 1) { + PyErr_SetString(PyExc_ValueError, "ordinal must be >= 1"); + } + else { + ord_to_ymd(ordinal, &year, &month, &day); + datetime_state *st = get_module_state_by_cls(defcls); + result = new_date_subclass_ex(st, year, month, day, cls); } return result; } -/* Return the new date from a string as generated by date.isoformat() */ +/*[clinic input] +@classmethod +datetime.date.fromisoformat + + cls: self(type="PyObject *") + defcls: defining_class + dtstr: object + / + +str -> Construct a date from a string in ISO 8601 format. + +Return the new date from a string as generated by date.isoformat(). +[clinic start generated code]*/ + static PyObject * -date_fromisoformat(PyObject *cls, PyObject *dtstr) +datetime_date_fromisoformat_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *dtstr) +/*[clinic end generated code: output=c382fc14a39f8b89 input=67564908cc8f0013]*/ { assert(dtstr != NULL); @@ -3199,7 +3224,7 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) if (rv < 0) { goto invalid_string_error; } - datetime_state *st = find_module_state_by_def(cls); + datetime_state *st = get_module_state_by_cls(defcls); return new_date_subclass_ex(st, year, month, day, cls); invalid_string_error: @@ -3717,15 +3742,8 @@ static PyMethodDef date_methods[] = { /* Class methods: */ DATETIME_DATE_FROMTIMESTAMP_METHODDEF - - {"fromordinal", (PyCFunction)date_fromordinal, METH_VARARGS | - METH_CLASS, - PyDoc_STR("int -> date corresponding to a proleptic Gregorian " - "ordinal.")}, - - {"fromisoformat", (PyCFunction)date_fromisoformat, METH_O | - METH_CLASS, - PyDoc_STR("str -> Construct a date from a string in ISO 8601 format.")}, + DATETIME_DATE_FROMORDINAL_METHODDEF + DATETIME_DATE_FROMISOFORMAT_METHODDEF {"fromisocalendar", _PyCFunction_CAST(date_fromisocalendar), METH_VARARGS | METH_KEYWORDS | METH_CLASS, From c1f6a754539db33c9ac60b2ae543a1cc579702be Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:17:06 +0900 Subject: [PATCH 07/50] date.fromisocalendar() with converter --- Modules/_datetimemodule.c | 61 ++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 5bb4013f278432..d90b1a3edbc1c0 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -209,6 +209,8 @@ class datetime.timezone "PyDateTime_TimeZone *" "clinic_state()->PyDateTime_Time [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c941b310de347082]*/ +static int calendar_int_converter(PyObject* arg, int *value); + #define clinic_state() (get_module_state_by_cls(defcls)) #include "clinic/_datetimemodule.c.h" #undef clinic_state @@ -3232,26 +3234,50 @@ datetime_date_fromisoformat_impl(PyObject *cls, PyTypeObject *defcls, return NULL; } - -static PyObject * -date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) +static int +calendar_int_converter(PyObject* arg, int *value) { - static char *keywords[] = { - "year", "week", "day", NULL - }; - - int year, week, day; - if (PyArg_ParseTupleAndKeywords(args, kw, "iii:fromisocalendar", - keywords, - &year, &week, &day) == 0) { + int face_value = PyLong_AsInt(arg); + if (face_value == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_Format(PyExc_ValueError, "ISO calendar component out of range"); - } - return NULL; + *value = -1; + return 0; } + *value = face_value; + return 1; +} +/*[python input] +class calendar_int_converter(CConverter): + type = 'int' + converter = 'calendar_int_converter' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=62a8ae38ff2c9c0b]*/ + + +/*[clinic input] +@classmethod +datetime.date.fromisocalendar + + cls: self(type="PyObject *") + defcls: defining_class + year: calendar_int + week: calendar_int + day: calendar_int + +int, int, int -> Construct a date from the ISO year, week number and weekday. + +This is the inverse of the date.isocalendar() function. +[clinic start generated code]*/ + +static PyObject * +datetime_date_fromisocalendar_impl(PyObject *cls, PyTypeObject *defcls, + int year, int week, int day) +/*[clinic end generated code: output=bcf68c1effd051aa input=44ba1ccacefc1617]*/ +{ int month; int rv = iso_to_ymd(year, week, day, &year, &month, &day); @@ -3270,7 +3296,7 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) day); return NULL; } - datetime_state *st = find_module_state_by_def(cls); + datetime_state *st = get_module_state_by_cls(defcls); return new_date_subclass_ex(st, year, month, day, cls); } @@ -3744,12 +3770,7 @@ static PyMethodDef date_methods[] = { DATETIME_DATE_FROMTIMESTAMP_METHODDEF DATETIME_DATE_FROMORDINAL_METHODDEF DATETIME_DATE_FROMISOFORMAT_METHODDEF - - {"fromisocalendar", _PyCFunction_CAST(date_fromisocalendar), - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("int, int, int -> Construct a date from the ISO year, week " - "number and weekday.\n\n" - "This is the inverse of the date.isocalendar() function")}, + DATETIME_DATE_FROMISOCALENDAR_METHODDEF {"today", (PyCFunction)date_today, METH_NOARGS | METH_CLASS, PyDoc_STR("Current date or datetime: same as " From bd99b422ce44650ff9749e53d8160be59d05c309 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:19:57 +0900 Subject: [PATCH 08/50] date.strftime() --- Modules/_datetimemodule.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index d90b1a3edbc1c0..abcdf7faa87287 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3413,25 +3413,30 @@ date_ctime(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) return format_ctime(self, 0, 0, 0); } +/*[clinic input] +datetime.date.strftime + + defcls: defining_class + format: unicode + +format -> strftime() style string. +[clinic start generated code]*/ + static PyObject * -date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw) +datetime_date_strftime_impl(PyDateTime_Date *self, PyTypeObject *defcls, + PyObject *format) +/*[clinic end generated code: output=605af1ff474ad7ac input=3a6cf7ef6a95d3dd]*/ { /* This method can be inherited, and needs to call the * timetuple() method appropriate to self's class. */ PyObject *result; PyObject *tuple; - PyObject *format; - static char *keywords[] = {"format", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords, - &format)) - return NULL; tuple = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(timetuple)); if (tuple == NULL) return NULL; - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); result = wrap_strftime(st, (PyObject *)self, format, tuple, (PyObject *)self); Py_DECREF(tuple); @@ -3781,8 +3786,7 @@ static PyMethodDef date_methods[] = { {"ctime", (PyCFunction)date_ctime, METH_NOARGS, PyDoc_STR("Return ctime() style string.")}, - {"strftime", _PyCFunction_CAST(date_strftime), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("format -> strftime() style string.")}, + DATETIME_DATE_STRFTIME_METHODDEF {"__format__", (PyCFunction)date_format, METH_VARARGS, PyDoc_STR("Formats self with strftime.")}, From 126b6521db97e31da994fd0490fd5ed6a64666cf Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:22:13 +0900 Subject: [PATCH 09/50] date.isocalendar() --- Modules/_datetimemodule.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index abcdf7faa87287..e977b7e55ac436 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3619,8 +3619,17 @@ iso_calendar_date_new_impl(PyTypeObject *type, int year, int week, return (PyObject *)self; } +/*[clinic input] +datetime.date.isocalendar + + defcls: defining_class + / +Return a named tuple containing ISO year, week number, and weekday. +[clinic start generated code]*/ + static PyObject * -date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) +datetime_date_isocalendar_impl(PyDateTime_Date *self, PyTypeObject *defcls) +/*[clinic end generated code: output=1c363b5301019a12 input=67faf915bc47b3b1]*/ { int year = GET_YEAR(self); int week1_monday = iso_week1_monday(year); @@ -3639,7 +3648,7 @@ date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) week = 0; } - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); PyObject* v = iso_calendar_date_new_impl(st->PyDateTime_IsoCalendarDateType, year, week + 1, day + 1); if (v == NULL) { @@ -3794,9 +3803,7 @@ static PyMethodDef date_methods[] = { {"timetuple", (PyCFunction)date_timetuple, METH_NOARGS, PyDoc_STR("Return time tuple, compatible with time.localtime().")}, - {"isocalendar", (PyCFunction)date_isocalendar, METH_NOARGS, - PyDoc_STR("Return a named tuple containing ISO year, week number, and " - "weekday.")}, + DATETIME_DATE_ISOCALENDAR_METHODDEF {"isoformat", (PyCFunction)date_isoformat, METH_NOARGS, PyDoc_STR("Return string in ISO 8601 format, YYYY-MM-DD.")}, From 8e31f9dc96f852de1890cd42278188fc28d69101 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:24:50 +0900 Subject: [PATCH 10/50] date.replace() update --- Modules/_datetimemodule.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index e977b7e55ac436..14b07e6893ebb4 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3693,6 +3693,7 @@ date_timetuple(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) /*[clinic input] datetime.date.replace + defcls: defining_class year: int(c_default="GET_YEAR(self)") = unchanged month: int(c_default="GET_MONTH(self)") = unchanged day: int(c_default="GET_DAY(self)") = unchanged @@ -3701,11 +3702,11 @@ Return date with new specified fields. [clinic start generated code]*/ static PyObject * -datetime_date_replace_impl(PyDateTime_Date *self, int year, int month, - int day) -/*[clinic end generated code: output=2a9430d1e6318aeb input=0d1f02685b3e90f6]*/ +datetime_date_replace_impl(PyDateTime_Date *self, PyTypeObject *defcls, + int year, int month, int day) +/*[clinic end generated code: output=cd5959b5babf9c13 input=1e7b2e02b632f185]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); return new_date_subclass_ex(st, year, month, day, (PyObject *)Py_TYPE(self)); } From 109bea7c10bcb81cc912c5a80c4c27c227a969cb Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:28:05 +0900 Subject: [PATCH 11/50] date.__replace__() --- Modules/_datetimemodule.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 14b07e6893ebb4..8011bb6409f180 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3710,6 +3710,24 @@ datetime_date_replace_impl(PyDateTime_Date *self, PyTypeObject *defcls, return new_date_subclass_ex(st, year, month, day, (PyObject *)Py_TYPE(self)); } +/*[clinic input] +datetime.date.__replace__ + + defcls: defining_class + year: int(c_default="GET_YEAR(self)") = unchanged + month: int(c_default="GET_MONTH(self)") = unchanged + day: int(c_default="GET_DAY(self)") = unchanged + +[clinic start generated code]*/ + +static PyObject * +datetime_date___replace___impl(PyDateTime_Date *self, PyTypeObject *defcls, + int year, int month, int day) +/*[clinic end generated code: output=4274716e2fed7f61 input=7218fbab51692bf7]*/ +{ + return datetime_date_replace_impl(self, defcls, year, month, day); +} + static Py_hash_t generic_hash(unsigned char *data, int len) { @@ -3822,9 +3840,7 @@ static PyMethodDef date_methods[] = { "Monday == 0 ... Sunday == 6")}, DATETIME_DATE_REPLACE_METHODDEF - - {"__replace__", _PyCFunction_CAST(datetime_date_replace), METH_FASTCALL | METH_KEYWORDS, - PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, + DATETIME_DATE___REPLACE___METHODDEF {"__reduce__", (PyCFunction)date_reduce, METH_NOARGS, PyDoc_STR("__reduce__() -> (cls, state)")}, From 25bf57baca189d7537fb2ef476341c04a46e1bba Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:34:31 +0900 Subject: [PATCH 12/50] tzinfo.fromutc() --- Modules/_datetimemodule.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 8011bb6409f180..42e401945bbe6b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3937,14 +3937,26 @@ static inline PyObject * _datetime_dst(datetime_state *st, PyObject *self); +/*[clinic input] +datetime.tzinfo.fromutc + + defcls: defining_class + dt: object + / + +datetime in UTC -> datetime in local time. +[clinic start generated code]*/ + static PyObject * -tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) +datetime_tzinfo_fromutc_impl(PyDateTime_TZInfo *self, PyTypeObject *defcls, + PyObject *dt) +/*[clinic end generated code: output=94232bf0b95e71c6 input=8120c9bd10df62c9]*/ { PyObject *result = NULL; PyObject *off = NULL, *dst = NULL; PyDateTime_Delta *delta = NULL; - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); if (!PyDateTime_Check(st, dt)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); @@ -4073,8 +4085,7 @@ static PyMethodDef tzinfo_methods[] = { {"dst", (PyCFunction)tzinfo_dst, METH_O, PyDoc_STR("datetime -> DST offset as timedelta positive east of UTC.")}, - {"fromutc", (PyCFunction)tzinfo_fromutc, METH_O, - PyDoc_STR("datetime in UTC -> datetime in local time.")}, + DATETIME_TZINFO_FROMUTC_METHODDEF {"__reduce__", tzinfo_reduce, METH_NOARGS, PyDoc_STR("-> (cls, state)")}, From 82c65ce830d9530256850503d6659f335348ac75 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:35:28 +0900 Subject: [PATCH 13/50] timezone.tzname() --- Modules/_datetimemodule.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 42e401945bbe6b..59507cc7db7ee3 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4256,10 +4256,25 @@ timezone_str(PyDateTime_TimeZone *self) return PyUnicode_FromFormat("UTC%c%02d:%02d", sign, hours, minutes); } +/*[clinic input] +datetime.timezone.tzname + + defcls: defining_class + dt: object + / + +Return the name specified at timezone creation, or offset as 'UTC(+|-)HH:MM'. + +If name is specified when timezone is created, returns the name. +Otherwise returns offset as 'UTC(+|-)HH:MM'. +[clinic start generated code]*/ + static PyObject * -timezone_tzname(PyDateTime_TimeZone *self, PyObject *dt) +datetime_timezone_tzname_impl(PyDateTime_TimeZone *self, + PyTypeObject *defcls, PyObject *dt) +/*[clinic end generated code: output=113e7127189d5a8f input=5c1b6aa0f14fe729]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); if (_timezone_check_argument(st, dt, "tzname") == -1) return NULL; @@ -4313,9 +4328,7 @@ timezone_getinitargs(PyDateTime_TimeZone *self, PyObject *Py_UNUSED(ignored)) } static PyMethodDef timezone_methods[] = { - {"tzname", (PyCFunction)timezone_tzname, METH_O, - PyDoc_STR("If name is specified when timezone is created, returns the name." - " Otherwise returns offset as 'UTC(+|-)HH:MM'.")}, + DATETIME_TIMEZONE_TZNAME_METHODDEF {"utcoffset", (PyCFunction)timezone_utcoffset, METH_O, PyDoc_STR("Return fixed offset.")}, From 25dbfe964ee7d0aa1406606aabd347d3f62a2134 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:37:32 +0900 Subject: [PATCH 14/50] timezone.utcoffset() --- Modules/_datetimemodule.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 59507cc7db7ee3..9ed84907c3ae83 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4281,10 +4281,22 @@ datetime_timezone_tzname_impl(PyDateTime_TimeZone *self, return timezone_str(self); } +/*[clinic input] +datetime.timezone.utcoffset + + defcls: defining_class + dt: object + / + +Return fixed offset. +[clinic start generated code]*/ + static PyObject * -timezone_utcoffset(PyDateTime_TimeZone *self, PyObject *dt) +datetime_timezone_utcoffset_impl(PyDateTime_TimeZone *self, + PyTypeObject *defcls, PyObject *dt) +/*[clinic end generated code: output=89aaa9277a7bbb85 input=08741fbba8f1fc2b]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); if (_timezone_check_argument(st, dt, "utcoffset") == -1) return NULL; @@ -4329,9 +4341,7 @@ timezone_getinitargs(PyDateTime_TimeZone *self, PyObject *Py_UNUSED(ignored)) static PyMethodDef timezone_methods[] = { DATETIME_TIMEZONE_TZNAME_METHODDEF - - {"utcoffset", (PyCFunction)timezone_utcoffset, METH_O, - PyDoc_STR("Return fixed offset.")}, + DATETIME_TIMEZONE_UTCOFFSET_METHODDEF {"dst", (PyCFunction)timezone_dst, METH_O, PyDoc_STR("Return None.")}, From af1eaf57619df568be58636e5ee3ce965191ce51 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:39:06 +0900 Subject: [PATCH 15/50] timezone.dst() --- Modules/_datetimemodule.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 9ed84907c3ae83..bb6bd38d5d0724 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4303,10 +4303,22 @@ datetime_timezone_utcoffset_impl(PyDateTime_TimeZone *self, return Py_NewRef(self->offset); } +/*[clinic input] +datetime.timezone.dst + + defcls: defining_class + dt: object + / + +Return None. +[clinic start generated code]*/ + static PyObject * -timezone_dst(PyObject *self, PyObject *dt) +datetime_timezone_dst_impl(PyDateTime_TimeZone *self, PyTypeObject *defcls, + PyObject *dt) +/*[clinic end generated code: output=416cf0e62d3b6a59 input=35ad50ada9cb0080]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); if (_timezone_check_argument(st, dt, "dst") == -1) return NULL; @@ -4342,9 +4354,7 @@ timezone_getinitargs(PyDateTime_TimeZone *self, PyObject *Py_UNUSED(ignored)) static PyMethodDef timezone_methods[] = { DATETIME_TIMEZONE_TZNAME_METHODDEF DATETIME_TIMEZONE_UTCOFFSET_METHODDEF - - {"dst", (PyCFunction)timezone_dst, METH_O, - PyDoc_STR("Return None.")}, + DATETIME_TIMEZONE_DST_METHODDEF {"fromutc", (PyCFunction)timezone_fromutc, METH_O, PyDoc_STR("datetime in UTC -> datetime in local time.")}, From 0b5c97cd61d07f8953c4689d481e44f86c113075 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:40:38 +0900 Subject: [PATCH 16/50] timezone.fromutc() --- Modules/_datetimemodule.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index bb6bd38d5d0724..332781895d1b0f 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4325,10 +4325,22 @@ datetime_timezone_dst_impl(PyDateTime_TimeZone *self, PyTypeObject *defcls, Py_RETURN_NONE; } +/*[clinic input] +datetime.timezone.fromutc + + defcls: defining_class + dt: object(type="PyDateTime_DateTime *") + / + +datetime in UTC -> datetime in local time. +[clinic start generated code]*/ + static PyObject * -timezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt) +datetime_timezone_fromutc_impl(PyDateTime_TimeZone *self, + PyTypeObject *defcls, PyDateTime_DateTime *dt) +/*[clinic end generated code: output=dd223807a395bb47 input=46b13520da9ab86c]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); if (!PyDateTime_Check(st, dt)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); @@ -4355,9 +4367,7 @@ static PyMethodDef timezone_methods[] = { DATETIME_TIMEZONE_TZNAME_METHODDEF DATETIME_TIMEZONE_UTCOFFSET_METHODDEF DATETIME_TIMEZONE_DST_METHODDEF - - {"fromutc", (PyCFunction)timezone_fromutc, METH_O, - PyDoc_STR("datetime in UTC -> datetime in local time.")}, + DATETIME_TIMEZONE_FROMUTC_METHODDEF {"__getinitargs__", (PyCFunction)timezone_getinitargs, METH_NOARGS, PyDoc_STR("pickle support")}, From 903d26f627953e648e92560d186fa803c718f388 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:43:54 +0900 Subject: [PATCH 17/50] time.utcoffset() --- Modules/_datetimemodule.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 332781895d1b0f..199c1914dd9c1e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4591,9 +4591,20 @@ _time_utcoffset(datetime_state *st, PyObject *self) { return call_utcoffset(st, GET_TIME_TZINFO(self), Py_None); } + +/*[clinic input] +datetime.time.utcoffset + + defcls: defining_class + / +Return self.tzinfo.utcoffset(self). +[clinic start generated code]*/ + static PyObject * -time_utcoffset(PyObject *self, PyObject *unused) { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); +datetime_time_utcoffset_impl(PyDateTime_Time *self, PyTypeObject *defcls) +/*[clinic end generated code: output=ac5fef17552f8943 input=b98f428ad48b7daa]*/ +{ + datetime_state *st = get_module_state_by_cls(defcls); return _time_utcoffset(st, (PyObject *)self); } @@ -5021,8 +5032,7 @@ static PyMethodDef time_methods[] = { {"__format__", (PyCFunction)date_format, METH_VARARGS, PyDoc_STR("Formats self with strftime.")}, - {"utcoffset", (PyCFunction)time_utcoffset, METH_NOARGS, - PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, + DATETIME_TIME_UTCOFFSET_METHODDEF {"tzname", (PyCFunction)time_tzname, METH_NOARGS, PyDoc_STR("Return self.tzinfo.tzname(self).")}, From e4f6b7c752f9e10a1c7e24563dcaf4347502de25 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:45:56 +0900 Subject: [PATCH 18/50] time.dst() --- Modules/_datetimemodule.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 199c1914dd9c1e..dfba98add72668 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4608,9 +4608,19 @@ datetime_time_utcoffset_impl(PyDateTime_Time *self, PyTypeObject *defcls) return _time_utcoffset(st, (PyObject *)self); } +/*[clinic input] +datetime.time.dst + + defcls: defining_class + / +Return self.tzinfo.dst(self). +[clinic start generated code]*/ + static PyObject * -time_dst(PyObject *self, PyObject *unused) { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); +datetime_time_dst_impl(PyDateTime_Time *self, PyTypeObject *defcls) +/*[clinic end generated code: output=ac88a767bfd45c46 input=b61ebd917d818bc1]*/ +{ + datetime_state *st = get_module_state_by_cls(defcls); return call_dst(st, GET_TIME_TZINFO(self), Py_None); } @@ -5037,9 +5047,7 @@ static PyMethodDef time_methods[] = { {"tzname", (PyCFunction)time_tzname, METH_NOARGS, PyDoc_STR("Return self.tzinfo.tzname(self).")}, - {"dst", (PyCFunction)time_dst, METH_NOARGS, - PyDoc_STR("Return self.tzinfo.dst(self).")}, - + DATETIME_TIME_DST_METHODDEF DATETIME_TIME_REPLACE_METHODDEF {"__replace__", _PyCFunction_CAST(datetime_time_replace), METH_FASTCALL | METH_KEYWORDS, From 569bc03e9edb3faea09555b267d6fcc2cd038ddf Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:47:45 +0900 Subject: [PATCH 19/50] time.tzname() --- Modules/_datetimemodule.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index dfba98add72668..6134c6249ce587 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4624,9 +4624,19 @@ datetime_time_dst_impl(PyDateTime_Time *self, PyTypeObject *defcls) return call_dst(st, GET_TIME_TZINFO(self), Py_None); } +/*[clinic input] +datetime.time.tzname + + defcls: defining_class + / +Return self.tzinfo.tzname(self). +[clinic start generated code]*/ + static PyObject * -time_tzname(PyDateTime_Time *self, PyObject *unused) { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); +datetime_time_tzname_impl(PyDateTime_Time *self, PyTypeObject *defcls) +/*[clinic end generated code: output=3308d0b8deba7d33 input=4404cb8a7bff9ffa]*/ +{ + datetime_state *st = get_module_state_by_cls(defcls); return call_tzname(st, GET_TIME_TZINFO(self), Py_None); } @@ -5043,10 +5053,7 @@ static PyMethodDef time_methods[] = { PyDoc_STR("Formats self with strftime.")}, DATETIME_TIME_UTCOFFSET_METHODDEF - - {"tzname", (PyCFunction)time_tzname, METH_NOARGS, - PyDoc_STR("Return self.tzinfo.tzname(self).")}, - + DATETIME_TIME_TZNAME_METHODDEF DATETIME_TIME_DST_METHODDEF DATETIME_TIME_REPLACE_METHODDEF From d0556d0b76fc19f1d4979c323c72d01c9d0f38d8 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:51:31 +0900 Subject: [PATCH 20/50] time.isoformat() --- Modules/_datetimemodule.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 6134c6249ce587..f2cbb282a53747 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4676,12 +4676,25 @@ time_str(PyDateTime_Time *self) return PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(isoformat)); } +/*[clinic input] +datetime.time.isoformat + + defcls: defining_class + timespec: str = NULL; + +Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM]. + +The optional argument timespec specifies the number of additional terms +of the time to include. Valid options are 'auto', 'hours', 'minutes', +'seconds', 'milliseconds' and 'microseconds'. +[clinic start generated code]*/ + static PyObject * -time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw) +datetime_time_isoformat_impl(PyDateTime_Time *self, PyTypeObject *defcls, + const char *timespec) +/*[clinic end generated code: output=67801509cfb4fd5b input=61b371e51644bb49]*/ { char buf[100]; - const char *timespec = NULL; - static char *keywords[] = {"timespec", NULL}; PyObject *result; int us = TIME_GET_MICROSECOND(self); static const char *specs[][2] = { @@ -4693,9 +4706,6 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw) }; size_t given_spec; - if (!PyArg_ParseTupleAndKeywords(args, kw, "|s:isoformat", keywords, ×pec)) - return NULL; - if (timespec == NULL || strcmp(timespec, "auto") == 0) { if (us == 0) { /* seconds */ @@ -4732,7 +4742,7 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw) return result; /* We need to append the UTC offset. */ - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); if (format_utcoffset(st, buf, sizeof(buf), ":", self->tzinfo, Py_None) < 0) { Py_DECREF(result); @@ -5037,14 +5047,7 @@ time_reduce(PyDateTime_Time *self, PyObject *arg) } static PyMethodDef time_methods[] = { - - {"isoformat", _PyCFunction_CAST(time_isoformat), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]]" - "[+HH:MM].\n\n" - "The optional argument timespec specifies the number " - "of additional terms\nof the time to include. Valid " - "options are 'auto', 'hours', 'minutes',\n'seconds', " - "'milliseconds' and 'microseconds'.\n")}, + DATETIME_TIME_ISOFORMAT_METHODDEF {"strftime", _PyCFunction_CAST(time_strftime), METH_VARARGS | METH_KEYWORDS, PyDoc_STR("format -> strftime() style string.")}, From faf377252e472890baa5d50e1a05d7cd17eb132a Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:52:59 +0900 Subject: [PATCH 21/50] time.strftime() --- Modules/_datetimemodule.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index f2cbb282a53747..a12954ce8c8c67 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4752,17 +4752,22 @@ datetime_time_isoformat_impl(PyDateTime_Time *self, PyTypeObject *defcls, return result; } +/*[clinic input] +datetime.time.strftime + + defcls: defining_class + format: unicode + +format -> strftime() style string. +[clinic start generated code]*/ + static PyObject * -time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw) +datetime_time_strftime_impl(PyDateTime_Time *self, PyTypeObject *defcls, + PyObject *format) +/*[clinic end generated code: output=d52d5945421e204d input=13ae1ce9fed79229]*/ { PyObject *result; PyObject *tuple; - PyObject *format; - static char *keywords[] = {"format", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords, - &format)) - return NULL; /* Python's strftime does insane things with the year part of the * timetuple. The year is forced to (the otherwise nonsensical) @@ -4777,7 +4782,7 @@ time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw) if (tuple == NULL) return NULL; assert(PyTuple_Size(tuple) == 9); - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); result = wrap_strftime(st, (PyObject *)self, format, tuple, Py_None); Py_DECREF(tuple); @@ -5048,9 +5053,7 @@ time_reduce(PyDateTime_Time *self, PyObject *arg) static PyMethodDef time_methods[] = { DATETIME_TIME_ISOFORMAT_METHODDEF - - {"strftime", _PyCFunction_CAST(time_strftime), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("format -> strftime() style string.")}, + DATETIME_TIME_STRFTIME_METHODDEF {"__format__", (PyCFunction)date_format, METH_VARARGS, PyDoc_STR("Formats self with strftime.")}, From 489f173a12624c2bca68f62792cc43da64cb8eab Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:56:52 +0900 Subject: [PATCH 22/50] time.replace() update --- Modules/_datetimemodule.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index a12954ce8c8c67..e7002fd231bc3b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4925,6 +4925,7 @@ time_hash(PyDateTime_Time *self) /*[clinic input] datetime.time.replace + defcls: defining_class hour: int(c_default="TIME_GET_HOUR(self)") = unchanged minute: int(c_default="TIME_GET_MINUTE(self)") = unchanged second: int(c_default="TIME_GET_SECOND(self)") = unchanged @@ -4937,15 +4938,14 @@ Return time with new specified fields. [clinic start generated code]*/ static PyObject * -datetime_time_replace_impl(PyDateTime_Time *self, int hour, int minute, - int second, int microsecond, PyObject *tzinfo, - int fold) -/*[clinic end generated code: output=0b89a44c299e4f80 input=9b6a35b1e704b0ca]*/ +datetime_time_replace_impl(PyDateTime_Time *self, PyTypeObject *defcls, + int hour, int minute, int second, int microsecond, + PyObject *tzinfo, int fold) +/*[clinic end generated code: output=5afc2a8ba7546c79 input=0389d9824e5c911e]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); - return new_time_subclass_fold_ex(st, - hour, minute, second, microsecond, tzinfo, - fold, (PyObject *)Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); + return new_time_subclass_fold_ex(st, hour, minute, second, microsecond, + tzinfo, fold, (PyObject *)Py_TYPE(self)); } static PyObject * From fcf8c32d0c032397625c3c23c7cd547c9ac8bfbd Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 05:59:05 +0900 Subject: [PATCH 23/50] time.__replace__() --- Modules/_datetimemodule.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index e7002fd231bc3b..7e521cf725e88b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4948,6 +4948,29 @@ datetime_time_replace_impl(PyDateTime_Time *self, PyTypeObject *defcls, tzinfo, fold, (PyObject *)Py_TYPE(self)); } +/*[clinic input] +datetime.time.__replace__ + + defcls: defining_class + hour: int(c_default="TIME_GET_HOUR(self)") = unchanged + minute: int(c_default="TIME_GET_MINUTE(self)") = unchanged + second: int(c_default="TIME_GET_SECOND(self)") = unchanged + microsecond: int(c_default="TIME_GET_MICROSECOND(self)") = unchanged + tzinfo: object(c_default="HASTZINFO(self) ? self->tzinfo : Py_None") = unchanged + * + fold: int(c_default="TIME_GET_FOLD(self)") = unchanged +[clinic start generated code]*/ + +static PyObject * +datetime_time___replace___impl(PyDateTime_Time *self, PyTypeObject *defcls, + int hour, int minute, int second, + int microsecond, PyObject *tzinfo, int fold) +/*[clinic end generated code: output=0db4f39f3353ecf6 input=cf50f2b0e8925429]*/ +{ + return datetime_time_replace_impl(self, defcls, hour, minute, second, + microsecond, tzinfo, fold); +} + static PyObject * time_fromisoformat(PyObject *cls, PyObject *tstr) { assert(tstr != NULL); @@ -5062,9 +5085,7 @@ static PyMethodDef time_methods[] = { DATETIME_TIME_TZNAME_METHODDEF DATETIME_TIME_DST_METHODDEF DATETIME_TIME_REPLACE_METHODDEF - - {"__replace__", _PyCFunction_CAST(datetime_time_replace), METH_FASTCALL | METH_KEYWORDS, - PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, + DATETIME_TIME___REPLACE___METHODDEF {"fromisoformat", (PyCFunction)time_fromisoformat, METH_O | METH_CLASS, PyDoc_STR("string -> time from a string in ISO 8601 format")}, From af9c28e1a6a9ddebdbc825ddf3560c7e941209db Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:01:19 +0900 Subject: [PATCH 24/50] time.fromisoformat() --- Modules/_datetimemodule.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 7e521cf725e88b..721d3c5937dbad 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4971,8 +4971,22 @@ datetime_time___replace___impl(PyDateTime_Time *self, PyTypeObject *defcls, microsecond, tzinfo, fold); } +/*[clinic input] +@classmethod +datetime.time.fromisoformat + + cls: self(type="PyObject *") + defcls: defining_class + tstr: object + / +string -> time from a string in ISO 8601 format. +[clinic start generated code]*/ + static PyObject * -time_fromisoformat(PyObject *cls, PyObject *tstr) { +datetime_time_fromisoformat_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *tstr) +/*[clinic end generated code: output=a7090769b0254021 input=f7e5714b1c6fa564]*/ +{ assert(tstr != NULL); if (!PyUnicode_Check(tstr)) { @@ -5005,7 +5019,7 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) { goto invalid_string_error; } - datetime_state *st = find_module_state_by_def(cls); + datetime_state *st = get_module_state_by_cls(defcls); PyObject *tzinfo = tzinfo_from_isoformat_results(st, rv, tzoffset, tzimicrosecond); @@ -5086,9 +5100,7 @@ static PyMethodDef time_methods[] = { DATETIME_TIME_DST_METHODDEF DATETIME_TIME_REPLACE_METHODDEF DATETIME_TIME___REPLACE___METHODDEF - - {"fromisoformat", (PyCFunction)time_fromisoformat, METH_O | METH_CLASS, - PyDoc_STR("string -> time from a string in ISO 8601 format")}, + DATETIME_TIME_FROMISOFORMAT_METHODDEF {"__reduce_ex__", (PyCFunction)time_reduce_ex, METH_VARARGS, PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")}, From 0138f9b8e45da5842c631982962648453ee8b970 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:05:47 +0900 Subject: [PATCH 25/50] datetime.now() update --- Modules/_datetimemodule.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 721d3c5937dbad..e3b86693642133 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5464,10 +5464,10 @@ datetime_best_possible(datetime_state *st, } /*[clinic input] - @classmethod datetime.datetime.now + defcls: defining_class tz: object = None Timezone object. @@ -5477,15 +5477,16 @@ If no tz is specified, uses local timezone. [clinic start generated code]*/ static PyObject * -datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) -/*[clinic end generated code: output=b3386e5345e2b47a input=80d09869c5267d00]*/ +datetime_datetime_now_impl(PyTypeObject *type, PyTypeObject *defcls, + PyObject *tz) +/*[clinic end generated code: output=eee68d8dd2928931 input=7d43a283cbc7686b]*/ { PyObject *self; /* Return best possible local time -- this isn't constrained by the * precision of a timestamp. */ - datetime_state *st = find_module_state_by_def(type); + datetime_state *st = get_module_state_by_cls(defcls); if (check_tzinfo_subclass(st, tz) < 0) return NULL; From 991b858c10c241b0ddb17eb9e275f89e6bc2ef06 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:08:25 +0900 Subject: [PATCH 26/50] datetime.fromtimestamp() --- Modules/_datetimemodule.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index e3b86693642133..7205cd86619a18 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5520,19 +5520,27 @@ datetime_utcnow(PyObject *cls, PyObject *dummy) return datetime_best_possible(st, cls, _PyTime_gmtime, Py_None); } -/* Return new local datetime from timestamp (Python timestamp -- a double). */ +/*[clinic input] +@classmethod +datetime.datetime.fromtimestamp + + cls: self(type="PyObject *") + defcls: defining_class + timestamp: object + tz as tzinfo: object = None + +timestamp[, tz] -> tz's local time from POSIX timestamp. + +Return new local datetime from timestamp (Python timestamp -- a double). +[clinic start generated code]*/ + static PyObject * -datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) +datetime_datetime_fromtimestamp_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *timestamp, PyObject *tzinfo) +/*[clinic end generated code: output=2cbe69dea19b6df9 input=47b4a2977d90c439]*/ { PyObject *self; - PyObject *timestamp; - PyObject *tzinfo = Py_None; - static char *keywords[] = {"timestamp", "tz", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", - keywords, ×tamp, &tzinfo)) - return NULL; - datetime_state *st = find_module_state_by_def(cls); + datetime_state *st = get_module_state_by_cls(defcls); if (check_tzinfo_subclass(st, tzinfo) < 0) return NULL; @@ -6934,9 +6942,7 @@ static PyMethodDef datetime_methods[] = { METH_NOARGS | METH_CLASS, PyDoc_STR("Return a new datetime representing UTC day and time.")}, - {"fromtimestamp", _PyCFunction_CAST(datetime_fromtimestamp), - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")}, + DATETIME_DATETIME_FROMTIMESTAMP_METHODDEF {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp, METH_VARARGS | METH_CLASS, From a2cff70b5118c78679a1e214b060d47d118b465c Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:11:25 +0900 Subject: [PATCH 27/50] datetime_fromtimestamp_capi() --- Modules/_datetimemodule.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 7205cd86619a18..7bcfe549d5e2f3 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5558,6 +5558,18 @@ datetime_datetime_fromtimestamp_impl(PyObject *cls, PyTypeObject *defcls, return self; } +static PyObject * +datetime_fromtimestamp_capi(PyObject *cls, PyObject *args, PyObject *kw) +{ + PyObject *timestamp; + PyObject *tzinfo = Py_None; + static char *keywords[] = {"timestamp", "tz", NULL}; + if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", + keywords, ×tamp, &tzinfo)) + return NULL; + return datetime_datetime_fromtimestamp_impl(cls, (PyTypeObject *)cls, timestamp, tzinfo); +} + /* Return new UTC datetime from timestamp (Python timestamp -- a double). */ static PyObject * datetime_utcfromtimestamp(PyObject *cls, PyObject *args) @@ -7084,7 +7096,7 @@ get_datetime_capi(datetime_state *st) capi->Time_FromTime = new_time_ex_capi; capi->Delta_FromDelta = new_delta_ex; capi->TimeZone_FromTimeZone = new_timezone_capi; - capi->DateTime_FromTimestamp = datetime_fromtimestamp; + capi->DateTime_FromTimestamp = datetime_fromtimestamp_capi; capi->Date_FromTimestamp = datetime_date_fromtimestamp_capi; capi->DateTime_FromDateAndTimeAndFold = new_datetime_ex2_capi; capi->Time_FromTimeAndFold = new_time_ex2_capi; From 3811a3f4cdf29556b4aaa05003233016c2168d23 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:16:20 +0900 Subject: [PATCH 28/50] datetime.strptime() --- Modules/_datetimemodule.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 7bcfe549d5e2f3..ec3972d83c7b92 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5592,16 +5592,27 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) return result; } -/* Return new datetime from _strptime.strptime_datetime(). */ -static PyObject * -datetime_strptime(PyObject *cls, PyObject *args) -{ - PyObject *string, *format; +/*[clinic input] +@classmethod +datetime.datetime.strptime - if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format)) - return NULL; + cls: self(type="PyObject *") + defcls: defining_class + string: object + format: object + / - datetime_state *st = find_module_state_by_def(cls); +string, format -> new datetime parsed from a string (like time.strptime()). + +Return new datetime from _strptime.strptime_datetime(). +[clinic start generated code]*/ + +static PyObject * +datetime_datetime_strptime_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *string, PyObject *format) +/*[clinic end generated code: output=7b52ad40cc6f1ecc input=3aeadaad950da13a]*/ +{ + datetime_state *st = get_module_state_by_cls(defcls); if (st->strptime == NULL) { st->strptime = PyImport_ImportModule("_strptime"); if (st->strptime == NULL) { @@ -6960,10 +6971,7 @@ static PyMethodDef datetime_methods[] = { METH_VARARGS | METH_CLASS, PyDoc_STR("Construct a naive UTC datetime from a POSIX timestamp.")}, - {"strptime", (PyCFunction)datetime_strptime, - METH_VARARGS | METH_CLASS, - PyDoc_STR("string, format -> new datetime parsed from a string " - "(like time.strptime()).")}, + DATETIME_DATETIME_STRPTIME_METHODDEF {"combine", _PyCFunction_CAST(datetime_combine), METH_VARARGS | METH_KEYWORDS | METH_CLASS, From a48202b44034ada7224bc2ecc5d4468d0c8d3019 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:18:41 +0900 Subject: [PATCH 29/50] datetime.combine() --- Modules/_datetimemodule.c | 70 +++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index ec3972d83c7b92..d93b58568523ea 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5624,38 +5624,47 @@ datetime_datetime_strptime_impl(PyObject *cls, PyTypeObject *defcls, cls, string, format, NULL); } -/* Return new datetime from date/datetime and time arguments. */ +/*[clinic input] +@classmethod +datetime.datetime.combine + + cls: self(type="PyObject *") + defcls: defining_class + date: object(subclass_of='clinic_state()->PyDateTime_DateType') + time: object(subclass_of='clinic_state()->PyDateTime_TimeType') + tzinfo: object = NULL; + +date, time -> datetime with same date and time fields. + +Return new datetime from date/datetime and time arguments. +[clinic start generated code]*/ + static PyObject * -datetime_combine(PyObject *cls, PyObject *args, PyObject *kw) +datetime_datetime_combine_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *date, PyObject *time, + PyObject *tzinfo) +/*[clinic end generated code: output=973e7edbdf2370fb input=43f4cea1bfda8e92]*/ { - static char *keywords[] = {"date", "time", "tzinfo", NULL}; - PyObject *date; - PyObject *time; - PyObject *tzinfo = NULL; PyObject *result = NULL; - datetime_state *st = find_module_state_by_def(cls); - if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords, - st->PyDateTime_DateType, &date, - st->PyDateTime_TimeType, &time, &tzinfo)) { - if (tzinfo == NULL) { - if (HASTZINFO(time)) - tzinfo = ((PyDateTime_Time *)time)->tzinfo; - else - tzinfo = Py_None; - } - result = new_datetime_subclass_fold_ex(st, - GET_YEAR(date), - GET_MONTH(date), - GET_DAY(date), - TIME_GET_HOUR(time), - TIME_GET_MINUTE(time), - TIME_GET_SECOND(time), - TIME_GET_MICROSECOND(time), - tzinfo, - TIME_GET_FOLD(time), - cls); - } + datetime_state *st = get_module_state_by_cls(defcls); + if (tzinfo == NULL) { + if (HASTZINFO(time)) + tzinfo = ((PyDateTime_Time *)time)->tzinfo; + else + tzinfo = Py_None; + } + result = new_datetime_subclass_fold_ex(st, + GET_YEAR(date), + GET_MONTH(date), + GET_DAY(date), + TIME_GET_HOUR(time), + TIME_GET_MINUTE(time), + TIME_GET_SECOND(time), + TIME_GET_MICROSECOND(time), + tzinfo, + TIME_GET_FOLD(time), + cls); return result; } @@ -6972,10 +6981,7 @@ static PyMethodDef datetime_methods[] = { PyDoc_STR("Construct a naive UTC datetime from a POSIX timestamp.")}, DATETIME_DATETIME_STRPTIME_METHODDEF - - {"combine", _PyCFunction_CAST(datetime_combine), - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("date, time -> datetime with same date and time fields")}, + DATETIME_DATETIME_COMBINE_METHODDEF {"fromisoformat", (PyCFunction)datetime_fromisoformat, METH_O | METH_CLASS, From 492fe6fbc42d41df7bd3337a4cc57090dc782b2a Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:20:52 +0900 Subject: [PATCH 30/50] datetime.fromisoformat() --- Modules/_datetimemodule.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index d93b58568523ea..a9518a418ea580 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5823,8 +5823,22 @@ _find_isoformat_datetime_separator(const char *dtstr, Py_ssize_t len) { } } +/*[clinic input] +@classmethod +datetime.datetime.fromisoformat + + cls: self(type="PyObject *") + defcls: defining_class + dtstr: object + / + +string -> datetime from a string in most ISO 8601 formats +[clinic start generated code]*/ + static PyObject * -datetime_fromisoformat(PyObject *cls, PyObject *dtstr) +datetime_datetime_fromisoformat_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *dtstr) +/*[clinic end generated code: output=5f024cc279cd5ae5 input=bf5409a138f87123]*/ { assert(dtstr != NULL); @@ -5898,7 +5912,7 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr) goto invalid_string_error; } - datetime_state *st = find_module_state_by_def(cls); + datetime_state *st = get_module_state_by_cls(defcls); PyObject *tzinfo = tzinfo_from_isoformat_results(st, rv, tzoffset, tzusec); if (tzinfo == NULL) { goto error; @@ -6982,10 +6996,7 @@ static PyMethodDef datetime_methods[] = { DATETIME_DATETIME_STRPTIME_METHODDEF DATETIME_DATETIME_COMBINE_METHODDEF - - {"fromisoformat", (PyCFunction)datetime_fromisoformat, - METH_O | METH_CLASS, - PyDoc_STR("string -> datetime from a string in most ISO 8601 formats")}, + DATETIME_DATETIME_FROMISOFORMAT_METHODDEF /* Instance methods: */ From 92e6ed216d5ea10e39eed9e948421e8404a243aa Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:22:45 +0900 Subject: [PATCH 31/50] datetime.tzname() --- Modules/_datetimemodule.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index a9518a418ea580..00da9e99b82a23 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5978,9 +5978,21 @@ _datetime_dst(datetime_state *st, PyObject *self) return call_dst(st, GET_DT_TZINFO(self), self); } +/*[clinic input] +datetime.datetime.tzname + + self: self(type="PyObject *") + defcls: defining_class + / + +Return self.tzinfo.tzname(self). +[clinic start generated code]*/ + static PyObject * -datetime_tzname(PyObject *self, PyObject *unused) { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); +datetime_datetime_tzname_impl(PyObject *self, PyTypeObject *defcls) +/*[clinic end generated code: output=0c5b0a3e52e73c05 input=49b64ed4fce2233d]*/ +{ + datetime_state *st = get_module_state_by_cls(defcls); return call_tzname(st, GET_DT_TZINFO(self), self); } @@ -7034,8 +7046,7 @@ static PyMethodDef datetime_methods[] = { {"utcoffset", (PyCFunction)datetime_utcoffset, METH_NOARGS, PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, - {"tzname", (PyCFunction)datetime_tzname, METH_NOARGS, - PyDoc_STR("Return self.tzinfo.tzname(self).")}, + DATETIME_DATETIME_TZNAME_METHODDEF {"dst", (PyCFunction)datetime_dst, METH_NOARGS, PyDoc_STR("Return self.tzinfo.dst(self).")}, From 5c89a911bf9dbbe087949682bed102c0b6f03a85 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:24:22 +0900 Subject: [PATCH 32/50] datetime.utcoffset() --- Modules/_datetimemodule.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 00da9e99b82a23..46355f5e365d5c 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5996,10 +5996,21 @@ datetime_datetime_tzname_impl(PyObject *self, PyTypeObject *defcls) return call_tzname(st, GET_DT_TZINFO(self), self); } +/*[clinic input] +datetime.datetime.utcoffset + + self: self(type="PyObject *") + defcls: defining_class + / + +Return self.tzinfo.utcoffset(self). +[clinic start generated code]*/ static PyObject * -datetime_utcoffset(PyObject *self, PyObject *unused) { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); +datetime_datetime_utcoffset_impl(PyObject *self, PyTypeObject *defcls) +/*[clinic end generated code: output=28dadac514ad14f7 input=c415e161379a079e]*/ +{ + datetime_state *st = get_module_state_by_cls(defcls); return _datetime_utcoffset(st, self); } @@ -7043,9 +7054,7 @@ static PyMethodDef datetime_methods[] = { "options are 'auto', 'hours', 'minutes',\n'seconds', " "'milliseconds' and 'microseconds'.\n")}, - {"utcoffset", (PyCFunction)datetime_utcoffset, METH_NOARGS, - PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, - + DATETIME_DATETIME_UTCOFFSET_METHODDEF DATETIME_DATETIME_TZNAME_METHODDEF {"dst", (PyCFunction)datetime_dst, METH_NOARGS, From de23ca5a70871cfbe9b43db7891e0586f3e675f6 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:26:04 +0900 Subject: [PATCH 33/50] datetime.dst() --- Modules/_datetimemodule.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 46355f5e365d5c..8436ad19cbb10a 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6014,9 +6014,21 @@ datetime_datetime_utcoffset_impl(PyObject *self, PyTypeObject *defcls) return _datetime_utcoffset(st, self); } +/*[clinic input] +datetime.datetime.dst + + self: self(type="PyObject *") + defcls: defining_class + / + +Return self.tzinfo.dst(self). +[clinic start generated code]*/ + static PyObject * -datetime_dst(PyObject *self, PyObject *unused) { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); +datetime_datetime_dst_impl(PyObject *self, PyTypeObject *defcls) +/*[clinic end generated code: output=7fb2ddf5978f37f8 input=dcfdcaed1a5311e4]*/ +{ + datetime_state *st = get_module_state_by_cls(defcls); return _datetime_dst(st, self); } @@ -7056,10 +7068,7 @@ static PyMethodDef datetime_methods[] = { DATETIME_DATETIME_UTCOFFSET_METHODDEF DATETIME_DATETIME_TZNAME_METHODDEF - - {"dst", (PyCFunction)datetime_dst, METH_NOARGS, - PyDoc_STR("Return self.tzinfo.dst(self).")}, - + DATETIME_DATETIME_DST_METHODDEF DATETIME_DATETIME_REPLACE_METHODDEF {"__replace__", _PyCFunction_CAST(datetime_datetime_replace), METH_FASTCALL | METH_KEYWORDS, From c2b315e2ed4f76f947716d101ea31edbdf02a9ac Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:29:02 +0900 Subject: [PATCH 34/50] datetime.isoformat() --- Modules/_datetimemodule.c | 40 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 8436ad19cbb10a..df4dba7f8020ef 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6236,12 +6236,28 @@ datetime_str(PyDateTime_DateTime *self) return res; } +/*[clinic input] +datetime.datetime.isoformat + + defcls: defining_class + sep: int(accept={str}, c_default="'T'", py_default="'T'") = 0 + timespec: str = NULL + +[sep] -> string in ISO 8601 format, + +YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM]. +sep is used to separate the year from the time, and defaults to 'T'. +The optional argument timespec specifies the number of additional terms +of the time to include. Valid options are 'auto', 'hours', 'minutes', +'seconds', 'milliseconds' and 'microseconds'. +[clinic start generated code]*/ + static PyObject * -datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) +datetime_datetime_isoformat_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls, int sep, + const char *timespec) +/*[clinic end generated code: output=d7968a085a5f38c7 input=dbd22819421fe7be]*/ { - int sep = 'T'; - char *timespec = NULL; - static char *keywords[] = {"sep", "timespec", NULL}; char buffer[100]; PyObject *result = NULL; int us = DATE_GET_MICROSECOND(self); @@ -6254,9 +6270,6 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) }; size_t given_spec; - if (!PyArg_ParseTupleAndKeywords(args, kw, "|Cs:isoformat", keywords, &sep, ×pec)) - return NULL; - if (timespec == NULL || strcmp(timespec, "auto") == 0) { if (us == 0) { /* seconds */ @@ -6294,7 +6307,7 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) return result; /* We need to append the UTC offset. */ - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); if (format_utcoffset(st, buffer, sizeof(buffer), ":", self->tzinfo, (PyObject *)self) < 0) { Py_DECREF(result); @@ -7056,16 +7069,7 @@ static PyMethodDef datetime_methods[] = { {"utctimetuple", (PyCFunction)datetime_utctimetuple, METH_NOARGS, PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")}, - {"isoformat", _PyCFunction_CAST(datetime_isoformat), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("[sep] -> string in ISO 8601 format, " - "YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n" - "sep is used to separate the year from the time, and " - "defaults to 'T'.\n" - "The optional argument timespec specifies the number " - "of additional terms\nof the time to include. Valid " - "options are 'auto', 'hours', 'minutes',\n'seconds', " - "'milliseconds' and 'microseconds'.\n")}, - + DATETIME_DATETIME_ISOFORMAT_METHODDEF DATETIME_DATETIME_UTCOFFSET_METHODDEF DATETIME_DATETIME_TZNAME_METHODDEF DATETIME_DATETIME_DST_METHODDEF From 2c236672a23d774b225b23af773dc7104ab92404 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:31:01 +0900 Subject: [PATCH 35/50] datetime.replace() upadte --- Modules/_datetimemodule.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index df4dba7f8020ef..0a5e2d0f718bbb 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6543,6 +6543,7 @@ datetime_hash(PyDateTime_DateTime *self) /*[clinic input] datetime.datetime.replace + defcls: defining_class year: int(c_default="GET_YEAR(self)") = unchanged month: int(c_default="GET_MONTH(self)") = unchanged day: int(c_default="GET_DAY(self)") = unchanged @@ -6558,13 +6559,13 @@ Return datetime with new specified fields. [clinic start generated code]*/ static PyObject * -datetime_datetime_replace_impl(PyDateTime_DateTime *self, int year, - int month, int day, int hour, int minute, - int second, int microsecond, PyObject *tzinfo, - int fold) -/*[clinic end generated code: output=00bc96536833fddb input=9b38253d56d9bcad]*/ +datetime_datetime_replace_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls, int year, int month, + int day, int hour, int minute, int second, + int microsecond, PyObject *tzinfo, int fold) +/*[clinic end generated code: output=5d4ed85b97ed99c0 input=5265196eec76388f]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); return new_datetime_subclass_fold_ex(st, year, month, day, hour, minute, second, microsecond, tzinfo, fold, (PyObject *)Py_TYPE(self)); From e5b1db043caa91258ab92e06df1c90c299ebcec7 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:32:33 +0900 Subject: [PATCH 36/50] datetime.__replace__() --- Modules/_datetimemodule.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 0a5e2d0f718bbb..5d6ef6a5fba2d2 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6571,6 +6571,34 @@ datetime_datetime_replace_impl(PyDateTime_DateTime *self, (PyObject *)Py_TYPE(self)); } +/*[clinic input] +datetime.datetime.__replace__ + + defcls: defining_class + year: int(c_default="GET_YEAR(self)") = unchanged + month: int(c_default="GET_MONTH(self)") = unchanged + day: int(c_default="GET_DAY(self)") = unchanged + hour: int(c_default="DATE_GET_HOUR(self)") = unchanged + minute: int(c_default="DATE_GET_MINUTE(self)") = unchanged + second: int(c_default="DATE_GET_SECOND(self)") = unchanged + microsecond: int(c_default="DATE_GET_MICROSECOND(self)") = unchanged + tzinfo: object(c_default="HASTZINFO(self) ? self->tzinfo : Py_None") = unchanged + * + fold: int(c_default="DATE_GET_FOLD(self)") = unchanged +[clinic start generated code]*/ + +static PyObject * +datetime_datetime___replace___impl(PyDateTime_DateTime *self, + PyTypeObject *defcls, int year, int month, + int day, int hour, int minute, int second, + int microsecond, PyObject *tzinfo, + int fold) +/*[clinic end generated code: output=2b2c327c73986226 input=233cfaa570c8a3b0]*/ +{ + return datetime_datetime_replace_impl(self, defcls, year, month, day, + hour, minute, second, microsecond, tzinfo, fold); +} + static PyObject * local_timezone_from_timestamp(datetime_state *st, time_t timestamp) { @@ -7075,9 +7103,7 @@ static PyMethodDef datetime_methods[] = { DATETIME_DATETIME_TZNAME_METHODDEF DATETIME_DATETIME_DST_METHODDEF DATETIME_DATETIME_REPLACE_METHODDEF - - {"__replace__", _PyCFunction_CAST(datetime_datetime_replace), METH_FASTCALL | METH_KEYWORDS, - PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, + DATETIME_DATETIME___REPLACE___METHODDEF {"astimezone", _PyCFunction_CAST(datetime_astimezone), METH_VARARGS | METH_KEYWORDS, PyDoc_STR("tz -> convert to local time in new timezone tz\n")}, From 0c237bc07debdd91ca3235fbe57592f083c4a9c0 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:43:05 +0900 Subject: [PATCH 37/50] datetime.astimezone() --- Modules/_datetimemodule.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 5d6ef6a5fba2d2..9e02e281db5b9a 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6729,21 +6729,26 @@ local_timezone_from_local(datetime_state *st, PyDateTime_DateTime *local_dt) return local_timezone_from_timestamp(st, timestamp); } -static PyDateTime_DateTime * -datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) +/*[clinic input] +datetime.datetime.astimezone + + defcls: defining_class + tz as tzinfo: object = None + +tz -> convert to local time in new timezone tz. +[clinic start generated code]*/ + +static PyObject * +datetime_datetime_astimezone_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls, PyObject *tzinfo) +/*[clinic end generated code: output=c61c01074fcb3639 input=9c6b7ce67b3f2c50]*/ { PyDateTime_DateTime *result; PyObject *offset; PyObject *temp; PyObject *self_tzinfo; - PyObject *tzinfo = Py_None; - static char *keywords[] = {"tz", NULL}; - - if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:astimezone", keywords, - &tzinfo)) - return NULL; - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); if (check_tzinfo_subclass(st, tzinfo) == -1) return NULL; @@ -6759,7 +6764,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) /* Conversion to self's own time zone is a NOP. */ if (self_tzinfo == tzinfo) { Py_DECREF(self_tzinfo); - return (PyDateTime_DateTime*)Py_NewRef(self); + return Py_NewRef(self); } /* Convert self to UTC. */ @@ -6825,7 +6830,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) PyObject_CallMethodOneArg(tzinfo, &_Py_ID(fromutc), temp); Py_DECREF(temp); - return result; + return (PyObject *)result; } static PyObject * @@ -7104,9 +7109,7 @@ static PyMethodDef datetime_methods[] = { DATETIME_DATETIME_DST_METHODDEF DATETIME_DATETIME_REPLACE_METHODDEF DATETIME_DATETIME___REPLACE___METHODDEF - - {"astimezone", _PyCFunction_CAST(datetime_astimezone), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("tz -> convert to local time in new timezone tz\n")}, + DATETIME_DATETIME_ASTIMEZONE_METHODDEF {"__reduce_ex__", (PyCFunction)datetime_reduce_ex, METH_VARARGS, PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")}, From e210cc816241ccb727e183197ef477ea6e149b94 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:44:32 +0900 Subject: [PATCH 38/50] datetime.timetuple() --- Modules/_datetimemodule.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 9e02e281db5b9a..968311d5f29be8 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6833,15 +6833,26 @@ datetime_datetime_astimezone_impl(PyDateTime_DateTime *self, return (PyObject *)result; } +/*[clinic input] +datetime.datetime.timetuple + + defcls: defining_class + / + +Return time tuple, compatible with time.localtime(). +[clinic start generated code]*/ + static PyObject * -datetime_timetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_datetime_timetuple_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls) +/*[clinic end generated code: output=b89cf4ba3c0104c7 input=fa971a44619a864b]*/ { int dstflag = -1; if (HASTZINFO(self) && self->tzinfo != Py_None) { PyObject * dst; - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); dst = call_dst(st, self->tzinfo, (PyObject *)self); if (dst == NULL) return NULL; @@ -7094,8 +7105,7 @@ static PyMethodDef datetime_methods[] = { {"ctime", (PyCFunction)datetime_ctime, METH_NOARGS, PyDoc_STR("Return ctime() style string.")}, - {"timetuple", (PyCFunction)datetime_timetuple, METH_NOARGS, - PyDoc_STR("Return time tuple, compatible with time.localtime().")}, + DATETIME_DATETIME_TIMETUPLE_METHODDEF {"timestamp", (PyCFunction)datetime_timestamp, METH_NOARGS, PyDoc_STR("Return POSIX timestamp as float.")}, From 86bbbab8644750ab3df0a4c22127a14a2747946c Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:46:14 +0900 Subject: [PATCH 39/50] datetime.timestamp() --- Modules/_datetimemodule.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 968311d5f29be8..964431303cc119 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6920,13 +6920,24 @@ local_to_seconds(int year, int month, int day, /* date(1970,1,1).toordinal() == 719163 */ #define EPOCH_SECONDS (719163LL * 24 * 60 * 60) +/*[clinic input] +datetime.datetime.timestamp + + defcls: defining_class + / + +Return POSIX timestamp as float. +[clinic start generated code]*/ + static PyObject * -datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_datetime_timestamp_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls) +/*[clinic end generated code: output=2761fb3514c72fa7 input=605e82dfed8d9689]*/ { PyObject *result; if (HASTZINFO(self) && self->tzinfo != Py_None) { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); PyObject *delta; delta = _datetime_subtract(st, (PyObject *)self, st->epoch); if (delta == NULL) @@ -7106,9 +7117,7 @@ static PyMethodDef datetime_methods[] = { PyDoc_STR("Return ctime() style string.")}, DATETIME_DATETIME_TIMETUPLE_METHODDEF - - {"timestamp", (PyCFunction)datetime_timestamp, METH_NOARGS, - PyDoc_STR("Return POSIX timestamp as float.")}, + DATETIME_DATETIME_TIMESTAMP_METHODDEF {"utctimetuple", (PyCFunction)datetime_utctimetuple, METH_NOARGS, PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")}, From 610b30bb169fd255d85e80bf9631c2307da16bc0 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:49:57 +0900 Subject: [PATCH 40/50] datetime.date() --- Modules/_datetimemodule.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 964431303cc119..8bfb3fbbd351f4 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6962,10 +6962,21 @@ datetime_datetime_timestamp_impl(PyDateTime_DateTime *self, return result; } +/*[clinic input] +datetime.datetime.date as datetime_datetime_getdate + + defcls: defining_class + / + +Return date object with same year, month and day. +[clinic start generated code]*/ + static PyObject * -datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_datetime_getdate_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls) +/*[clinic end generated code: output=1f3378787dafdaca input=9fa762733596e558]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); return new_date(st, GET_YEAR(self), GET_MONTH(self), @@ -7104,8 +7115,7 @@ static PyMethodDef datetime_methods[] = { /* Instance methods: */ - {"date", (PyCFunction)datetime_getdate, METH_NOARGS, - PyDoc_STR("Return date object with same year, month and day.")}, + DATETIME_DATETIME_GETDATE_METHODDEF {"time", (PyCFunction)datetime_gettime, METH_NOARGS, PyDoc_STR("Return time object with same time but with tzinfo=None.")}, From a3b75f91d7270891931d42bd8870f296f7672169 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:51:35 +0900 Subject: [PATCH 41/50] datetime.time() --- Modules/_datetimemodule.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 8bfb3fbbd351f4..72a2d787f50e5e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6983,10 +6983,21 @@ datetime_datetime_getdate_impl(PyDateTime_DateTime *self, GET_DAY(self)); } +/*[clinic input] +datetime.datetime.time as datetime_datetime_gettime + + defcls: defining_class + / + +Return time object with same time but with tzinfo=None. +[clinic start generated code]*/ + static PyObject * -datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_datetime_gettime_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls) +/*[clinic end generated code: output=9c0cb01cd187e775 input=2b9b40cbdb28f5b9]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); return new_time(st, DATE_GET_HOUR(self), DATE_GET_MINUTE(self), @@ -7116,9 +7127,7 @@ static PyMethodDef datetime_methods[] = { /* Instance methods: */ DATETIME_DATETIME_GETDATE_METHODDEF - - {"time", (PyCFunction)datetime_gettime, METH_NOARGS, - PyDoc_STR("Return time object with same time but with tzinfo=None.")}, + DATETIME_DATETIME_GETTIME_METHODDEF {"timetz", (PyCFunction)datetime_gettimetz, METH_NOARGS, PyDoc_STR("Return time object with same time and tzinfo.")}, From a9f821d3aebc95d472c42b8e4ee48d45c5b8f401 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:53:14 +0900 Subject: [PATCH 42/50] datetime.timetz() --- Modules/_datetimemodule.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 72a2d787f50e5e..f14edbe355692b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -7007,10 +7007,21 @@ datetime_datetime_gettime_impl(PyDateTime_DateTime *self, DATE_GET_FOLD(self)); } +/*[clinic input] +datetime.datetime.timetz as datetime_datetime_gettimetz + + defcls: defining_class + / + +Return time object with same time and tzinfo. +[clinic start generated code]*/ + static PyObject * -datetime_gettimetz(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_datetime_gettimetz_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls) +/*[clinic end generated code: output=5dd413b4496a15d7 input=5e303916b45c585f]*/ { - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); return new_time(st, DATE_GET_HOUR(self), DATE_GET_MINUTE(self), @@ -7128,9 +7139,7 @@ static PyMethodDef datetime_methods[] = { DATETIME_DATETIME_GETDATE_METHODDEF DATETIME_DATETIME_GETTIME_METHODDEF - - {"timetz", (PyCFunction)datetime_gettimetz, METH_NOARGS, - PyDoc_STR("Return time object with same time and tzinfo.")}, + DATETIME_DATETIME_GETTIMETZ_METHODDEF {"ctime", (PyCFunction)datetime_ctime, METH_NOARGS, PyDoc_STR("Return ctime() style string.")}, From 5188e7b4c3151569836ba6585f62f89a3dc2b992 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:54:57 +0900 Subject: [PATCH 43/50] datetime.utctimetuple() --- Modules/_datetimemodule.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index f14edbe355692b..c75fa801c8214d 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -7031,8 +7031,19 @@ datetime_datetime_gettimetz_impl(PyDateTime_DateTime *self, DATE_GET_FOLD(self)); } +/*[clinic input] +datetime.datetime.utctimetuple + + defcls: defining_class + / + +Return UTC time tuple, compatible with time.localtime(). +[clinic start generated code]*/ + static PyObject * -datetime_utctimetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_datetime_utctimetuple_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls) +/*[clinic end generated code: output=f680a4fb9fbf0581 input=2275032fc3aa0754]*/ { int y, m, d, hh, mm, ss; PyObject *tzinfo; @@ -7044,7 +7055,7 @@ datetime_utctimetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) } else { PyObject *offset; - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + datetime_state *st = get_module_state_by_cls(defcls); offset = call_utcoffset(st, tzinfo, (PyObject *)self); if (offset == NULL) return NULL; @@ -7146,10 +7157,7 @@ static PyMethodDef datetime_methods[] = { DATETIME_DATETIME_TIMETUPLE_METHODDEF DATETIME_DATETIME_TIMESTAMP_METHODDEF - - {"utctimetuple", (PyCFunction)datetime_utctimetuple, METH_NOARGS, - PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")}, - + DATETIME_DATETIME_UTCTIMETUPLE_METHODDEF DATETIME_DATETIME_ISOFORMAT_METHODDEF DATETIME_DATETIME_UTCOFFSET_METHODDEF DATETIME_DATETIME_TZNAME_METHODDEF From 7823d6b9db8c4cc2e087f83fdb859c2705a8ebba Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 06:58:10 +0900 Subject: [PATCH 44/50] update _datetimemodule.c.h --- Modules/clinic/_datetimemodule.c.h | 1954 ++++++++++++++++++++++++++-- 1 file changed, 1835 insertions(+), 119 deletions(-) diff --git a/Modules/clinic/_datetimemodule.c.h b/Modules/clinic/_datetimemodule.c.h index 48499e0aaf7783..d7e877e730a3d8 100644 --- a/Modules/clinic/_datetimemodule.c.h +++ b/Modules/clinic/_datetimemodule.c.h @@ -8,6 +8,28 @@ preserve #endif #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +PyDoc_STRVAR(datetime_timedelta_total_seconds__doc__, +"total_seconds($self, /)\n" +"--\n" +"\n" +"Total seconds in the duration."); + +#define DATETIME_TIMEDELTA_TOTAL_SECONDS_METHODDEF \ + {"total_seconds", _PyCFunction_CAST(datetime_timedelta_total_seconds), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_timedelta_total_seconds__doc__}, + +static PyObject * +datetime_timedelta_total_seconds_impl(PyObject *self, PyTypeObject *defcls); + +static PyObject * +datetime_timedelta_total_seconds(PyObject *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "total_seconds() takes no arguments"); + return NULL; + } + return datetime_timedelta_total_seconds_impl(self, defcls); +} + PyDoc_STRVAR(datetime_date_fromtimestamp__doc__, "fromtimestamp($type, timestamp, /)\n" "--\n" @@ -18,7 +40,266 @@ PyDoc_STRVAR(datetime_date_fromtimestamp__doc__, "as local time."); #define DATETIME_DATE_FROMTIMESTAMP_METHODDEF \ - {"fromtimestamp", (PyCFunction)datetime_date_fromtimestamp, METH_O|METH_CLASS, datetime_date_fromtimestamp__doc__}, + {"fromtimestamp", _PyCFunction_CAST(datetime_date_fromtimestamp), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_date_fromtimestamp__doc__}, + +static PyObject * +datetime_date_fromtimestamp_impl(PyTypeObject *type, PyTypeObject *defcls, + PyObject *timestamp); + +static PyObject * +datetime_date_fromtimestamp(PyTypeObject *type, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromtimestamp", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *timestamp; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + timestamp = args[0]; + return_value = datetime_date_fromtimestamp_impl(type, defcls, timestamp); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_fromordinal__doc__, +"fromordinal($type, ordinal, /)\n" +"--\n" +"\n" +"int -> date corresponding to a proleptic Gregorian ordinal.\n" +"\n" +"Return new date from proleptic Gregorian ordinal. Raises ValueError\n" +"if the ordinal is out of range."); + +#define DATETIME_DATE_FROMORDINAL_METHODDEF \ + {"fromordinal", _PyCFunction_CAST(datetime_date_fromordinal), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_date_fromordinal__doc__}, + +static PyObject * +datetime_date_fromordinal_impl(PyObject *cls, PyTypeObject *defcls, + int ordinal); + +static PyObject * +datetime_date_fromordinal(PyTypeObject *cls, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromordinal", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int ordinal; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + ordinal = PyLong_AsInt(args[0]); + if (ordinal == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = datetime_date_fromordinal_impl((PyObject *)cls, defcls, ordinal); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_fromisoformat__doc__, +"fromisoformat($type, dtstr, /)\n" +"--\n" +"\n" +"str -> Construct a date from a string in ISO 8601 format.\n" +"\n" +"Return the new date from a string as generated by date.isoformat()."); + +#define DATETIME_DATE_FROMISOFORMAT_METHODDEF \ + {"fromisoformat", _PyCFunction_CAST(datetime_date_fromisoformat), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_date_fromisoformat__doc__}, + +static PyObject * +datetime_date_fromisoformat_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *dtstr); + +static PyObject * +datetime_date_fromisoformat(PyTypeObject *cls, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromisoformat", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *dtstr; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + dtstr = args[0]; + return_value = datetime_date_fromisoformat_impl((PyObject *)cls, defcls, dtstr); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_fromisocalendar__doc__, +"fromisocalendar($type, /, year, week, day)\n" +"--\n" +"\n" +"int, int, int -> Construct a date from the ISO year, week number and weekday.\n" +"\n" +"This is the inverse of the date.isocalendar() function."); + +#define DATETIME_DATE_FROMISOCALENDAR_METHODDEF \ + {"fromisocalendar", _PyCFunction_CAST(datetime_date_fromisocalendar), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_date_fromisocalendar__doc__}, + +static PyObject * +datetime_date_fromisocalendar_impl(PyObject *cls, PyTypeObject *defcls, + int year, int week, int day); + +static PyObject * +datetime_date_fromisocalendar(PyTypeObject *cls, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(year), &_Py_ID(week), &_Py_ID(day), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"year", "week", "day", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromisocalendar", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + int year; + int week; + int day; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (!calendar_int_converter(args[0], &year)) { + goto exit; + } + if (!calendar_int_converter(args[1], &week)) { + goto exit; + } + if (!calendar_int_converter(args[2], &day)) { + goto exit; + } + return_value = datetime_date_fromisocalendar_impl((PyObject *)cls, defcls, year, week, day); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_date_strftime__doc__, +"strftime($self, /, format)\n" +"--\n" +"\n" +"format -> strftime() style string."); + +#define DATETIME_DATE_STRFTIME_METHODDEF \ + {"strftime", _PyCFunction_CAST(datetime_date_strftime), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_date_strftime__doc__}, + +static PyObject * +datetime_date_strftime_impl(PyDateTime_Date *self, PyTypeObject *defcls, + PyObject *format); + +static PyObject * +datetime_date_strftime(PyDateTime_Date *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(format), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"format", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "strftime", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *format; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("strftime", "argument 'format'", "str", args[0]); + goto exit; + } + format = args[0]; + return_value = datetime_date_strftime_impl(self, defcls, format); + +exit: + return return_value; +} static PyObject * iso_calendar_date_new_impl(PyTypeObject *type, int year, int week, @@ -82,6 +363,28 @@ iso_calendar_date_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) return return_value; } +PyDoc_STRVAR(datetime_date_isocalendar__doc__, +"isocalendar($self, /)\n" +"--\n" +"\n" +"Return a named tuple containing ISO year, week number, and weekday."); + +#define DATETIME_DATE_ISOCALENDAR_METHODDEF \ + {"isocalendar", _PyCFunction_CAST(datetime_date_isocalendar), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_date_isocalendar__doc__}, + +static PyObject * +datetime_date_isocalendar_impl(PyDateTime_Date *self, PyTypeObject *defcls); + +static PyObject * +datetime_date_isocalendar(PyDateTime_Date *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "isocalendar() takes no arguments"); + return NULL; + } + return datetime_date_isocalendar_impl(self, defcls); +} + PyDoc_STRVAR(datetime_date_replace__doc__, "replace($self, /, year=unchanged, month=unchanged, day=unchanged)\n" "--\n" @@ -89,14 +392,14 @@ PyDoc_STRVAR(datetime_date_replace__doc__, "Return date with new specified fields."); #define DATETIME_DATE_REPLACE_METHODDEF \ - {"replace", _PyCFunction_CAST(datetime_date_replace), METH_FASTCALL|METH_KEYWORDS, datetime_date_replace__doc__}, + {"replace", _PyCFunction_CAST(datetime_date_replace), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_date_replace__doc__}, static PyObject * -datetime_date_replace_impl(PyDateTime_Date *self, int year, int month, - int day); +datetime_date_replace_impl(PyDateTime_Date *self, PyTypeObject *defcls, + int year, int month, int day); static PyObject * -datetime_date_replace(PyDateTime_Date *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +datetime_date_replace(PyDateTime_Date *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -160,41 +463,1290 @@ datetime_date_replace(PyDateTime_Date *self, PyObject *const *args, Py_ssize_t n goto exit; } skip_optional_pos: - return_value = datetime_date_replace_impl(self, year, month, day); + return_value = datetime_date_replace_impl(self, defcls, year, month, day); exit: return return_value; } -PyDoc_STRVAR(datetime_time_replace__doc__, -"replace($self, /, hour=unchanged, minute=unchanged, second=unchanged,\n" -" microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged)\n" +PyDoc_STRVAR(datetime_date___replace____doc__, +"__replace__($self, /, year=unchanged, month=unchanged, day=unchanged)\n" "--\n" -"\n" -"Return time with new specified fields."); +"\n"); + +#define DATETIME_DATE___REPLACE___METHODDEF \ + {"__replace__", _PyCFunction_CAST(datetime_date___replace__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_date___replace____doc__}, + +static PyObject * +datetime_date___replace___impl(PyDateTime_Date *self, PyTypeObject *defcls, + int year, int month, int day); + +static PyObject * +datetime_date___replace__(PyDateTime_Date *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(year), &_Py_ID(month), &_Py_ID(day), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"year", "month", "day", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__replace__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int year = GET_YEAR(self); + int month = GET_MONTH(self); + int day = GET_DAY(self); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + year = PyLong_AsInt(args[0]); + if (year == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[1]) { + month = PyLong_AsInt(args[1]); + if (month == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + day = PyLong_AsInt(args[2]); + if (day == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = datetime_date___replace___impl(self, defcls, year, month, day); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_tzinfo_fromutc__doc__, +"fromutc($self, dt, /)\n" +"--\n" +"\n" +"datetime in UTC -> datetime in local time."); + +#define DATETIME_TZINFO_FROMUTC_METHODDEF \ + {"fromutc", _PyCFunction_CAST(datetime_tzinfo_fromutc), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_tzinfo_fromutc__doc__}, + +static PyObject * +datetime_tzinfo_fromutc_impl(PyDateTime_TZInfo *self, PyTypeObject *defcls, + PyObject *dt); + +static PyObject * +datetime_tzinfo_fromutc(PyDateTime_TZInfo *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromutc", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *dt; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + dt = args[0]; + return_value = datetime_tzinfo_fromutc_impl(self, defcls, dt); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_timezone_tzname__doc__, +"tzname($self, dt, /)\n" +"--\n" +"\n" +"Return the name specified at timezone creation, or offset as \'UTC(+|-)HH:MM\'.\n" +"\n" +"If name is specified when timezone is created, returns the name.\n" +"Otherwise returns offset as \'UTC(+|-)HH:MM\'."); + +#define DATETIME_TIMEZONE_TZNAME_METHODDEF \ + {"tzname", _PyCFunction_CAST(datetime_timezone_tzname), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_timezone_tzname__doc__}, + +static PyObject * +datetime_timezone_tzname_impl(PyDateTime_TimeZone *self, + PyTypeObject *defcls, PyObject *dt); + +static PyObject * +datetime_timezone_tzname(PyDateTime_TimeZone *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "tzname", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *dt; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + dt = args[0]; + return_value = datetime_timezone_tzname_impl(self, defcls, dt); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_timezone_utcoffset__doc__, +"utcoffset($self, dt, /)\n" +"--\n" +"\n" +"Return fixed offset."); + +#define DATETIME_TIMEZONE_UTCOFFSET_METHODDEF \ + {"utcoffset", _PyCFunction_CAST(datetime_timezone_utcoffset), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_timezone_utcoffset__doc__}, + +static PyObject * +datetime_timezone_utcoffset_impl(PyDateTime_TimeZone *self, + PyTypeObject *defcls, PyObject *dt); + +static PyObject * +datetime_timezone_utcoffset(PyDateTime_TimeZone *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "utcoffset", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *dt; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + dt = args[0]; + return_value = datetime_timezone_utcoffset_impl(self, defcls, dt); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_timezone_dst__doc__, +"dst($self, dt, /)\n" +"--\n" +"\n" +"Return None."); + +#define DATETIME_TIMEZONE_DST_METHODDEF \ + {"dst", _PyCFunction_CAST(datetime_timezone_dst), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_timezone_dst__doc__}, + +static PyObject * +datetime_timezone_dst_impl(PyDateTime_TimeZone *self, PyTypeObject *defcls, + PyObject *dt); + +static PyObject * +datetime_timezone_dst(PyDateTime_TimeZone *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "dst", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *dt; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + dt = args[0]; + return_value = datetime_timezone_dst_impl(self, defcls, dt); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_timezone_fromutc__doc__, +"fromutc($self, dt, /)\n" +"--\n" +"\n" +"datetime in UTC -> datetime in local time."); + +#define DATETIME_TIMEZONE_FROMUTC_METHODDEF \ + {"fromutc", _PyCFunction_CAST(datetime_timezone_fromutc), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_timezone_fromutc__doc__}, + +static PyObject * +datetime_timezone_fromutc_impl(PyDateTime_TimeZone *self, + PyTypeObject *defcls, PyDateTime_DateTime *dt); + +static PyObject * +datetime_timezone_fromutc(PyDateTime_TimeZone *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromutc", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyDateTime_DateTime *dt; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + dt = (PyDateTime_DateTime *)args[0]; + return_value = datetime_timezone_fromutc_impl(self, defcls, dt); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_utcoffset__doc__, +"utcoffset($self, /)\n" +"--\n" +"\n" +"Return self.tzinfo.utcoffset(self)."); + +#define DATETIME_TIME_UTCOFFSET_METHODDEF \ + {"utcoffset", _PyCFunction_CAST(datetime_time_utcoffset), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_time_utcoffset__doc__}, + +static PyObject * +datetime_time_utcoffset_impl(PyDateTime_Time *self, PyTypeObject *defcls); + +static PyObject * +datetime_time_utcoffset(PyDateTime_Time *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "utcoffset() takes no arguments"); + return NULL; + } + return datetime_time_utcoffset_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_time_dst__doc__, +"dst($self, /)\n" +"--\n" +"\n" +"Return self.tzinfo.dst(self)."); + +#define DATETIME_TIME_DST_METHODDEF \ + {"dst", _PyCFunction_CAST(datetime_time_dst), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_time_dst__doc__}, + +static PyObject * +datetime_time_dst_impl(PyDateTime_Time *self, PyTypeObject *defcls); + +static PyObject * +datetime_time_dst(PyDateTime_Time *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "dst() takes no arguments"); + return NULL; + } + return datetime_time_dst_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_time_tzname__doc__, +"tzname($self, /)\n" +"--\n" +"\n" +"Return self.tzinfo.tzname(self)."); + +#define DATETIME_TIME_TZNAME_METHODDEF \ + {"tzname", _PyCFunction_CAST(datetime_time_tzname), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_time_tzname__doc__}, + +static PyObject * +datetime_time_tzname_impl(PyDateTime_Time *self, PyTypeObject *defcls); + +static PyObject * +datetime_time_tzname(PyDateTime_Time *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "tzname() takes no arguments"); + return NULL; + } + return datetime_time_tzname_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_time_isoformat__doc__, +"isoformat($self, /, timespec=)\n" +"--\n" +"\n" +"Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n" +"\n" +"The optional argument timespec specifies the number of additional terms\n" +"of the time to include. Valid options are \'auto\', \'hours\', \'minutes\',\n" +"\'seconds\', \'milliseconds\' and \'microseconds\'."); + +#define DATETIME_TIME_ISOFORMAT_METHODDEF \ + {"isoformat", _PyCFunction_CAST(datetime_time_isoformat), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_time_isoformat__doc__}, + +static PyObject * +datetime_time_isoformat_impl(PyDateTime_Time *self, PyTypeObject *defcls, + const char *timespec); + +static PyObject * +datetime_time_isoformat(PyDateTime_Time *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(timespec), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"timespec", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "isoformat", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + const char *timespec = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("isoformat", "argument 'timespec'", "str", args[0]); + goto exit; + } + Py_ssize_t timespec_length; + timespec = PyUnicode_AsUTF8AndSize(args[0], ×pec_length); + if (timespec == NULL) { + goto exit; + } + if (strlen(timespec) != (size_t)timespec_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +skip_optional_pos: + return_value = datetime_time_isoformat_impl(self, defcls, timespec); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_strftime__doc__, +"strftime($self, /, format)\n" +"--\n" +"\n" +"format -> strftime() style string."); + +#define DATETIME_TIME_STRFTIME_METHODDEF \ + {"strftime", _PyCFunction_CAST(datetime_time_strftime), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_time_strftime__doc__}, + +static PyObject * +datetime_time_strftime_impl(PyDateTime_Time *self, PyTypeObject *defcls, + PyObject *format); + +static PyObject * +datetime_time_strftime(PyDateTime_Time *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(format), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"format", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "strftime", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *format; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("strftime", "argument 'format'", "str", args[0]); + goto exit; + } + format = args[0]; + return_value = datetime_time_strftime_impl(self, defcls, format); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_replace__doc__, +"replace($self, /, hour=unchanged, minute=unchanged, second=unchanged,\n" +" microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged)\n" +"--\n" +"\n" +"Return time with new specified fields."); + +#define DATETIME_TIME_REPLACE_METHODDEF \ + {"replace", _PyCFunction_CAST(datetime_time_replace), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_time_replace__doc__}, + +static PyObject * +datetime_time_replace_impl(PyDateTime_Time *self, PyTypeObject *defcls, + int hour, int minute, int second, int microsecond, + PyObject *tzinfo, int fold); + +static PyObject * +datetime_time_replace(PyDateTime_Time *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 6 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(hour), &_Py_ID(minute), &_Py_ID(second), &_Py_ID(microsecond), &_Py_ID(tzinfo), &_Py_ID(fold), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "replace", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[6]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int hour = TIME_GET_HOUR(self); + int minute = TIME_GET_MINUTE(self); + int second = TIME_GET_SECOND(self); + int microsecond = TIME_GET_MICROSECOND(self); + PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; + int fold = TIME_GET_FOLD(self); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 5, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + hour = PyLong_AsInt(args[0]); + if (hour == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[1]) { + minute = PyLong_AsInt(args[1]); + if (minute == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[2]) { + second = PyLong_AsInt(args[2]); + if (second == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[3]) { + microsecond = PyLong_AsInt(args[3]); + if (microsecond == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[4]) { + tzinfo = args[4]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + fold = PyLong_AsInt(args[5]); + if (fold == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_kwonly: + return_value = datetime_time_replace_impl(self, defcls, hour, minute, second, microsecond, tzinfo, fold); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time___replace____doc__, +"__replace__($self, /, hour=unchanged, minute=unchanged,\n" +" second=unchanged, microsecond=unchanged, tzinfo=unchanged,\n" +" *, fold=unchanged)\n" +"--\n" +"\n"); + +#define DATETIME_TIME___REPLACE___METHODDEF \ + {"__replace__", _PyCFunction_CAST(datetime_time___replace__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_time___replace____doc__}, + +static PyObject * +datetime_time___replace___impl(PyDateTime_Time *self, PyTypeObject *defcls, + int hour, int minute, int second, + int microsecond, PyObject *tzinfo, int fold); + +static PyObject * +datetime_time___replace__(PyDateTime_Time *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 6 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(hour), &_Py_ID(minute), &_Py_ID(second), &_Py_ID(microsecond), &_Py_ID(tzinfo), &_Py_ID(fold), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__replace__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[6]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int hour = TIME_GET_HOUR(self); + int minute = TIME_GET_MINUTE(self); + int second = TIME_GET_SECOND(self); + int microsecond = TIME_GET_MICROSECOND(self); + PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; + int fold = TIME_GET_FOLD(self); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 5, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + hour = PyLong_AsInt(args[0]); + if (hour == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[1]) { + minute = PyLong_AsInt(args[1]); + if (minute == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[2]) { + second = PyLong_AsInt(args[2]); + if (second == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[3]) { + microsecond = PyLong_AsInt(args[3]); + if (microsecond == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[4]) { + tzinfo = args[4]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + fold = PyLong_AsInt(args[5]); + if (fold == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_kwonly: + return_value = datetime_time___replace___impl(self, defcls, hour, minute, second, microsecond, tzinfo, fold); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_time_fromisoformat__doc__, +"fromisoformat($type, tstr, /)\n" +"--\n" +"\n" +"string -> time from a string in ISO 8601 format."); + +#define DATETIME_TIME_FROMISOFORMAT_METHODDEF \ + {"fromisoformat", _PyCFunction_CAST(datetime_time_fromisoformat), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_time_fromisoformat__doc__}, + +static PyObject * +datetime_time_fromisoformat_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *tstr); + +static PyObject * +datetime_time_fromisoformat(PyTypeObject *cls, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromisoformat", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *tstr; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + tstr = args[0]; + return_value = datetime_time_fromisoformat_impl((PyObject *)cls, defcls, tstr); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_now__doc__, +"now($type, /, tz=None)\n" +"--\n" +"\n" +"Returns new datetime object representing current time local to tz.\n" +"\n" +" tz\n" +" Timezone object.\n" +"\n" +"If no tz is specified, uses local timezone."); + +#define DATETIME_DATETIME_NOW_METHODDEF \ + {"now", _PyCFunction_CAST(datetime_datetime_now), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_now__doc__}, + +static PyObject * +datetime_datetime_now_impl(PyTypeObject *type, PyTypeObject *defcls, + PyObject *tz); + +static PyObject * +datetime_datetime_now(PyTypeObject *type, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(tz), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"tz", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "now", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *tz = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + tz = args[0]; +skip_optional_pos: + return_value = datetime_datetime_now_impl(type, defcls, tz); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_fromtimestamp__doc__, +"fromtimestamp($type, /, timestamp, tz=None)\n" +"--\n" +"\n" +"timestamp[, tz] -> tz\'s local time from POSIX timestamp.\n" +"\n" +"Return new local datetime from timestamp (Python timestamp -- a double)."); + +#define DATETIME_DATETIME_FROMTIMESTAMP_METHODDEF \ + {"fromtimestamp", _PyCFunction_CAST(datetime_datetime_fromtimestamp), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_fromtimestamp__doc__}, + +static PyObject * +datetime_datetime_fromtimestamp_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *timestamp, PyObject *tzinfo); + +static PyObject * +datetime_datetime_fromtimestamp(PyTypeObject *cls, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(timestamp), &_Py_ID(tz), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"timestamp", "tz", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromtimestamp", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *timestamp; + PyObject *tzinfo = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { + goto exit; + } + timestamp = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + tzinfo = args[1]; +skip_optional_pos: + return_value = datetime_datetime_fromtimestamp_impl((PyObject *)cls, defcls, timestamp, tzinfo); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_strptime__doc__, +"strptime($type, string, format, /)\n" +"--\n" +"\n" +"string, format -> new datetime parsed from a string (like time.strptime()).\n" +"\n" +"Return new datetime from _strptime.strptime_datetime()."); + +#define DATETIME_DATETIME_STRPTIME_METHODDEF \ + {"strptime", _PyCFunction_CAST(datetime_datetime_strptime), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_strptime__doc__}, + +static PyObject * +datetime_datetime_strptime_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *string, PyObject *format); + +static PyObject * +datetime_datetime_strptime(PyTypeObject *cls, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "strptime", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject *string; + PyObject *format; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { + goto exit; + } + string = args[0]; + format = args[1]; + return_value = datetime_datetime_strptime_impl((PyObject *)cls, defcls, string, format); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_combine__doc__, +"combine($type, /, date, time, tzinfo=)\n" +"--\n" +"\n" +"date, time -> datetime with same date and time fields.\n" +"\n" +"Return new datetime from date/datetime and time arguments."); + +#define DATETIME_DATETIME_COMBINE_METHODDEF \ + {"combine", _PyCFunction_CAST(datetime_datetime_combine), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_combine__doc__}, + +static PyObject * +datetime_datetime_combine_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *date, PyObject *time, + PyObject *tzinfo); + +static PyObject * +datetime_datetime_combine(PyTypeObject *cls, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(date), &_Py_ID(time), &_Py_ID(tzinfo), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"date", "time", "tzinfo", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "combine", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; + PyObject *date; + PyObject *time; + PyObject *tzinfo = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyObject_TypeCheck(args[0], clinic_state()->PyDateTime_DateType)) { + _PyArg_BadArgument("combine", "argument 'date'", (clinic_state()->PyDateTime_DateType)->tp_name, args[0]); + goto exit; + } + date = args[0]; + if (!PyObject_TypeCheck(args[1], clinic_state()->PyDateTime_TimeType)) { + _PyArg_BadArgument("combine", "argument 'time'", (clinic_state()->PyDateTime_TimeType)->tp_name, args[1]); + goto exit; + } + time = args[1]; + if (!noptargs) { + goto skip_optional_pos; + } + tzinfo = args[2]; +skip_optional_pos: + return_value = datetime_datetime_combine_impl((PyObject *)cls, defcls, date, time, tzinfo); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_fromisoformat__doc__, +"fromisoformat($type, dtstr, /)\n" +"--\n" +"\n" +"string -> datetime from a string in most ISO 8601 formats"); + +#define DATETIME_DATETIME_FROMISOFORMAT_METHODDEF \ + {"fromisoformat", _PyCFunction_CAST(datetime_datetime_fromisoformat), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_fromisoformat__doc__}, + +static PyObject * +datetime_datetime_fromisoformat_impl(PyObject *cls, PyTypeObject *defcls, + PyObject *dtstr); + +static PyObject * +datetime_datetime_fromisoformat(PyTypeObject *cls, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fromisoformat", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *dtstr; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + dtstr = args[0]; + return_value = datetime_datetime_fromisoformat_impl((PyObject *)cls, defcls, dtstr); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_tzname__doc__, +"tzname($self, /)\n" +"--\n" +"\n" +"Return self.tzinfo.tzname(self)."); + +#define DATETIME_DATETIME_TZNAME_METHODDEF \ + {"tzname", _PyCFunction_CAST(datetime_datetime_tzname), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_tzname__doc__}, + +static PyObject * +datetime_datetime_tzname_impl(PyObject *self, PyTypeObject *defcls); + +static PyObject * +datetime_datetime_tzname(PyObject *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "tzname() takes no arguments"); + return NULL; + } + return datetime_datetime_tzname_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_datetime_utcoffset__doc__, +"utcoffset($self, /)\n" +"--\n" +"\n" +"Return self.tzinfo.utcoffset(self)."); + +#define DATETIME_DATETIME_UTCOFFSET_METHODDEF \ + {"utcoffset", _PyCFunction_CAST(datetime_datetime_utcoffset), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_utcoffset__doc__}, + +static PyObject * +datetime_datetime_utcoffset_impl(PyObject *self, PyTypeObject *defcls); + +static PyObject * +datetime_datetime_utcoffset(PyObject *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "utcoffset() takes no arguments"); + return NULL; + } + return datetime_datetime_utcoffset_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_datetime_dst__doc__, +"dst($self, /)\n" +"--\n" +"\n" +"Return self.tzinfo.dst(self)."); + +#define DATETIME_DATETIME_DST_METHODDEF \ + {"dst", _PyCFunction_CAST(datetime_datetime_dst), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_dst__doc__}, + +static PyObject * +datetime_datetime_dst_impl(PyObject *self, PyTypeObject *defcls); + +static PyObject * +datetime_datetime_dst(PyObject *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "dst() takes no arguments"); + return NULL; + } + return datetime_datetime_dst_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_datetime_isoformat__doc__, +"isoformat($self, /, sep=\'T\', timespec=)\n" +"--\n" +"\n" +"[sep] -> string in ISO 8601 format,\n" +"\n" +"YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n" +"sep is used to separate the year from the time, and defaults to \'T\'.\n" +"The optional argument timespec specifies the number of additional terms\n" +"of the time to include. Valid options are \'auto\', \'hours\', \'minutes\',\n" +"\'seconds\', \'milliseconds\' and \'microseconds\'."); + +#define DATETIME_DATETIME_ISOFORMAT_METHODDEF \ + {"isoformat", _PyCFunction_CAST(datetime_datetime_isoformat), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_isoformat__doc__}, + +static PyObject * +datetime_datetime_isoformat_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls, int sep, + const char *timespec); + +static PyObject * +datetime_datetime_isoformat(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(sep), &_Py_ID(timespec), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"sep", "timespec", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "isoformat", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int sep = 'T'; + const char *timespec = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("isoformat", "argument 'sep'", "a unicode character", args[0]); + goto exit; + } + if (PyUnicode_GET_LENGTH(args[0]) != 1) { + _PyArg_BadArgument("isoformat", "argument 'sep'", "a unicode character", args[0]); + goto exit; + } + sep = PyUnicode_READ_CHAR(args[0], 0); + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("isoformat", "argument 'timespec'", "str", args[1]); + goto exit; + } + Py_ssize_t timespec_length; + timespec = PyUnicode_AsUTF8AndSize(args[1], ×pec_length); + if (timespec == NULL) { + goto exit; + } + if (strlen(timespec) != (size_t)timespec_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +skip_optional_pos: + return_value = datetime_datetime_isoformat_impl(self, defcls, sep, timespec); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_replace__doc__, +"replace($self, /, year=unchanged, month=unchanged, day=unchanged,\n" +" hour=unchanged, minute=unchanged, second=unchanged,\n" +" microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged)\n" +"--\n" +"\n" +"Return datetime with new specified fields."); -#define DATETIME_TIME_REPLACE_METHODDEF \ - {"replace", _PyCFunction_CAST(datetime_time_replace), METH_FASTCALL|METH_KEYWORDS, datetime_time_replace__doc__}, +#define DATETIME_DATETIME_REPLACE_METHODDEF \ + {"replace", _PyCFunction_CAST(datetime_datetime_replace), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_replace__doc__}, static PyObject * -datetime_time_replace_impl(PyDateTime_Time *self, int hour, int minute, - int second, int microsecond, PyObject *tzinfo, - int fold); +datetime_datetime_replace_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls, int year, int month, + int day, int hour, int minute, int second, + int microsecond, PyObject *tzinfo, int fold); static PyObject * -datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +datetime_datetime_replace(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 6 + #define NUM_KEYWORDS 9 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(hour), &_Py_ID(minute), &_Py_ID(second), &_Py_ID(microsecond), &_Py_ID(tzinfo), &_Py_ID(fold), }, + .ob_item = { &_Py_ID(year), &_Py_ID(month), &_Py_ID(day), &_Py_ID(hour), &_Py_ID(minute), &_Py_ID(second), &_Py_ID(microsecond), &_Py_ID(tzinfo), &_Py_ID(fold), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -203,23 +1755,26 @@ datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t n # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; + static const char * const _keywords[] = {"year", "month", "day", "hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "replace", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[6]; + PyObject *argsbuf[9]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - int hour = TIME_GET_HOUR(self); - int minute = TIME_GET_MINUTE(self); - int second = TIME_GET_SECOND(self); - int microsecond = TIME_GET_MICROSECOND(self); + int year = GET_YEAR(self); + int month = GET_MONTH(self); + int day = GET_DAY(self); + int hour = DATE_GET_HOUR(self); + int minute = DATE_GET_MINUTE(self); + int second = DATE_GET_SECOND(self); + int microsecond = DATE_GET_MICROSECOND(self); PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; - int fold = TIME_GET_FOLD(self); + int fold = DATE_GET_FOLD(self); - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 5, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 8, 0, argsbuf); if (!args) { goto exit; } @@ -227,8 +1782,8 @@ datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t n goto skip_optional_pos; } if (args[0]) { - hour = PyLong_AsInt(args[0]); - if (hour == -1 && PyErr_Occurred()) { + year = PyLong_AsInt(args[0]); + if (year == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { @@ -236,8 +1791,8 @@ datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t n } } if (args[1]) { - minute = PyLong_AsInt(args[1]); - if (minute == -1 && PyErr_Occurred()) { + month = PyLong_AsInt(args[1]); + if (month == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { @@ -245,8 +1800,8 @@ datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t n } } if (args[2]) { - second = PyLong_AsInt(args[2]); - if (second == -1 && PyErr_Occurred()) { + day = PyLong_AsInt(args[2]); + if (day == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { @@ -254,8 +1809,8 @@ datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t n } } if (args[3]) { - microsecond = PyLong_AsInt(args[3]); - if (microsecond == -1 && PyErr_Occurred()) { + hour = PyLong_AsInt(args[3]); + if (hour == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { @@ -263,7 +1818,34 @@ datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t n } } if (args[4]) { - tzinfo = args[4]; + minute = PyLong_AsInt(args[4]); + if (minute == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[5]) { + second = PyLong_AsInt(args[5]); + if (second == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[6]) { + microsecond = PyLong_AsInt(args[6]); + if (microsecond == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[7]) { + tzinfo = args[7]; if (!--noptargs) { goto skip_optional_pos; } @@ -272,101 +1854,36 @@ datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t n if (!noptargs) { goto skip_optional_kwonly; } - fold = PyLong_AsInt(args[5]); + fold = PyLong_AsInt(args[8]); if (fold == -1 && PyErr_Occurred()) { goto exit; } skip_optional_kwonly: - return_value = datetime_time_replace_impl(self, hour, minute, second, microsecond, tzinfo, fold); - -exit: - return return_value; -} - -PyDoc_STRVAR(datetime_datetime_now__doc__, -"now($type, /, tz=None)\n" -"--\n" -"\n" -"Returns new datetime object representing current time local to tz.\n" -"\n" -" tz\n" -" Timezone object.\n" -"\n" -"If no tz is specified, uses local timezone."); - -#define DATETIME_DATETIME_NOW_METHODDEF \ - {"now", _PyCFunction_CAST(datetime_datetime_now), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, datetime_datetime_now__doc__}, - -static PyObject * -datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz); - -static PyObject * -datetime_datetime_now(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(tz), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"tz", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "now", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *tz = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - tz = args[0]; -skip_optional_pos: - return_value = datetime_datetime_now_impl(type, tz); + return_value = datetime_datetime_replace_impl(self, defcls, year, month, day, hour, minute, second, microsecond, tzinfo, fold); exit: return return_value; } -PyDoc_STRVAR(datetime_datetime_replace__doc__, -"replace($self, /, year=unchanged, month=unchanged, day=unchanged,\n" -" hour=unchanged, minute=unchanged, second=unchanged,\n" -" microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged)\n" +PyDoc_STRVAR(datetime_datetime___replace____doc__, +"__replace__($self, /, year=unchanged, month=unchanged, day=unchanged,\n" +" hour=unchanged, minute=unchanged, second=unchanged,\n" +" microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged)\n" "--\n" -"\n" -"Return datetime with new specified fields."); +"\n"); -#define DATETIME_DATETIME_REPLACE_METHODDEF \ - {"replace", _PyCFunction_CAST(datetime_datetime_replace), METH_FASTCALL|METH_KEYWORDS, datetime_datetime_replace__doc__}, +#define DATETIME_DATETIME___REPLACE___METHODDEF \ + {"__replace__", _PyCFunction_CAST(datetime_datetime___replace__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime___replace____doc__}, static PyObject * -datetime_datetime_replace_impl(PyDateTime_DateTime *self, int year, - int month, int day, int hour, int minute, - int second, int microsecond, PyObject *tzinfo, - int fold); +datetime_datetime___replace___impl(PyDateTime_DateTime *self, + PyTypeObject *defcls, int year, int month, + int day, int hour, int minute, int second, + int microsecond, PyObject *tzinfo, + int fold); static PyObject * -datetime_datetime_replace(PyDateTime_DateTime *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +datetime_datetime___replace__(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -390,7 +1907,7 @@ datetime_datetime_replace(PyDateTime_DateTime *self, PyObject *const *args, Py_s static const char * const _keywords[] = {"year", "month", "day", "hour", "minute", "second", "microsecond", "tzinfo", "fold", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "replace", + .fname = "__replace__", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -491,9 +2008,208 @@ datetime_datetime_replace(PyDateTime_DateTime *self, PyObject *const *args, Py_s goto exit; } skip_optional_kwonly: - return_value = datetime_datetime_replace_impl(self, year, month, day, hour, minute, second, microsecond, tzinfo, fold); + return_value = datetime_datetime___replace___impl(self, defcls, year, month, day, hour, minute, second, microsecond, tzinfo, fold); + +exit: + return return_value; +} + +PyDoc_STRVAR(datetime_datetime_astimezone__doc__, +"astimezone($self, /, tz=None)\n" +"--\n" +"\n" +"tz -> convert to local time in new timezone tz."); + +#define DATETIME_DATETIME_ASTIMEZONE_METHODDEF \ + {"astimezone", _PyCFunction_CAST(datetime_datetime_astimezone), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_astimezone__doc__}, + +static PyObject * +datetime_datetime_astimezone_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls, PyObject *tzinfo); + +static PyObject * +datetime_datetime_astimezone(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(tz), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"tz", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "astimezone", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *tzinfo = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + tzinfo = args[0]; +skip_optional_pos: + return_value = datetime_datetime_astimezone_impl(self, defcls, tzinfo); exit: return return_value; } -/*[clinic end generated code: output=c7a04b865b1e0890 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(datetime_datetime_timetuple__doc__, +"timetuple($self, /)\n" +"--\n" +"\n" +"Return time tuple, compatible with time.localtime()."); + +#define DATETIME_DATETIME_TIMETUPLE_METHODDEF \ + {"timetuple", _PyCFunction_CAST(datetime_datetime_timetuple), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_timetuple__doc__}, + +static PyObject * +datetime_datetime_timetuple_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls); + +static PyObject * +datetime_datetime_timetuple(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "timetuple() takes no arguments"); + return NULL; + } + return datetime_datetime_timetuple_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_datetime_timestamp__doc__, +"timestamp($self, /)\n" +"--\n" +"\n" +"Return POSIX timestamp as float."); + +#define DATETIME_DATETIME_TIMESTAMP_METHODDEF \ + {"timestamp", _PyCFunction_CAST(datetime_datetime_timestamp), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_timestamp__doc__}, + +static PyObject * +datetime_datetime_timestamp_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls); + +static PyObject * +datetime_datetime_timestamp(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "timestamp() takes no arguments"); + return NULL; + } + return datetime_datetime_timestamp_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_datetime_getdate__doc__, +"date($self, /)\n" +"--\n" +"\n" +"Return date object with same year, month and day."); + +#define DATETIME_DATETIME_GETDATE_METHODDEF \ + {"date", _PyCFunction_CAST(datetime_datetime_getdate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_getdate__doc__}, + +static PyObject * +datetime_datetime_getdate_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls); + +static PyObject * +datetime_datetime_getdate(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "date() takes no arguments"); + return NULL; + } + return datetime_datetime_getdate_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_datetime_gettime__doc__, +"time($self, /)\n" +"--\n" +"\n" +"Return time object with same time but with tzinfo=None."); + +#define DATETIME_DATETIME_GETTIME_METHODDEF \ + {"time", _PyCFunction_CAST(datetime_datetime_gettime), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_gettime__doc__}, + +static PyObject * +datetime_datetime_gettime_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls); + +static PyObject * +datetime_datetime_gettime(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "time() takes no arguments"); + return NULL; + } + return datetime_datetime_gettime_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_datetime_gettimetz__doc__, +"timetz($self, /)\n" +"--\n" +"\n" +"Return time object with same time and tzinfo."); + +#define DATETIME_DATETIME_GETTIMETZ_METHODDEF \ + {"timetz", _PyCFunction_CAST(datetime_datetime_gettimetz), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_gettimetz__doc__}, + +static PyObject * +datetime_datetime_gettimetz_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls); + +static PyObject * +datetime_datetime_gettimetz(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "timetz() takes no arguments"); + return NULL; + } + return datetime_datetime_gettimetz_impl(self, defcls); +} + +PyDoc_STRVAR(datetime_datetime_utctimetuple__doc__, +"utctimetuple($self, /)\n" +"--\n" +"\n" +"Return UTC time tuple, compatible with time.localtime()."); + +#define DATETIME_DATETIME_UTCTIMETUPLE_METHODDEF \ + {"utctimetuple", _PyCFunction_CAST(datetime_datetime_utctimetuple), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime_utctimetuple__doc__}, + +static PyObject * +datetime_datetime_utctimetuple_impl(PyDateTime_DateTime *self, + PyTypeObject *defcls); + +static PyObject * +datetime_datetime_utctimetuple(PyDateTime_DateTime *self, PyTypeObject *defcls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "utctimetuple() takes no arguments"); + return NULL; + } + return datetime_datetime_utctimetuple_impl(self, defcls); +} +/*[clinic end generated code: output=ababb7cd1b7359a6 input=a9049054013a1b77]*/ From 0720cf97e45c0d050149904cbf4ac651ac613b19 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 07:46:39 +0900 Subject: [PATCH 45/50] regen --- .../internal/pycore_global_objects_fini_generated.h | 4 ++++ Include/internal/pycore_global_strings.h | 4 ++++ Include/internal/pycore_runtime_init_generated.h | 4 ++++ Include/internal/pycore_unicodeobject_generated.h | 12 ++++++++++++ .../2023-03-24-11-10-16.gh-issue-117398.q4ueXs.rst | 1 + 5 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-03-24-11-10-16.gh-issue-117398.q4ueXs.rst diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4a6f40c84088e8..30789544a34053 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -881,6 +881,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(d)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(data)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(database)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(date)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(day)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(decode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(decoder)); @@ -1254,8 +1255,11 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(text)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(threading)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(throw)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(time)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeout)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(times)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timespec)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timestamp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timetuple)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(top)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(trace_callback)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 8332cdf874c0c9..dc2df652cccd95 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -370,6 +370,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(d) STRUCT_FOR_ID(data) STRUCT_FOR_ID(database) + STRUCT_FOR_ID(date) STRUCT_FOR_ID(day) STRUCT_FOR_ID(decode) STRUCT_FOR_ID(decoder) @@ -743,8 +744,11 @@ struct _Py_global_strings { STRUCT_FOR_ID(text) STRUCT_FOR_ID(threading) STRUCT_FOR_ID(throw) + STRUCT_FOR_ID(time) STRUCT_FOR_ID(timeout) STRUCT_FOR_ID(times) + STRUCT_FOR_ID(timespec) + STRUCT_FOR_ID(timestamp) STRUCT_FOR_ID(timetuple) STRUCT_FOR_ID(top) STRUCT_FOR_ID(trace_callback) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 103279a4cf228b..24d277f886a7ca 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -879,6 +879,7 @@ extern "C" { INIT_ID(d), \ INIT_ID(data), \ INIT_ID(database), \ + INIT_ID(date), \ INIT_ID(day), \ INIT_ID(decode), \ INIT_ID(decoder), \ @@ -1252,8 +1253,11 @@ extern "C" { INIT_ID(text), \ INIT_ID(threading), \ INIT_ID(throw), \ + INIT_ID(time), \ INIT_ID(timeout), \ INIT_ID(times), \ + INIT_ID(timespec), \ + INIT_ID(timestamp), \ INIT_ID(timetuple), \ INIT_ID(top), \ INIT_ID(trace_callback), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index a180054d407b39..2b9dd538017706 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -951,6 +951,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(database); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(date); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(day); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -2070,12 +2073,21 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(throw); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(time); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(timeout); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(times); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(timespec); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(timestamp); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(timetuple); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Misc/NEWS.d/next/Library/2023-03-24-11-10-16.gh-issue-117398.q4ueXs.rst b/Misc/NEWS.d/next/Library/2023-03-24-11-10-16.gh-issue-117398.q4ueXs.rst new file mode 100644 index 00000000000000..843e44d0b78cb8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-24-11-10-16.gh-issue-117398.q4ueXs.rst @@ -0,0 +1 @@ +Apply :pep:`687` to :mod:`datetime`. Patch by Erlend Aasland. From f474febd9d5dded98cefe2666596600c8a55bbd8 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 27 Apr 2024 08:25:14 +0900 Subject: [PATCH 46/50] Update ignored.tsv --- Tools/c-analyzer/cpython/ignored.tsv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 87b695de23e25e..dede0d63af9184 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -214,9 +214,9 @@ Modules/_ctypes/cfield.c - ffi_type_uint8 - Modules/_ctypes/cfield.c - ffi_type_void - Modules/_datetimemodule.c - epoch - Modules/_datetimemodule.c - max_fold_seconds - -Modules/_datetimemodule.c datetime_isoformat specs - +Modules/_datetimemodule.c datetime_datetime_isoformat_impl specs - Modules/_datetimemodule.c parse_hh_mm_ss_ff correction - -Modules/_datetimemodule.c time_isoformat specs - +Modules/_datetimemodule.c datetime_time_isoformat_impl specs - Modules/_decimal/_decimal.c - cond_map_template - Modules/_decimal/_decimal.c - dec_signal_string - Modules/_decimal/_decimal.c - dflt_ctx - From 1ed62de9637b91788b7ee6c9c313692ce529301d Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Mon, 29 Apr 2024 01:02:42 +0900 Subject: [PATCH 47/50] fix gil-disabled test --- Modules/_testmultiphase.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index e09de1d5a7b793..a8ed507f8815d0 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -965,19 +965,20 @@ datetime_capi_client_exec(PyObject *m) } PyDateTime_IMPORT; - if (PyDateTimeAPI == NULL) { - return -1; - } - if (PyDateTimeAPI != PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)) { + PyErr_Clear(); + PyDateTime_CAPI *capi = PyDateTimeAPI; + PyErr_Clear(); + if (capi != PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)) { return -1; } + PyErr_Clear(); if (ismain) { - if (PyDateTimeAPI != _pydatetimeapi_main) { + if (capi != _pydatetimeapi_main) { return -1; } } else { - if (PyDateTimeAPI == _pydatetimeapi_main) { + if (capi == _pydatetimeapi_main) { PyObject *module = PyImport_ImportModule("_datetime"); if (module == NULL) { return -1; From cc0c974f1ba171e5040d4cb0d8b3b3905c159dad Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Mon, 29 Apr 2024 03:17:37 +0900 Subject: [PATCH 48/50] add missing docstr for *.__replace__() --- Modules/_datetimemodule.c | 11 ++++++++--- Modules/clinic/_datetimemodule.c.h | 11 +++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index c75fa801c8214d..da323de4ca9a25 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3718,12 +3718,13 @@ datetime.date.__replace__ month: int(c_default="GET_MONTH(self)") = unchanged day: int(c_default="GET_DAY(self)") = unchanged +The same as replace(). [clinic start generated code]*/ static PyObject * datetime_date___replace___impl(PyDateTime_Date *self, PyTypeObject *defcls, int year, int month, int day) -/*[clinic end generated code: output=4274716e2fed7f61 input=7218fbab51692bf7]*/ +/*[clinic end generated code: output=4274716e2fed7f61 input=adb04c14fd81386e]*/ { return datetime_date_replace_impl(self, defcls, year, month, day); } @@ -4959,13 +4960,15 @@ datetime.time.__replace__ tzinfo: object(c_default="HASTZINFO(self) ? self->tzinfo : Py_None") = unchanged * fold: int(c_default="TIME_GET_FOLD(self)") = unchanged + +The same as replace(). [clinic start generated code]*/ static PyObject * datetime_time___replace___impl(PyDateTime_Time *self, PyTypeObject *defcls, int hour, int minute, int second, int microsecond, PyObject *tzinfo, int fold) -/*[clinic end generated code: output=0db4f39f3353ecf6 input=cf50f2b0e8925429]*/ +/*[clinic end generated code: output=0db4f39f3353ecf6 input=dbffeada7075f7f0]*/ { return datetime_time_replace_impl(self, defcls, hour, minute, second, microsecond, tzinfo, fold); @@ -6585,6 +6588,8 @@ datetime.datetime.__replace__ tzinfo: object(c_default="HASTZINFO(self) ? self->tzinfo : Py_None") = unchanged * fold: int(c_default="DATE_GET_FOLD(self)") = unchanged + +The same as replace(). [clinic start generated code]*/ static PyObject * @@ -6593,7 +6598,7 @@ datetime_datetime___replace___impl(PyDateTime_DateTime *self, int day, int hour, int minute, int second, int microsecond, PyObject *tzinfo, int fold) -/*[clinic end generated code: output=2b2c327c73986226 input=233cfaa570c8a3b0]*/ +/*[clinic end generated code: output=2b2c327c73986226 input=152de8462978aa03]*/ { return datetime_datetime_replace_impl(self, defcls, year, month, day, hour, minute, second, microsecond, tzinfo, fold); diff --git a/Modules/clinic/_datetimemodule.c.h b/Modules/clinic/_datetimemodule.c.h index d7e877e730a3d8..4b9ad3f67e5c37 100644 --- a/Modules/clinic/_datetimemodule.c.h +++ b/Modules/clinic/_datetimemodule.c.h @@ -472,7 +472,8 @@ datetime_date_replace(PyDateTime_Date *self, PyTypeObject *defcls, PyObject *con PyDoc_STRVAR(datetime_date___replace____doc__, "__replace__($self, /, year=unchanged, month=unchanged, day=unchanged)\n" "--\n" -"\n"); +"\n" +"The same as replace()."); #define DATETIME_DATE___REPLACE___METHODDEF \ {"__replace__", _PyCFunction_CAST(datetime_date___replace__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_date___replace____doc__}, @@ -1100,7 +1101,8 @@ PyDoc_STRVAR(datetime_time___replace____doc__, " second=unchanged, microsecond=unchanged, tzinfo=unchanged,\n" " *, fold=unchanged)\n" "--\n" -"\n"); +"\n" +"The same as replace()."); #define DATETIME_TIME___REPLACE___METHODDEF \ {"__replace__", _PyCFunction_CAST(datetime_time___replace__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_time___replace____doc__}, @@ -1870,7 +1872,8 @@ PyDoc_STRVAR(datetime_datetime___replace____doc__, " hour=unchanged, minute=unchanged, second=unchanged,\n" " microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged)\n" "--\n" -"\n"); +"\n" +"The same as replace()."); #define DATETIME_DATETIME___REPLACE___METHODDEF \ {"__replace__", _PyCFunction_CAST(datetime_datetime___replace__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, datetime_datetime___replace____doc__}, @@ -2212,4 +2215,4 @@ datetime_datetime_utctimetuple(PyDateTime_DateTime *self, PyTypeObject *defcls, } return datetime_datetime_utctimetuple_impl(self, defcls); } -/*[clinic end generated code: output=ababb7cd1b7359a6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8e2d5fc079c3daeb input=a9049054013a1b77]*/ From 49b16c00464c063a8a190c6eefd1721f32d78b66 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 1 May 2024 21:02:37 +0900 Subject: [PATCH 49/50] apply PR: Access C-API via PyInterpreterState --- Include/datetime.h | 34 ++++----- Include/internal/pycore_interp.h | 1 + Lib/test/datetimetester.py | 2 +- Lib/test/test_capi/test_misc.py | 1 + Modules/_datetimemodule.c | 38 ++++++++++ Modules/_testcapi/datetime.c | 16 ++++- Modules/_testmultiphase.c | 78 +++++++++++++-------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 2 +- Tools/c-analyzer/cpython/ignored.tsv | 1 + 9 files changed, 122 insertions(+), 51 deletions(-) diff --git a/Include/datetime.h b/Include/datetime.h index 76544a5ece7267..0573e39e399b0f 100644 --- a/Include/datetime.h +++ b/Include/datetime.h @@ -186,34 +186,34 @@ typedef struct { } PyDateTime_CAPI; #define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI" - +#define PyDateTime_INTERNAL_CAPSULE_NAME "datetime.datetime_CAPI_INTERNAL" /* This block is only used as part of the public API and should not be * included in _datetimemodule.c, which does not use the C API capsule. * See bpo-35081 for more details. * */ #ifndef _PY_DATETIME_IMPL -/* Define global variable for the C API and a macro for setting it. */ -static PyDateTime_CAPI *_pydatetimeapi_main = NULL; +static PyDateTime_CAPI * +_PyDateTimeAPI_not_ready(void) +{ + return NULL; +} +// typedef PyDateTime_CAPI *(*datetime_api_getfunc)(void); +// static datetime_api_getfunc _PyDateTimeAPI_Get = _PyDateTimeAPI_not_ready; +static PyDateTime_CAPI *(*_PyDateTimeAPI_Get)(void) = _PyDateTimeAPI_not_ready; + static inline void -_import_pydatetime(void) { - if (PyInterpreterState_Get() == PyInterpreterState_Main()) { - _pydatetimeapi_main = PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0); +_PyDateTimeAPI_Import(void) +{ + void *(*func)(void) = PyCapsule_Import(PyDateTime_INTERNAL_CAPSULE_NAME, 0); + if (func) { + _PyDateTimeAPI_Get = func(); } } -#define PyDateTime_IMPORT _import_pydatetime() -static inline PyDateTime_CAPI * -_get_pydatetime_api(void) { - if (PyInterpreterState_Get() == PyInterpreterState_Main()) { - return _pydatetimeapi_main; - } - else { - return PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0); - } -} -#define PyDateTimeAPI _get_pydatetime_api() +#define PyDateTimeAPI _PyDateTimeAPI_Get() +#define PyDateTime_IMPORT _PyDateTimeAPI_Import() /* Macro for access to the UTC singleton */ #define PyDateTime_TimeZone_UTC PyDateTimeAPI->TimeZone_UTC diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index d38959e3ce4ec5..eb21e10fb224ee 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -236,6 +236,7 @@ struct _is { // more comments. struct _obmalloc_state *obmalloc; + void *datetime_capi; PyObject *audit_hooks; PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS]; diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 570110893629cf..6946b394e68a82 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -91,7 +91,7 @@ def test_name_cleanup(self): if not name.startswith('__') and not name.endswith('__')) allowed = set(['MAXYEAR', 'MINYEAR', 'date', 'datetime', 'datetime_CAPI', 'time', 'timedelta', 'timezone', - 'tzinfo', 'UTC', 'sys']) + 'tzinfo', 'UTC', 'sys', 'datetime_CAPI_INTERNAL']) self.assertEqual(names - allowed, set([])) def test_divide_and_round(self): diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 9786e0d88cbf66..2cbaac346e915c 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2295,6 +2295,7 @@ def test_datetime_capi_client(self): spec.loader.exec_module(module) """) exec(script) # run main interp first + exec(script) # run main interp twice ret = support.run_in_subinterp(script) self.assertEqual(ret, 0) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index da323de4ca9a25..de7fb952a3e780 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -108,6 +108,30 @@ find_state_left_or_right(PyObject *left, PyObject *right) #define find_module_state_by_def(obj) find_module_state_by_def((PyTypeObject *)(obj)) +static inline void +set_datetime_capi_by_interp(PyDateTime_CAPI *capi) +{ + _PyInterpreterState_GET()->datetime_capi = capi; +} + +static PyDateTime_CAPI * +_PyDateTimeAPI_Get(void) +{ + return (PyDateTime_CAPI *)_PyInterpreterState_GET()->datetime_capi; +} + +static void * +_PyDateTimeAPI_Import(void) +{ + PyDateTime_CAPI *capi = PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0); + if (capi) { + // PyInit__datetime() is not called when the module is already loaded + // with single-phase init. + set_datetime_capi_by_interp(capi); + return (void *)_PyDateTimeAPI_Get; + } + return NULL; +} /* We require that C int be at least 32 bits, and use int virtually * everywhere. In just a few cases we use a temp long, where a Python @@ -7457,6 +7481,20 @@ _datetime_exec(PyObject *module) goto error; } + capsule = PyCapsule_New(_PyDateTimeAPI_Import, + PyDateTime_INTERNAL_CAPSULE_NAME, NULL); + if (capsule == NULL) { + PyMem_Free(capi); + goto error; + } + if (PyModule_Add(module, "datetime_CAPI_INTERNAL", capsule) < 0) { + PyMem_Free(capi); + goto error; + } + + /* Ensure that the newest capi is used on multi-phase init */ + set_datetime_capi_by_interp(capi); + /* A 4-year cycle has an extra leap day over what we'd get from * pasting together 4 single years. */ diff --git a/Modules/_testcapi/datetime.c b/Modules/_testcapi/datetime.c index 9803a830a25af1..b1796039f0d83a 100644 --- a/Modules/_testcapi/datetime.c +++ b/Modules/_testcapi/datetime.c @@ -3,11 +3,23 @@ #include "datetime.h" // PyDateTimeAPI +static int test_run_counter = 0; + static PyObject * test_datetime_capi(PyObject *self, PyObject *args) { - // PyDateTimeAPI cannot be carried over - // with multi-phase init enabled. + if (PyDateTimeAPI) { + if (test_run_counter) { + /* Probably regrtest.py -R */ + Py_RETURN_NONE; + } + else { + PyErr_SetString(PyExc_AssertionError, + "PyDateTime_CAPI somehow initialized"); + return NULL; + } + } + test_run_counter++; PyDateTime_IMPORT; if (PyDateTimeAPI) { diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index a8ed507f8815d0..429824fbede1fa 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -957,44 +957,62 @@ PyInit__test_shared_gil_only(void) #include "datetime.h" static int -datetime_capi_client_exec(PyObject *m) +datetime_capi_import_with_error(void) { + static int is_datetime_multiphase = -1; int ismain = PyInterpreterState_Get() == PyInterpreterState_Main(); - if (ismain) { - _pydatetimeapi_main = NULL; + if (ismain && is_datetime_multiphase < 0) { + PyObject *module = PyImport_ImportModule("_datetime"); + if (module == NULL) { + return -1; + } + PyModuleDef *def = PyModule_GetDef(module); + Py_DECREF(module); + if (def && def->m_size >= 0) { + is_datetime_multiphase = 1; + } + else { + is_datetime_multiphase = 0; + } + } + if (is_datetime_multiphase < 0) { + PyErr_SetString(PyExc_AssertionError, + "Main interpreter must be loaded first."); + return -1; } - PyDateTime_IMPORT; - PyErr_Clear(); - PyDateTime_CAPI *capi = PyDateTimeAPI; - PyErr_Clear(); - if (capi != PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)) { + _PyDateTimeAPI_Import(); + if (!PyErr_Occurred()) { + return 0; + } +#ifdef Py_GIL_DISABLED + if (!ismain && !is_datetime_multiphase) { + // _datetime module and Capsule are not imported + PyErr_WriteUnraisable(NULL); + return 0; + } +#endif + return -1; +} + +static int +datetime_capi_client_exec(PyObject *m) +{ + _PyDateTimeAPI_Get = _PyDateTimeAPI_not_ready; + if (_PyDateTimeAPI_Get() != NULL) { + PyErr_SetString(PyExc_AssertionError, + "DateTime API is expected to remain NULL."); return -1; } - PyErr_Clear(); - if (ismain) { - if (capi != _pydatetimeapi_main) { - return -1; - } + if (datetime_capi_import_with_error() < 0) { + return -1; } - else { - if (capi == _pydatetimeapi_main) { - PyObject *module = PyImport_ImportModule("_datetime"); - if (module == NULL) { - return -1; - } - PyModuleDef *def = PyModule_GetDef(module); - Py_DECREF(module); - if (def) { - // multi-phase init - return -1; - } - else { - // legacy init (shared module) - return 0; - } - } + if (PyDateTimeAPI != PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)) { + PyErr_SetString(PyExc_AssertionError, + "DateTime API does not match Capsule CAPI."); + return -1; } + PyErr_Clear(); return 0; } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 3e4b36ce411d90..675ab4aff5f7f6 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -437,7 +437,7 @@ Modules/_tkinter.c - trbInCmd - ## initialized once ## other -Include/datetime.h - _pydatetimeapi_main - +Include/datetime.h - _PyDateTimeAPI_Get - Modules/_ctypes/cfield.c _ctypes_get_fielddesc initialized - Modules/_ctypes/malloc_closure.c - _pagesize - Modules/_cursesmodule.c - initialised - diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index dede0d63af9184..33142b12af789f 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -591,6 +591,7 @@ Modules/_testmultiphase.c - slots_exec_unreported_exception - Modules/_testmultiphase.c - slots_nonmodule_with_exec_slots - Modules/_testmultiphase.c - testexport_methods - Modules/_testmultiphase.c - uninitialized_def - +Modules/_testmultiphase.c datetime_capi_import_with_error is_datetime_multiphase - Modules/_testsinglephase.c - global_state - Modules/_xxtestfuzz/_xxtestfuzz.c - _fuzzmodule - Modules/_xxtestfuzz/_xxtestfuzz.c - module_methods - From 2637e04a539ef7e5d1e120c0a51bff80b6b305be Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 1 May 2024 21:53:05 +0900 Subject: [PATCH 50/50] edit fix --- Include/datetime.h | 3 --- Modules/_datetimemodule.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Include/datetime.h b/Include/datetime.h index 0573e39e399b0f..54d80303a281ce 100644 --- a/Include/datetime.h +++ b/Include/datetime.h @@ -198,11 +198,8 @@ _PyDateTimeAPI_not_ready(void) { return NULL; } -// typedef PyDateTime_CAPI *(*datetime_api_getfunc)(void); -// static datetime_api_getfunc _PyDateTimeAPI_Get = _PyDateTimeAPI_not_ready; static PyDateTime_CAPI *(*_PyDateTimeAPI_Get)(void) = _PyDateTimeAPI_not_ready; - static inline void _PyDateTimeAPI_Import(void) { diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index de7fb952a3e780..5f9b31e3b699b9 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -128,7 +128,7 @@ _PyDateTimeAPI_Import(void) // PyInit__datetime() is not called when the module is already loaded // with single-phase init. set_datetime_capi_by_interp(capi); - return (void *)_PyDateTimeAPI_Get; + return _PyDateTimeAPI_Get; } return NULL; }