1 #include "parts.h"
2
3 #include "datetime.h" // PyDateTimeAPI
4
5
6 static int test_run_counter = 0;
7
8 static PyObject *
test_datetime_capi(PyObject * self,PyObject * args)9 test_datetime_capi(PyObject *self, PyObject *args)
10 {
11 if (PyDateTimeAPI) {
12 if (test_run_counter) {
13 /* Probably regrtest.py -R */
14 Py_RETURN_NONE;
15 }
16 else {
17 PyErr_SetString(PyExc_AssertionError,
18 "PyDateTime_CAPI somehow initialized");
19 return NULL;
20 }
21 }
22 test_run_counter++;
23 PyDateTime_IMPORT;
24
25 if (PyDateTimeAPI == NULL) {
26 return NULL;
27 }
28 // The following C API types need to outlive interpreters, since the
29 // borrowed references to them can be held by users without being updated.
30 assert(!PyType_HasFeature(PyDateTimeAPI->DateType, Py_TPFLAGS_HEAPTYPE));
31 assert(!PyType_HasFeature(PyDateTimeAPI->TimeType, Py_TPFLAGS_HEAPTYPE));
32 assert(!PyType_HasFeature(PyDateTimeAPI->DateTimeType, Py_TPFLAGS_HEAPTYPE));
33 assert(!PyType_HasFeature(PyDateTimeAPI->DeltaType, Py_TPFLAGS_HEAPTYPE));
34 assert(!PyType_HasFeature(PyDateTimeAPI->TZInfoType, Py_TPFLAGS_HEAPTYPE));
35 Py_RETURN_NONE;
36 }
37
38 /* Functions exposing the C API type checking for testing */
39 #define MAKE_DATETIME_CHECK_FUNC(check_method, exact_method) \
40 do { \
41 PyObject *obj; \
42 int exact = 0; \
43 if (!PyArg_ParseTuple(args, "O|p", &obj, &exact)) { \
44 return NULL; \
45 } \
46 int rv = exact?exact_method(obj):check_method(obj); \
47 if (rv) { \
48 Py_RETURN_TRUE; \
49 } \
50 Py_RETURN_FALSE; \
51 } while (0) \
52
53 static PyObject *
datetime_check_date(PyObject * self,PyObject * args)54 datetime_check_date(PyObject *self, PyObject *args)
55 {
56 MAKE_DATETIME_CHECK_FUNC(PyDate_Check, PyDate_CheckExact);
57 }
58
59 static PyObject *
datetime_check_time(PyObject * self,PyObject * args)60 datetime_check_time(PyObject *self, PyObject *args)
61 {
62 MAKE_DATETIME_CHECK_FUNC(PyTime_Check, PyTime_CheckExact);
63 }
64
65 static PyObject *
datetime_check_datetime(PyObject * self,PyObject * args)66 datetime_check_datetime(PyObject *self, PyObject *args)
67 {
68 MAKE_DATETIME_CHECK_FUNC(PyDateTime_Check, PyDateTime_CheckExact);
69 }
70
71 static PyObject *
datetime_check_delta(PyObject * self,PyObject * args)72 datetime_check_delta(PyObject *self, PyObject *args)
73 {
74 MAKE_DATETIME_CHECK_FUNC(PyDelta_Check, PyDelta_CheckExact);
75 }
76
77 static PyObject *
datetime_check_tzinfo(PyObject * self,PyObject * args)78 datetime_check_tzinfo(PyObject *self, PyObject *args)
79 {
80 MAKE_DATETIME_CHECK_FUNC(PyTZInfo_Check, PyTZInfo_CheckExact);
81 }
82 #undef MAKE_DATETIME_CHECK_FUNC
83
84
85 /* Makes three variations on timezone representing UTC-5:
86 1. timezone with offset and name from PyDateTimeAPI
87 2. timezone with offset and name from PyTimeZone_FromOffsetAndName
88 3. timezone with offset (no name) from PyTimeZone_FromOffset
89 */
90 static PyObject *
make_timezones_capi(PyObject * self,PyObject * args)91 make_timezones_capi(PyObject *self, PyObject *args)
92 {
93 PyObject *offset = PyDelta_FromDSU(0, -18000, 0);
94 PyObject *name = PyUnicode_FromString("EST");
95 if (offset == NULL || name == NULL) {
96 Py_XDECREF(offset);
97 Py_XDECREF(name);
98 return NULL;
99 }
100
101 PyObject *est_zone_capi = PyDateTimeAPI->TimeZone_FromTimeZone(offset, name);
102 PyObject *est_zone_macro = PyTimeZone_FromOffsetAndName(offset, name);
103 PyObject *est_zone_macro_noname = PyTimeZone_FromOffset(offset);
104 Py_DECREF(offset);
105 Py_DECREF(name);
106 if (est_zone_capi == NULL || est_zone_macro == NULL ||
107 est_zone_macro_noname == NULL)
108 {
109 goto error;
110 }
111 PyObject *rv = PyTuple_New(3);
112 if (rv == NULL) {
113 goto error;
114 }
115
116 PyTuple_SET_ITEM(rv, 0, est_zone_capi);
117 PyTuple_SET_ITEM(rv, 1, est_zone_macro);
118 PyTuple_SET_ITEM(rv, 2, est_zone_macro_noname);
119
120 return rv;
121 error:
122 Py_XDECREF(est_zone_capi);
123 Py_XDECREF(est_zone_macro);
124 Py_XDECREF(est_zone_macro_noname);
125 return NULL;
126 }
127
128 static PyObject *
get_timezones_offset_zero(PyObject * self,PyObject * args)129 get_timezones_offset_zero(PyObject *self, PyObject *args)
130 {
131 PyObject *offset = PyDelta_FromDSU(0, 0, 0);
132 PyObject *name = PyUnicode_FromString("");
133 if (offset == NULL || name == NULL) {
134 Py_XDECREF(offset);
135 Py_XDECREF(name);
136 return NULL;
137 }
138
139 // These two should return the UTC singleton
140 PyObject *utc_singleton_0 = PyTimeZone_FromOffset(offset);
141 PyObject *utc_singleton_1 = PyTimeZone_FromOffsetAndName(offset, NULL);
142
143 // This one will return +00:00 zone, but not the UTC singleton
144 PyObject *non_utc_zone = PyTimeZone_FromOffsetAndName(offset, name);
145 Py_DECREF(offset);
146 Py_DECREF(name);
147 if (utc_singleton_0 == NULL || utc_singleton_1 == NULL ||
148 non_utc_zone == NULL)
149 {
150 goto error;
151 }
152
153 PyObject *rv = PyTuple_New(3);
154 if (rv == NULL) {
155 goto error;
156 }
157 PyTuple_SET_ITEM(rv, 0, utc_singleton_0);
158 PyTuple_SET_ITEM(rv, 1, utc_singleton_1);
159 PyTuple_SET_ITEM(rv, 2, non_utc_zone);
160
161 return rv;
162 error:
163 Py_XDECREF(utc_singleton_0);
164 Py_XDECREF(utc_singleton_1);
165 Py_XDECREF(non_utc_zone);
166 return NULL;
167 }
168
169 static PyObject *
get_timezone_utc_capi(PyObject * self,PyObject * args)170 get_timezone_utc_capi(PyObject *self, PyObject *args)
171 {
172 int macro = 0;
173 if (!PyArg_ParseTuple(args, "|p", ¯o)) {
174 return NULL;
175 }
176 if (macro) {
177 return Py_NewRef(PyDateTime_TimeZone_UTC);
178 }
179 return Py_NewRef(PyDateTimeAPI->TimeZone_UTC);
180 }
181
182 static PyObject *
get_date_fromdate(PyObject * self,PyObject * args)183 get_date_fromdate(PyObject *self, PyObject *args)
184 {
185 PyObject *rv = NULL;
186 int macro;
187 int year, month, day;
188
189 if (!PyArg_ParseTuple(args, "piii", ¯o, &year, &month, &day)) {
190 return NULL;
191 }
192
193 if (macro) {
194 rv = PyDate_FromDate(year, month, day);
195 }
196 else {
197 rv = PyDateTimeAPI->Date_FromDate(
198 year, month, day,
199 PyDateTimeAPI->DateType);
200 }
201 return rv;
202 }
203
204 static PyObject *
get_datetime_fromdateandtime(PyObject * self,PyObject * args)205 get_datetime_fromdateandtime(PyObject *self, PyObject *args)
206 {
207 PyObject *rv = NULL;
208 int macro;
209 int year, month, day;
210 int hour, minute, second, microsecond;
211
212 if (!PyArg_ParseTuple(args, "piiiiiii",
213 ¯o,
214 &year, &month, &day,
215 &hour, &minute, &second, µsecond)) {
216 return NULL;
217 }
218
219 if (macro) {
220 rv = PyDateTime_FromDateAndTime(
221 year, month, day,
222 hour, minute, second, microsecond);
223 }
224 else {
225 rv = PyDateTimeAPI->DateTime_FromDateAndTime(
226 year, month, day,
227 hour, minute, second, microsecond,
228 Py_None,
229 PyDateTimeAPI->DateTimeType);
230 }
231 return rv;
232 }
233
234 static PyObject *
get_datetime_fromdateandtimeandfold(PyObject * self,PyObject * args)235 get_datetime_fromdateandtimeandfold(PyObject *self, PyObject *args)
236 {
237 PyObject *rv = NULL;
238 int macro;
239 int year, month, day;
240 int hour, minute, second, microsecond, fold;
241
242 if (!PyArg_ParseTuple(args, "piiiiiiii",
243 ¯o,
244 &year, &month, &day,
245 &hour, &minute, &second, µsecond,
246 &fold)) {
247 return NULL;
248 }
249
250 if (macro) {
251 rv = PyDateTime_FromDateAndTimeAndFold(
252 year, month, day,
253 hour, minute, second, microsecond,
254 fold);
255 }
256 else {
257 rv = PyDateTimeAPI->DateTime_FromDateAndTimeAndFold(
258 year, month, day,
259 hour, minute, second, microsecond,
260 Py_None,
261 fold,
262 PyDateTimeAPI->DateTimeType);
263 }
264 return rv;
265 }
266
267 static PyObject *
get_time_fromtime(PyObject * self,PyObject * args)268 get_time_fromtime(PyObject *self, PyObject *args)
269 {
270 PyObject *rv = NULL;
271 int macro;
272 int hour, minute, second, microsecond;
273
274 if (!PyArg_ParseTuple(args, "piiii",
275 ¯o,
276 &hour, &minute, &second, µsecond))
277 {
278 return NULL;
279 }
280
281 if (macro) {
282 rv = PyTime_FromTime(hour, minute, second, microsecond);
283 }
284 else {
285 rv = PyDateTimeAPI->Time_FromTime(
286 hour, minute, second, microsecond,
287 Py_None,
288 PyDateTimeAPI->TimeType);
289 }
290 return rv;
291 }
292
293 static PyObject *
get_time_fromtimeandfold(PyObject * self,PyObject * args)294 get_time_fromtimeandfold(PyObject *self, PyObject *args)
295 {
296 PyObject *rv = NULL;
297 int macro;
298 int hour, minute, second, microsecond, fold;
299
300 if (!PyArg_ParseTuple(args, "piiiii",
301 ¯o,
302 &hour, &minute, &second, µsecond,
303 &fold)) {
304 return NULL;
305 }
306
307 if (macro) {
308 rv = PyTime_FromTimeAndFold(hour, minute, second, microsecond, fold);
309 }
310 else {
311 rv = PyDateTimeAPI->Time_FromTimeAndFold(
312 hour, minute, second, microsecond,
313 Py_None,
314 fold,
315 PyDateTimeAPI->TimeType);
316 }
317 return rv;
318 }
319
320 static PyObject *
get_delta_fromdsu(PyObject * self,PyObject * args)321 get_delta_fromdsu(PyObject *self, PyObject *args)
322 {
323 PyObject *rv = NULL;
324 int macro;
325 int days, seconds, microseconds;
326
327 if (!PyArg_ParseTuple(args, "piii",
328 ¯o,
329 &days, &seconds, µseconds)) {
330 return NULL;
331 }
332
333 if (macro) {
334 rv = PyDelta_FromDSU(days, seconds, microseconds);
335 }
336 else {
337 rv = PyDateTimeAPI->Delta_FromDelta(
338 days, seconds, microseconds, 1,
339 PyDateTimeAPI->DeltaType);
340 }
341
342 return rv;
343 }
344
345 static PyObject *
get_date_fromtimestamp(PyObject * self,PyObject * args)346 get_date_fromtimestamp(PyObject *self, PyObject *args)
347 {
348 PyObject *tsargs = NULL, *ts = NULL, *rv = NULL;
349 int macro = 0;
350
351 if (!PyArg_ParseTuple(args, "O|p", &ts, ¯o)) {
352 return NULL;
353 }
354
355 // Construct the argument tuple
356 if ((tsargs = PyTuple_Pack(1, ts)) == NULL) {
357 return NULL;
358 }
359
360 // Pass along to the API function
361 if (macro) {
362 rv = PyDate_FromTimestamp(tsargs);
363 }
364 else {
365 rv = PyDateTimeAPI->Date_FromTimestamp(
366 (PyObject *)PyDateTimeAPI->DateType, tsargs
367 );
368 }
369
370 Py_DECREF(tsargs);
371 return rv;
372 }
373
374 static PyObject *
get_datetime_fromtimestamp(PyObject * self,PyObject * args)375 get_datetime_fromtimestamp(PyObject *self, PyObject *args)
376 {
377 int macro = 0;
378 int usetz = 0;
379 PyObject *tsargs = NULL, *ts = NULL, *tzinfo = Py_None, *rv = NULL;
380 if (!PyArg_ParseTuple(args, "OO|pp", &ts, &tzinfo, &usetz, ¯o)) {
381 return NULL;
382 }
383
384 // Construct the argument tuple
385 if (usetz) {
386 tsargs = PyTuple_Pack(2, ts, tzinfo);
387 }
388 else {
389 tsargs = PyTuple_Pack(1, ts);
390 }
391
392 if (tsargs == NULL) {
393 return NULL;
394 }
395
396 // Pass along to the API function
397 if (macro) {
398 rv = PyDateTime_FromTimestamp(tsargs);
399 }
400 else {
401 rv = PyDateTimeAPI->DateTime_FromTimestamp(
402 (PyObject *)PyDateTimeAPI->DateTimeType, tsargs, NULL
403 );
404 }
405
406 Py_DECREF(tsargs);
407 return rv;
408 }
409
410 static PyObject *
test_PyDateTime_GET(PyObject * self,PyObject * obj)411 test_PyDateTime_GET(PyObject *self, PyObject *obj)
412 {
413 int year, month, day;
414
415 year = PyDateTime_GET_YEAR(obj);
416 month = PyDateTime_GET_MONTH(obj);
417 day = PyDateTime_GET_DAY(obj);
418
419 return Py_BuildValue("(iii)", year, month, day);
420 }
421
422 static PyObject *
test_PyDateTime_DATE_GET(PyObject * self,PyObject * obj)423 test_PyDateTime_DATE_GET(PyObject *self, PyObject *obj)
424 {
425 int hour = PyDateTime_DATE_GET_HOUR(obj);
426 int minute = PyDateTime_DATE_GET_MINUTE(obj);
427 int second = PyDateTime_DATE_GET_SECOND(obj);
428 int microsecond = PyDateTime_DATE_GET_MICROSECOND(obj);
429 PyObject *tzinfo = PyDateTime_DATE_GET_TZINFO(obj);
430
431 return Py_BuildValue("(iiiiO)", hour, minute, second, microsecond, tzinfo);
432 }
433
434 static PyObject *
test_PyDateTime_TIME_GET(PyObject * self,PyObject * obj)435 test_PyDateTime_TIME_GET(PyObject *self, PyObject *obj)
436 {
437 int hour = PyDateTime_TIME_GET_HOUR(obj);
438 int minute = PyDateTime_TIME_GET_MINUTE(obj);
439 int second = PyDateTime_TIME_GET_SECOND(obj);
440 int microsecond = PyDateTime_TIME_GET_MICROSECOND(obj);
441 PyObject *tzinfo = PyDateTime_TIME_GET_TZINFO(obj);
442
443 return Py_BuildValue("(iiiiO)", hour, minute, second, microsecond, tzinfo);
444 }
445
446 static PyObject *
test_PyDateTime_DELTA_GET(PyObject * self,PyObject * obj)447 test_PyDateTime_DELTA_GET(PyObject *self, PyObject *obj)
448 {
449 int days = PyDateTime_DELTA_GET_DAYS(obj);
450 int seconds = PyDateTime_DELTA_GET_SECONDS(obj);
451 int microseconds = PyDateTime_DELTA_GET_MICROSECONDS(obj);
452
453 return Py_BuildValue("(iii)", days, seconds, microseconds);
454 }
455
456 static PyMethodDef test_methods[] = {
457 {"PyDateTime_DATE_GET", test_PyDateTime_DATE_GET, METH_O},
458 {"PyDateTime_DELTA_GET", test_PyDateTime_DELTA_GET, METH_O},
459 {"PyDateTime_GET", test_PyDateTime_GET, METH_O},
460 {"PyDateTime_TIME_GET", test_PyDateTime_TIME_GET, METH_O},
461 {"datetime_check_date", datetime_check_date, METH_VARARGS},
462 {"datetime_check_datetime", datetime_check_datetime, METH_VARARGS},
463 {"datetime_check_delta", datetime_check_delta, METH_VARARGS},
464 {"datetime_check_time", datetime_check_time, METH_VARARGS},
465 {"datetime_check_tzinfo", datetime_check_tzinfo, METH_VARARGS},
466 {"get_date_fromdate", get_date_fromdate, METH_VARARGS},
467 {"get_date_fromtimestamp", get_date_fromtimestamp, METH_VARARGS},
468 {"get_datetime_fromdateandtime", get_datetime_fromdateandtime, METH_VARARGS},
469 {"get_datetime_fromdateandtimeandfold", get_datetime_fromdateandtimeandfold, METH_VARARGS},
470 {"get_datetime_fromtimestamp", get_datetime_fromtimestamp, METH_VARARGS},
471 {"get_delta_fromdsu", get_delta_fromdsu, METH_VARARGS},
472 {"get_time_fromtime", get_time_fromtime, METH_VARARGS},
473 {"get_time_fromtimeandfold", get_time_fromtimeandfold, METH_VARARGS},
474 {"get_timezone_utc_capi", get_timezone_utc_capi, METH_VARARGS},
475 {"get_timezones_offset_zero", get_timezones_offset_zero, METH_NOARGS},
476 {"make_timezones_capi", make_timezones_capi, METH_NOARGS},
477 {"test_datetime_capi", test_datetime_capi, METH_NOARGS},
478 {NULL},
479 };
480
481 int
_PyTestCapi_Init_DateTime(PyObject * mod)482 _PyTestCapi_Init_DateTime(PyObject *mod)
483 {
484 if (PyModule_AddFunctions(mod, test_methods) < 0) {
485 return -1;
486 }
487 return 0;
488 }
489
490
491 /* ---------------------------------------------------------------------------
492 * Test module for subinterpreters.
493 */
494
495 static int
_testcapi_datetime_exec(PyObject * mod)496 _testcapi_datetime_exec(PyObject *mod)
497 {
498 if (test_datetime_capi(NULL, NULL) == NULL) {
499 return -1;
500 }
501 return 0;
502 }
503
504 static PyModuleDef_Slot _testcapi_datetime_slots[] = {
505 {Py_mod_exec, _testcapi_datetime_exec},
506 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
507 {Py_mod_gil, Py_MOD_GIL_NOT_USED},
508 {0, NULL},
509 };
510
511 static struct PyModuleDef _testcapi_datetime_module = {
512 PyModuleDef_HEAD_INIT,
513 .m_name = "_testcapi_datetime",
514 .m_size = 0,
515 .m_methods = test_methods,
516 .m_slots = _testcapi_datetime_slots,
517 };
518
519 PyMODINIT_FUNC
PyInit__testcapi_datetime(void)520 PyInit__testcapi_datetime(void)
521 {
522 return PyModuleDef_Init(&_testcapi_datetime_module);
523 }
524