diff --git a/psycopg/psycopg.h b/psycopg/psycopg.h index b0734a63..8818ee52 100644 --- a/psycopg/psycopg.h +++ b/psycopg/psycopg.h @@ -27,42 +27,12 @@ #include #include "psycopg/config.h" +#include "psycopg/python.h" #ifdef __cplusplus extern "C" { #endif -/* Python 2.5+ Py_ssize_t compatibility: */ -#ifndef PY_FORMAT_SIZE_T - #define PY_FORMAT_SIZE_T "" -#endif - -/* FORMAT_CODE_SIZE_T is for plain size_t, not for Py_ssize_t: */ -#ifdef _MSC_VER - /* For MSVC: */ - #define FORMAT_CODE_SIZE_T "%Iu" -#else - /* C99 standard format code: */ - #define FORMAT_CODE_SIZE_T "%zu" -#endif -/* FORMAT_CODE_PY_SSIZE_T is for Py_ssize_t: */ -#define FORMAT_CODE_PY_SSIZE_T "%" PY_FORMAT_SIZE_T "d" - -#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 5 - #define CONV_CODE_PY_SSIZE_T "n" -#else - #define CONV_CODE_PY_SSIZE_T "i" - - typedef int Py_ssize_t; - #define PY_SSIZE_T_MIN INT_MIN - #define PY_SSIZE_T_MAX INT_MAX - - #define readbufferproc getreadbufferproc - #define writebufferproc getwritebufferproc - #define segcountproc getsegcountproc - #define charbufferproc getcharbufferproc -#endif - /* DBAPI compliance parameters */ #define APILEVEL "2.0" #define THREADSAFETY 2 diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c index 6c658fcb..43e0402a 100644 --- a/psycopg/psycopgmodule.c +++ b/psycopg/psycopgmodule.c @@ -47,7 +47,6 @@ HIDDEN mxDateTimeModule_APIObject *mxDateTimeP = NULL; #endif /* some module-level variables, like the datetime module */ -#ifdef HAVE_PYDATETIME #include #include "psycopg/adapter_datetime.h" HIDDEN PyObject *pyDateTimeModuleP = NULL; @@ -55,7 +54,6 @@ HIDDEN PyObject *pyDateTypeP = NULL; HIDDEN PyObject *pyTimeTypeP = NULL; HIDDEN PyObject *pyDateTimeTypeP = NULL; HIDDEN PyObject *pyDeltaTypeP = NULL; -#endif /* pointers to the psycopg.tz classes */ HIDDEN PyObject *pyPsycopgTzModule = NULL; @@ -276,23 +274,17 @@ psyco_adapters_init(PyObject *mod) microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&asisType); microprotocols_add(&PyInt_Type, NULL, (PyObject*)&asisType); microprotocols_add(&PyLong_Type, NULL, (PyObject*)&asisType); + microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType); microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType); microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType); microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType); microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType); + microprotocols_add((PyTypeObject*)psyco_GetDecimalType(), + NULL, (PyObject*)&asisType); -#ifdef HAVE_MXDATETIME /* the module has already been initialized, so we can obtain the callable objects directly from its dictionary :) */ - call = PyMapping_GetItemString(mod, "TimestampFromMx"); - microprotocols_add(mxDateTimeP->DateTime_Type, NULL, call); - call = PyMapping_GetItemString(mod, "TimeFromMx"); - microprotocols_add(mxDateTimeP->DateTimeDelta_Type, NULL, call); -#endif - -#ifdef HAVE_PYDATETIME - /* as above, we use the callable objects from the psycopg module */ call = PyMapping_GetItemString(mod, "DateFromPy"); microprotocols_add((PyTypeObject*)pyDateTypeP, NULL, call); call = PyMapping_GetItemString(mod, "TimeFromPy"); @@ -301,15 +293,13 @@ psyco_adapters_init(PyObject *mod) microprotocols_add((PyTypeObject*)pyDateTimeTypeP, NULL, call); call = PyMapping_GetItemString(mod, "IntervalFromPy"); microprotocols_add((PyTypeObject*)pyDeltaTypeP, NULL, call); -#endif -#ifdef HAVE_PYBOOL - microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType); -#endif - -#ifdef HAVE_DECIMAL - microprotocols_add((PyTypeObject*)psyco_GetDecimalType(), - NULL, (PyObject*)&asisType); +#ifdef HAVE_MXDATETIME + /* as above, we use the callable objects from the psycopg module */ + call = PyMapping_GetItemString(mod, "TimestampFromMx"); + microprotocols_add(mxDateTimeP->DateTime_Type, NULL, call); + call = PyMapping_GetItemString(mod, "TimeFromMx"); + microprotocols_add(mxDateTimeP->DateTimeDelta_Type, NULL, call); #endif } @@ -590,9 +580,7 @@ psyco_GetDecimalType(void) { PyObject *decimalType = NULL; static PyObject *cachedType = NULL; - -#ifdef HAVE_DECIMAL - PyObject *decimal = PyImport_ImportModule("decimal"); + PyObject *decimal; /* Use the cached object if running from the main interpreter. */ int can_cache = psyco_is_main_interp(); @@ -602,6 +590,7 @@ psyco_GetDecimalType(void) } /* Get a new reference to the Decimal type. */ + decimal = PyImport_ImportModule("decimal"); if (decimal) { decimalType = PyObject_GetAttrString(decimal, "Decimal"); Py_DECREF(decimal); @@ -614,11 +603,10 @@ psyco_GetDecimalType(void) /* Store the object from future uses. */ if (can_cache && !cachedType) { + Py_INCREF(decimalType); cachedType = decimalType; } -#endif /* HAVE_DECIMAL */ - return decimalType; } @@ -659,6 +647,15 @@ static PyMethodDef psycopgMethods[] = { {"List", (PyCFunction)psyco_List, METH_VARARGS, psyco_List_doc}, + {"DateFromPy", (PyCFunction)psyco_DateFromPy, + METH_VARARGS, psyco_DateFromPy_doc}, + {"TimeFromPy", (PyCFunction)psyco_TimeFromPy, + METH_VARARGS, psyco_TimeFromPy_doc}, + {"TimestampFromPy", (PyCFunction)psyco_TimestampFromPy, + METH_VARARGS, psyco_TimestampFromPy_doc}, + {"IntervalFromPy", (PyCFunction)psyco_IntervalFromPy, + METH_VARARGS, psyco_IntervalFromPy_doc}, + #ifdef HAVE_MXDATETIME {"DateFromMx", (PyCFunction)psyco_DateFromMx, METH_VARARGS, psyco_DateFromMx_doc}, @@ -670,17 +667,6 @@ static PyMethodDef psycopgMethods[] = { METH_VARARGS, psyco_IntervalFromMx_doc}, #endif -#ifdef HAVE_PYDATETIME - {"DateFromPy", (PyCFunction)psyco_DateFromPy, - METH_VARARGS, psyco_DateFromPy_doc}, - {"TimeFromPy", (PyCFunction)psyco_TimeFromPy, - METH_VARARGS, psyco_TimeFromPy_doc}, - {"TimestampFromPy", (PyCFunction)psyco_TimestampFromPy, - METH_VARARGS, psyco_TimestampFromPy_doc}, - {"IntervalFromPy", (PyCFunction)psyco_IntervalFromPy, - METH_VARARGS, psyco_IntervalFromPy_doc}, -#endif - {NULL, NULL, 0, NULL} /* Sentinel */ }; @@ -694,7 +680,7 @@ init_psycopg(void) #ifdef PSYCOPG_DEBUG if (getenv("PSYCOPG_DEBUG")) - psycopg_debug_enabled = 1; + psycopg_debug_enabled = 1; #endif Dprintf("initpsycopg: initializing psycopg %s", PSYCOPG_VERSION); @@ -706,6 +692,7 @@ init_psycopg(void) qstringType.ob_type = &PyType_Type; binaryType.ob_type = &PyType_Type; isqlquoteType.ob_type = &PyType_Type; + pbooleanType.ob_type = &PyType_Type; asisType.ob_type = &PyType_Type; listType.ob_type = &PyType_Type; chunkType.ob_type = &PyType_Type; @@ -716,6 +703,7 @@ init_psycopg(void) if (PyType_Ready(&qstringType) == -1) return; if (PyType_Ready(&binaryType) == -1) return; if (PyType_Ready(&isqlquoteType) == -1) return; + if (PyType_Ready(&pbooleanType) == -1) return; if (PyType_Ready(&asisType) == -1) return; if (PyType_Ready(&listType) == -1) return; if (PyType_Ready(&chunkType) == -1) return; @@ -725,11 +713,6 @@ init_psycopg(void) if (PyType_Ready(&lobjectType) == -1) return; #endif -#ifdef HAVE_PYBOOL - pbooleanType.ob_type = &PyType_Type; - if (PyType_Ready(&pbooleanType) == -1) return; -#endif - /* import mx.DateTime module, if necessary */ #ifdef HAVE_MXDATETIME mxdatetimeType.ob_type = &PyType_Type; @@ -743,7 +726,6 @@ init_psycopg(void) #endif /* import python builtin datetime module, if available */ -#ifdef HAVE_PYDATETIME pyDateTimeModuleP = PyImport_ImportModule("datetime"); if (pyDateTimeModuleP == NULL) { Dprintf("initpsycopg: can't import datetime module"); @@ -759,7 +741,6 @@ init_psycopg(void) pyTimeTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "time"); pyDateTimeTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "datetime"); pyDeltaTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "timedelta"); -#endif /* import psycopg2.tz anyway (TODO: replace with C-level module?) */ pyPsycopgTzModule = PyImport_ImportModule("psycopg2.tz"); @@ -828,14 +809,12 @@ init_psycopg(void) qstringType.tp_alloc = PyType_GenericAlloc; listType.tp_alloc = PyType_GenericAlloc; chunkType.tp_alloc = PyType_GenericAlloc; + pydatetimeType.tp_alloc = PyType_GenericAlloc; #ifdef PSYCOPG_EXTENSIONS lobjectType.tp_alloc = PyType_GenericAlloc; #endif -#ifdef HAVE_PYDATETIME - pydatetimeType.tp_alloc = PyType_GenericAlloc; -#endif #ifdef HAVE_MXDATETIME mxdatetimeType.tp_alloc = PyType_GenericAlloc; diff --git a/psycopg/python.h b/psycopg/python.h index 13d6ce79..22cae4aa 100644 --- a/psycopg/python.h +++ b/psycopg/python.h @@ -26,42 +26,36 @@ #include #include -/* python < 2.2 does not have PyMemeberDef */ -#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 2 -#define PyMemberDef memberlist +#if PY_VERSION_HEX < 0x02040000 +# error "psycopg requires Python >= 2.4" #endif -/* PyObject_TypeCheck introduced in 2.2 */ -#ifndef PyObject_TypeCheck -#define PyObject_TypeCheck(o, t) ((o)->ob_type == (t)) +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) + typedef int Py_ssize_t; + #define PY_SSIZE_T_MIN INT_MIN + #define PY_SSIZE_T_MAX INT_MAX + #define PY_FORMAT_SIZE_T "" + + #define readbufferproc getreadbufferproc + #define writebufferproc getwritebufferproc + #define segcountproc getsegcountproc + #define charbufferproc getcharbufferproc + + #define CONV_CODE_PY_SSIZE_T "i" +#else + #define CONV_CODE_PY_SSIZE_T "n" #endif -/* python 2.2 does not have freefunc (it has destructor instead) */ -#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 3 -#define freefunc destructor -#endif +/* FORMAT_CODE_PY_SSIZE_T is for Py_ssize_t: */ +#define FORMAT_CODE_PY_SSIZE_T "%" PY_FORMAT_SIZE_T "d" -/* Py_VISIT and Py_CLEAR introduced in Python 2.4 */ -#ifndef Py_VISIT -#define Py_VISIT(op) \ - do { \ - if (op) { \ - int vret = visit((op), arg); \ - if (vret) \ - return vret; \ - } \ - } while (0) -#endif - -#ifndef Py_CLEAR -#define Py_CLEAR(op) \ - do { \ - if (op) { \ - PyObject *tmp = (PyObject *)(op); \ - (op) = NULL; \ - Py_DECREF(tmp); \ - } \ - } while (0) +/* FORMAT_CODE_SIZE_T is for plain size_t, not for Py_ssize_t: */ +#ifdef _MSC_VER + /* For MSVC: */ + #define FORMAT_CODE_SIZE_T "%Iu" +#else + /* C99 standard format code: */ + #define FORMAT_CODE_SIZE_T "%zu" #endif #endif /* !defined(PSYCOPG_PYTHON_H) */ diff --git a/psycopg/typecast.c b/psycopg/typecast.c index f7869608..dcd9b376 100644 --- a/psycopg/typecast.c +++ b/psycopg/typecast.c @@ -167,21 +167,17 @@ typecast_parse_time(const char* s, const char** t, Py_ssize_t* len, /** include casting objects **/ #include "psycopg/typecast_basic.c" #include "psycopg/typecast_binary.c" +#include "psycopg/typecast_datetime.c" #ifdef HAVE_MXDATETIME #include "psycopg/typecast_mxdatetime.c" #endif -#ifdef HAVE_PYDATETIME -#include "psycopg/typecast_datetime.c" -#endif - #include "psycopg/typecast_array.c" #include "psycopg/typecast_builtins.c" /* a list of initializers, used to make the typecasters accessible anyway */ -#ifdef HAVE_PYDATETIME static typecastObject_initlist typecast_pydatetime[] = { {"PYDATETIME", typecast_DATETIME_types, typecast_PYDATETIME_cast}, {"PYTIME", typecast_TIME_types, typecast_PYTIME_cast}, @@ -189,7 +185,6 @@ static typecastObject_initlist typecast_pydatetime[] = { {"PYINTERVAL", typecast_INTERVAL_types, typecast_PYINTERVAL_cast}, {NULL, NULL, NULL} }; -#endif /* a list of initializers, used to make the typecasters accessible anyway */ #ifdef HAVE_MXDATETIME @@ -267,7 +262,6 @@ typecast_init(PyObject *dict) PyDict_SetItem(dict, t->name, (PyObject *)t); } #endif -#ifdef HAVE_PYDATETIME for (i = 0; typecast_pydatetime[i].name != NULL; i++) { typecastObject *t; Dprintf("typecast_init: initializing %s", typecast_pydatetime[i].name); @@ -275,7 +269,6 @@ typecast_init(PyObject *dict) if (t == NULL) return -1; PyDict_SetItem(dict, t->name, (PyObject *)t); } -#endif return 0; } diff --git a/psycopg/typecast_basic.c b/psycopg/typecast_basic.c index c4f3cf62..5d91e3ca 100644 --- a/psycopg/typecast_basic.c +++ b/psycopg/typecast_basic.c @@ -115,7 +115,6 @@ typecast_BOOLEAN_cast(const char *s, Py_ssize_t len, PyObject *curs) /** DECIMAL - cast any kind of number into a Python Decimal object **/ -#ifdef HAVE_DECIMAL static PyObject * typecast_DECIMAL_cast(const char *s, Py_ssize_t len, PyObject *curs) { @@ -135,9 +134,6 @@ typecast_DECIMAL_cast(const char *s, Py_ssize_t len, PyObject *curs) return res; } -#else -#define typecast_DECIMAL_cast typecast_FLOAT_cast -#endif /* some needed aliases */ #define typecast_NUMBER_cast typecast_FLOAT_cast diff --git a/setup.cfg b/setup.cfg index 77247f3c..1d6b2157 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,12 +12,6 @@ define=PSYCOPG_EXTENSIONS,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3,PS # Set to 1 to use Python datatime objects for default date/time representation use_pydatetime=1 -# Set to 1 if you want to enable "Decimal" type on python 2.3. -# If the "decimal" module is found in the PYTHONPATH it will be used, else -# fall back on the float type (this is disabled by default to be compatible -# with old versions of psycopg 1 and pre-beta versions of psycopg 2.) -use_decimal=0 - # If the build system does not find the mx.DateTime headers, try # uncommenting the following line and setting its value to the right path. #mx_include_dir= diff --git a/setup.py b/setup.py index 79a90932..10a04450 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ Operating System :: Unix import os import os.path import sys -import popen2 +import subprocess import ConfigParser from distutils.core import setup, Extension from distutils.errors import DistutilsFileError @@ -55,23 +55,19 @@ from distutils.sysconfig import get_python_inc from distutils.ccompiler import get_default_compiler PSYCOPG_VERSION = '2.0.8' -version_flags = [] +version_flags = ['dt', 'dec'] PLATFORM_IS_WINDOWS = sys.platform.lower().startswith('win') -# to work around older distutil limitations -if sys.version < '2.2.3': - from distutils.dist import DistributionMetadata - DistributionMetadata.classifiers = None - DistributionMetadata.download_url = None - def get_pg_config(kind, pg_config="pg_config"): - if ' ' in pg_config: - pg_config = '"'+pg_config+'"' - p = popen2.popen3(pg_config + " --" + kind) - r = p[0].readline().strip() + p = subprocess.Popen([pg_config, "--" + kind], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + p.stdin.close() + r = p.stdout.readline().strip() if not r: - raise Warning(p[2].readline()) + raise Warning(p.stderr.readline()) return r class psycopg_build_ext(build_ext): @@ -90,14 +86,12 @@ class psycopg_build_ext(build_ext): "Use Python datatime objects for date and time representation."), ('pg-config=', None, "The name of the pg_config binary and/or full path to find it"), - ('use-decimal', None, - "Use Decimal type even on Python 2.3 if the module is provided."), ('have-ssl', None, "Compile with OpenSSL built PostgreSQL libraries (Windows only)."), ]) boolean_options = build_ext.boolean_options[:] - boolean_options.extend(('use-pydatetime', 'use-decimal', 'have-ssl')) + boolean_options.extend(('use-pydatetime', 'have-ssl')) DEFAULT_PG_CONFIG = "pg_config" @@ -311,14 +305,6 @@ class psycopg_build_ext(build_ext): define_macros = [] include_dirs = [] -# python version -define_macros.append(('PY_MAJOR_VERSION', str(sys.version_info[0]))) -define_macros.append(('PY_MINOR_VERSION', str(sys.version_info[1]))) - -# some macros related to python versions and features -if sys.version_info[0] >= 2 and sys.version_info[1] >= 3: - define_macros.append(('HAVE_PYBOOL','1')) - # gather information to build the extension module ext = [] ; data_files = [] @@ -330,20 +316,13 @@ sources = [ 'connection_type.c', 'connection_int.c', 'cursor_type.c', 'cursor_int.c', 'lobject_type.c', 'lobject_int.c', 'adapter_qstring.c', 'adapter_pboolean.c', 'adapter_binary.c', - 'adapter_asis.c', 'adapter_list.c', 'utils.c'] + 'adapter_asis.c', 'adapter_list.c', 'adapter_datetime.c', 'utils.c'] parser = ConfigParser.ConfigParser() parser.read('setup.cfg') -# Choose if to use Decimal type -use_decimal = int(parser.get('build_ext', 'use_decimal')) -if sys.version_info[0] >= 2 and ( - sys.version_info[1] >= 4 or (sys.version_info[1] == 3 and use_decimal)): - define_macros.append(('HAVE_DECIMAL','1')) - version_flags.append('dec') - # Choose a datetime module -have_pydatetime = False +have_pydatetime = True have_mxdatetime = False use_pydatetime = int(parser.get('build_ext', 'use_pydatetime')) @@ -359,16 +338,8 @@ if os.path.exists(mxincludedir): have_mxdatetime = True version_flags.append('mx') -# check for python datetime package -if os.path.exists(os.path.join(get_python_inc(plat_specific=1),"datetime.h")): - define_macros.append(('HAVE_PYDATETIME','1')) - sources.append('adapter_datetime.c') - have_pydatetime = True - version_flags.append('dt') - # now decide which package will be the default for date/time typecasts -if have_pydatetime and use_pydatetime \ - or have_pydatetime and not have_mxdatetime: +if have_pydatetime and (use_pydatetime or not have_mxdatetime): define_macros.append(('PSYCOPG_DEFAULT_PYDATETIME','1')) elif have_mxdatetime: define_macros.append(('PSYCOPG_DEFAULT_MXDATETIME','1'))