mirror of https://github.com/python/cpython
gh-99138: Isolate _zoneinfo (#99218)
* Convert zone info type to heap type and add it to module state * Add global variables to module state
This commit is contained in:
parent
eb0c485b6c
commit
c1ce0d178f
|
@ -241,7 +241,7 @@ The following class methods are also available:
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
Invoking this function may change the semantics of datetimes using
|
Invoking this function may change the semantics of datetimes using
|
||||||
``ZoneInfo`` in surprising ways; this modifies process-wide global state
|
``ZoneInfo`` in surprising ways; this modifies module state
|
||||||
and thus may have wide-ranging effects. Only use it if you know that you
|
and thus may have wide-ranging effects. Only use it if you know that you
|
||||||
need to.
|
need to.
|
||||||
|
|
||||||
|
|
|
@ -1797,12 +1797,10 @@ class ExtensionBuiltTest(unittest.TestCase):
|
||||||
self.assertTrue(hasattr(py_zoneinfo.ZoneInfo, "_weak_cache"))
|
self.assertTrue(hasattr(py_zoneinfo.ZoneInfo, "_weak_cache"))
|
||||||
|
|
||||||
def test_gc_tracked(self):
|
def test_gc_tracked(self):
|
||||||
# The pure Python version is tracked by the GC but (for now) the C
|
|
||||||
# version is not.
|
|
||||||
import gc
|
import gc
|
||||||
|
|
||||||
self.assertTrue(gc.is_tracked(py_zoneinfo.ZoneInfo))
|
self.assertTrue(gc.is_tracked(py_zoneinfo.ZoneInfo))
|
||||||
self.assertFalse(gc.is_tracked(c_zoneinfo.ZoneInfo))
|
self.assertTrue(gc.is_tracked(c_zoneinfo.ZoneInfo))
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Apply :pep:`687` to :mod:`zoneinfo`. Patch by Erlend E. Aasland.
|
|
@ -19,10 +19,6 @@ class zoneinfo.ZoneInfo "PyObject *" "PyTypeObject *"
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d12c73c0eef36df8]*/
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d12c73c0eef36df8]*/
|
||||||
|
|
||||||
// Imports
|
|
||||||
static PyObject *io_open = NULL;
|
|
||||||
static PyObject *_tzpath_find_tzfile = NULL;
|
|
||||||
static PyObject *_common_mod = NULL;
|
|
||||||
|
|
||||||
typedef struct TransitionRuleType TransitionRuleType;
|
typedef struct TransitionRuleType TransitionRuleType;
|
||||||
typedef struct StrongCacheNode StrongCacheNode;
|
typedef struct StrongCacheNode StrongCacheNode;
|
||||||
|
@ -90,15 +86,21 @@ struct StrongCacheNode {
|
||||||
PyObject *zone;
|
PyObject *zone;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyTypeObject PyZoneInfo_ZoneInfoType;
|
typedef struct {
|
||||||
|
PyTypeObject *ZoneInfoType;
|
||||||
|
|
||||||
// Globals
|
// Imports
|
||||||
static PyObject *TIMEDELTA_CACHE = NULL;
|
PyObject *io_open;
|
||||||
static PyObject *ZONEINFO_WEAK_CACHE = NULL;
|
PyObject *_tzpath_find_tzfile;
|
||||||
static StrongCacheNode *ZONEINFO_STRONG_CACHE = NULL;
|
PyObject *_common_mod;
|
||||||
static size_t ZONEINFO_STRONG_CACHE_MAX_SIZE = 8;
|
|
||||||
|
|
||||||
static _ttinfo NO_TTINFO = {NULL, NULL, NULL, 0};
|
// Caches
|
||||||
|
PyObject *TIMEDELTA_CACHE;
|
||||||
|
PyObject *ZONEINFO_WEAK_CACHE;
|
||||||
|
StrongCacheNode *ZONEINFO_STRONG_CACHE;
|
||||||
|
|
||||||
|
_ttinfo NO_TTINFO;
|
||||||
|
} zoneinfo_state;
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
static const int EPOCHORDINAL = 719163;
|
static const int EPOCHORDINAL = 719163;
|
||||||
|
@ -114,9 +116,12 @@ static const int SOURCE_NOCACHE = 0;
|
||||||
static const int SOURCE_CACHE = 1;
|
static const int SOURCE_CACHE = 1;
|
||||||
static const int SOURCE_FILE = 2;
|
static const int SOURCE_FILE = 2;
|
||||||
|
|
||||||
|
static const size_t ZONEINFO_STRONG_CACHE_MAX_SIZE = 8;
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
static int
|
static int
|
||||||
load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj);
|
load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self,
|
||||||
|
PyObject *file_obj);
|
||||||
static void
|
static void
|
||||||
utcoff_to_dstoff(size_t *trans_idx, long *utcoffs, long *dstoffs,
|
utcoff_to_dstoff(size_t *trans_idx, long *utcoffs, long *dstoffs,
|
||||||
unsigned char *isdsts, size_t num_transitions,
|
unsigned char *isdsts, size_t num_transitions,
|
||||||
|
@ -127,7 +132,7 @@ ts_to_local(size_t *trans_idx, int64_t *trans_utc, long *utcoff,
|
||||||
size_t num_transitions);
|
size_t num_transitions);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_tz_str(PyObject *tz_str_obj, _tzrule *out);
|
parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out);
|
||||||
|
|
||||||
static Py_ssize_t
|
static Py_ssize_t
|
||||||
parse_abbr(const char *const p, PyObject **abbr);
|
parse_abbr(const char *const p, PyObject **abbr);
|
||||||
|
@ -146,26 +151,27 @@ find_tzrule_ttinfo_fromutc(_tzrule *rule, int64_t ts, int year,
|
||||||
unsigned char *fold);
|
unsigned char *fold);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
build_ttinfo(long utcoffset, long dstoffset, PyObject *tzname, _ttinfo *out);
|
build_ttinfo(zoneinfo_state *state, long utcoffset, long dstoffset,
|
||||||
|
PyObject *tzname, _ttinfo *out);
|
||||||
static void
|
static void
|
||||||
xdecref_ttinfo(_ttinfo *ttinfo);
|
xdecref_ttinfo(_ttinfo *ttinfo);
|
||||||
static int
|
static int
|
||||||
ttinfo_eq(const _ttinfo *const tti0, const _ttinfo *const tti1);
|
ttinfo_eq(const _ttinfo *const tti0, const _ttinfo *const tti1);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
build_tzrule(PyObject *std_abbr, PyObject *dst_abbr, long std_offset,
|
build_tzrule(zoneinfo_state *state, PyObject *std_abbr, PyObject *dst_abbr,
|
||||||
long dst_offset, TransitionRuleType *start,
|
long std_offset, long dst_offset, TransitionRuleType *start,
|
||||||
TransitionRuleType *end, _tzrule *out);
|
TransitionRuleType *end, _tzrule *out);
|
||||||
static void
|
static void
|
||||||
free_tzrule(_tzrule *tzrule);
|
free_tzrule(_tzrule *tzrule);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
load_timedelta(long seconds);
|
load_timedelta(zoneinfo_state *state, long seconds);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_local_timestamp(PyObject *dt, int64_t *local_ts);
|
get_local_timestamp(PyObject *dt, int64_t *local_ts);
|
||||||
static _ttinfo *
|
static _ttinfo *
|
||||||
find_ttinfo(PyZoneInfo_ZoneInfo *self, PyObject *dt);
|
find_ttinfo(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *dt);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ymd_to_ord(int y, int m, int d);
|
ymd_to_ord(int y, int m, int d);
|
||||||
|
@ -176,27 +182,57 @@ static size_t
|
||||||
_bisect(const int64_t value, const int64_t *arr, size_t size);
|
_bisect(const int64_t value, const int64_t *arr, size_t size);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
eject_from_strong_cache(const PyTypeObject *const type, PyObject *key);
|
eject_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
|
||||||
|
PyObject *key);
|
||||||
static void
|
static void
|
||||||
clear_strong_cache(const PyTypeObject *const type);
|
clear_strong_cache(zoneinfo_state *state, const PyTypeObject *const type);
|
||||||
static void
|
static void
|
||||||
update_strong_cache(const PyTypeObject *const type, PyObject *key,
|
update_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
|
||||||
PyObject *zone);
|
PyObject *key, PyObject *zone);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zone_from_strong_cache(const PyTypeObject *const type, PyObject *const key);
|
zone_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
|
||||||
|
PyObject *const key);
|
||||||
|
|
||||||
|
static inline zoneinfo_state *
|
||||||
|
zoneinfo_get_state(PyObject *mod)
|
||||||
|
{
|
||||||
|
zoneinfo_state *state = (zoneinfo_state *)PyModule_GetState(mod);
|
||||||
|
assert(state != NULL);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline zoneinfo_state *
|
||||||
|
zoneinfo_get_state_by_cls(PyTypeObject *cls)
|
||||||
|
{
|
||||||
|
zoneinfo_state *state = (zoneinfo_state *)PyType_GetModuleState(cls);
|
||||||
|
assert(state != NULL);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct PyModuleDef zoneinfomodule;
|
||||||
|
|
||||||
|
static inline zoneinfo_state *
|
||||||
|
zoneinfo_get_state_by_self(PyTypeObject *self)
|
||||||
|
{
|
||||||
|
PyObject *mod = PyType_GetModuleByDef(self, &zoneinfomodule);
|
||||||
|
assert(mod != NULL);
|
||||||
|
return zoneinfo_get_state(mod);
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_new_instance(PyTypeObject *type, PyObject *key)
|
zoneinfo_new_instance(zoneinfo_state *state, PyTypeObject *type, PyObject *key)
|
||||||
{
|
{
|
||||||
PyObject *file_obj = NULL;
|
PyObject *file_obj = NULL;
|
||||||
PyObject *file_path = NULL;
|
PyObject *file_path = NULL;
|
||||||
|
|
||||||
file_path = PyObject_CallFunctionObjArgs(_tzpath_find_tzfile, key, NULL);
|
file_path = PyObject_CallFunctionObjArgs(state->_tzpath_find_tzfile,
|
||||||
|
key, NULL);
|
||||||
if (file_path == NULL) {
|
if (file_path == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (file_path == Py_None) {
|
else if (file_path == Py_None) {
|
||||||
file_obj = PyObject_CallMethod(_common_mod, "load_tzdata", "O", key);
|
PyObject *meth = state->_common_mod;
|
||||||
|
file_obj = PyObject_CallMethod(meth, "load_tzdata", "O", key);
|
||||||
if (file_obj == NULL) {
|
if (file_obj == NULL) {
|
||||||
Py_DECREF(file_path);
|
Py_DECREF(file_path);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -209,13 +245,14 @@ zoneinfo_new_instance(PyTypeObject *type, PyObject *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_obj == NULL) {
|
if (file_obj == NULL) {
|
||||||
file_obj = PyObject_CallFunction(io_open, "Os", file_path, "rb");
|
PyObject *func = state->io_open;
|
||||||
|
file_obj = PyObject_CallFunction(func, "Os", file_path, "rb");
|
||||||
if (file_obj == NULL) {
|
if (file_obj == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load_data((PyZoneInfo_ZoneInfo *)self, file_obj)) {
|
if (load_data(state, (PyZoneInfo_ZoneInfo *)self, file_obj)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,10 +285,10 @@ cleanup:
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_weak_cache(PyTypeObject *type)
|
get_weak_cache(zoneinfo_state *state, PyTypeObject *type)
|
||||||
{
|
{
|
||||||
if (type == &PyZoneInfo_ZoneInfoType) {
|
if (type == state->ZoneInfoType) {
|
||||||
return ZONEINFO_WEAK_CACHE;
|
return state->ZONEINFO_WEAK_CACHE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *cache =
|
PyObject *cache =
|
||||||
|
@ -273,12 +310,13 @@ zoneinfo_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *instance = zone_from_strong_cache(type, key);
|
zoneinfo_state *state = zoneinfo_get_state_by_self(type);
|
||||||
|
PyObject *instance = zone_from_strong_cache(state, type, key);
|
||||||
if (instance != NULL || PyErr_Occurred()) {
|
if (instance != NULL || PyErr_Occurred()) {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *weak_cache = get_weak_cache(type);
|
PyObject *weak_cache = get_weak_cache(state, type);
|
||||||
instance = PyObject_CallMethod(weak_cache, "get", "O", key, Py_None);
|
instance = PyObject_CallMethod(weak_cache, "get", "O", key, Py_None);
|
||||||
if (instance == NULL) {
|
if (instance == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -286,7 +324,7 @@ zoneinfo_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
|
|
||||||
if (instance == Py_None) {
|
if (instance == Py_None) {
|
||||||
Py_DECREF(instance);
|
Py_DECREF(instance);
|
||||||
PyObject *tmp = zoneinfo_new_instance(type, key);
|
PyObject *tmp = zoneinfo_new_instance(state, type, key);
|
||||||
if (tmp == NULL) {
|
if (tmp == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -300,14 +338,32 @@ zoneinfo_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
((PyZoneInfo_ZoneInfo *)instance)->source = SOURCE_CACHE;
|
((PyZoneInfo_ZoneInfo *)instance)->source = SOURCE_CACHE;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_strong_cache(type, key, instance);
|
update_strong_cache(state, type, key, instance);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
zoneinfo_traverse(PyZoneInfo_ZoneInfo *self, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
Py_VISIT(Py_TYPE(self));
|
||||||
|
Py_VISIT(self->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
zoneinfo_clear(PyZoneInfo_ZoneInfo *self)
|
||||||
|
{
|
||||||
|
Py_CLEAR(self->key);
|
||||||
|
Py_CLEAR(self->file_repr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
zoneinfo_dealloc(PyObject *obj_self)
|
zoneinfo_dealloc(PyObject *obj_self)
|
||||||
{
|
{
|
||||||
PyZoneInfo_ZoneInfo *self = (PyZoneInfo_ZoneInfo *)obj_self;
|
PyZoneInfo_ZoneInfo *self = (PyZoneInfo_ZoneInfo *)obj_self;
|
||||||
|
PyTypeObject *tp = Py_TYPE(self);
|
||||||
|
PyObject_GC_UnTrack(self);
|
||||||
|
|
||||||
if (self->weakreflist != NULL) {
|
if (self->weakreflist != NULL) {
|
||||||
PyObject_ClearWeakRefs(obj_self);
|
PyObject_ClearWeakRefs(obj_self);
|
||||||
|
@ -336,16 +392,16 @@ zoneinfo_dealloc(PyObject *obj_self)
|
||||||
|
|
||||||
free_tzrule(&(self->tzrule_after));
|
free_tzrule(&(self->tzrule_after));
|
||||||
|
|
||||||
Py_XDECREF(self->key);
|
zoneinfo_clear(self);
|
||||||
Py_XDECREF(self->file_repr);
|
tp->tp_free(obj_self);
|
||||||
|
Py_DECREF(tp);
|
||||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
@classmethod
|
@classmethod
|
||||||
zoneinfo.ZoneInfo.from_file
|
zoneinfo.ZoneInfo.from_file
|
||||||
|
|
||||||
|
cls: defining_class
|
||||||
file_obj: object
|
file_obj: object
|
||||||
/
|
/
|
||||||
key: object = None
|
key: object = None
|
||||||
|
@ -354,9 +410,9 @@ Create a ZoneInfo file from a file object.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_from_file_impl(PyTypeObject *type, PyObject *file_obj,
|
zoneinfo_ZoneInfo_from_file_impl(PyTypeObject *type, PyTypeObject *cls,
|
||||||
PyObject *key)
|
PyObject *file_obj, PyObject *key)
|
||||||
/*[clinic end generated code: output=68ed2022404ae5be input=ccfe73708133d2e4]*/
|
/*[clinic end generated code: output=77887d1d56a48324 input=d26111f29eed6863]*/
|
||||||
{
|
{
|
||||||
PyObject *file_repr = NULL;
|
PyObject *file_repr = NULL;
|
||||||
PyZoneInfo_ZoneInfo *self = NULL;
|
PyZoneInfo_ZoneInfo *self = NULL;
|
||||||
|
@ -372,7 +428,8 @@ zoneinfo_ZoneInfo_from_file_impl(PyTypeObject *type, PyObject *file_obj,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load_data(self, file_obj)) {
|
zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
|
||||||
|
if (load_data(state, self, file_obj)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,16 +448,20 @@ error:
|
||||||
@classmethod
|
@classmethod
|
||||||
zoneinfo.ZoneInfo.no_cache
|
zoneinfo.ZoneInfo.no_cache
|
||||||
|
|
||||||
|
cls: defining_class
|
||||||
|
/
|
||||||
key: object
|
key: object
|
||||||
|
|
||||||
Get a new instance of ZoneInfo, bypassing the cache.
|
Get a new instance of ZoneInfo, bypassing the cache.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyObject *key)
|
zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyTypeObject *cls,
|
||||||
/*[clinic end generated code: output=751c6894ad66f91b input=bb24afd84a80ba46]*/
|
PyObject *key)
|
||||||
|
/*[clinic end generated code: output=b0b09b3344c171b7 input=0238f3d56b1ea3f1]*/
|
||||||
{
|
{
|
||||||
PyObject *out = zoneinfo_new_instance(type, key);
|
zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
|
||||||
|
PyObject *out = zoneinfo_new_instance(state, type, key);
|
||||||
if (out != NULL) {
|
if (out != NULL) {
|
||||||
((PyZoneInfo_ZoneInfo *)out)->source = SOURCE_NOCACHE;
|
((PyZoneInfo_ZoneInfo *)out)->source = SOURCE_NOCACHE;
|
||||||
}
|
}
|
||||||
|
@ -412,6 +473,8 @@ zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyObject *key)
|
||||||
@classmethod
|
@classmethod
|
||||||
zoneinfo.ZoneInfo.clear_cache
|
zoneinfo.ZoneInfo.clear_cache
|
||||||
|
|
||||||
|
cls: defining_class
|
||||||
|
/
|
||||||
*
|
*
|
||||||
only_keys: object = None
|
only_keys: object = None
|
||||||
|
|
||||||
|
@ -419,10 +482,12 @@ Clear the ZoneInfo cache.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyObject *only_keys)
|
zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls,
|
||||||
/*[clinic end generated code: output=eec0a3276f07bd90 input=8cff0182a95f295b]*/
|
PyObject *only_keys)
|
||||||
|
/*[clinic end generated code: output=114d9b7c8a22e660 input=e32ca3bb396788ba]*/
|
||||||
{
|
{
|
||||||
PyObject *weak_cache = get_weak_cache(type);
|
zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
|
||||||
|
PyObject *weak_cache = get_weak_cache(state, type);
|
||||||
|
|
||||||
if (only_keys == NULL || only_keys == Py_None) {
|
if (only_keys == NULL || only_keys == Py_None) {
|
||||||
PyObject *rv = PyObject_CallMethod(weak_cache, "clear", NULL);
|
PyObject *rv = PyObject_CallMethod(weak_cache, "clear", NULL);
|
||||||
|
@ -430,7 +495,7 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyObject *only_keys)
|
||||||
Py_DECREF(rv);
|
Py_DECREF(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_strong_cache(type);
|
clear_strong_cache(state, type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *item = NULL;
|
PyObject *item = NULL;
|
||||||
|
@ -447,7 +512,7 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyObject *only_keys)
|
||||||
|
|
||||||
while ((item = PyIter_Next(iter))) {
|
while ((item = PyIter_Next(iter))) {
|
||||||
// Remove from strong cache
|
// Remove from strong cache
|
||||||
if (eject_from_strong_cache(type, item) < 0) {
|
if (eject_from_strong_cache(state, type, item) < 0) {
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -473,30 +538,68 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyObject *only_keys)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*[clinic input]
|
||||||
|
zoneinfo.ZoneInfo.utcoffset
|
||||||
|
|
||||||
|
cls: defining_class
|
||||||
|
dt: object
|
||||||
|
/
|
||||||
|
|
||||||
|
Retrieve a timedelta representing the UTC offset in a zone at the given datetime.
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_utcoffset(PyObject *self, PyObject *dt)
|
zoneinfo_ZoneInfo_utcoffset_impl(PyObject *self, PyTypeObject *cls,
|
||||||
|
PyObject *dt)
|
||||||
|
/*[clinic end generated code: output=b71016c319ba1f91 input=2bb6c5364938f19c]*/
|
||||||
{
|
{
|
||||||
_ttinfo *tti = find_ttinfo((PyZoneInfo_ZoneInfo *)self, dt);
|
zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
|
||||||
|
_ttinfo *tti = find_ttinfo(state, (PyZoneInfo_ZoneInfo *)self, dt);
|
||||||
if (tti == NULL) {
|
if (tti == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return Py_NewRef(tti->utcoff);
|
return Py_NewRef(tti->utcoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*[clinic input]
|
||||||
|
zoneinfo.ZoneInfo.dst
|
||||||
|
|
||||||
|
cls: defining_class
|
||||||
|
dt: object
|
||||||
|
/
|
||||||
|
|
||||||
|
Retrieve a timedelta representing the amount of DST applied in a zone at the given datetime.
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_dst(PyObject *self, PyObject *dt)
|
zoneinfo_ZoneInfo_dst_impl(PyObject *self, PyTypeObject *cls, PyObject *dt)
|
||||||
|
/*[clinic end generated code: output=cb6168d7723a6ae6 input=2167fb80cf8645c6]*/
|
||||||
{
|
{
|
||||||
_ttinfo *tti = find_ttinfo((PyZoneInfo_ZoneInfo *)self, dt);
|
zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
|
||||||
|
_ttinfo *tti = find_ttinfo(state, (PyZoneInfo_ZoneInfo *)self, dt);
|
||||||
if (tti == NULL) {
|
if (tti == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return Py_NewRef(tti->dstoff);
|
return Py_NewRef(tti->dstoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*[clinic input]
|
||||||
|
zoneinfo.ZoneInfo.tzname
|
||||||
|
|
||||||
|
cls: defining_class
|
||||||
|
dt: object
|
||||||
|
/
|
||||||
|
|
||||||
|
Retrieve a string containing the abbreviation for the time zone that applies in a zone at a given datetime.
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_tzname(PyObject *self, PyObject *dt)
|
zoneinfo_ZoneInfo_tzname_impl(PyObject *self, PyTypeObject *cls,
|
||||||
|
PyObject *dt)
|
||||||
|
/*[clinic end generated code: output=3b6ae6c3053ea75a input=15a59a4f92ed1f1f]*/
|
||||||
{
|
{
|
||||||
_ttinfo *tti = find_ttinfo((PyZoneInfo_ZoneInfo *)self, dt);
|
zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
|
||||||
|
_ttinfo *tti = find_ttinfo(state, (PyZoneInfo_ZoneInfo *)self, dt);
|
||||||
if (tti == NULL) {
|
if (tti == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -693,28 +796,37 @@ zoneinfo_reduce(PyObject *obj_self, PyObject *unused)
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
/*[clinic input]
|
||||||
zoneinfo__unpickle(PyTypeObject *cls, PyObject *args)
|
@classmethod
|
||||||
{
|
zoneinfo.ZoneInfo._unpickle
|
||||||
PyObject *key;
|
|
||||||
unsigned char from_cache;
|
|
||||||
if (!PyArg_ParseTuple(args, "OB", &key, &from_cache)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
cls: defining_class
|
||||||
|
key: object
|
||||||
|
from_cache: unsigned_char(bitwise=True)
|
||||||
|
/
|
||||||
|
|
||||||
|
Private method used in unpickling.
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo__unpickle_impl(PyTypeObject *type, PyTypeObject *cls,
|
||||||
|
PyObject *key, unsigned char from_cache)
|
||||||
|
/*[clinic end generated code: output=556712fc709deecb input=6ac8c73eed3de316]*/
|
||||||
|
{
|
||||||
if (from_cache) {
|
if (from_cache) {
|
||||||
PyObject *val_args = Py_BuildValue("(O)", key);
|
PyObject *val_args = Py_BuildValue("(O)", key);
|
||||||
if (val_args == NULL) {
|
if (val_args == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *rv = zoneinfo_new(cls, val_args, NULL);
|
PyObject *rv = zoneinfo_new(type, val_args, NULL);
|
||||||
|
|
||||||
Py_DECREF(val_args);
|
Py_DECREF(val_args);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return zoneinfo_new_instance(cls, key);
|
zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
|
||||||
|
return zoneinfo_new_instance(state, type, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,14 +844,14 @@ zoneinfo__unpickle(PyTypeObject *cls, PyObject *args)
|
||||||
* This returns a new reference to the timedelta.
|
* This returns a new reference to the timedelta.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
load_timedelta(long seconds)
|
load_timedelta(zoneinfo_state *state, long seconds)
|
||||||
{
|
{
|
||||||
PyObject *rv;
|
PyObject *rv;
|
||||||
PyObject *pyoffset = PyLong_FromLong(seconds);
|
PyObject *pyoffset = PyLong_FromLong(seconds);
|
||||||
if (pyoffset == NULL) {
|
if (pyoffset == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
rv = PyDict_GetItemWithError(TIMEDELTA_CACHE, pyoffset);
|
rv = PyDict_GetItemWithError(state->TIMEDELTA_CACHE, pyoffset);
|
||||||
if (rv == NULL) {
|
if (rv == NULL) {
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -751,7 +863,7 @@ load_timedelta(long seconds)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = PyDict_SetDefault(TIMEDELTA_CACHE, pyoffset, tmp);
|
rv = PyDict_SetDefault(state->TIMEDELTA_CACHE, pyoffset, tmp);
|
||||||
Py_DECREF(tmp);
|
Py_DECREF(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,19 +880,20 @@ error:
|
||||||
* initialized _ttinfo objects.
|
* initialized _ttinfo objects.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
build_ttinfo(long utcoffset, long dstoffset, PyObject *tzname, _ttinfo *out)
|
build_ttinfo(zoneinfo_state *state, long utcoffset, long dstoffset,
|
||||||
|
PyObject *tzname, _ttinfo *out)
|
||||||
{
|
{
|
||||||
out->utcoff = NULL;
|
out->utcoff = NULL;
|
||||||
out->dstoff = NULL;
|
out->dstoff = NULL;
|
||||||
out->tzname = NULL;
|
out->tzname = NULL;
|
||||||
|
|
||||||
out->utcoff_seconds = utcoffset;
|
out->utcoff_seconds = utcoffset;
|
||||||
out->utcoff = load_timedelta(utcoffset);
|
out->utcoff = load_timedelta(state, utcoffset);
|
||||||
if (out->utcoff == NULL) {
|
if (out->utcoff == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out->dstoff = load_timedelta(dstoffset);
|
out->dstoff = load_timedelta(state, dstoffset);
|
||||||
if (out->dstoff == NULL) {
|
if (out->dstoff == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -836,7 +949,7 @@ end:
|
||||||
* the object only needs to be freed / deallocated if this succeeds.
|
* the object only needs to be freed / deallocated if this succeeds.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
|
load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
|
||||||
{
|
{
|
||||||
PyObject *data_tuple = NULL;
|
PyObject *data_tuple = NULL;
|
||||||
|
|
||||||
|
@ -854,7 +967,8 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
|
||||||
|
|
||||||
size_t ttinfos_allocated = 0;
|
size_t ttinfos_allocated = 0;
|
||||||
|
|
||||||
data_tuple = PyObject_CallMethod(_common_mod, "load_data", "O", file_obj);
|
data_tuple = PyObject_CallMethod(state->_common_mod, "load_data", "O",
|
||||||
|
file_obj);
|
||||||
|
|
||||||
if (data_tuple == NULL) {
|
if (data_tuple == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1012,7 +1126,9 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
ttinfos_allocated++;
|
ttinfos_allocated++;
|
||||||
if (build_ttinfo(utcoff[i], dstoff[i], tzname, &(self->_ttinfos[i]))) {
|
int rc = build_ttinfo(state, utcoff[i], dstoff[i], tzname,
|
||||||
|
&(self->_ttinfos[i]));
|
||||||
|
if (rc) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1044,7 +1160,7 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tz_str != Py_None && PyObject_IsTrue(tz_str)) {
|
if (tz_str != Py_None && PyObject_IsTrue(tz_str)) {
|
||||||
if (parse_tz_str(tz_str, &(self->tzrule_after))) {
|
if (parse_tz_str(state, tz_str, &(self->tzrule_after))) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,8 +1179,8 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ttinfo *tti = &(self->_ttinfos[idx]);
|
_ttinfo *tti = &(self->_ttinfos[idx]);
|
||||||
build_tzrule(tti->tzname, NULL, tti->utcoff_seconds, 0, NULL, NULL,
|
build_tzrule(state, tti->tzname, NULL, tti->utcoff_seconds, 0, NULL,
|
||||||
&(self->tzrule_after));
|
NULL, &(self->tzrule_after));
|
||||||
|
|
||||||
// We've abused the build_tzrule constructor to construct an STD-only
|
// We've abused the build_tzrule constructor to construct an STD-only
|
||||||
// rule mimicking whatever ttinfo we've picked up, but it's possible
|
// rule mimicking whatever ttinfo we've picked up, but it's possible
|
||||||
|
@ -1463,7 +1579,7 @@ find_tzrule_ttinfo_fromutc(_tzrule *rule, int64_t ts, int year,
|
||||||
* https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
|
* https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
parse_tz_str(PyObject *tz_str_obj, _tzrule *out)
|
parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out)
|
||||||
{
|
{
|
||||||
PyObject *std_abbr = NULL;
|
PyObject *std_abbr = NULL;
|
||||||
PyObject *dst_abbr = NULL;
|
PyObject *dst_abbr = NULL;
|
||||||
|
@ -1555,7 +1671,8 @@ parse_tz_str(PyObject *tz_str_obj, _tzrule *out)
|
||||||
}
|
}
|
||||||
|
|
||||||
complete:
|
complete:
|
||||||
build_tzrule(std_abbr, dst_abbr, std_offset, dst_offset, start, end, out);
|
build_tzrule(state, std_abbr, dst_abbr, std_offset, dst_offset,
|
||||||
|
start, end, out);
|
||||||
Py_DECREF(std_abbr);
|
Py_DECREF(std_abbr);
|
||||||
Py_XDECREF(dst_abbr);
|
Py_XDECREF(dst_abbr);
|
||||||
|
|
||||||
|
@ -1913,8 +2030,8 @@ parse_transition_time(const char *const p, int8_t *hour, int8_t *minute,
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
build_tzrule(PyObject *std_abbr, PyObject *dst_abbr, long std_offset,
|
build_tzrule(zoneinfo_state *state, PyObject *std_abbr, PyObject *dst_abbr,
|
||||||
long dst_offset, TransitionRuleType *start,
|
long std_offset, long dst_offset, TransitionRuleType *start,
|
||||||
TransitionRuleType *end, _tzrule *out)
|
TransitionRuleType *end, _tzrule *out)
|
||||||
{
|
{
|
||||||
_tzrule rv = {{0}};
|
_tzrule rv = {{0}};
|
||||||
|
@ -1922,13 +2039,13 @@ build_tzrule(PyObject *std_abbr, PyObject *dst_abbr, long std_offset,
|
||||||
rv.start = start;
|
rv.start = start;
|
||||||
rv.end = end;
|
rv.end = end;
|
||||||
|
|
||||||
if (build_ttinfo(std_offset, 0, std_abbr, &rv.std)) {
|
if (build_ttinfo(state, std_offset, 0, std_abbr, &rv.std)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst_abbr != NULL) {
|
if (dst_abbr != NULL) {
|
||||||
rv.dst_diff = dst_offset - std_offset;
|
rv.dst_diff = dst_offset - std_offset;
|
||||||
if (build_ttinfo(dst_offset, rv.dst_diff, dst_abbr, &rv.dst)) {
|
if (build_ttinfo(state, dst_offset, rv.dst_diff, dst_abbr, &rv.dst)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2132,7 +2249,7 @@ _bisect(const int64_t value, const int64_t *arr, size_t size)
|
||||||
|
|
||||||
/* Find the ttinfo rules that apply at a given local datetime. */
|
/* Find the ttinfo rules that apply at a given local datetime. */
|
||||||
static _ttinfo *
|
static _ttinfo *
|
||||||
find_ttinfo(PyZoneInfo_ZoneInfo *self, PyObject *dt)
|
find_ttinfo(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *dt)
|
||||||
{
|
{
|
||||||
// datetime.time has a .tzinfo attribute that passes None as the dt
|
// datetime.time has a .tzinfo attribute that passes None as the dt
|
||||||
// argument; it only really has meaning for fixed-offset zones.
|
// argument; it only really has meaning for fixed-offset zones.
|
||||||
|
@ -2141,7 +2258,7 @@ find_ttinfo(PyZoneInfo_ZoneInfo *self, PyObject *dt)
|
||||||
return &(self->tzrule_after.std);
|
return &(self->tzrule_after.std);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return &NO_TTINFO;
|
return &(state->NO_TTINFO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2317,10 +2434,10 @@ strong_cache_free(StrongCacheNode *root)
|
||||||
* the front of the cache.
|
* the front of the cache.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
remove_from_strong_cache(StrongCacheNode *node)
|
remove_from_strong_cache(zoneinfo_state *state, StrongCacheNode *node)
|
||||||
{
|
{
|
||||||
if (ZONEINFO_STRONG_CACHE == node) {
|
if (state->ZONEINFO_STRONG_CACHE == node) {
|
||||||
ZONEINFO_STRONG_CACHE = node->next;
|
state->ZONEINFO_STRONG_CACHE = node->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->prev != NULL) {
|
if (node->prev != NULL) {
|
||||||
|
@ -2366,15 +2483,17 @@ find_in_strong_cache(const StrongCacheNode *const root, PyObject *const key)
|
||||||
* This function is used to enable the per-key functionality in clear_cache.
|
* This function is used to enable the per-key functionality in clear_cache.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
eject_from_strong_cache(const PyTypeObject *const type, PyObject *key)
|
eject_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
|
||||||
|
PyObject *key)
|
||||||
{
|
{
|
||||||
if (type != &PyZoneInfo_ZoneInfoType) {
|
if (type != state->ZoneInfoType) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
StrongCacheNode *node = find_in_strong_cache(ZONEINFO_STRONG_CACHE, key);
|
StrongCacheNode *cache = state->ZONEINFO_STRONG_CACHE;
|
||||||
|
StrongCacheNode *node = find_in_strong_cache(cache, key);
|
||||||
if (node != NULL) {
|
if (node != NULL) {
|
||||||
remove_from_strong_cache(node);
|
remove_from_strong_cache(state, node);
|
||||||
|
|
||||||
strong_cache_node_free(node);
|
strong_cache_node_free(node);
|
||||||
}
|
}
|
||||||
|
@ -2390,14 +2509,15 @@ eject_from_strong_cache(const PyTypeObject *const type, PyObject *key)
|
||||||
* it is not at the front of the cache, it needs to be moved there.
|
* it is not at the front of the cache, it needs to be moved there.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
move_strong_cache_node_to_front(StrongCacheNode **root, StrongCacheNode *node)
|
move_strong_cache_node_to_front(zoneinfo_state *state, StrongCacheNode **root,
|
||||||
|
StrongCacheNode *node)
|
||||||
{
|
{
|
||||||
StrongCacheNode *root_p = *root;
|
StrongCacheNode *root_p = *root;
|
||||||
if (root_p == node) {
|
if (root_p == node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_from_strong_cache(node);
|
remove_from_strong_cache(state, node);
|
||||||
|
|
||||||
node->prev = NULL;
|
node->prev = NULL;
|
||||||
node->next = root_p;
|
node->next = root_p;
|
||||||
|
@ -2419,16 +2539,19 @@ move_strong_cache_node_to_front(StrongCacheNode **root, StrongCacheNode *node)
|
||||||
* always returns a cache miss for subclasses.
|
* always returns a cache miss for subclasses.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zone_from_strong_cache(const PyTypeObject *const type, PyObject *const key)
|
zone_from_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
|
||||||
|
PyObject *const key)
|
||||||
{
|
{
|
||||||
if (type != &PyZoneInfo_ZoneInfoType) {
|
if (type != state->ZoneInfoType) {
|
||||||
return NULL; // Strong cache currently only implemented for base class
|
return NULL; // Strong cache currently only implemented for base class
|
||||||
}
|
}
|
||||||
|
|
||||||
StrongCacheNode *node = find_in_strong_cache(ZONEINFO_STRONG_CACHE, key);
|
StrongCacheNode *cache = state->ZONEINFO_STRONG_CACHE;
|
||||||
|
StrongCacheNode *node = find_in_strong_cache(cache, key);
|
||||||
|
|
||||||
if (node != NULL) {
|
if (node != NULL) {
|
||||||
move_strong_cache_node_to_front(&ZONEINFO_STRONG_CACHE, node);
|
StrongCacheNode **root = &(state->ZONEINFO_STRONG_CACHE);
|
||||||
|
move_strong_cache_node_to_front(state, root, node);
|
||||||
return Py_NewRef(node->zone);
|
return Py_NewRef(node->zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2442,16 +2565,16 @@ zone_from_strong_cache(const PyTypeObject *const type, PyObject *const key)
|
||||||
* the cache to at most ZONEINFO_STRONG_CACHE_MAX_SIZE).
|
* the cache to at most ZONEINFO_STRONG_CACHE_MAX_SIZE).
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
update_strong_cache(const PyTypeObject *const type, PyObject *key,
|
update_strong_cache(zoneinfo_state *state, const PyTypeObject *const type,
|
||||||
PyObject *zone)
|
PyObject *key, PyObject *zone)
|
||||||
{
|
{
|
||||||
if (type != &PyZoneInfo_ZoneInfoType) {
|
if (type != state->ZoneInfoType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StrongCacheNode *new_node = strong_cache_node_new(key, zone);
|
StrongCacheNode *new_node = strong_cache_node_new(key, zone);
|
||||||
|
StrongCacheNode **root = &(state->ZONEINFO_STRONG_CACHE);
|
||||||
move_strong_cache_node_to_front(&ZONEINFO_STRONG_CACHE, new_node);
|
move_strong_cache_node_to_front(state, root, new_node);
|
||||||
|
|
||||||
StrongCacheNode *node = new_node->next;
|
StrongCacheNode *node = new_node->next;
|
||||||
for (size_t i = 1; i < ZONEINFO_STRONG_CACHE_MAX_SIZE; ++i) {
|
for (size_t i = 1; i < ZONEINFO_STRONG_CACHE_MAX_SIZE; ++i) {
|
||||||
|
@ -2476,14 +2599,14 @@ update_strong_cache(const PyTypeObject *const type, PyObject *key,
|
||||||
* for everything except the base class.
|
* for everything except the base class.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
clear_strong_cache(const PyTypeObject *const type)
|
clear_strong_cache(zoneinfo_state *state, const PyTypeObject *const type)
|
||||||
{
|
{
|
||||||
if (type != &PyZoneInfo_ZoneInfoType) {
|
if (type != state->ZoneInfoType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
strong_cache_free(ZONEINFO_STRONG_CACHE);
|
strong_cache_free(state->ZONEINFO_STRONG_CACHE);
|
||||||
ZONEINFO_STRONG_CACHE = NULL;
|
state->ZONEINFO_STRONG_CACHE = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -2499,29 +2622,17 @@ new_weak_cache(void)
|
||||||
return weak_cache;
|
return weak_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is not idempotent and must be called on a new module object.
|
||||||
static int
|
static int
|
||||||
initialize_caches(void)
|
initialize_caches(zoneinfo_state *state)
|
||||||
{
|
{
|
||||||
// TODO: Move to a PyModule_GetState / PEP 573 based caching system.
|
state->TIMEDELTA_CACHE = PyDict_New();
|
||||||
if (TIMEDELTA_CACHE == NULL) {
|
if (state->TIMEDELTA_CACHE == NULL) {
|
||||||
TIMEDELTA_CACHE = PyDict_New();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Py_INCREF(TIMEDELTA_CACHE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TIMEDELTA_CACHE == NULL) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ZONEINFO_WEAK_CACHE == NULL) {
|
state->ZONEINFO_WEAK_CACHE = new_weak_cache();
|
||||||
ZONEINFO_WEAK_CACHE = new_weak_cache();
|
if (state->ZONEINFO_WEAK_CACHE == NULL) {
|
||||||
}
|
|
||||||
else {
|
|
||||||
Py_INCREF(ZONEINFO_WEAK_CACHE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ZONEINFO_WEAK_CACHE == NULL) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2551,22 +2662,15 @@ static PyMethodDef zoneinfo_methods[] = {
|
||||||
ZONEINFO_ZONEINFO_CLEAR_CACHE_METHODDEF
|
ZONEINFO_ZONEINFO_CLEAR_CACHE_METHODDEF
|
||||||
ZONEINFO_ZONEINFO_NO_CACHE_METHODDEF
|
ZONEINFO_ZONEINFO_NO_CACHE_METHODDEF
|
||||||
ZONEINFO_ZONEINFO_FROM_FILE_METHODDEF
|
ZONEINFO_ZONEINFO_FROM_FILE_METHODDEF
|
||||||
{"utcoffset", (PyCFunction)zoneinfo_utcoffset, METH_O,
|
ZONEINFO_ZONEINFO_UTCOFFSET_METHODDEF
|
||||||
PyDoc_STR("Retrieve a timedelta representing the UTC offset in a zone at "
|
ZONEINFO_ZONEINFO_DST_METHODDEF
|
||||||
"the given datetime.")},
|
ZONEINFO_ZONEINFO_TZNAME_METHODDEF
|
||||||
{"dst", (PyCFunction)zoneinfo_dst, METH_O,
|
|
||||||
PyDoc_STR("Retrieve a timedelta representing the amount of DST applied "
|
|
||||||
"in a zone at the given datetime.")},
|
|
||||||
{"tzname", (PyCFunction)zoneinfo_tzname, METH_O,
|
|
||||||
PyDoc_STR("Retrieve a string containing the abbreviation for the time "
|
|
||||||
"zone that applies in a zone at a given datetime.")},
|
|
||||||
{"fromutc", (PyCFunction)zoneinfo_fromutc, METH_O,
|
{"fromutc", (PyCFunction)zoneinfo_fromutc, METH_O,
|
||||||
PyDoc_STR("Given a datetime with local time in UTC, retrieve an adjusted "
|
PyDoc_STR("Given a datetime with local time in UTC, retrieve an adjusted "
|
||||||
"datetime in local time.")},
|
"datetime in local time.")},
|
||||||
{"__reduce__", (PyCFunction)zoneinfo_reduce, METH_NOARGS,
|
{"__reduce__", (PyCFunction)zoneinfo_reduce, METH_NOARGS,
|
||||||
PyDoc_STR("Function for serialization with the pickle protocol.")},
|
PyDoc_STR("Function for serialization with the pickle protocol.")},
|
||||||
{"_unpickle", (PyCFunction)zoneinfo__unpickle, METH_VARARGS | METH_CLASS,
|
ZONEINFO_ZONEINFO__UNPICKLE_METHODDEF
|
||||||
PyDoc_STR("Private method used in unpickling.")},
|
|
||||||
{"__init_subclass__", (PyCFunction)(void (*)(void))zoneinfo_init_subclass,
|
{"__init_subclass__", (PyCFunction)(void (*)(void))zoneinfo_init_subclass,
|
||||||
METH_VARARGS | METH_KEYWORDS | METH_CLASS,
|
METH_VARARGS | METH_KEYWORDS | METH_CLASS,
|
||||||
PyDoc_STR("Function to initialize subclasses.")},
|
PyDoc_STR("Function to initialize subclasses.")},
|
||||||
|
@ -2579,50 +2683,88 @@ static PyMemberDef zoneinfo_members[] = {
|
||||||
.type = T_OBJECT_EX,
|
.type = T_OBJECT_EX,
|
||||||
.flags = READONLY,
|
.flags = READONLY,
|
||||||
.doc = NULL},
|
.doc = NULL},
|
||||||
|
{.name = "__weaklistoffset__",
|
||||||
|
.offset = offsetof(PyZoneInfo_ZoneInfo, weakreflist),
|
||||||
|
.type = T_PYSSIZET,
|
||||||
|
.flags = READONLY},
|
||||||
{NULL}, /* Sentinel */
|
{NULL}, /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyTypeObject PyZoneInfo_ZoneInfoType = {
|
static PyType_Slot zoneinfo_slots[] = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0) //
|
{Py_tp_repr, zoneinfo_repr},
|
||||||
.tp_name = "zoneinfo.ZoneInfo",
|
{Py_tp_str, zoneinfo_str},
|
||||||
.tp_basicsize = sizeof(PyZoneInfo_ZoneInfo),
|
{Py_tp_getattro, PyObject_GenericGetAttr},
|
||||||
.tp_weaklistoffset = offsetof(PyZoneInfo_ZoneInfo, weakreflist),
|
{Py_tp_methods, zoneinfo_methods},
|
||||||
.tp_repr = (reprfunc)zoneinfo_repr,
|
{Py_tp_members, zoneinfo_members},
|
||||||
.tp_str = (reprfunc)zoneinfo_str,
|
{Py_tp_new, zoneinfo_new},
|
||||||
.tp_getattro = PyObject_GenericGetAttr,
|
{Py_tp_dealloc, zoneinfo_dealloc},
|
||||||
.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE),
|
{Py_tp_traverse, zoneinfo_traverse},
|
||||||
/* .tp_doc = zoneinfo_doc, */
|
{Py_tp_clear, zoneinfo_clear},
|
||||||
.tp_methods = zoneinfo_methods,
|
{0, NULL},
|
||||||
.tp_members = zoneinfo_members,
|
};
|
||||||
.tp_new = zoneinfo_new,
|
|
||||||
.tp_dealloc = zoneinfo_dealloc,
|
static PyType_Spec zoneinfo_spec = {
|
||||||
|
.name = "zoneinfo.ZoneInfo",
|
||||||
|
.basicsize = sizeof(PyZoneInfo_ZoneInfo),
|
||||||
|
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
|
||||||
|
Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
|
||||||
|
.slots = zoneinfo_slots,
|
||||||
};
|
};
|
||||||
|
|
||||||
/////
|
/////
|
||||||
// Specify the _zoneinfo module
|
// Specify the _zoneinfo module
|
||||||
static PyMethodDef module_methods[] = {{NULL, NULL}};
|
static PyMethodDef module_methods[] = {{NULL, NULL}};
|
||||||
static void
|
|
||||||
module_free(void *m)
|
static int
|
||||||
|
module_traverse(PyObject *mod, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
Py_CLEAR(_tzpath_find_tzfile);
|
zoneinfo_state *state = zoneinfo_get_state(mod);
|
||||||
Py_CLEAR(_common_mod);
|
|
||||||
Py_CLEAR(io_open);
|
|
||||||
|
|
||||||
xdecref_ttinfo(&NO_TTINFO);
|
Py_VISIT(state->ZoneInfoType);
|
||||||
|
Py_VISIT(state->io_open);
|
||||||
|
Py_VISIT(state->_tzpath_find_tzfile);
|
||||||
|
Py_VISIT(state->_common_mod);
|
||||||
|
Py_VISIT(state->TIMEDELTA_CACHE);
|
||||||
|
Py_VISIT(state->ZONEINFO_WEAK_CACHE);
|
||||||
|
|
||||||
if (TIMEDELTA_CACHE != NULL && Py_REFCNT(TIMEDELTA_CACHE) > 1) {
|
StrongCacheNode *node = state->ZONEINFO_STRONG_CACHE;
|
||||||
Py_DECREF(TIMEDELTA_CACHE);
|
while (node != NULL) {
|
||||||
} else {
|
StrongCacheNode *next = node->next;
|
||||||
Py_CLEAR(TIMEDELTA_CACHE);
|
Py_VISIT(node->key);
|
||||||
|
Py_VISIT(node->zone);
|
||||||
|
node = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ZONEINFO_WEAK_CACHE != NULL && Py_REFCNT(ZONEINFO_WEAK_CACHE) > 1) {
|
Py_VISIT(state->NO_TTINFO.utcoff);
|
||||||
Py_DECREF(ZONEINFO_WEAK_CACHE);
|
Py_VISIT(state->NO_TTINFO.dstoff);
|
||||||
} else {
|
Py_VISIT(state->NO_TTINFO.tzname);
|
||||||
Py_CLEAR(ZONEINFO_WEAK_CACHE);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_strong_cache(&PyZoneInfo_ZoneInfoType);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
module_clear(PyObject *mod)
|
||||||
|
{
|
||||||
|
zoneinfo_state *state = zoneinfo_get_state(mod);
|
||||||
|
|
||||||
|
Py_CLEAR(state->ZoneInfoType);
|
||||||
|
Py_CLEAR(state->io_open);
|
||||||
|
Py_CLEAR(state->_tzpath_find_tzfile);
|
||||||
|
Py_CLEAR(state->_common_mod);
|
||||||
|
Py_CLEAR(state->TIMEDELTA_CACHE);
|
||||||
|
Py_CLEAR(state->ZONEINFO_WEAK_CACHE);
|
||||||
|
clear_strong_cache(state, state->ZoneInfoType);
|
||||||
|
Py_CLEAR(state->NO_TTINFO.utcoff);
|
||||||
|
Py_CLEAR(state->NO_TTINFO.dstoff);
|
||||||
|
Py_CLEAR(state->NO_TTINFO.tzname);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
module_free(void *mod)
|
||||||
|
{
|
||||||
|
(void)module_clear((PyObject *)mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -2632,39 +2774,45 @@ zoneinfomodule_exec(PyObject *m)
|
||||||
if (PyDateTimeAPI == NULL) {
|
if (PyDateTimeAPI == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
PyZoneInfo_ZoneInfoType.tp_base = PyDateTimeAPI->TZInfoType;
|
|
||||||
if (PyType_Ready(&PyZoneInfo_ZoneInfoType) < 0) {
|
zoneinfo_state *state = zoneinfo_get_state(m);
|
||||||
|
PyObject *base = (PyObject *)PyDateTimeAPI->TZInfoType;
|
||||||
|
state->ZoneInfoType = (PyTypeObject *)PyType_FromModuleAndSpec(m,
|
||||||
|
&zoneinfo_spec, base);
|
||||||
|
if (state->ZoneInfoType == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyModule_AddObjectRef(m, "ZoneInfo", (PyObject *)&PyZoneInfo_ZoneInfoType) < 0) {
|
int rc = PyModule_AddObjectRef(m, "ZoneInfo",
|
||||||
|
(PyObject *)state->ZoneInfoType);
|
||||||
|
if (rc < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Populate imports */
|
/* Populate imports */
|
||||||
_tzpath_find_tzfile =
|
state->_tzpath_find_tzfile =
|
||||||
_PyImport_GetModuleAttrString("zoneinfo._tzpath", "find_tzfile");
|
_PyImport_GetModuleAttrString("zoneinfo._tzpath", "find_tzfile");
|
||||||
if (_tzpath_find_tzfile == NULL) {
|
if (state->_tzpath_find_tzfile == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
io_open = _PyImport_GetModuleAttrString("io", "open");
|
state->io_open = _PyImport_GetModuleAttrString("io", "open");
|
||||||
if (io_open == NULL) {
|
if (state->io_open == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
_common_mod = PyImport_ImportModule("zoneinfo._common");
|
state->_common_mod = PyImport_ImportModule("zoneinfo._common");
|
||||||
if (_common_mod == NULL) {
|
if (state->_common_mod == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NO_TTINFO.utcoff == NULL) {
|
if (state->NO_TTINFO.utcoff == NULL) {
|
||||||
NO_TTINFO.utcoff = Py_NewRef(Py_None);
|
state->NO_TTINFO.utcoff = Py_NewRef(Py_None);
|
||||||
NO_TTINFO.dstoff = Py_NewRef(Py_None);
|
state->NO_TTINFO.dstoff = Py_NewRef(Py_None);
|
||||||
NO_TTINFO.tzname = Py_NewRef(Py_None);
|
state->NO_TTINFO.tzname = Py_NewRef(Py_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initialize_caches()) {
|
if (initialize_caches(state)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2678,13 +2826,16 @@ static PyModuleDef_Slot zoneinfomodule_slots[] = {
|
||||||
{Py_mod_exec, zoneinfomodule_exec}, {0, NULL}};
|
{Py_mod_exec, zoneinfomodule_exec}, {0, NULL}};
|
||||||
|
|
||||||
static struct PyModuleDef zoneinfomodule = {
|
static struct PyModuleDef zoneinfomodule = {
|
||||||
PyModuleDef_HEAD_INIT,
|
.m_base = PyModuleDef_HEAD_INIT,
|
||||||
.m_name = "_zoneinfo",
|
.m_name = "_zoneinfo",
|
||||||
.m_doc = "C implementation of the zoneinfo module",
|
.m_doc = "C implementation of the zoneinfo module",
|
||||||
.m_size = 0,
|
.m_size = sizeof(zoneinfo_state),
|
||||||
.m_methods = module_methods,
|
.m_methods = module_methods,
|
||||||
.m_slots = zoneinfomodule_slots,
|
.m_slots = zoneinfomodule_slots,
|
||||||
.m_free = (freefunc)module_free};
|
.m_traverse = module_traverse,
|
||||||
|
.m_clear = module_clear,
|
||||||
|
.m_free = module_free,
|
||||||
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
PyInit__zoneinfo(void)
|
PyInit__zoneinfo(void)
|
||||||
|
|
|
@ -15,14 +15,14 @@ PyDoc_STRVAR(zoneinfo_ZoneInfo_from_file__doc__,
|
||||||
"Create a ZoneInfo file from a file object.");
|
"Create a ZoneInfo file from a file object.");
|
||||||
|
|
||||||
#define ZONEINFO_ZONEINFO_FROM_FILE_METHODDEF \
|
#define ZONEINFO_ZONEINFO_FROM_FILE_METHODDEF \
|
||||||
{"from_file", _PyCFunction_CAST(zoneinfo_ZoneInfo_from_file), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_from_file__doc__},
|
{"from_file", _PyCFunction_CAST(zoneinfo_ZoneInfo_from_file), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_from_file__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_from_file_impl(PyTypeObject *type, PyObject *file_obj,
|
zoneinfo_ZoneInfo_from_file_impl(PyTypeObject *type, PyTypeObject *cls,
|
||||||
PyObject *key);
|
PyObject *file_obj, PyObject *key);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_from_file(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
zoneinfo_ZoneInfo_from_file(PyTypeObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
||||||
|
@ -65,7 +65,7 @@ zoneinfo_ZoneInfo_from_file(PyTypeObject *type, PyObject *const *args, Py_ssize_
|
||||||
}
|
}
|
||||||
key = args[1];
|
key = args[1];
|
||||||
skip_optional_pos:
|
skip_optional_pos:
|
||||||
return_value = zoneinfo_ZoneInfo_from_file_impl(type, file_obj, key);
|
return_value = zoneinfo_ZoneInfo_from_file_impl(type, cls, file_obj, key);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -78,13 +78,14 @@ PyDoc_STRVAR(zoneinfo_ZoneInfo_no_cache__doc__,
|
||||||
"Get a new instance of ZoneInfo, bypassing the cache.");
|
"Get a new instance of ZoneInfo, bypassing the cache.");
|
||||||
|
|
||||||
#define ZONEINFO_ZONEINFO_NO_CACHE_METHODDEF \
|
#define ZONEINFO_ZONEINFO_NO_CACHE_METHODDEF \
|
||||||
{"no_cache", _PyCFunction_CAST(zoneinfo_ZoneInfo_no_cache), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_no_cache__doc__},
|
{"no_cache", _PyCFunction_CAST(zoneinfo_ZoneInfo_no_cache), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_no_cache__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyObject *key);
|
zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, PyTypeObject *cls,
|
||||||
|
PyObject *key);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_no_cache(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
zoneinfo_ZoneInfo_no_cache(PyTypeObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
||||||
|
@ -120,7 +121,7 @@ zoneinfo_ZoneInfo_no_cache(PyTypeObject *type, PyObject *const *args, Py_ssize_t
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
key = args[0];
|
key = args[0];
|
||||||
return_value = zoneinfo_ZoneInfo_no_cache_impl(type, key);
|
return_value = zoneinfo_ZoneInfo_no_cache_impl(type, cls, key);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -133,13 +134,14 @@ PyDoc_STRVAR(zoneinfo_ZoneInfo_clear_cache__doc__,
|
||||||
"Clear the ZoneInfo cache.");
|
"Clear the ZoneInfo cache.");
|
||||||
|
|
||||||
#define ZONEINFO_ZONEINFO_CLEAR_CACHE_METHODDEF \
|
#define ZONEINFO_ZONEINFO_CLEAR_CACHE_METHODDEF \
|
||||||
{"clear_cache", _PyCFunction_CAST(zoneinfo_ZoneInfo_clear_cache), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_clear_cache__doc__},
|
{"clear_cache", _PyCFunction_CAST(zoneinfo_ZoneInfo_clear_cache), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo_clear_cache__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyObject *only_keys);
|
zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls,
|
||||||
|
PyObject *only_keys);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
zoneinfo_ZoneInfo_clear_cache(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
zoneinfo_ZoneInfo_clear_cache(PyTypeObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
||||||
|
@ -180,9 +182,194 @@ zoneinfo_ZoneInfo_clear_cache(PyTypeObject *type, PyObject *const *args, Py_ssiz
|
||||||
}
|
}
|
||||||
only_keys = args[0];
|
only_keys = args[0];
|
||||||
skip_optional_kwonly:
|
skip_optional_kwonly:
|
||||||
return_value = zoneinfo_ZoneInfo_clear_cache_impl(type, only_keys);
|
return_value = zoneinfo_ZoneInfo_clear_cache_impl(type, cls, only_keys);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=d2da73ef66146b83 input=a9049054013a1b77]*/
|
|
||||||
|
PyDoc_STRVAR(zoneinfo_ZoneInfo_utcoffset__doc__,
|
||||||
|
"utcoffset($self, dt, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Retrieve a timedelta representing the UTC offset in a zone at the given datetime.");
|
||||||
|
|
||||||
|
#define ZONEINFO_ZONEINFO_UTCOFFSET_METHODDEF \
|
||||||
|
{"utcoffset", _PyCFunction_CAST(zoneinfo_ZoneInfo_utcoffset), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, zoneinfo_ZoneInfo_utcoffset__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo_utcoffset_impl(PyObject *self, PyTypeObject *cls,
|
||||||
|
PyObject *dt);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo_utcoffset(PyObject *self, PyTypeObject *cls, 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 = zoneinfo_ZoneInfo_utcoffset_impl(self, cls, dt);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(zoneinfo_ZoneInfo_dst__doc__,
|
||||||
|
"dst($self, dt, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Retrieve a timedelta representing the amount of DST applied in a zone at the given datetime.");
|
||||||
|
|
||||||
|
#define ZONEINFO_ZONEINFO_DST_METHODDEF \
|
||||||
|
{"dst", _PyCFunction_CAST(zoneinfo_ZoneInfo_dst), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, zoneinfo_ZoneInfo_dst__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo_dst_impl(PyObject *self, PyTypeObject *cls, PyObject *dt);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo_dst(PyObject *self, PyTypeObject *cls, 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 = zoneinfo_ZoneInfo_dst_impl(self, cls, dt);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(zoneinfo_ZoneInfo_tzname__doc__,
|
||||||
|
"tzname($self, dt, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Retrieve a string containing the abbreviation for the time zone that applies in a zone at a given datetime.");
|
||||||
|
|
||||||
|
#define ZONEINFO_ZONEINFO_TZNAME_METHODDEF \
|
||||||
|
{"tzname", _PyCFunction_CAST(zoneinfo_ZoneInfo_tzname), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, zoneinfo_ZoneInfo_tzname__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo_tzname_impl(PyObject *self, PyTypeObject *cls,
|
||||||
|
PyObject *dt);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo_tzname(PyObject *self, PyTypeObject *cls, 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 = zoneinfo_ZoneInfo_tzname_impl(self, cls, dt);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(zoneinfo_ZoneInfo__unpickle__doc__,
|
||||||
|
"_unpickle($type, key, from_cache, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Private method used in unpickling.");
|
||||||
|
|
||||||
|
#define ZONEINFO_ZONEINFO__UNPICKLE_METHODDEF \
|
||||||
|
{"_unpickle", _PyCFunction_CAST(zoneinfo_ZoneInfo__unpickle), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo__unpickle__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo__unpickle_impl(PyTypeObject *type, PyTypeObject *cls,
|
||||||
|
PyObject *key, unsigned char from_cache);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
zoneinfo_ZoneInfo__unpickle(PyTypeObject *type, PyTypeObject *cls, 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 = "_unpickle",
|
||||||
|
.kwtuple = KWTUPLE,
|
||||||
|
};
|
||||||
|
#undef KWTUPLE
|
||||||
|
PyObject *argsbuf[2];
|
||||||
|
PyObject *key;
|
||||||
|
unsigned char from_cache;
|
||||||
|
|
||||||
|
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
|
||||||
|
if (!args) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
key = args[0];
|
||||||
|
{
|
||||||
|
unsigned long ival = PyLong_AsUnsignedLongMask(args[1]);
|
||||||
|
if (ival == (unsigned long)-1 && PyErr_Occurred()) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
from_cache = (unsigned char) ival;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return_value = zoneinfo_ZoneInfo__unpickle_impl(type, cls, key, from_cache);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
/*[clinic end generated code: output=54051388dfc408af input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -403,7 +403,6 @@ Modules/_pickle.c - PicklerMemoProxyType -
|
||||||
Modules/_pickle.c - Pickler_Type -
|
Modules/_pickle.c - Pickler_Type -
|
||||||
Modules/_pickle.c - UnpicklerMemoProxyType -
|
Modules/_pickle.c - UnpicklerMemoProxyType -
|
||||||
Modules/_pickle.c - Unpickler_Type -
|
Modules/_pickle.c - Unpickler_Type -
|
||||||
Modules/_zoneinfo.c - PyZoneInfo_ZoneInfoType -
|
|
||||||
Modules/ossaudiodev.c - OSSAudioType -
|
Modules/ossaudiodev.c - OSSAudioType -
|
||||||
Modules/ossaudiodev.c - OSSMixerType -
|
Modules/ossaudiodev.c - OSSMixerType -
|
||||||
Modules/socketmodule.c - sock_type -
|
Modules/socketmodule.c - sock_type -
|
||||||
|
@ -442,11 +441,6 @@ Modules/xxmodule.c - ErrorObject -
|
||||||
Modules/_ctypes/callproc.c _ctypes_get_errobj error_object_name -
|
Modules/_ctypes/callproc.c _ctypes_get_errobj error_object_name -
|
||||||
Modules/_ctypes/_ctypes.c CreateSwappedType suffix -
|
Modules/_ctypes/_ctypes.c CreateSwappedType suffix -
|
||||||
|
|
||||||
## other - during module init
|
|
||||||
Modules/_zoneinfo.c - io_open -
|
|
||||||
Modules/_zoneinfo.c - _tzpath_find_tzfile -
|
|
||||||
Modules/_zoneinfo.c - _common_mod -
|
|
||||||
|
|
||||||
##-----------------------
|
##-----------------------
|
||||||
## other
|
## other
|
||||||
|
|
||||||
|
@ -481,8 +475,6 @@ Modules/_tkinter.c - tcl_lock -
|
||||||
Modules/_tkinter.c - excInCmd -
|
Modules/_tkinter.c - excInCmd -
|
||||||
Modules/_tkinter.c - valInCmd -
|
Modules/_tkinter.c - valInCmd -
|
||||||
Modules/_tkinter.c - trbInCmd -
|
Modules/_tkinter.c - trbInCmd -
|
||||||
Modules/_zoneinfo.c - TIMEDELTA_CACHE -
|
|
||||||
Modules/_zoneinfo.c - ZONEINFO_WEAK_CACHE -
|
|
||||||
|
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
@ -556,9 +548,6 @@ Modules/_tkinter.c - HeadFHCD -
|
||||||
Modules/_tkinter.c - stdin_ready -
|
Modules/_tkinter.c - stdin_ready -
|
||||||
Modules/_tkinter.c - event_tstate -
|
Modules/_tkinter.c - event_tstate -
|
||||||
Modules/_xxsubinterpretersmodule.c - _globals -
|
Modules/_xxsubinterpretersmodule.c - _globals -
|
||||||
Modules/_zoneinfo.c - ZONEINFO_STRONG_CACHE -
|
|
||||||
Modules/_zoneinfo.c - ZONEINFO_STRONG_CACHE_MAX_SIZE -
|
|
||||||
Modules/_zoneinfo.c - NO_TTINFO -
|
|
||||||
Modules/readline.c - completer_word_break_characters -
|
Modules/readline.c - completer_word_break_characters -
|
||||||
Modules/readline.c - _history_length -
|
Modules/readline.c - _history_length -
|
||||||
Modules/readline.c - should_auto_add_history -
|
Modules/readline.c - should_auto_add_history -
|
||||||
|
|
Can't render this file because it has a wrong number of fields in line 4.
|
Loading…
Reference in New Issue