diff --git a/ChangeLog b/ChangeLog index 94113025..2305813b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,8 @@ * typecast.h: functions exported to drop warnings. + * datetime module initialized at is supposed to be. + 2010-11-17 Daniele Varrazzo * psycopg/connection_type.c: don't clobber exception if diff --git a/psycopg/adapter_datetime.c b/psycopg/adapter_datetime.c index 7ba98f29..08b0cd64 100644 --- a/psycopg/adapter_datetime.c +++ b/psycopg/adapter_datetime.c @@ -39,18 +39,23 @@ #include "psycopg/adapter_datetime.h" #include "psycopg/microprotocols_proto.h" - -/* the pointer to the datetime module API is initialized by the module init - code, we just need to grab it */ -extern HIDDEN PyObject* pyDateTimeModuleP; -extern HIDDEN PyObject *pyDateTypeP; -extern HIDDEN PyObject *pyTimeTypeP; -extern HIDDEN PyObject *pyDateTimeTypeP; -extern HIDDEN PyObject *pyDeltaTypeP; - extern HIDDEN PyObject *pyPsycopgTzModule; extern HIDDEN PyObject *pyPsycopgTzLOCAL; +int +psyco_adapter_datetime_init(void) +{ + Dprintf("psyco_adapter_datetime_init: datetime init"); + + PyDateTime_IMPORT; + + if (!PyDateTimeAPI) { + PyErr_SetString(PyExc_ImportError, "datetime initialization failed"); + return -1; + } + return 0; +} + /* datetime_str, datetime_getquoted - return result of quoting */ static PyObject * @@ -298,7 +303,8 @@ psyco_Date(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "iii", &year, &month, &day)) return NULL; - obj = PyObject_CallFunction(pyDateTypeP, "iii", year, month, day); + obj = PyObject_CallFunction((PyObject*)PyDateTimeAPI->DateType, + "iii", year, month, day); if (obj) { res = PyObject_CallFunction((PyObject *)&pydatetimeType, @@ -327,10 +333,10 @@ psyco_Time(PyObject *self, PyObject *args) second = floor(second); if (tzinfo == NULL) - obj = PyObject_CallFunction(pyTimeTypeP, "iiii", + obj = PyObject_CallFunction((PyObject*)PyDateTimeAPI->TimeType, "iiii", hours, minutes, (int)second, (int)round(micro)); else - obj = PyObject_CallFunction(pyTimeTypeP, "iiiiO", + obj = PyObject_CallFunction((PyObject*)PyDateTimeAPI->TimeType, "iiiiO", hours, minutes, (int)second, (int)round(micro), tzinfo); if (obj) { @@ -361,11 +367,13 @@ psyco_Timestamp(PyObject *self, PyObject *args) second = floor(second); if (tzinfo == NULL) - obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiii", + obj = PyObject_CallFunction((PyObject*)PyDateTimeAPI->DateTimeType, + "iiiiiii", year, month, day, hour, minute, (int)second, (int)round(micro)); else - obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiiiO", + obj = PyObject_CallFunction((PyObject*)PyDateTimeAPI->DateTimeType, + "iiiiiiiO", year, month, day, hour, minute, (int)second, (int)round(micro), tzinfo); @@ -462,7 +470,7 @@ psyco_DateFromPy(PyObject *self, PyObject *args) { PyObject *obj; - if (!PyArg_ParseTuple(args, "O!", pyDateTypeP, &obj)) + if (!PyArg_ParseTuple(args, "O!", PyDateTimeAPI->DateType, &obj)) return NULL; return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj, @@ -474,7 +482,7 @@ psyco_TimeFromPy(PyObject *self, PyObject *args) { PyObject *obj; - if (!PyArg_ParseTuple(args, "O!", pyTimeTypeP, &obj)) + if (!PyArg_ParseTuple(args, "O!", PyDateTimeAPI->TimeType, &obj)) return NULL; return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj, @@ -486,7 +494,7 @@ psyco_TimestampFromPy(PyObject *self, PyObject *args) { PyObject *obj; - if (!PyArg_ParseTuple(args, "O!", pyDateTimeTypeP, &obj)) + if (!PyArg_ParseTuple(args, "O!", PyDateTimeAPI->DateTimeType, &obj)) return NULL; return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj, @@ -498,7 +506,7 @@ psyco_IntervalFromPy(PyObject *self, PyObject *args) { PyObject *obj; - if (!PyArg_ParseTuple(args, "O!", pyDeltaTypeP, &obj)) + if (!PyArg_ParseTuple(args, "O!", PyDateTimeAPI->DeltaType, &obj)) return NULL; return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj, diff --git a/psycopg/adapter_datetime.h b/psycopg/adapter_datetime.h index a0df12e1..a2c36fb9 100644 --- a/psycopg/adapter_datetime.h +++ b/psycopg/adapter_datetime.h @@ -53,6 +53,8 @@ typedef struct { /* functions exported to psycopgmodule.c */ #ifdef PSYCOPG_DEFAULT_PYDATETIME +HIDDEN int psyco_adapter_datetime_init(void); + HIDDEN PyObject *psyco_Date(PyObject *module, PyObject *args); #define psyco_Date_doc \ "Date(year, month, day) -> new date\n\n" \ diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c index 4764b8ea..26e17e09 100644 --- a/psycopg/psycopgmodule.c +++ b/psycopg/psycopgmodule.c @@ -48,6 +48,7 @@ #include "psycopg/adapter_asis.h" #include "psycopg/adapter_list.h" #include "psycopg/typecast_binary.h" +#include "psycopg/typecast_datetime.h" #ifdef HAVE_MXDATETIME #include @@ -59,10 +60,6 @@ HIDDEN mxDateTimeModule_APIObject *mxDateTimeP = NULL; #include #include "psycopg/adapter_datetime.h" HIDDEN PyObject *pyDateTimeModuleP = NULL; -HIDDEN PyObject *pyDateTypeP = NULL; -HIDDEN PyObject *pyTimeTypeP = NULL; -HIDDEN PyObject *pyDateTimeTypeP = NULL; -HIDDEN PyObject *pyDeltaTypeP = NULL; /* pointers to the psycopg.tz classes */ HIDDEN PyObject *pyPsycopgTzModule = NULL; @@ -312,13 +309,13 @@ psyco_adapters_init(PyObject *mod) /* the module has already been initialized, so we can obtain the callable objects directly from its dictionary :) */ call = PyMapping_GetItemString(mod, "DateFromPy"); - microprotocols_add((PyTypeObject*)pyDateTypeP, NULL, call); + microprotocols_add(PyDateTimeAPI->DateType, NULL, call); call = PyMapping_GetItemString(mod, "TimeFromPy"); - microprotocols_add((PyTypeObject*)pyTimeTypeP, NULL, call); + microprotocols_add(PyDateTimeAPI->TimeType, NULL, call); call = PyMapping_GetItemString(mod, "TimestampFromPy"); - microprotocols_add((PyTypeObject*)pyDateTimeTypeP, NULL, call); + microprotocols_add(PyDateTimeAPI->DateTimeType, NULL, call); call = PyMapping_GetItemString(mod, "IntervalFromPy"); - microprotocols_add((PyTypeObject*)pyDeltaTypeP, NULL, call); + microprotocols_add(PyDateTimeAPI->DeltaType, NULL, call); #ifdef HAVE_MXDATETIME /* as above, we use the callable objects from the psycopg module */ @@ -776,16 +773,15 @@ init_psycopg(void) PyErr_SetString(PyExc_ImportError, "can't import datetime module"); return; } + + /* Initialize the PyDateTimeAPI everywhere is used */ + PyDateTime_IMPORT; + if (psyco_adapter_datetime_init()) { return; } + if (psyco_typecast_datetime_init()) { return; } + pydatetimeType.ob_type = &PyType_Type; if (PyType_Ready(&pydatetimeType) == -1) return; - /* now we define the datetime types, this is crazy because python should - be doing that, not us! */ - pyDateTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "date"); - pyTimeTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "time"); - pyDateTimeTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "datetime"); - pyDeltaTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "timedelta"); - /* import psycopg2.tz anyway (TODO: replace with C-level module?) */ pyPsycopgTzModule = PyImport_ImportModule("psycopg2.tz"); if (pyPsycopgTzModule == NULL) { diff --git a/psycopg/typecast_datetime.c b/psycopg/typecast_datetime.c index 759633b6..871965bd 100644 --- a/psycopg/typecast_datetime.c +++ b/psycopg/typecast_datetime.c @@ -26,14 +26,19 @@ #include #include "datetime.h" +int +psyco_typecast_datetime_init(void) +{ + Dprintf("psyco_typecast_datetime_init: datetime init"); -/* the pointer to the datetime module API is initialized by the module init - code, we just need to grab it */ -extern HIDDEN PyObject* pyDateTimeModuleP; -extern HIDDEN PyObject *pyDateTypeP; -extern HIDDEN PyObject *pyTimeTypeP; -extern HIDDEN PyObject *pyDateTimeTypeP; -extern HIDDEN PyObject *pyDeltaTypeP; + PyDateTime_IMPORT; + + if (!PyDateTimeAPI) { + PyErr_SetString(PyExc_ImportError, "datetime initialization failed"); + return -1; + } + return 0; +} /** DATE - cast a date into a date python object **/ @@ -47,10 +52,12 @@ typecast_PYDATE_cast(const char *str, Py_ssize_t len, PyObject *curs) if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) { if (str[0] == '-') { - obj = PyObject_GetAttrString(pyDateTypeP, "min"); + obj = PyObject_GetAttrString( + (PyObject*)PyDateTimeAPI->DateType, "min"); } else { - obj = PyObject_GetAttrString(pyDateTypeP, "max"); + obj = PyObject_GetAttrString( + (PyObject*)PyDateTimeAPI->DateType, "max"); } } @@ -66,7 +73,8 @@ typecast_PYDATE_cast(const char *str, Py_ssize_t len, PyObject *curs) } else { if (y > 9999) y = 9999; - obj = PyObject_CallFunction(pyDateTypeP, "iii", y, m, d); + obj = PyObject_CallFunction( + (PyObject*)PyDateTimeAPI->DateType, "iii", y, m, d); } } return obj; @@ -89,10 +97,12 @@ typecast_PYDATETIME_cast(const char *str, Py_ssize_t len, PyObject *curs) /* check for infinity */ if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) { if (str[0] == '-') { - obj = PyObject_GetAttrString(pyDateTimeTypeP, "min"); + obj = PyObject_GetAttrString( + (PyObject*)PyDateTimeAPI->DateTimeType, "min"); } else { - obj = PyObject_GetAttrString(pyDateTimeTypeP, "max"); + obj = PyObject_GetAttrString( + (PyObject*)PyDateTimeAPI->DateTimeType, "max"); } } @@ -144,8 +154,9 @@ typecast_PYDATETIME_cast(const char *str, Py_ssize_t len, PyObject *curs) tzinfo = Py_None; } if (tzinfo != NULL) { - obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiiiO", - y, m, d, hh, mm, ss, us, tzinfo); + obj = PyObject_CallFunction( + (PyObject*)PyDateTimeAPI->DateTimeType, "iiiiiiiO", + y, m, d, hh, mm, ss, us, tzinfo); Dprintf("typecast_PYDATETIME_cast: tzinfo: %p, refcnt = " FORMAT_CODE_PY_SSIZE_T, tzinfo, tzinfo->ob_refcnt @@ -197,7 +208,7 @@ typecast_PYTIME_cast(const char *str, Py_ssize_t len, PyObject *curs) tzinfo = Py_None; } if (tzinfo != NULL) { - obj = PyObject_CallFunction(pyTimeTypeP, "iiiiO", + obj = PyObject_CallFunction((PyObject*)PyDateTimeAPI->TimeType, "iiiiO", hh, mm, ss, us, tzinfo); Py_DECREF(tzinfo); } @@ -308,7 +319,7 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs) micro = (seconds - floor(seconds)) * 1000000.0; sec = (int)floor(seconds); - return PyObject_CallFunction(pyDeltaTypeP, "iii", + return PyObject_CallFunction((PyObject*)PyDateTimeAPI->DeltaType, "iii", days, sec, (int)round(micro)); } diff --git a/psycopg/typecast_datetime.h b/psycopg/typecast_datetime.h new file mode 100644 index 00000000..cb01c6f0 --- /dev/null +++ b/psycopg/typecast_datetime.h @@ -0,0 +1,44 @@ +/* typecast_datetime.h - definitions for datetime objects typecasters + * + * Copyright (C) 2010 Daniele Varrazzo + * + * This file is part of psycopg. + * + * psycopg2 is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link this program with the OpenSSL library (or with + * modified versions of OpenSSL that use the same license as OpenSSL), + * and distribute linked combinations including the two. + * + * You must obey the GNU Lesser General Public License in all respects for + * all of the code used other than OpenSSL. + * + * psycopg2 is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + */ + +#ifndef PSYCOPG_TYPECAST_DATETIME_H +#define PSYCOPG_TYPECAST_DATETIME_H 1 + +#define PY_SSIZE_T_CLEAN +#include + +#include "psycopg/config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +HIDDEN int psyco_typecast_datetime_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_TYPECAST_DATETIME_H) */