mirror of
https://github.com/python/cpython.git
synced 2025-09-25 17:59:57 +00:00
gh-117398: Add datetime Module State (gh-119810)
I was able to make use of the existing datetime_state struct, but there was one tricky thing I had to sort out. We mostly aren't converting to heap types, so we can't use things like PyType_GetModuleByDef() to look up the module state. The solution I came up with is somewhat novel, but I consider it straightforward. Also, it shouldn't have much impact on performance. In summary, this main changes here are: * I've added some macros to help hide how various objects relate to module state * as a solution to the module state lookup problem, I've stored the last loaded module on the current interpreter's internal dict (actually a weakref) * if the static type method is used after the module has been deleted, it is reloaded * to avoid extra work when loading the module, we directly copy the objects (new refs only) from the old module state into the new state if the old module hasn't been deleted yet * during module init we set various objects on the static types' __dict__s; to simplify things, we only do that the first time; once those static types have a separate __dict__ per interpreter, we'll do it every time * we now clear the module state when the module is destroyed (before, we were leaking everything in _datetime_global_state)
This commit is contained in:
parent
47fb4327b5
commit
d82a7ba041
5 changed files with 375 additions and 161 deletions
|
@ -829,6 +829,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_call));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_call));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_exception));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_exception));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_return));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_return));
|
||||||
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_datetime_module));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_statements));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_statements));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cadata));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cadata));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cafile));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cafile));
|
||||||
|
|
|
@ -318,6 +318,7 @@ struct _Py_global_strings {
|
||||||
STRUCT_FOR_ID(c_call)
|
STRUCT_FOR_ID(c_call)
|
||||||
STRUCT_FOR_ID(c_exception)
|
STRUCT_FOR_ID(c_exception)
|
||||||
STRUCT_FOR_ID(c_return)
|
STRUCT_FOR_ID(c_return)
|
||||||
|
STRUCT_FOR_ID(cached_datetime_module)
|
||||||
STRUCT_FOR_ID(cached_statements)
|
STRUCT_FOR_ID(cached_statements)
|
||||||
STRUCT_FOR_ID(cadata)
|
STRUCT_FOR_ID(cadata)
|
||||||
STRUCT_FOR_ID(cafile)
|
STRUCT_FOR_ID(cafile)
|
||||||
|
|
1
Include/internal/pycore_runtime_init_generated.h
generated
1
Include/internal/pycore_runtime_init_generated.h
generated
|
@ -827,6 +827,7 @@ extern "C" {
|
||||||
INIT_ID(c_call), \
|
INIT_ID(c_call), \
|
||||||
INIT_ID(c_exception), \
|
INIT_ID(c_exception), \
|
||||||
INIT_ID(c_return), \
|
INIT_ID(c_return), \
|
||||||
|
INIT_ID(cached_datetime_module), \
|
||||||
INIT_ID(cached_statements), \
|
INIT_ID(cached_statements), \
|
||||||
INIT_ID(cadata), \
|
INIT_ID(cadata), \
|
||||||
INIT_ID(cafile), \
|
INIT_ID(cafile), \
|
||||||
|
|
|
@ -795,6 +795,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
|
||||||
string = &_Py_ID(c_return);
|
string = &_Py_ID(c_return);
|
||||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||||
_PyUnicode_InternInPlace(interp, &string);
|
_PyUnicode_InternInPlace(interp, &string);
|
||||||
|
string = &_Py_ID(cached_datetime_module);
|
||||||
|
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||||
|
_PyUnicode_InternInPlace(interp, &string);
|
||||||
string = &_Py_ID(cached_statements);
|
string = &_Py_ID(cached_statements);
|
||||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||||
_PyUnicode_InternInPlace(interp, &string);
|
_PyUnicode_InternInPlace(interp, &string);
|
||||||
|
|
|
@ -25,17 +25,18 @@
|
||||||
# include <winsock2.h> /* struct timeval */
|
# include <winsock2.h> /* struct timeval */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* Static types exposed by the datetime C-API. */
|
|
||||||
PyTypeObject *date_type;
|
|
||||||
PyTypeObject *datetime_type;
|
|
||||||
PyTypeObject *delta_type;
|
|
||||||
PyTypeObject *time_type;
|
|
||||||
PyTypeObject *tzinfo_type;
|
|
||||||
/* Exposed indirectly via TimeZone_UTC. */
|
|
||||||
PyTypeObject *timezone_type;
|
|
||||||
|
|
||||||
/* Other module classes. */
|
/* forward declarations */
|
||||||
|
static PyTypeObject PyDateTime_DateType;
|
||||||
|
static PyTypeObject PyDateTime_DateTimeType;
|
||||||
|
static PyTypeObject PyDateTime_TimeType;
|
||||||
|
static PyTypeObject PyDateTime_DeltaType;
|
||||||
|
static PyTypeObject PyDateTime_TZInfoType;
|
||||||
|
static PyTypeObject PyDateTime_TimeZoneType;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* Module heap types. */
|
||||||
PyTypeObject *isocalendar_date_type;
|
PyTypeObject *isocalendar_date_type;
|
||||||
|
|
||||||
/* Conversion factors. */
|
/* Conversion factors. */
|
||||||
|
@ -47,39 +48,182 @@ typedef struct {
|
||||||
PyObject *us_per_week; // 1e6 * 3600 * 24 * 7 as Python int
|
PyObject *us_per_week; // 1e6 * 3600 * 24 * 7 as Python int
|
||||||
PyObject *seconds_per_day; // 3600 * 24 as Python int
|
PyObject *seconds_per_day; // 3600 * 24 as Python int
|
||||||
|
|
||||||
/* The interned UTC timezone instance */
|
|
||||||
PyObject *utc;
|
|
||||||
|
|
||||||
/* The interned Unix epoch datetime instance */
|
/* The interned Unix epoch datetime instance */
|
||||||
PyObject *epoch;
|
PyObject *epoch;
|
||||||
|
|
||||||
/* While we use a global state, we ensure it's only initialized once */
|
|
||||||
int initialized;
|
|
||||||
} datetime_state;
|
} datetime_state;
|
||||||
|
|
||||||
static datetime_state _datetime_global_state;
|
/* The module has a fixed number of static objects, due to being exposed
|
||||||
|
* through the datetime C-API. There are five types exposed directly,
|
||||||
|
* one type exposed indirectly, and one singleton constant (UTC).
|
||||||
|
*
|
||||||
|
* Each of these objects is hidden behind a macro in the same way as
|
||||||
|
* the per-module objects stored in module state. The macros for the
|
||||||
|
* static objects don't need to be passed a state, but the consistency
|
||||||
|
* of doing so is more clear. We use a dedicated noop macro, NO_STATE,
|
||||||
|
* to make the special case obvious. */
|
||||||
|
|
||||||
static inline datetime_state* get_datetime_state(void)
|
#define NO_STATE NULL
|
||||||
|
|
||||||
|
#define DATE_TYPE(st) &PyDateTime_DateType
|
||||||
|
#define DATETIME_TYPE(st) &PyDateTime_DateTimeType
|
||||||
|
#define TIME_TYPE(st) &PyDateTime_TimeType
|
||||||
|
#define DELTA_TYPE(st) &PyDateTime_DeltaType
|
||||||
|
#define TZINFO_TYPE(st) &PyDateTime_TZInfoType
|
||||||
|
#define TIMEZONE_TYPE(st) &PyDateTime_TimeZoneType
|
||||||
|
#define ISOCALENDAR_DATE_TYPE(st) st->isocalendar_date_type
|
||||||
|
|
||||||
|
#define PyDate_Check(op) PyObject_TypeCheck(op, DATE_TYPE(NO_STATE))
|
||||||
|
#define PyDate_CheckExact(op) Py_IS_TYPE(op, DATE_TYPE(NO_STATE))
|
||||||
|
|
||||||
|
#define PyDateTime_Check(op) PyObject_TypeCheck(op, DATETIME_TYPE(NO_STATE))
|
||||||
|
#define PyDateTime_CheckExact(op) Py_IS_TYPE(op, DATETIME_TYPE(NO_STATE))
|
||||||
|
|
||||||
|
#define PyTime_Check(op) PyObject_TypeCheck(op, TIME_TYPE(NO_STATE))
|
||||||
|
#define PyTime_CheckExact(op) Py_IS_TYPE(op, TIME_TYPE(NO_STATE))
|
||||||
|
|
||||||
|
#define PyDelta_Check(op) PyObject_TypeCheck(op, DELTA_TYPE(NO_STATE))
|
||||||
|
#define PyDelta_CheckExact(op) Py_IS_TYPE(op, DELTA_TYPE(NO_STATE))
|
||||||
|
|
||||||
|
#define PyTZInfo_Check(op) PyObject_TypeCheck(op, TZINFO_TYPE(NO_STATE))
|
||||||
|
#define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, TZINFO_TYPE(NO_STATE))
|
||||||
|
|
||||||
|
#define PyTimezone_Check(op) PyObject_TypeCheck(op, TIMEZONE_TYPE(NO_STATE))
|
||||||
|
|
||||||
|
#define CONST_US_PER_MS(st) st->us_per_ms
|
||||||
|
#define CONST_US_PER_SECOND(st) st->us_per_second
|
||||||
|
#define CONST_US_PER_MINUTE(st) st->us_per_minute
|
||||||
|
#define CONST_US_PER_HOUR(st) st->us_per_hour
|
||||||
|
#define CONST_US_PER_DAY(st) st->us_per_day
|
||||||
|
#define CONST_US_PER_WEEK(st) st->us_per_week
|
||||||
|
#define CONST_SEC_PER_DAY(st) st->seconds_per_day
|
||||||
|
#define CONST_EPOCH(st) st->epoch
|
||||||
|
#define CONST_UTC(st) ((PyObject *)&utc_timezone)
|
||||||
|
|
||||||
|
static datetime_state *
|
||||||
|
get_module_state(PyObject *module)
|
||||||
{
|
{
|
||||||
return &_datetime_global_state;
|
void *state = _PyModule_GetState(module);
|
||||||
|
assert(state != NULL);
|
||||||
|
return (datetime_state *)state;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PyDate_Check(op) PyObject_TypeCheck(op, get_datetime_state()->date_type)
|
|
||||||
#define PyDate_CheckExact(op) Py_IS_TYPE(op, get_datetime_state()->date_type)
|
|
||||||
|
|
||||||
#define PyDateTime_Check(op) PyObject_TypeCheck(op, get_datetime_state()->datetime_type)
|
#define INTERP_KEY ((PyObject *)&_Py_ID(cached_datetime_module))
|
||||||
#define PyDateTime_CheckExact(op) Py_IS_TYPE(op, get_datetime_state()->datetime_type)
|
|
||||||
|
|
||||||
#define PyTime_Check(op) PyObject_TypeCheck(op, get_datetime_state()->time_type)
|
static PyObject *
|
||||||
#define PyTime_CheckExact(op) Py_IS_TYPE(op, get_datetime_state()->time_type)
|
get_current_module(PyInterpreterState *interp)
|
||||||
|
{
|
||||||
|
PyObject *dict = PyInterpreterState_GetDict(interp);
|
||||||
|
if (dict == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *ref = NULL;
|
||||||
|
if (PyDict_GetItemRef(dict, INTERP_KEY, &ref) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (ref == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *mod = NULL;
|
||||||
|
(void)PyWeakref_GetRef(ref, &mod);
|
||||||
|
if (mod == Py_None) {
|
||||||
|
Py_CLEAR(mod);
|
||||||
|
}
|
||||||
|
Py_DECREF(ref);
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
#define PyDelta_Check(op) PyObject_TypeCheck(op, get_datetime_state()->delta_type)
|
static PyModuleDef datetimemodule;
|
||||||
#define PyDelta_CheckExact(op) Py_IS_TYPE(op, get_datetime_state()->delta_type)
|
|
||||||
|
|
||||||
#define PyTZInfo_Check(op) PyObject_TypeCheck(op, get_datetime_state()->tzinfo_type)
|
static datetime_state *
|
||||||
#define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, get_datetime_state()->tzinfo_type)
|
_get_current_state(PyObject **p_mod)
|
||||||
|
{
|
||||||
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
PyObject *mod = get_current_module(interp);
|
||||||
|
if (mod == NULL) {
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* The static types can outlive the module,
|
||||||
|
* so we must re-import the module. */
|
||||||
|
mod = PyImport_ImportModule("_datetime");
|
||||||
|
if (mod == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
datetime_state *st = get_module_state(mod);
|
||||||
|
*p_mod = mod;
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GET_CURRENT_STATE(MOD_VAR) \
|
||||||
|
_get_current_state(&MOD_VAR)
|
||||||
|
#define RELEASE_CURRENT_STATE(ST_VAR, MOD_VAR) \
|
||||||
|
Py_DECREF(MOD_VAR)
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_current_module(PyInterpreterState *interp, PyObject *mod)
|
||||||
|
{
|
||||||
|
assert(mod != NULL);
|
||||||
|
PyObject *dict = PyInterpreterState_GetDict(interp);
|
||||||
|
if (dict == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyObject *ref = PyWeakref_NewRef(mod, NULL);
|
||||||
|
if (ref == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int rc = PyDict_SetItem(dict, INTERP_KEY, ref);
|
||||||
|
Py_DECREF(ref);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clear_current_module(PyInterpreterState *interp, PyObject *expected)
|
||||||
|
{
|
||||||
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
|
|
||||||
|
PyObject *current = NULL;
|
||||||
|
|
||||||
|
PyObject *dict = PyInterpreterState_GetDict(interp);
|
||||||
|
if (dict == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expected != NULL) {
|
||||||
|
PyObject *ref = NULL;
|
||||||
|
if (PyDict_GetItemRef(dict, INTERP_KEY, &ref) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (ref != NULL) {
|
||||||
|
int rc = PyWeakref_GetRef(ref, ¤t);
|
||||||
|
Py_DECREF(ref);
|
||||||
|
if (rc < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (current != expected) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyDict_DelItem(dict, INTERP_KEY) < 0) {
|
||||||
|
if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
error:
|
||||||
|
PyErr_Print();
|
||||||
|
|
||||||
|
finally:
|
||||||
|
Py_XDECREF(current);
|
||||||
|
PyErr_SetRaisedException(exc);
|
||||||
|
}
|
||||||
|
|
||||||
#define PyTimezone_Check(op) PyObject_TypeCheck(op, get_datetime_state()->timezone_type)
|
|
||||||
|
|
||||||
/* We require that C int be at least 32 bits, and use int virtually
|
/* 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
|
* everywhere. In just a few cases we use a temp long, where a Python
|
||||||
|
@ -988,7 +1132,7 @@ new_date_ex(int year, int month, int day, PyTypeObject *type)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define new_date(year, month, day) \
|
#define new_date(year, month, day) \
|
||||||
new_date_ex(year, month, day, get_datetime_state()->date_type)
|
new_date_ex(year, month, day, DATE_TYPE(NO_STATE))
|
||||||
|
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -998,13 +1142,12 @@ new_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
new_date_subclass_ex(int year, int month, int day, PyObject *cls)
|
new_date_subclass_ex(int year, int month, int day, PyObject *cls)
|
||||||
{
|
{
|
||||||
datetime_state *st = get_datetime_state();
|
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
// We have "fast path" constructors for two subclasses: date and datetime
|
// We have "fast path" constructors for two subclasses: date and datetime
|
||||||
if ((PyTypeObject *)cls == st->date_type) {
|
if ((PyTypeObject *)cls == DATE_TYPE(NO_STATE)) {
|
||||||
result = new_date_ex(year, month, day, (PyTypeObject *)cls);
|
result = new_date_ex(year, month, day, (PyTypeObject *)cls);
|
||||||
}
|
}
|
||||||
else if ((PyTypeObject *)cls == st->datetime_type) {
|
else if ((PyTypeObject *)cls == DATETIME_TYPE(NO_STATE)) {
|
||||||
result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None,
|
result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None,
|
||||||
(PyTypeObject *)cls);
|
(PyTypeObject *)cls);
|
||||||
}
|
}
|
||||||
|
@ -1058,8 +1201,7 @@ new_datetime_ex(int year, int month, int day, int hour, int minute,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo, fold) \
|
#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo, fold) \
|
||||||
new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, \
|
new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, DATETIME_TYPE(NO_STATE))
|
||||||
get_datetime_state()->datetime_type)
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
call_subclass_fold(PyObject *cls, int fold, const char *format, ...)
|
call_subclass_fold(PyObject *cls, int fold, const char *format, ...)
|
||||||
|
@ -1100,9 +1242,8 @@ new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute
|
||||||
int second, int usecond, PyObject *tzinfo,
|
int second, int usecond, PyObject *tzinfo,
|
||||||
int fold, PyObject *cls)
|
int fold, PyObject *cls)
|
||||||
{
|
{
|
||||||
datetime_state *st = get_datetime_state();
|
|
||||||
PyObject* dt;
|
PyObject* dt;
|
||||||
if ((PyTypeObject*)cls == st->datetime_type) {
|
if ((PyTypeObject*)cls == DATETIME_TYPE(NO_STATE)) {
|
||||||
// Use the fast path constructor
|
// Use the fast path constructor
|
||||||
dt = new_datetime(year, month, day, hour, minute, second, usecond,
|
dt = new_datetime(year, month, day, hour, minute, second, usecond,
|
||||||
tzinfo, fold);
|
tzinfo, fold);
|
||||||
|
@ -1164,15 +1305,14 @@ new_time_ex(int hour, int minute, int second, int usecond,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define new_time(hh, mm, ss, us, tzinfo, fold) \
|
#define new_time(hh, mm, ss, us, tzinfo, fold) \
|
||||||
new_time_ex2(hh, mm, ss, us, tzinfo, fold, get_datetime_state()->time_type)
|
new_time_ex2(hh, mm, ss, us, tzinfo, fold, TIME_TYPE(NO_STATE))
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
new_time_subclass_fold_ex(int hour, int minute, int second, int usecond,
|
new_time_subclass_fold_ex(int hour, int minute, int second, int usecond,
|
||||||
PyObject *tzinfo, int fold, PyObject *cls)
|
PyObject *tzinfo, int fold, PyObject *cls)
|
||||||
{
|
{
|
||||||
PyObject *t;
|
PyObject *t;
|
||||||
datetime_state *st = get_datetime_state();
|
if ((PyTypeObject*)cls == TIME_TYPE(NO_STATE)) {
|
||||||
if ((PyTypeObject*)cls == st->time_type) {
|
|
||||||
// Use the fast path constructor
|
// Use the fast path constructor
|
||||||
t = new_time(hour, minute, second, usecond, tzinfo, fold);
|
t = new_time(hour, minute, second, usecond, tzinfo, fold);
|
||||||
}
|
}
|
||||||
|
@ -1224,7 +1364,7 @@ new_delta_ex(int days, int seconds, int microseconds, int normalize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define new_delta(d, s, us, normalize) \
|
#define new_delta(d, s, us, normalize) \
|
||||||
new_delta_ex(d, s, us, normalize, get_datetime_state()->delta_type)
|
new_delta_ex(d, s, us, normalize, DELTA_TYPE(NO_STATE))
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -1244,8 +1384,7 @@ static PyObject *
|
||||||
create_timezone(PyObject *offset, PyObject *name)
|
create_timezone(PyObject *offset, PyObject *name)
|
||||||
{
|
{
|
||||||
PyDateTime_TimeZone *self;
|
PyDateTime_TimeZone *self;
|
||||||
datetime_state *st = get_datetime_state();
|
PyTypeObject *type = TIMEZONE_TYPE(NO_STATE);
|
||||||
PyTypeObject *type = st->timezone_type;
|
|
||||||
|
|
||||||
assert(offset != NULL);
|
assert(offset != NULL);
|
||||||
assert(PyDelta_Check(offset));
|
assert(PyDelta_Check(offset));
|
||||||
|
@ -1267,6 +1406,7 @@ create_timezone(PyObject *offset, PyObject *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int delta_bool(PyDateTime_Delta *self);
|
static int delta_bool(PyDateTime_Delta *self);
|
||||||
|
static PyDateTime_TimeZone utc_timezone;
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
new_timezone(PyObject *offset, PyObject *name)
|
new_timezone(PyObject *offset, PyObject *name)
|
||||||
|
@ -1276,8 +1416,7 @@ new_timezone(PyObject *offset, PyObject *name)
|
||||||
assert(name == NULL || PyUnicode_Check(name));
|
assert(name == NULL || PyUnicode_Check(name));
|
||||||
|
|
||||||
if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) {
|
if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) {
|
||||||
datetime_state *st = get_datetime_state();
|
return Py_NewRef(CONST_UTC(NO_STATE));
|
||||||
return Py_NewRef(st->utc);
|
|
||||||
}
|
}
|
||||||
if ((GET_TD_DAYS(offset) == -1 &&
|
if ((GET_TD_DAYS(offset) == -1 &&
|
||||||
GET_TD_SECONDS(offset) == 0 &&
|
GET_TD_SECONDS(offset) == 0 &&
|
||||||
|
@ -1490,8 +1629,7 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds)
|
||||||
if (rv == 1) {
|
if (rv == 1) {
|
||||||
// Create a timezone from offset in seconds (0 returns UTC)
|
// Create a timezone from offset in seconds (0 returns UTC)
|
||||||
if (tzoffset == 0) {
|
if (tzoffset == 0) {
|
||||||
datetime_state *st = get_datetime_state();
|
return Py_NewRef(CONST_UTC(NO_STATE));
|
||||||
return Py_NewRef(st->utc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1);
|
PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1);
|
||||||
|
@ -1920,11 +2058,13 @@ delta_to_microseconds(PyDateTime_Delta *self)
|
||||||
PyObject *x3 = NULL;
|
PyObject *x3 = NULL;
|
||||||
PyObject *result = NULL;
|
PyObject *result = NULL;
|
||||||
|
|
||||||
|
PyObject *current_mod = NULL;
|
||||||
|
datetime_state *st = GET_CURRENT_STATE(current_mod);
|
||||||
|
|
||||||
x1 = PyLong_FromLong(GET_TD_DAYS(self));
|
x1 = PyLong_FromLong(GET_TD_DAYS(self));
|
||||||
if (x1 == NULL)
|
if (x1 == NULL)
|
||||||
goto Done;
|
goto Done;
|
||||||
datetime_state *st = get_datetime_state();
|
x2 = PyNumber_Multiply(x1, CONST_SEC_PER_DAY(st)); /* days in seconds */
|
||||||
x2 = PyNumber_Multiply(x1, st->seconds_per_day); /* days in seconds */
|
|
||||||
if (x2 == NULL)
|
if (x2 == NULL)
|
||||||
goto Done;
|
goto Done;
|
||||||
Py_SETREF(x1, NULL);
|
Py_SETREF(x1, NULL);
|
||||||
|
@ -1941,7 +2081,7 @@ delta_to_microseconds(PyDateTime_Delta *self)
|
||||||
/* x1 = */ x2 = NULL;
|
/* x1 = */ x2 = NULL;
|
||||||
|
|
||||||
/* x3 has days+seconds in seconds */
|
/* x3 has days+seconds in seconds */
|
||||||
x1 = PyNumber_Multiply(x3, st->us_per_second); /* us */
|
x1 = PyNumber_Multiply(x3, CONST_US_PER_SECOND(st)); /* us */
|
||||||
if (x1 == NULL)
|
if (x1 == NULL)
|
||||||
goto Done;
|
goto Done;
|
||||||
Py_SETREF(x3, NULL);
|
Py_SETREF(x3, NULL);
|
||||||
|
@ -1957,6 +2097,7 @@ Done:
|
||||||
Py_XDECREF(x1);
|
Py_XDECREF(x1);
|
||||||
Py_XDECREF(x2);
|
Py_XDECREF(x2);
|
||||||
Py_XDECREF(x3);
|
Py_XDECREF(x3);
|
||||||
|
RELEASE_CURRENT_STATE(st, current_mod);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1996,8 +2137,10 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
|
||||||
PyObject *num = NULL;
|
PyObject *num = NULL;
|
||||||
PyObject *result = NULL;
|
PyObject *result = NULL;
|
||||||
|
|
||||||
datetime_state *st = get_datetime_state();
|
PyObject *current_mod = NULL;
|
||||||
tuple = checked_divmod(pyus, st->us_per_second);
|
datetime_state *st = GET_CURRENT_STATE(current_mod);
|
||||||
|
|
||||||
|
tuple = checked_divmod(pyus, CONST_US_PER_SECOND(st));
|
||||||
if (tuple == NULL) {
|
if (tuple == NULL) {
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
|
@ -2015,7 +2158,7 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
|
||||||
num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover seconds */
|
num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover seconds */
|
||||||
Py_DECREF(tuple);
|
Py_DECREF(tuple);
|
||||||
|
|
||||||
tuple = checked_divmod(num, st->seconds_per_day);
|
tuple = checked_divmod(num, CONST_SEC_PER_DAY(st));
|
||||||
if (tuple == NULL)
|
if (tuple == NULL)
|
||||||
goto Done;
|
goto Done;
|
||||||
Py_DECREF(num);
|
Py_DECREF(num);
|
||||||
|
@ -2040,6 +2183,7 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
|
||||||
Done:
|
Done:
|
||||||
Py_XDECREF(tuple);
|
Py_XDECREF(tuple);
|
||||||
Py_XDECREF(num);
|
Py_XDECREF(num);
|
||||||
|
RELEASE_CURRENT_STATE(st, current_mod);
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
BadDivmod:
|
BadDivmod:
|
||||||
|
@ -2049,7 +2193,7 @@ BadDivmod:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define microseconds_to_delta(pymicros) \
|
#define microseconds_to_delta(pymicros) \
|
||||||
microseconds_to_delta_ex(pymicros, get_datetime_state()->delta_type)
|
microseconds_to_delta_ex(pymicros, DELTA_TYPE(NO_STATE))
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
|
multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
|
||||||
|
@ -2577,6 +2721,9 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
{
|
{
|
||||||
PyObject *self = NULL;
|
PyObject *self = NULL;
|
||||||
|
|
||||||
|
PyObject *current_mod = NULL;
|
||||||
|
datetime_state *st = GET_CURRENT_STATE(current_mod);
|
||||||
|
|
||||||
/* Argument objects. */
|
/* Argument objects. */
|
||||||
PyObject *day = NULL;
|
PyObject *day = NULL;
|
||||||
PyObject *second = NULL;
|
PyObject *second = NULL;
|
||||||
|
@ -2615,29 +2762,28 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us);
|
y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
datetime_state *st = get_datetime_state();
|
|
||||||
if (ms) {
|
if (ms) {
|
||||||
y = accum("milliseconds", x, ms, st->us_per_ms, &leftover_us);
|
y = accum("milliseconds", x, ms, CONST_US_PER_MS(st), &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (second) {
|
if (second) {
|
||||||
y = accum("seconds", x, second, st->us_per_second, &leftover_us);
|
y = accum("seconds", x, second, CONST_US_PER_SECOND(st), &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (minute) {
|
if (minute) {
|
||||||
y = accum("minutes", x, minute, st->us_per_minute, &leftover_us);
|
y = accum("minutes", x, minute, CONST_US_PER_MINUTE(st), &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (hour) {
|
if (hour) {
|
||||||
y = accum("hours", x, hour, st->us_per_hour, &leftover_us);
|
y = accum("hours", x, hour, CONST_US_PER_HOUR(st), &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (day) {
|
if (day) {
|
||||||
y = accum("days", x, day, st->us_per_day, &leftover_us);
|
y = accum("days", x, day, CONST_US_PER_DAY(st), &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (week) {
|
if (week) {
|
||||||
y = accum("weeks", x, week, st->us_per_week, &leftover_us);
|
y = accum("weeks", x, week, CONST_US_PER_WEEK(st), &leftover_us);
|
||||||
CLEANUP;
|
CLEANUP;
|
||||||
}
|
}
|
||||||
if (leftover_us) {
|
if (leftover_us) {
|
||||||
|
@ -2679,7 +2825,9 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
|
|
||||||
self = microseconds_to_delta_ex(x, type);
|
self = microseconds_to_delta_ex(x, type);
|
||||||
Py_DECREF(x);
|
Py_DECREF(x);
|
||||||
|
|
||||||
Done:
|
Done:
|
||||||
|
RELEASE_CURRENT_STATE(st, current_mod);
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
#undef CLEANUP
|
#undef CLEANUP
|
||||||
|
@ -2792,9 +2940,12 @@ delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
if (total_microseconds == NULL)
|
if (total_microseconds == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
datetime_state *st = get_datetime_state();
|
PyObject *current_mod = NULL;
|
||||||
total_seconds = PyNumber_TrueDivide(total_microseconds, st->us_per_second);
|
datetime_state *st = GET_CURRENT_STATE(current_mod);
|
||||||
|
|
||||||
|
total_seconds = PyNumber_TrueDivide(total_microseconds, CONST_US_PER_SECOND(st));
|
||||||
|
|
||||||
|
RELEASE_CURRENT_STATE(st, current_mod);
|
||||||
Py_DECREF(total_microseconds);
|
Py_DECREF(total_microseconds);
|
||||||
return total_seconds;
|
return total_seconds;
|
||||||
}
|
}
|
||||||
|
@ -3547,9 +3698,12 @@ date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
|
||||||
week = 0;
|
week = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
datetime_state *st = get_datetime_state();
|
PyObject *current_mod = NULL;
|
||||||
PyObject *v = iso_calendar_date_new_impl(st->isocalendar_date_type,
|
datetime_state *st = GET_CURRENT_STATE(current_mod);
|
||||||
|
|
||||||
|
PyObject *v = iso_calendar_date_new_impl(ISOCALENDAR_DATE_TYPE(st),
|
||||||
year, week + 1, day + 1);
|
year, week + 1, day + 1);
|
||||||
|
RELEASE_CURRENT_STATE(st, current_mod);
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -4018,9 +4172,8 @@ timezone_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
{
|
{
|
||||||
PyObject *offset;
|
PyObject *offset;
|
||||||
PyObject *name = NULL;
|
PyObject *name = NULL;
|
||||||
datetime_state *st = get_datetime_state();
|
|
||||||
if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws,
|
if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws,
|
||||||
st->delta_type, &offset, &name))
|
DELTA_TYPE(NO_STATE), &offset, &name))
|
||||||
return new_timezone(offset, name);
|
return new_timezone(offset, name);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -4073,8 +4226,7 @@ timezone_repr(PyDateTime_TimeZone *self)
|
||||||
to use Py_TYPE(self)->tp_name here. */
|
to use Py_TYPE(self)->tp_name here. */
|
||||||
const char *type_name = Py_TYPE(self)->tp_name;
|
const char *type_name = Py_TYPE(self)->tp_name;
|
||||||
|
|
||||||
datetime_state *st = get_datetime_state();
|
if ((PyObject *)self == CONST_UTC(NO_STATE)) {
|
||||||
if (((PyObject *)self) == st->utc) {
|
|
||||||
return PyUnicode_FromFormat("%s.utc", type_name);
|
return PyUnicode_FromFormat("%s.utc", type_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4096,8 +4248,7 @@ timezone_str(PyDateTime_TimeZone *self)
|
||||||
if (self->name != NULL) {
|
if (self->name != NULL) {
|
||||||
return Py_NewRef(self->name);
|
return Py_NewRef(self->name);
|
||||||
}
|
}
|
||||||
datetime_state *st = get_datetime_state();
|
if ((PyObject *)self == CONST_UTC(NO_STATE) ||
|
||||||
if ((PyObject *)self == st->utc ||
|
|
||||||
(GET_TD_DAYS(self->offset) == 0 &&
|
(GET_TD_DAYS(self->offset) == 0 &&
|
||||||
GET_TD_SECONDS(self->offset) == 0 &&
|
GET_TD_SECONDS(self->offset) == 0 &&
|
||||||
GET_TD_MICROSECONDS(self->offset) == 0))
|
GET_TD_MICROSECONDS(self->offset) == 0))
|
||||||
|
@ -4260,7 +4411,7 @@ static PyDateTime_TimeZone *
|
||||||
look_up_timezone(PyObject *offset, PyObject *name)
|
look_up_timezone(PyObject *offset, PyObject *name)
|
||||||
{
|
{
|
||||||
if (offset == utc_timezone.offset && name == NULL) {
|
if (offset == utc_timezone.offset && name == NULL) {
|
||||||
return &utc_timezone;
|
return (PyDateTime_TimeZone *)CONST_UTC(NO_STATE);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -4777,8 +4928,7 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *t;
|
PyObject *t;
|
||||||
datetime_state *st = get_datetime_state();
|
if ( (PyTypeObject *)cls == TIME_TYPE(NO_STATE)) {
|
||||||
if ( (PyTypeObject *)cls == st->time_type) {
|
|
||||||
t = new_time(hour, minute, second, microsecond, tzinfo, 0);
|
t = new_time(hour, minute, second, microsecond, tzinfo, 0);
|
||||||
} else {
|
} else {
|
||||||
t = PyObject_CallFunction(cls, "iiiiO",
|
t = PyObject_CallFunction(cls, "iiiiO",
|
||||||
|
@ -5376,10 +5526,9 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
|
||||||
PyObject *tzinfo = NULL;
|
PyObject *tzinfo = NULL;
|
||||||
PyObject *result = NULL;
|
PyObject *result = NULL;
|
||||||
|
|
||||||
datetime_state *st = get_datetime_state();
|
|
||||||
if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords,
|
if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords,
|
||||||
st->date_type, &date,
|
DATE_TYPE(NO_STATE), &date,
|
||||||
st->time_type, &time, &tzinfo)) {
|
TIME_TYPE(NO_STATE), &time, &tzinfo)) {
|
||||||
if (tzinfo == NULL) {
|
if (tzinfo == NULL) {
|
||||||
if (HASTZINFO(time))
|
if (HASTZINFO(time))
|
||||||
tzinfo = ((PyDateTime_Time *)time)->tzinfo;
|
tzinfo = ((PyDateTime_Time *)time)->tzinfo;
|
||||||
|
@ -6209,7 +6358,6 @@ local_timezone_from_timestamp(time_t timestamp)
|
||||||
delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1);
|
delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1);
|
||||||
#else /* HAVE_STRUCT_TM_TM_ZONE */
|
#else /* HAVE_STRUCT_TM_TM_ZONE */
|
||||||
{
|
{
|
||||||
datetime_state *st = get_datetime_state();
|
|
||||||
PyObject *local_time, *utc_time;
|
PyObject *local_time, *utc_time;
|
||||||
struct tm utc_time_tm;
|
struct tm utc_time_tm;
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
@ -6264,8 +6412,11 @@ local_timezone(PyDateTime_DateTime *utc_time)
|
||||||
PyObject *one_second;
|
PyObject *one_second;
|
||||||
PyObject *seconds;
|
PyObject *seconds;
|
||||||
|
|
||||||
datetime_state *st = get_datetime_state();
|
PyObject *current_mod = NULL;
|
||||||
delta = datetime_subtract((PyObject *)utc_time, st->epoch);
|
datetime_state *st = GET_CURRENT_STATE(current_mod);
|
||||||
|
|
||||||
|
delta = datetime_subtract((PyObject *)utc_time, CONST_EPOCH(st));
|
||||||
|
RELEASE_CURRENT_STATE(st, current_mod);
|
||||||
if (delta == NULL)
|
if (delta == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -6378,7 +6529,6 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
datetime_state *st = get_datetime_state();
|
|
||||||
/* Make sure result is aware and UTC. */
|
/* Make sure result is aware and UTC. */
|
||||||
if (!HASTZINFO(result)) {
|
if (!HASTZINFO(result)) {
|
||||||
temp = (PyObject *)result;
|
temp = (PyObject *)result;
|
||||||
|
@ -6390,7 +6540,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
|
||||||
DATE_GET_MINUTE(result),
|
DATE_GET_MINUTE(result),
|
||||||
DATE_GET_SECOND(result),
|
DATE_GET_SECOND(result),
|
||||||
DATE_GET_MICROSECOND(result),
|
DATE_GET_MICROSECOND(result),
|
||||||
st->utc,
|
CONST_UTC(NO_STATE),
|
||||||
DATE_GET_FOLD(result),
|
DATE_GET_FOLD(result),
|
||||||
Py_TYPE(result));
|
Py_TYPE(result));
|
||||||
Py_DECREF(temp);
|
Py_DECREF(temp);
|
||||||
|
@ -6399,7 +6549,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Result is already aware - just replace tzinfo. */
|
/* Result is already aware - just replace tzinfo. */
|
||||||
Py_SETREF(result->tzinfo, Py_NewRef(st->utc));
|
Py_SETREF(result->tzinfo, Py_NewRef(CONST_UTC(NO_STATE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attach new tzinfo and let fromutc() do the rest. */
|
/* Attach new tzinfo and let fromutc() do the rest. */
|
||||||
|
@ -6503,9 +6653,12 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
|
|
||||||
if (HASTZINFO(self) && self->tzinfo != Py_None) {
|
if (HASTZINFO(self) && self->tzinfo != Py_None) {
|
||||||
datetime_state *st = get_datetime_state();
|
PyObject *current_mod = NULL;
|
||||||
|
datetime_state *st = GET_CURRENT_STATE(current_mod);
|
||||||
|
|
||||||
PyObject *delta;
|
PyObject *delta;
|
||||||
delta = datetime_subtract((PyObject *)self, st->epoch);
|
delta = datetime_subtract((PyObject *)self, CONST_EPOCH(st));
|
||||||
|
RELEASE_CURRENT_STATE(st, current_mod);
|
||||||
if (delta == NULL)
|
if (delta == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
result = delta_total_seconds(delta, NULL);
|
result = delta_total_seconds(delta, NULL);
|
||||||
|
@ -6839,23 +6992,6 @@ get_datetime_capi(void)
|
||||||
return &capi;
|
return &capi;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
datetime_clear(PyObject *module)
|
|
||||||
{
|
|
||||||
datetime_state *st = get_datetime_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 *
|
static PyObject *
|
||||||
create_timezone_from_delta(int days, int sec, int ms, int normalize)
|
create_timezone_from_delta(int days, int sec, int ms, int normalize)
|
||||||
{
|
{
|
||||||
|
@ -6869,25 +7005,39 @@ create_timezone_from_delta(int days, int sec, int ms, int normalize)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
init_state(datetime_state *st, PyTypeObject *PyDateTime_IsoCalendarDateType)
|
init_state(datetime_state *st, PyObject *module, PyObject *old_module)
|
||||||
{
|
{
|
||||||
// While datetime uses global module "state", we unly initialize it once.
|
/* Each module gets its own heap types. */
|
||||||
// The PyLong objects created here (once per process) are not decref'd.
|
#define ADD_TYPE(FIELD, SPEC, BASE) \
|
||||||
if (st->initialized) {
|
do { \
|
||||||
|
PyObject *cls = PyType_FromModuleAndSpec( \
|
||||||
|
module, SPEC, (PyObject *)BASE); \
|
||||||
|
if (cls == NULL) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
st->FIELD = (PyTypeObject *)cls; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
ADD_TYPE(isocalendar_date_type, &isocal_spec, &PyTuple_Type);
|
||||||
|
#undef ADD_TYPE
|
||||||
|
|
||||||
|
if (old_module != NULL) {
|
||||||
|
assert(old_module != module);
|
||||||
|
datetime_state *st_old = get_module_state(old_module);
|
||||||
|
*st = (datetime_state){
|
||||||
|
.isocalendar_date_type = st->isocalendar_date_type,
|
||||||
|
.us_per_ms = Py_NewRef(st_old->us_per_ms),
|
||||||
|
.us_per_second = Py_NewRef(st_old->us_per_second),
|
||||||
|
.us_per_minute = Py_NewRef(st_old->us_per_minute),
|
||||||
|
.us_per_hour = Py_NewRef(st_old->us_per_hour),
|
||||||
|
.us_per_day = Py_NewRef(st_old->us_per_day),
|
||||||
|
.us_per_week = Py_NewRef(st_old->us_per_week),
|
||||||
|
.seconds_per_day = Py_NewRef(st_old->seconds_per_day),
|
||||||
|
.epoch = Py_NewRef(st_old->epoch),
|
||||||
|
};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Static types exposed by the C-API. */
|
|
||||||
st->date_type = &PyDateTime_DateType;
|
|
||||||
st->datetime_type = &PyDateTime_DateTimeType;
|
|
||||||
st->delta_type = &PyDateTime_DeltaType;
|
|
||||||
st->time_type = &PyDateTime_TimeType;
|
|
||||||
st->tzinfo_type = &PyDateTime_TZInfoType;
|
|
||||||
st->timezone_type = &PyDateTime_TimeZoneType;
|
|
||||||
|
|
||||||
/* Per-module heap types. */
|
|
||||||
st->isocalendar_date_type = PyDateTime_IsoCalendarDateType;
|
|
||||||
|
|
||||||
st->us_per_ms = PyLong_FromLong(1000);
|
st->us_per_ms = PyLong_FromLong(1000);
|
||||||
if (st->us_per_ms == NULL) {
|
if (st->us_per_ms == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -6921,26 +7071,54 @@ init_state(datetime_state *st, PyTypeObject *PyDateTime_IsoCalendarDateType)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init UTC timezone */
|
|
||||||
st->utc = create_timezone_from_delta(0, 0, 0, 0);
|
|
||||||
if (st->utc == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Init Unix epoch */
|
/* Init Unix epoch */
|
||||||
st->epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->utc, 0);
|
st->epoch = new_datetime(
|
||||||
|
1970, 1, 1, 0, 0, 0, 0, (PyObject *)&utc_timezone, 0);
|
||||||
if (st->epoch == NULL) {
|
if (st->epoch == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->initialized = 1;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
traverse_state(datetime_state *st, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
/* heap types */
|
||||||
|
Py_VISIT(st->isocalendar_date_type);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
clear_state(datetime_state *st)
|
||||||
|
{
|
||||||
|
Py_CLEAR(st->isocalendar_date_type);
|
||||||
|
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->epoch);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_datetime_exec(PyObject *module)
|
_datetime_exec(PyObject *module)
|
||||||
{
|
{
|
||||||
|
int rc = -1;
|
||||||
|
datetime_state *st = get_module_state(module);
|
||||||
|
|
||||||
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
PyObject *old_module = get_current_module(interp);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
assert(old_module == NULL);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
/* We actually set the "current" module right before a successful return. */
|
||||||
|
|
||||||
// `&...` is not a constant expression according to a strict reading
|
// `&...` is not a constant expression according to a strict reading
|
||||||
// of C standards. Fill tp_base at run-time rather than statically.
|
// of C standards. Fill tp_base at run-time rather than statically.
|
||||||
// See https://bugs.python.org/issue40777
|
// See https://bugs.python.org/issue40777
|
||||||
|
@ -6953,6 +7131,7 @@ _datetime_exec(PyObject *module)
|
||||||
&PyDateTime_TimeType,
|
&PyDateTime_TimeType,
|
||||||
&PyDateTime_DeltaType,
|
&PyDateTime_DeltaType,
|
||||||
&PyDateTime_TZInfoType,
|
&PyDateTime_TZInfoType,
|
||||||
|
/* Indirectly, via the utc object. */
|
||||||
&PyDateTime_TimeZoneType,
|
&PyDateTime_TimeZoneType,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6962,29 +7141,16 @@ _datetime_exec(PyObject *module)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CREATE_TYPE(VAR, SPEC, BASE) \
|
if (init_state(st, module, old_module) < 0) {
|
||||||
do { \
|
|
||||||
VAR = (PyTypeObject *)PyType_FromModuleAndSpec( \
|
|
||||||
module, SPEC, (PyObject *)BASE); \
|
|
||||||
if (VAR == NULL) { \
|
|
||||||
goto error; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
PyTypeObject *PyDateTime_IsoCalendarDateType = NULL;
|
|
||||||
datetime_state *st = get_datetime_state();
|
|
||||||
|
|
||||||
if (!st->initialized) {
|
|
||||||
CREATE_TYPE(PyDateTime_IsoCalendarDateType, &isocal_spec, &PyTuple_Type);
|
|
||||||
}
|
|
||||||
#undef CREATE_TYPE
|
|
||||||
|
|
||||||
if (init_state(st, PyDateTime_IsoCalendarDateType) < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For now we only set the objects on the static types once.
|
||||||
|
* We will relax that once each types __dict__ is per-interpreter. */
|
||||||
#define DATETIME_ADD_MACRO(dict, c, value_expr) \
|
#define DATETIME_ADD_MACRO(dict, c, value_expr) \
|
||||||
do { \
|
do { \
|
||||||
|
if (PyDict_GetItemString(dict, c) == NULL) { \
|
||||||
|
assert(!PyErr_Occurred()); \
|
||||||
PyObject *value = (value_expr); \
|
PyObject *value = (value_expr); \
|
||||||
if (value == NULL) { \
|
if (value == NULL) { \
|
||||||
goto error; \
|
goto error; \
|
||||||
|
@ -6994,29 +7160,30 @@ _datetime_exec(PyObject *module)
|
||||||
goto error; \
|
goto error; \
|
||||||
} \
|
} \
|
||||||
Py_DECREF(value); \
|
Py_DECREF(value); \
|
||||||
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/* timedelta values */
|
/* timedelta values */
|
||||||
PyObject *d = st->delta_type->tp_dict;
|
PyObject *d = PyDateTime_DeltaType.tp_dict;
|
||||||
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
|
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
|
||||||
DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
|
DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
|
||||||
DATETIME_ADD_MACRO(d, "max",
|
DATETIME_ADD_MACRO(d, "max",
|
||||||
new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));
|
new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));
|
||||||
|
|
||||||
/* date values */
|
/* date values */
|
||||||
d = st->date_type->tp_dict;
|
d = PyDateTime_DateType.tp_dict;
|
||||||
DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
|
DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
|
||||||
DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
|
DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
|
||||||
DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));
|
DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));
|
||||||
|
|
||||||
/* time values */
|
/* time values */
|
||||||
d = st->time_type->tp_dict;
|
d = PyDateTime_TimeType.tp_dict;
|
||||||
DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
|
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, "max", new_time(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(0, 0, 1, 0));
|
||||||
|
|
||||||
/* datetime values */
|
/* datetime values */
|
||||||
d = st->datetime_type->tp_dict;
|
d = PyDateTime_DateTimeType.tp_dict;
|
||||||
DATETIME_ADD_MACRO(d, "min",
|
DATETIME_ADD_MACRO(d, "min",
|
||||||
new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
|
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,
|
DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
|
||||||
|
@ -7024,8 +7191,8 @@ _datetime_exec(PyObject *module)
|
||||||
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
|
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
|
||||||
|
|
||||||
/* timezone values */
|
/* timezone values */
|
||||||
d = st->timezone_type->tp_dict;
|
d = PyDateTime_TimeZoneType.tp_dict;
|
||||||
if (PyDict_SetItemString(d, "utc", st->utc) < 0) {
|
if (PyDict_SetItemString(d, "utc", (PyObject *)&utc_timezone) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7034,12 +7201,13 @@ _datetime_exec(PyObject *module)
|
||||||
* values. This may change in the future.*/
|
* values. This may change in the future.*/
|
||||||
|
|
||||||
/* -23:59 */
|
/* -23:59 */
|
||||||
PyObject *min = create_timezone_from_delta(-1, 60, 0, 1);
|
DATETIME_ADD_MACRO(d, "min", create_timezone_from_delta(-1, 60, 0, 1));
|
||||||
DATETIME_ADD_MACRO(d, "min", min);
|
|
||||||
|
|
||||||
/* +23:59 */
|
/* +23:59 */
|
||||||
PyObject *max = create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0);
|
DATETIME_ADD_MACRO(
|
||||||
DATETIME_ADD_MACRO(d, "max", max);
|
d, "max", create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0));
|
||||||
|
|
||||||
|
#undef DATETIME_ADD_MACRO
|
||||||
|
|
||||||
/* Add module level attributes */
|
/* Add module level attributes */
|
||||||
if (PyModule_AddIntMacro(module, MINYEAR) < 0) {
|
if (PyModule_AddIntMacro(module, MINYEAR) < 0) {
|
||||||
|
@ -7048,7 +7216,7 @@ _datetime_exec(PyObject *module)
|
||||||
if (PyModule_AddIntMacro(module, MAXYEAR) < 0) {
|
if (PyModule_AddIntMacro(module, MAXYEAR) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (PyModule_AddObjectRef(module, "UTC", st->utc) < 0) {
|
if (PyModule_AddObjectRef(module, "UTC", (PyObject *)&utc_timezone) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7081,13 +7249,20 @@ _datetime_exec(PyObject *module)
|
||||||
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
|
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
|
||||||
assert(DI100Y == days_before_year(100+1));
|
assert(DI100Y == days_before_year(100+1));
|
||||||
|
|
||||||
return 0;
|
if (set_current_module(interp, module) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
datetime_clear(module);
|
clear_state(st);
|
||||||
return -1;
|
|
||||||
|
finally:
|
||||||
|
Py_XDECREF(old_module);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
#undef DATETIME_ADD_MACRO
|
|
||||||
|
|
||||||
static PyModuleDef_Slot module_slots[] = {
|
static PyModuleDef_Slot module_slots[] = {
|
||||||
{Py_mod_exec, _datetime_exec},
|
{Py_mod_exec, _datetime_exec},
|
||||||
|
@ -7096,13 +7271,46 @@ static PyModuleDef_Slot module_slots[] = {
|
||||||
{0, NULL},
|
{0, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
module_traverse(PyObject *mod, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
datetime_state *st = get_module_state(mod);
|
||||||
|
traverse_state(st, visit, arg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
module_clear(PyObject *mod)
|
||||||
|
{
|
||||||
|
datetime_state *st = get_module_state(mod);
|
||||||
|
clear_state(st);
|
||||||
|
|
||||||
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
clear_current_module(interp, mod);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
module_free(void *mod)
|
||||||
|
{
|
||||||
|
datetime_state *st = get_module_state((PyObject *)mod);
|
||||||
|
clear_state(st);
|
||||||
|
|
||||||
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
clear_current_module(interp, (PyObject *)mod);
|
||||||
|
}
|
||||||
|
|
||||||
static PyModuleDef datetimemodule = {
|
static PyModuleDef datetimemodule = {
|
||||||
.m_base = PyModuleDef_HEAD_INIT,
|
.m_base = PyModuleDef_HEAD_INIT,
|
||||||
.m_name = "_datetime",
|
.m_name = "_datetime",
|
||||||
.m_doc = "Fast implementation of the datetime type.",
|
.m_doc = "Fast implementation of the datetime type.",
|
||||||
.m_size = 0,
|
.m_size = sizeof(datetime_state),
|
||||||
.m_methods = module_methods,
|
.m_methods = module_methods,
|
||||||
.m_slots = module_slots,
|
.m_slots = module_slots,
|
||||||
|
.m_traverse = module_traverse,
|
||||||
|
.m_clear = module_clear,
|
||||||
|
.m_free = module_free,
|
||||||
};
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue