From 0c0e2a2455ba829a1ac28b962208a7adb616208f Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Wed, 20 Mar 2013 17:13:33 +0000 Subject: [PATCH 1/5] Fixed broken test decorator preventing 3 tests to run --- tests/test_lobject.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_lobject.py b/tests/test_lobject.py index 9c1c44f2..199b4ac3 100755 --- a/tests/test_lobject.py +++ b/tests/test_lobject.py @@ -395,6 +395,8 @@ def skip_if_no_truncate(f): return f(self) + return skip_if_no_truncate_ + class LargeObjectTruncateTests(LargeObjectMixin, unittest.TestCase): def test_truncate(self): lo = self.conn.lobject() From 09629a6dbcf8744648e954bb526ff101cbe5dc81 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Wed, 20 Mar 2013 17:17:10 +0000 Subject: [PATCH 2/5] Use wrap to fix names of decorated test methods Decorators not using wrap() prevent running the test from command line, e.g. with: python tests/__init__.py test_module.TestSuite.test_method --- tests/test_lobject.py | 17 +++++++---------- tests/test_types_basic.py | 3 +++ tests/test_types_extras.py | 11 ++++++++--- tests/testutils.py | 33 +++++++++++++++++++++++---------- 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/tests/test_lobject.py b/tests/test_lobject.py index 199b4ac3..632b1f7a 100755 --- a/tests/test_lobject.py +++ b/tests/test_lobject.py @@ -25,14 +25,17 @@ import os import shutil import tempfile +from functools import wraps import psycopg2 import psycopg2.extensions from psycopg2.extensions import b from testconfig import dsn, green from testutils import unittest, decorate_all_tests, skip_if_tpc_disabled +from testutils import skip_if_green def skip_if_no_lo(f): + @wraps(f) def skip_if_no_lo_(self): if self.conn.server_version < 80100: return self.skipTest("large objects only supported from PG 8.1") @@ -41,14 +44,7 @@ def skip_if_no_lo(f): return skip_if_no_lo_ -def skip_if_green(f): - def skip_if_green_(self): - if green: - return self.skipTest("libpq doesn't support LO in async mode") - else: - return f(self) - - return skip_if_green_ +skip_lo_if_green = skip_if_green("libpq doesn't support LO in async mode") class LargeObjectMixin(object): @@ -379,10 +375,11 @@ class LargeObjectTests(LargeObjectMixin, unittest.TestCase): decorate_all_tests(LargeObjectTests, skip_if_no_lo) -decorate_all_tests(LargeObjectTests, skip_if_green) +decorate_all_tests(LargeObjectTests, skip_lo_if_green) def skip_if_no_truncate(f): + @wraps(f) def skip_if_no_truncate_(self): if self.conn.server_version < 80300: return self.skipTest( @@ -434,7 +431,7 @@ class LargeObjectTruncateTests(LargeObjectMixin, unittest.TestCase): self.assertRaises(psycopg2.ProgrammingError, lo.truncate) decorate_all_tests(LargeObjectTruncateTests, skip_if_no_lo) -decorate_all_tests(LargeObjectTruncateTests, skip_if_green) +decorate_all_tests(LargeObjectTruncateTests, skip_lo_if_green) decorate_all_tests(LargeObjectTruncateTests, skip_if_no_truncate) diff --git a/tests/test_types_basic.py b/tests/test_types_basic.py index c2a47e93..4e41d9f4 100755 --- a/tests/test_types_basic.py +++ b/tests/test_types_basic.py @@ -26,7 +26,9 @@ try: import decimal except: pass + import sys +from functools import wraps import testutils from testutils import unittest, decorate_all_tests from testconfig import dsn @@ -461,6 +463,7 @@ class ByteaParserTest(unittest.TestCase): self.assertEqual(rv, tgt) def skip_if_cant_cast(f): + @wraps(f) def skip_if_cant_cast_(self, *args, **kwargs): if self._cast is None: return self.skipTest("can't test bytea parser: %s - %s" diff --git a/tests/test_types_extras.py b/tests/test_types_extras.py index 0dd9aad6..1b26c9e3 100755 --- a/tests/test_types_extras.py +++ b/tests/test_types_extras.py @@ -18,6 +18,7 @@ import re import sys from decimal import Decimal from datetime import date, datetime +from functools import wraps from testutils import unittest, skip_if_no_uuid, skip_before_postgres from testutils import decorate_all_tests @@ -124,6 +125,7 @@ class TypesExtrasTests(unittest.TestCase): def skip_if_no_hstore(f): + @wraps(f) def skip_if_no_hstore_(self): from psycopg2.extras import HstoreAdapter oids = HstoreAdapter.get_oids(self.conn) @@ -447,6 +449,7 @@ class HstoreTestCase(unittest.TestCase): def skip_if_no_composite(f): + @wraps(f) def skip_if_no_composite_(self): if self.conn.server_version < 80000: return self.skipTest( @@ -455,7 +458,6 @@ def skip_if_no_composite(f): return f(self) - skip_if_no_composite_.__name__ = f.__name__ return skip_if_no_composite_ class AdaptTypeTestCase(unittest.TestCase): @@ -831,7 +833,8 @@ class AdaptTypeTestCase(unittest.TestCase): def skip_if_json_module(f): - """Skip a test if no Python json module is available""" + """Skip a test if a Python json module *is* available""" + @wraps(f) def skip_if_json_module_(self): if psycopg2.extras.json is not None: return self.skipTest("json module is available") @@ -842,6 +845,7 @@ def skip_if_json_module(f): def skip_if_no_json_module(f): """Skip a test if no Python json module is available""" + @wraps(f) def skip_if_no_json_module_(self): if psycopg2.extras.json is None: return self.skipTest("json module not available") @@ -852,6 +856,7 @@ def skip_if_no_json_module(f): def skip_if_no_json_type(f): """Skip a test if PostgreSQL json type is not available""" + @wraps(f) def skip_if_no_json_type_(self): curs = self.conn.cursor() curs.execute("select oid from pg_type where typname = 'json'") @@ -1242,6 +1247,7 @@ class RangeTestCase(unittest.TestCase): def skip_if_no_range(f): + @wraps(f) def skip_if_no_range_(self): if self.conn.server_version < 90200: return self.skipTest( @@ -1250,7 +1256,6 @@ def skip_if_no_range(f): return f(self) - skip_if_no_range_.__name__ = f.__name__ return skip_if_no_range_ diff --git a/tests/testutils.py b/tests/testutils.py index 34adb85c..26b8d815 100644 --- a/tests/testutils.py +++ b/tests/testutils.py @@ -26,6 +26,7 @@ import os import sys +from functools import wraps try: import unittest2 @@ -43,6 +44,7 @@ else: def skipIf(cond, msg): def skipIf_(f): + @wraps(f) def skipIf__(self): if cond: warnings.warn(msg) @@ -81,6 +83,7 @@ def decorate_all_tests(cls, decorator): def skip_if_no_uuid(f): """Decorator to skip a test if uuid is not supported by Py/PG.""" + @wraps(f) def skip_if_no_uuid_(self): try: import uuid @@ -104,6 +107,7 @@ def skip_if_no_uuid(f): def skip_if_tpc_disabled(f): """Skip a test if the server has tpc support disabled.""" + @wraps(f) def skip_if_tpc_disabled_(self): from psycopg2 import ProgrammingError cnn = self.connect() @@ -123,11 +127,11 @@ def skip_if_tpc_disabled(f): "set max_prepared_transactions to > 0 to run the test") return f(self) - skip_if_tpc_disabled_.__name__ = f.__name__ return skip_if_tpc_disabled_ def skip_if_no_namedtuple(f): + @wraps(f) def skip_if_no_namedtuple_(self): try: from collections import namedtuple @@ -136,12 +140,12 @@ def skip_if_no_namedtuple(f): else: return f(self) - skip_if_no_namedtuple_.__name__ = f.__name__ return skip_if_no_namedtuple_ def skip_if_no_iobase(f): """Skip a test if io.TextIOBase is not available.""" + @wraps(f) def skip_if_no_iobase_(self): try: from io import TextIOBase @@ -157,6 +161,7 @@ def skip_before_postgres(*ver): """Skip a test on PostgreSQL before a certain version.""" ver = ver + (0,) * (3 - len(ver)) def skip_before_postgres_(f): + @wraps(f) def skip_before_postgres__(self): if self.conn.server_version < int("%d%02d%02d" % ver): return self.skipTest("skipped because PostgreSQL %s" @@ -171,6 +176,7 @@ def skip_after_postgres(*ver): """Skip a test on PostgreSQL after (including) a certain version.""" ver = ver + (0,) * (3 - len(ver)) def skip_after_postgres_(f): + @wraps(f) def skip_after_postgres__(self): if self.conn.server_version >= int("%d%02d%02d" % ver): return self.skipTest("skipped because PostgreSQL %s" @@ -184,6 +190,7 @@ def skip_after_postgres(*ver): def skip_before_python(*ver): """Skip a test on Python before a certain version.""" def skip_before_python_(f): + @wraps(f) def skip_before_python__(self): if sys.version_info[:len(ver)] < ver: return self.skipTest("skipped because Python %s" @@ -197,6 +204,7 @@ def skip_before_python(*ver): def skip_from_python(*ver): """Skip a test on Python after (including) a certain version.""" def skip_from_python_(f): + @wraps(f) def skip_from_python__(self): if sys.version_info[:len(ver)] >= ver: return self.skipTest("skipped because Python %s" @@ -209,6 +217,7 @@ def skip_from_python(*ver): def skip_if_no_superuser(f): """Skip a test if the database user running the test is not a superuser""" + @wraps(f) def skip_if_no_superuser_(self): from psycopg2 import ProgrammingError try: @@ -222,16 +231,20 @@ def skip_if_no_superuser(f): return skip_if_no_superuser_ -def skip_copy_if_green(f): - def skip_copy_if_green_(self): - from testconfig import green - if green: - return self.skipTest("copy in async mode currently not supported") - else: - return f(self) +def skip_if_green(reason): + def skip_if_green_(f): + @wraps(f) + def skip_if_green__(self): + from testconfig import green + if green: + return self.skipTest(reason) + else: + return f(self) - return skip_copy_if_green_ + return skip_if_green__ + return skip_if_green_ +skip_copy_if_green = skip_if_green("copy in async mode currently not supported") def script_to_py3(script): """Convert a script to Python3 syntax if required.""" From 8a59e75d62216d37892dab832f8cbfd8b335bf90 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Wed, 20 Mar 2013 22:15:32 +0000 Subject: [PATCH 3/5] Better use of Py_CLEAR and implicit zeroed-out structures --- psycopg/cursor_int.c | 12 ++------ psycopg/cursor_type.c | 19 +------------ psycopg/notify_type.c | 4 +-- psycopg/xid_type.c | 66 ++++++++++--------------------------------- 4 files changed, 19 insertions(+), 82 deletions(-) diff --git a/psycopg/cursor_int.c b/psycopg/cursor_int.c index 1ac3f550..dd4c0d7d 100644 --- a/psycopg/cursor_int.c +++ b/psycopg/cursor_int.c @@ -72,19 +72,11 @@ curs_get_cast(cursorObject *self, PyObject *oid) void curs_reset(cursorObject *self) { - PyObject *tmp; - /* initialize some variables to default values */ self->notuples = 1; self->rowcount = -1; self->row = 0; - tmp = self->description; - Py_INCREF(Py_None); - self->description = Py_None; - Py_XDECREF(tmp); - - tmp = self->casts; - self->casts = NULL; - Py_XDECREF(tmp); + Py_CLEAR(self->description); + Py_CLEAR(self->casts); } diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index 4b221902..dd1780d7 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -474,7 +474,7 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs) } if (self->name != NULL) { - if (self->query != Py_None) { + if (self->query) { psyco_set_error(ProgrammingError, self, "can't call .execute() on named cursors more than once"); return NULL; @@ -1843,32 +1843,15 @@ cursor_setup(cursorObject *self, connectionObject *conn, const char *name) Py_INCREF(conn); self->conn = conn; - self->closed = 0; - self->withhold = 0; - self->scrollable = 0; self->mark = conn->mark; - self->pgres = NULL; self->notuples = 1; self->arraysize = 1; self->itersize = 2000; self->rowcount = -1; self->lastoid = InvalidOid; - self->casts = NULL; - self->notice = NULL; - - self->string_types = NULL; - self->binary_types = NULL; - self->weakreflist = NULL; - - Py_INCREF(Py_None); - self->description = Py_None; - Py_INCREF(Py_None); - self->pgstatus = Py_None; Py_INCREF(Py_None); self->tuple_factory = Py_None; - Py_INCREF(Py_None); - self->query = Py_None; /* default tzinfo factory */ Py_INCREF(pyPsycopgTzFixedOffsetTimezone); diff --git a/psycopg/notify_type.c b/psycopg/notify_type.c index beec933c..17620c4d 100644 --- a/psycopg/notify_type.c +++ b/psycopg/notify_type.c @@ -61,9 +61,7 @@ static PyMemberDef notify_members[] = { static PyObject * notify_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - notifyObject *self = (notifyObject *)type->tp_alloc(type, 0); - - return (PyObject *)self; + return type->tp_alloc(type, 0); } static int diff --git a/psycopg/xid_type.c b/psycopg/xid_type.c index 70cbb048..bd4f0e4c 100644 --- a/psycopg/xid_type.c +++ b/psycopg/xid_type.c @@ -79,24 +79,7 @@ static PyMemberDef xid_members[] = { static PyObject * xid_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - xidObject *self; - - if (!(self = (xidObject *)type->tp_alloc(type, 0))) { return NULL; } - - Py_INCREF(Py_None); - self->format_id = Py_None; - Py_INCREF(Py_None); - self->gtrid = Py_None; - Py_INCREF(Py_None); - self->bqual = Py_None; - Py_INCREF(Py_None); - self->prepared = Py_None; - Py_INCREF(Py_None); - self->owner = Py_None; - Py_INCREF(Py_None); - self->database = Py_None; - - return (PyObject *)self; + return type->tp_alloc(type, 0); } static int @@ -106,7 +89,6 @@ xid_init(xidObject *self, PyObject *args, PyObject *kwargs) int format_id; size_t i, gtrid_len, bqual_len; const char *gtrid, *bqual; - PyObject *tmp; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iss", kwlist, &format_id, >rid, &bqual)) @@ -149,17 +131,12 @@ xid_init(xidObject *self, PyObject *args, PyObject *kwargs) } } - tmp = self->format_id; self->format_id = PyInt_FromLong(format_id); - Py_XDECREF(tmp); - - tmp = self->gtrid; self->gtrid = Text_FromUTF8(gtrid); - Py_XDECREF(tmp); - - tmp = self->bqual; self->bqual = Text_FromUTF8(bqual); - Py_XDECREF(tmp); + Py_INCREF(Py_None); self->prepared = Py_None; + Py_INCREF(Py_None); self->owner = Py_None; + Py_INCREF(Py_None); self->database = Py_None; return 0; } @@ -555,7 +532,6 @@ static xidObject * _xid_unparsed_from_string(PyObject *str) { xidObject *xid = NULL; xidObject *rv = NULL; - PyObject *tmp; /* fake args to work around the checks performed by the xid init */ if (!(xid = (xidObject *)PyObject_CallFunction((PyObject *)&xidType, @@ -564,22 +540,19 @@ _xid_unparsed_from_string(PyObject *str) { } /* set xid.gtrid = str */ - tmp = xid->gtrid; + Py_CLEAR(xid->gtrid); Py_INCREF(str); xid->gtrid = str; - Py_DECREF(tmp); /* set xid.format_id = None */ - tmp = xid->format_id; + Py_CLEAR(xid->format_id); Py_INCREF(Py_None); xid->format_id = Py_None; - Py_DECREF(tmp); /* set xid.bqual = None */ - tmp = xid->bqual; + Py_CLEAR(xid->bqual); Py_INCREF(Py_None); xid->bqual = Py_None; - Py_DECREF(tmp); /* return the finished object */ rv = xid; @@ -665,34 +638,25 @@ xid_recover(PyObject *conn) /* Get the xid with the XA triple set */ if (!(item = PySequence_GetItem(rec, 0))) { goto exit; } if (!(xid = xid_from_string(item))) { goto exit; } - Py_DECREF(item); item = NULL; + Py_CLEAR(item); /* set xid.prepared */ - if (!(item = PySequence_GetItem(rec, 1))) { goto exit; } - tmp = xid->prepared; - xid->prepared = item; - Py_DECREF(tmp); - item = NULL; + Py_CLEAR(xid->prepared); + if (!(xid->prepared = PySequence_GetItem(rec, 1))) { goto exit; } /* set xid.owner */ - if (!(item = PySequence_GetItem(rec, 2))) { goto exit; } - tmp = xid->owner; - xid->owner = item; - Py_DECREF(tmp); - item = NULL; + Py_CLEAR(xid->owner); + if (!(xid->owner = PySequence_GetItem(rec, 2))) { goto exit; } /* set xid.database */ - if (!(item = PySequence_GetItem(rec, 3))) { goto exit; } - tmp = xid->database; - xid->database = item; - Py_DECREF(tmp); - item = NULL; + Py_CLEAR(xid->database); + if (!(xid->database = PySequence_GetItem(rec, 3))) { goto exit; } /* xid finished: add it to the returned list */ PyList_SET_ITEM(xids, i, (PyObject *)xid); xid = NULL; /* ref stolen */ - Py_DECREF(rec); rec = NULL; + Py_CLEAR(rec); } /* set the return value. */ From e65392e0d87c601822c51c50c803eab58f1508d3 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Wed, 20 Mar 2013 22:27:10 +0000 Subject: [PATCH 4/5] PyType_GenericAlloc is the default allocator: no need to specify --- psycopg/adapter_asis.c | 2 +- psycopg/adapter_binary.c | 2 +- psycopg/adapter_datetime.c | 2 +- psycopg/adapter_list.c | 2 +- psycopg/adapter_pboolean.c | 2 +- psycopg/adapter_pdecimal.c | 2 +- psycopg/adapter_pfloat.c | 2 +- psycopg/adapter_pint.c | 2 +- psycopg/adapter_qstring.c | 2 +- psycopg/connection_type.c | 2 +- psycopg/cursor_type.c | 2 +- psycopg/diagnostics_type.c | 2 +- psycopg/error_type.c | 2 +- psycopg/lobject_type.c | 2 +- psycopg/microprotocols_proto.c | 2 +- psycopg/notify_type.c | 2 +- psycopg/psycopgmodule.c | 79 +++++++++++++++------------------- psycopg/typecast.c | 8 ++-- psycopg/xid_type.c | 2 +- 19 files changed, 55 insertions(+), 66 deletions(-) diff --git a/psycopg/adapter_asis.c b/psycopg/adapter_asis.c index 7952bbae..7f5d3850 100644 --- a/psycopg/adapter_asis.c +++ b/psycopg/adapter_asis.c @@ -204,7 +204,7 @@ PyTypeObject asisType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ asis_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ asis_new, /*tp_new*/ }; diff --git a/psycopg/adapter_binary.c b/psycopg/adapter_binary.c index 058c9b9b..08f41b84 100644 --- a/psycopg/adapter_binary.c +++ b/psycopg/adapter_binary.c @@ -313,7 +313,7 @@ PyTypeObject binaryType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ binary_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ binary_new, /*tp_new*/ }; diff --git a/psycopg/adapter_datetime.c b/psycopg/adapter_datetime.c index 0fa10092..9713a5a5 100644 --- a/psycopg/adapter_datetime.c +++ b/psycopg/adapter_datetime.c @@ -271,7 +271,7 @@ PyTypeObject pydatetimeType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ pydatetime_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ pydatetime_new, /*tp_new*/ }; diff --git a/psycopg/adapter_list.c b/psycopg/adapter_list.c index 5e25234b..6650dd96 100644 --- a/psycopg/adapter_list.c +++ b/psycopg/adapter_list.c @@ -268,7 +268,7 @@ PyTypeObject listType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ list_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ list_new, /*tp_new*/ }; diff --git a/psycopg/adapter_pboolean.c b/psycopg/adapter_pboolean.c index 75b0723d..879e233d 100644 --- a/psycopg/adapter_pboolean.c +++ b/psycopg/adapter_pboolean.c @@ -204,7 +204,7 @@ PyTypeObject pbooleanType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ pboolean_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ pboolean_new, /*tp_new*/ }; diff --git a/psycopg/adapter_pdecimal.c b/psycopg/adapter_pdecimal.c index 1e3b6f97..09748514 100644 --- a/psycopg/adapter_pdecimal.c +++ b/psycopg/adapter_pdecimal.c @@ -260,7 +260,7 @@ PyTypeObject pdecimalType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ pdecimal_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ pdecimal_new, /*tp_new*/ }; diff --git a/psycopg/adapter_pfloat.c b/psycopg/adapter_pfloat.c index 8871c54b..abdc8a4c 100644 --- a/psycopg/adapter_pfloat.c +++ b/psycopg/adapter_pfloat.c @@ -233,7 +233,7 @@ PyTypeObject pfloatType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ pfloat_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ pfloat_new, /*tp_new*/ }; diff --git a/psycopg/adapter_pint.c b/psycopg/adapter_pint.c index b8383d71..ece7a9ca 100644 --- a/psycopg/adapter_pint.c +++ b/psycopg/adapter_pint.c @@ -219,7 +219,7 @@ PyTypeObject pintType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ pint_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ pint_new, /*tp_new*/ }; diff --git a/psycopg/adapter_qstring.c b/psycopg/adapter_qstring.c index 04bde73c..f2efac34 100644 --- a/psycopg/adapter_qstring.c +++ b/psycopg/adapter_qstring.c @@ -296,7 +296,7 @@ PyTypeObject qstringType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ qstring_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ qstring_new, /*tp_new*/ }; diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c index af8905d5..1192a4ac 100644 --- a/psycopg/connection_type.c +++ b/psycopg/connection_type.c @@ -1243,6 +1243,6 @@ PyTypeObject connectionType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ connection_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ connection_new, /*tp_new*/ }; diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index dd1780d7..8794e7fe 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -2002,6 +2002,6 @@ PyTypeObject cursorType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ cursor_init, /*tp_init*/ - 0, /*tp_alloc Will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ cursor_new, /*tp_new*/ }; diff --git a/psycopg/diagnostics_type.c b/psycopg/diagnostics_type.c index 36354ff5..77019bfb 100644 --- a/psycopg/diagnostics_type.c +++ b/psycopg/diagnostics_type.c @@ -200,6 +200,6 @@ PyTypeObject diagnosticsType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)diagnostics_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ diagnostics_new, /*tp_new*/ }; diff --git a/psycopg/error_type.c b/psycopg/error_type.c index da3056b7..fd0947bc 100644 --- a/psycopg/error_type.c +++ b/psycopg/error_type.c @@ -282,6 +282,6 @@ PyTypeObject errorType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)error_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ error_new, /*tp_new*/ }; diff --git a/psycopg/lobject_type.c b/psycopg/lobject_type.c index 6f6ac335..90546e79 100644 --- a/psycopg/lobject_type.c +++ b/psycopg/lobject_type.c @@ -441,7 +441,7 @@ PyTypeObject lobjectType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ lobject_init, /*tp_init*/ - 0, /*tp_alloc Will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ lobject_new, /*tp_new*/ }; diff --git a/psycopg/microprotocols_proto.c b/psycopg/microprotocols_proto.c index c0afc23d..6065efdf 100644 --- a/psycopg/microprotocols_proto.c +++ b/psycopg/microprotocols_proto.c @@ -179,6 +179,6 @@ PyTypeObject isqlquoteType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ isqlquote_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ isqlquote_new, /*tp_new*/ }; diff --git a/psycopg/notify_type.c b/psycopg/notify_type.c index 17620c4d..973ee169 100644 --- a/psycopg/notify_type.c +++ b/psycopg/notify_type.c @@ -303,7 +303,7 @@ PyTypeObject notifyType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)notify_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ notify_new, /*tp_new*/ }; diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c index 36984e59..4f61d765 100644 --- a/psycopg/psycopgmodule.c +++ b/psycopg/psycopgmodule.c @@ -768,44 +768,59 @@ INIT_MODULE(_psycopg)(void) /* initialize all the new types and then the module */ Py_TYPE(&connectionType) = &PyType_Type; - Py_TYPE(&cursorType) = &PyType_Type; - Py_TYPE(&typecastType) = &PyType_Type; - Py_TYPE(&qstringType) = &PyType_Type; - Py_TYPE(&binaryType) = &PyType_Type; - Py_TYPE(&isqlquoteType) = &PyType_Type; - Py_TYPE(&pbooleanType) = &PyType_Type; - Py_TYPE(&pintType) = &PyType_Type; - Py_TYPE(&pfloatType) = &PyType_Type; - Py_TYPE(&pdecimalType) = &PyType_Type; - Py_TYPE(&asisType) = &PyType_Type; - Py_TYPE(&listType) = &PyType_Type; - Py_TYPE(&chunkType) = &PyType_Type; - Py_TYPE(¬ifyType) = &PyType_Type; - Py_TYPE(&xidType) = &PyType_Type; - Py_TYPE(&errorType) = &PyType_Type; - Py_TYPE(&diagnosticsType) = &PyType_Type; - if (PyType_Ready(&connectionType) == -1) goto exit; + + Py_TYPE(&cursorType) = &PyType_Type; if (PyType_Ready(&cursorType) == -1) goto exit; + + Py_TYPE(&typecastType) = &PyType_Type; if (PyType_Ready(&typecastType) == -1) goto exit; + + Py_TYPE(&qstringType) = &PyType_Type; if (PyType_Ready(&qstringType) == -1) goto exit; + + Py_TYPE(&binaryType) = &PyType_Type; if (PyType_Ready(&binaryType) == -1) goto exit; + + Py_TYPE(&isqlquoteType) = &PyType_Type; if (PyType_Ready(&isqlquoteType) == -1) goto exit; + + Py_TYPE(&pbooleanType) = &PyType_Type; if (PyType_Ready(&pbooleanType) == -1) goto exit; + + Py_TYPE(&pintType) = &PyType_Type; if (PyType_Ready(&pintType) == -1) goto exit; + + Py_TYPE(&pfloatType) = &PyType_Type; if (PyType_Ready(&pfloatType) == -1) goto exit; + + Py_TYPE(&pdecimalType) = &PyType_Type; if (PyType_Ready(&pdecimalType) == -1) goto exit; + + Py_TYPE(&asisType) = &PyType_Type; if (PyType_Ready(&asisType) == -1) goto exit; + + Py_TYPE(&listType) = &PyType_Type; if (PyType_Ready(&listType) == -1) goto exit; + + Py_TYPE(&chunkType) = &PyType_Type; if (PyType_Ready(&chunkType) == -1) goto exit; + + Py_TYPE(¬ifyType) = &PyType_Type; if (PyType_Ready(¬ifyType) == -1) goto exit; + + Py_TYPE(&xidType) = &PyType_Type; if (PyType_Ready(&xidType) == -1) goto exit; + + Py_TYPE(&errorType) = &PyType_Type; errorType.tp_base = (PyTypeObject *)PyExc_StandardError; if (PyType_Ready(&errorType) == -1) goto exit; + + Py_TYPE(&diagnosticsType) = &PyType_Type; if (PyType_Ready(&diagnosticsType) == -1) goto exit; #ifdef PSYCOPG_EXTENSIONS - Py_TYPE(&lobjectType) = &PyType_Type; + Py_TYPE(&lobjectType) = &PyType_Type; if (PyType_Ready(&lobjectType) == -1) goto exit; #endif @@ -813,6 +828,7 @@ INIT_MODULE(_psycopg)(void) #ifdef HAVE_MXDATETIME Py_TYPE(&mxdatetimeType) = &PyType_Type; if (PyType_Ready(&mxdatetimeType) == -1) goto exit; + if (0 != mxDateTime_ImportModuleAndAPI()) { PyErr_Clear(); @@ -921,33 +937,6 @@ INIT_MODULE(_psycopg)(void) if (0 != psyco_errors_init()) { goto exit; } psyco_errors_fill(dict); - /* Solve win32 build issue about non-constant initializer element */ - cursorType.tp_alloc = PyType_GenericAlloc; - binaryType.tp_alloc = PyType_GenericAlloc; - isqlquoteType.tp_alloc = PyType_GenericAlloc; - pbooleanType.tp_alloc = PyType_GenericAlloc; - pintType.tp_alloc = PyType_GenericAlloc; - pfloatType.tp_alloc = PyType_GenericAlloc; - pdecimalType.tp_alloc = PyType_GenericAlloc; - connectionType.tp_alloc = PyType_GenericAlloc; - asisType.tp_alloc = PyType_GenericAlloc; - qstringType.tp_alloc = PyType_GenericAlloc; - listType.tp_alloc = PyType_GenericAlloc; - chunkType.tp_alloc = PyType_GenericAlloc; - pydatetimeType.tp_alloc = PyType_GenericAlloc; - notifyType.tp_alloc = PyType_GenericAlloc; - xidType.tp_alloc = PyType_GenericAlloc; - errorType.tp_alloc = PyType_GenericAlloc; - diagnosticsType.tp_alloc = PyType_GenericAlloc; - -#ifdef PSYCOPG_EXTENSIONS - lobjectType.tp_alloc = PyType_GenericAlloc; -#endif - -#ifdef HAVE_MXDATETIME - mxdatetimeType.tp_alloc = PyType_GenericAlloc; -#endif - Dprintf("initpsycopg: module initialization complete"); exit: diff --git a/psycopg/typecast.c b/psycopg/typecast.c index 74506906..048f44a6 100644 --- a/psycopg/typecast.c +++ b/psycopg/typecast.c @@ -508,7 +508,7 @@ PyTypeObject typecastType = { 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ - 0, /*tp_methods*/ + 0, /*tp_methods*/ typecastObject_members, /*tp_members*/ 0, /*tp_getset*/ 0, /*tp_base*/ @@ -516,9 +516,9 @@ PyTypeObject typecastType = { 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ - 0, /*tp_new*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ }; static PyObject * diff --git a/psycopg/xid_type.c b/psycopg/xid_type.c index bd4f0e4c..67ea0112 100644 --- a/psycopg/xid_type.c +++ b/psycopg/xid_type.c @@ -312,7 +312,7 @@ PyTypeObject xidType = { 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)xid_init, /*tp_init*/ - 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_alloc*/ xid_new, /*tp_new*/ }; From b6873ee1ab9c38d446508e64a18b44c20951502d Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Wed, 20 Mar 2013 23:40:13 +0000 Subject: [PATCH 5/5] Dropped support for Python 2.4 --- NEWS | 1 + doc/src/install.rst | 2 +- lib/__init__.py | 17 ----------------- psycopg/cursor_type.c | 4 ++-- psycopg/error_type.c | 15 +-------------- psycopg/lobject_type.c | 2 +- psycopg/python.h | 33 ++------------------------------- tests/test_types_basic.py | 36 +++++++++++++----------------------- 8 files changed, 21 insertions(+), 89 deletions(-) diff --git a/NEWS b/NEWS index 6e0f7662..065a6b2f 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,7 @@ Bug fixes: Other changes: - Added support for Python 3.3. +- Dropped support for Python 2.4. Please use Psycopg 2.4.x if you need it. - `~psycopg2.errorcodes` map updated to PostgreSQL 9.2. - Dropped Zope adapter from source repository. ZPsycopgDA now has its own project at . diff --git a/doc/src/install.rst b/doc/src/install.rst index 3fa480cf..017be955 100644 --- a/doc/src/install.rst +++ b/doc/src/install.rst @@ -14,7 +14,7 @@ mature as the C implementation yet. The current `!psycopg2` implementation supports: -- Python 2 versions from 2.4 to 2.7 +- Python 2 versions from 2.5 to 2.7 - Python 3 versions from 3.1 to 3.3 - PostgreSQL versions from 7.4 to 9.2 diff --git a/lib/__init__.py b/lib/__init__.py index 892d8038..e9618fd0 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -41,23 +41,6 @@ Homepage: http://initd.org/projects/psycopg2 # Import modules needed by _psycopg to allow tools like py2exe to do # their work without bothering about the module dependencies. -import sys, warnings -if sys.version_info >= (2, 3): - try: - import datetime as _psycopg_needs_datetime - except: - warnings.warn( - "can't import datetime module probably needed by _psycopg", - RuntimeWarning) -if sys.version_info >= (2, 4): - try: - import decimal as _psycopg_needs_decimal - except: - warnings.warn( - "can't import decimal module probably needed by _psycopg", - RuntimeWarning) -del sys, warnings - # Note: the first internal import should be _psycopg, otherwise the real cause # of a failed loading of the C module may get hidden, see # http://archives.postgresql.org/psycopg/2011-02/msg00044.php diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index 8794e7fe..3f5d3ba6 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -1358,7 +1358,7 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs) PyObject *file, *columns = NULL, *res = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O&s|ss" CONV_CODE_PY_SSIZE_T "O", kwlist, + "O&s|ssnO", kwlist, _psyco_curs_has_read_check, &file, &table_name, &sep, &null, &bufsize, &columns)) { @@ -1535,7 +1535,7 @@ psyco_curs_copy_expert(cursorObject *self, PyObject *args, PyObject *kwargs) static char *kwlist[] = {"sql", "file", "size", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "OO|" CONV_CODE_PY_SSIZE_T, kwlist, &sql, &file, &bufsize)) + "OO|n", kwlist, &sql, &file, &bufsize)) { return NULL; } EXC_IF_CURS_CLOSED(self); diff --git a/psycopg/error_type.c b/psycopg/error_type.c index fd0947bc..8e916530 100644 --- a/psycopg/error_type.c +++ b/psycopg/error_type.c @@ -131,8 +131,6 @@ static struct PyGetSetDef error_getsets[] = { }; -#if PY_VERSION_HEX >= 0x02050000 - /* Error.__reduce__ * * The method is required to make exceptions picklable: set the cursor @@ -227,21 +225,10 @@ error: return rv; } -#endif /* PY_VERSION_HEX >= 0x02050000 */ - static PyMethodDef error_methods[] = { -#if PY_VERSION_HEX >= 0x02050000 - /* Make Error and all its subclasses picklable. - * - * TODO: this comment applied to the __reduce_ex__ implementation: now - * pickling may work on Py 2.4 too... but it's 2013 now. - * - * Don't do it it on Py 2.4: [__reduce_ex__] it is not used by the pickle - * protocol, and if called manually fails in an unsettling way, - * probably because the exceptions were old-style classes. */ + /* Make Error and all its subclasses picklable. */ {"__reduce__", (PyCFunction)psyco_error_reduce, METH_NOARGS }, {"__setstate__", (PyCFunction)psyco_error_setstate, METH_O }, -#endif {NULL} }; diff --git a/psycopg/lobject_type.c b/psycopg/lobject_type.c index 90546e79..b25074d9 100644 --- a/psycopg/lobject_type.c +++ b/psycopg/lobject_type.c @@ -128,7 +128,7 @@ psyco_lobj_read(lobjectObject *self, PyObject *args) Py_ssize_t size = -1; char *buffer; - if (!PyArg_ParseTuple(args, "|" CONV_CODE_PY_SSIZE_T, &size)) return NULL; + if (!PyArg_ParseTuple(args, "|n", &size)) return NULL; EXC_IF_LOBJ_CLOSED(self); EXC_IF_LOBJ_LEVEL0(self); diff --git a/psycopg/python.h b/psycopg/python.h index 9fce6e13..90c82516 100644 --- a/psycopg/python.h +++ b/psycopg/python.h @@ -31,36 +31,12 @@ #include #endif -#if PY_VERSION_HEX < 0x02040000 -# error "psycopg requires Python >= 2.4" -#endif - #if PY_VERSION_HEX < 0x02050000 -/* Function missing in Py 2.4 */ -#define PyErr_WarnEx(cat,msg,lvl) PyErr_Warn(cat,msg) -#endif - -#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 PyInt_FromSsize_t(x) PyInt_FromLong((x)) - - #define lenfunc inquiry - #define ssizeargfunc intargfunc - #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" +# error "psycopg requires Python >= 2.5" #endif /* hash() return size changed around version 3.2a4 on 64bit platforms. Before - * this, the return size was always a long, regardless of arch. ~3.2 + * this, the return size was always a long, regardless of arch. ~3.2 * introduced the Py_hash_t & Py_uhash_t typedefs with the resulting sizes * based upon arch. */ #if PY_VERSION_HEX < 0x030200A4 @@ -76,11 +52,6 @@ typedef unsigned long Py_uhash_t; #define PyVarObject_HEAD_INIT(x,n) PyObject_HEAD_INIT(x) n, #endif -/* Missing at least in Python 2.4 */ -#ifndef Py_MEMCPY -#define Py_MEMCPY memcpy -#endif - /* FORMAT_CODE_PY_SSIZE_T is for Py_ssize_t: */ #define FORMAT_CODE_PY_SSIZE_T "%" PY_FORMAT_SIZE_T "d" diff --git a/tests/test_types_basic.py b/tests/test_types_basic.py index 4e41d9f4..6f7294ee 100755 --- a/tests/test_types_basic.py +++ b/tests/test_types_basic.py @@ -22,10 +22,7 @@ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. -try: - import decimal -except: - pass +import decimal import sys from functools import wraps @@ -66,10 +63,6 @@ class TypesBasicTests(unittest.TestCase): self.failUnless(s == 1971, "wrong integer quoting: " + str(s)) s = self.execute("SELECT %s AS foo", (1971L,)) self.failUnless(s == 1971L, "wrong integer quoting: " + str(s)) - if sys.version_info[0:2] < (2, 4): - s = self.execute("SELECT %s AS foo", (19.10,)) - self.failUnless(abs(s - 19.10) < 0.001, - "wrong float quoting: " + str(s)) def testBoolean(self): x = self.execute("SELECT %s as foo", (False,)) @@ -78,21 +71,18 @@ class TypesBasicTests(unittest.TestCase): self.assert_(x is True) def testDecimal(self): - if sys.version_info[0:2] >= (2, 4): - s = self.execute("SELECT %s AS foo", (decimal.Decimal("19.10"),)) - self.failUnless(s - decimal.Decimal("19.10") == 0, - "wrong decimal quoting: " + str(s)) - s = self.execute("SELECT %s AS foo", (decimal.Decimal("NaN"),)) - self.failUnless(str(s) == "NaN", "wrong decimal quoting: " + str(s)) - self.failUnless(type(s) == decimal.Decimal, "wrong decimal conversion: " + repr(s)) - s = self.execute("SELECT %s AS foo", (decimal.Decimal("infinity"),)) - self.failUnless(str(s) == "NaN", "wrong decimal quoting: " + str(s)) - self.failUnless(type(s) == decimal.Decimal, "wrong decimal conversion: " + repr(s)) - s = self.execute("SELECT %s AS foo", (decimal.Decimal("-infinity"),)) - self.failUnless(str(s) == "NaN", "wrong decimal quoting: " + str(s)) - self.failUnless(type(s) == decimal.Decimal, "wrong decimal conversion: " + repr(s)) - else: - return self.skipTest("decimal not available") + s = self.execute("SELECT %s AS foo", (decimal.Decimal("19.10"),)) + self.failUnless(s - decimal.Decimal("19.10") == 0, + "wrong decimal quoting: " + str(s)) + s = self.execute("SELECT %s AS foo", (decimal.Decimal("NaN"),)) + self.failUnless(str(s) == "NaN", "wrong decimal quoting: " + str(s)) + self.failUnless(type(s) == decimal.Decimal, "wrong decimal conversion: " + repr(s)) + s = self.execute("SELECT %s AS foo", (decimal.Decimal("infinity"),)) + self.failUnless(str(s) == "NaN", "wrong decimal quoting: " + str(s)) + self.failUnless(type(s) == decimal.Decimal, "wrong decimal conversion: " + repr(s)) + s = self.execute("SELECT %s AS foo", (decimal.Decimal("-infinity"),)) + self.failUnless(str(s) == "NaN", "wrong decimal quoting: " + str(s)) + self.failUnless(type(s) == decimal.Decimal, "wrong decimal conversion: " + repr(s)) def testFloatNan(self): try: