summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>2021-05-20 16:36:55 +0200
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>2021-05-20 16:36:55 +0200
commit8f40c648aff0874ae0311a35b6751ea8fd1aed5c (patch)
tree7d6e2057c42edd86ee990027a45d5cfc815ca94c
parent8830e30f73adebdcc0449981a864ffaf06b19444 (diff)
parent45599b2716eb7fbbce19da219c4e63e630395b05 (diff)
downloadpsycopg2-8f40c648aff0874ae0311a35b6751ea8fd1aed5c.tar.gz
Merge branch 'master' into rm-2.7
-rw-r--r--NEWS8
-rw-r--r--doc/src/cursor.rst2
-rw-r--r--doc/src/extras.rst4
-rw-r--r--doc/src/faq.rst2
-rw-r--r--lib/__init__.py3
-rw-r--r--psycopg/column_type.c25
-rw-r--r--psycopg/cursor_type.c2
-rw-r--r--psycopg/psycopgmodule.c9
-rw-r--r--psycopg/xid_type.c2
-rwxr-xr-xscripts/make_errorcodes.py2
-rwxr-xr-xscripts/make_errors.py2
-rw-r--r--tests/dbapi20.py4
-rwxr-xr-xtests/test_connection.py3
-rwxr-xr-xtests/test_cursor.py10
-rwxr-xr-xtests/test_module.py21
-rw-r--r--tests/testutils.py1
16 files changed, 76 insertions, 24 deletions
diff --git a/NEWS b/NEWS
index f7e467b..58a7fb3 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,14 @@ What's new in psycopg 2.9
`~psycopg2.errors.DatabaseError`) (:ticket:`#1148`).
+What's new in psycopg 2.8.7
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Accept empty params as `~psycopg2.connect()` (:ticket:`#1250`).
+- Fix attributes refcount in `Column` initialisation (:ticket:`#1252`).
+- Allow re-initialisation of static variables in the C module (:ticket:`#1267`).
+
+
What's new in psycopg 2.8.6
^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/src/cursor.rst b/doc/src/cursor.rst
index 78db03f..8398c98 100644
--- a/doc/src/cursor.rst
+++ b/doc/src/cursor.rst
@@ -124,7 +124,7 @@ The ``cursor`` class
.. attribute:: name
Read-only attribute containing the name of the cursor if it was
- creates as named cursor by `connection.cursor()`, or `!None` if
+ created as named cursor by `connection.cursor()`, or `!None` if
it is a client side cursor. See :ref:`server-side-cursors`.
.. extension::
diff --git a/doc/src/extras.rst b/doc/src/extras.rst
index eed049c..96f801b 100644
--- a/doc/src/extras.rst
+++ b/doc/src/extras.rst
@@ -445,7 +445,9 @@ The individual messages in the replication stream are represented by
If the *reply* or *force* parameters are not set, this method will
just update internal structures without sending the feedback message
to the server. The library sends feedback message automatically
- when *status_interval* timeout is reached.
+ when *status_interval* timeout is reached. For this to work, you must
+ call `send_feedback()` on the same Cursor that you called `start_replication()`
+ on (the one in `message.cursor`) or your feedback will be lost.
.. versionchanged:: 2.8.3
added the *force* parameter.
diff --git a/doc/src/faq.rst b/doc/src/faq.rst
index a737431..9d1dbeb 100644
--- a/doc/src/faq.rst
+++ b/doc/src/faq.rst
@@ -180,7 +180,7 @@ Psycopg automatically converts PostgreSQL :sql:`json` data into Python objects.
Psycopg converts :sql:`json` values into Python objects but :sql:`jsonb` values are returned as strings. Can :sql:`jsonb` be converted automatically?
Automatic conversion of :sql:`jsonb` values is supported from Psycopg
release 2.5.4. For previous versions you can register the :sql:`json`
- typecaster on the :sql:`jsonb` oids (which are known and not suppsed to
+ typecaster on the :sql:`jsonb` oids (which are known and not supposed to
change in future PostgreSQL versions)::
psycopg2.extras.register_json(oid=3802, array_oid=3807, globally=True)
diff --git a/lib/__init__.py b/lib/__init__.py
index 3cd4640..52c82bc 100644
--- a/lib/__init__.py
+++ b/lib/__init__.py
@@ -120,9 +120,6 @@ def connect(dsn=None, connection_factory=None, cursor_factory=None, **kwargs):
if 'async_' in kwargs:
kwasync['async_'] = kwargs.pop('async_')
- if dsn is None and not kwargs:
- raise TypeError('missing dsn and no parameters')
-
dsn = _ext.make_dsn(dsn, **kwargs)
conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
if cursor_factory is not None:
diff --git a/psycopg/column_type.c b/psycopg/column_type.c
index b700706..80e6d31 100644
--- a/psycopg/column_type.c
+++ b/psycopg/column_type.c
@@ -97,17 +97,36 @@ column_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
static int
column_init(columnObject *self, PyObject *args, PyObject *kwargs)
{
+ PyObject *name = NULL;
+ PyObject *type_code = NULL;
+ PyObject *display_size = NULL;
+ PyObject *internal_size = NULL;
+ PyObject *precision = NULL;
+ PyObject *scale = NULL;
+ PyObject *null_ok = NULL;
+ PyObject *table_oid = NULL;
+ PyObject *table_column = NULL;
+
static char *kwlist[] = {
"name", "type_code", "display_size", "internal_size",
"precision", "scale", "null_ok", "table_oid", "table_column", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOOOOOOO", kwlist,
- &self->name, &self->type_code, &self->display_size,
- &self->internal_size, &self->precision, &self->scale,
- &self->null_ok, &self->table_oid, &self->table_column)) {
+ &name, &type_code, &display_size, &internal_size, &precision,
+ &scale, &null_ok, &table_oid, &table_column)) {
return -1;
}
+ Py_XINCREF(name); self->name = name;
+ Py_XINCREF(type_code); self->type_code = type_code;
+ Py_XINCREF(display_size); self->display_size = display_size;
+ Py_XINCREF(internal_size); self->internal_size = internal_size;
+ Py_XINCREF(precision); self->precision = precision;
+ Py_XINCREF(scale); self->scale = scale;
+ Py_XINCREF(null_ok); self->null_ok = null_ok;
+ Py_XINCREF(table_oid); self->table_oid = table_oid;
+ Py_XINCREF(table_column); self->table_column = table_column;
+
return 0;
}
diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c
index c290c71..199c8a3 100644
--- a/psycopg/cursor_type.c
+++ b/psycopg/cursor_type.c
@@ -768,7 +768,7 @@ curs_fetchone(cursorObject *self, PyObject *dummy)
Dprintf("curs_fetchone: rowcount = %ld", self->rowcount);
if (self->row >= self->rowcount) {
- /* we exausted available data: return None */
+ /* we exhausted available data: return None */
Py_RETURN_NONE;
}
diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c
index 9aebfb8..acb6781 100644
--- a/psycopg/psycopgmodule.c
+++ b/psycopg/psycopgmodule.c
@@ -592,6 +592,10 @@ encodings_init(PyObject *module)
int rv = -1;
Dprintf("psycopgmodule: initializing encodings table");
+ if (psycoEncodings) {
+ Dprintf("encodings_init(): already called");
+ return 0;
+ }
if (!(psycoEncodings = PyDict_New())) { goto exit; }
Py_INCREF(psycoEncodings);
@@ -754,9 +758,8 @@ sqlstate_errors_init(PyObject *module)
Dprintf("psycopgmodule: initializing sqlstate exceptions");
if (sqlstate_errors) {
- PyErr_SetString(PyExc_SystemError,
- "sqlstate_errors_init(): already called");
- goto exit;
+ Dprintf("sqlstate_errors_init(): already called");
+ return 0;
}
if (!(errmodule = PyImport_ImportModule("psycopg2.errors"))) {
/* don't inject the exceptions into the errors module */
diff --git a/psycopg/xid_type.c b/psycopg/xid_type.c
index a4e05cb..2ac36ed 100644
--- a/psycopg/xid_type.c
+++ b/psycopg/xid_type.c
@@ -598,7 +598,7 @@ xid_recover(PyObject *conn)
/* curs = conn.cursor()
* (sort of. Use the real cursor in case the connection returns
- * somenthing non-dbapi -- see ticket #114) */
+ * something non-dbapi -- see ticket #114) */
if (!(curs = PyObject_CallFunctionObjArgs(
(PyObject *)&cursorType, conn, NULL))) { goto exit; }
diff --git a/scripts/make_errorcodes.py b/scripts/make_errorcodes.py
index 0c07f37..6152db7 100755
--- a/scripts/make_errorcodes.py
+++ b/scripts/make_errorcodes.py
@@ -76,7 +76,7 @@ def parse_errors_txt(url):
m = re.match(r"(.....)\s+(?:E|W|S)\s+ERRCODE_(\S+)(?:\s+(\S+))?$", line)
if m:
errcode, macro, spec = m.groups()
- # skip errcodes without specs as they are not publically visible
+ # skip errcodes without specs as they are not publicly visible
if not spec:
continue
errlabel = spec.upper()
diff --git a/scripts/make_errors.py b/scripts/make_errors.py
index 0b795fa..0b4f0b1 100755
--- a/scripts/make_errors.py
+++ b/scripts/make_errors.py
@@ -60,7 +60,7 @@ def parse_errors_txt(url):
m = re.match(r"(.....)\s+(?:E|W|S)\s+ERRCODE_(\S+)(?:\s+(\S+))?$", line)
if m:
errcode, macro, spec = m.groups()
- # skip errcodes without specs as they are not publically visible
+ # skip errcodes without specs as they are not publicly visible
if not spec:
continue
errlabel = spec.upper()
diff --git a/tests/dbapi20.py b/tests/dbapi20.py
index 5a98b4a..a5e12c5 100644
--- a/tests/dbapi20.py
+++ b/tests/dbapi20.py
@@ -64,7 +64,7 @@ import sys
# - self.populate is now self._populate(), so if a driver stub
# overrides self.ddl1 this change propagates
# - VARCHAR columns now have a width, which will hopefully make the
-# DDL even more portible (this will be reversed if it causes more problems)
+# DDL even more portable (this will be reversed if it causes more problems)
# - cursor.rowcount being checked after various execute and fetchXXX methods
# - Check for fetchall and fetchmany returning empty lists after results
# are exhausted (already checking for empty lists if select retrieved
@@ -76,7 +76,7 @@ class DatabaseAPI20Test(unittest.TestCase):
''' Test a database self.driver for DB API 2.0 compatibility.
This implementation tests Gadfly, but the TestCase
is structured so that other self.drivers can subclass this
- test case to ensure compiliance with the DB-API. It is
+ test case to ensure compliance with the DB-API. It is
expected that this TestCase may be expanded in the future
if ambiguities or edge conditions are discovered.
diff --git a/tests/test_connection.py b/tests/test_connection.py
index 8281c1c..96a8301 100755
--- a/tests/test_connection.py
+++ b/tests/test_connection.py
@@ -1238,7 +1238,7 @@ class ConnectionTwoPhaseTests(ConnectingTestCase):
def test_xid_unicode_unparsed(self):
# We don't expect people shooting snowmen as transaction ids,
# so if something explodes in an encode error I don't mind.
- # Let's just check uniconde is accepted as type.
+ # Let's just check unicode is accepted as type.
cnn = self.connect()
cnn.set_client_encoding('utf8')
cnn.tpc_begin("transaction-id")
@@ -1513,6 +1513,7 @@ class TestEncryptPassword(ConnectingTestCase):
scope=self.conn, algorithm='md5'),
'md594839d658c28a357126f105b9cb14cfc')
+ @skip_if_crdb("password_encryption")
@skip_before_libpq(10)
@skip_before_postgres(10)
def test_encrypt_server(self):
diff --git a/tests/test_cursor.py b/tests/test_cursor.py
index 391af56..0549e3c 100755
--- a/tests/test_cursor.py
+++ b/tests/test_cursor.py
@@ -249,6 +249,16 @@ class CursorTests(ConnectingTestCase):
self.assertEqual(description, unpickled)
+ def test_column_refcount(self):
+ # Reproduce crash describe in ticket #1252
+ from psycopg2.extensions import Column
+
+ def do_stuff():
+ _ = Column(name='my_column')
+
+ for _ in range(1000):
+ do_stuff()
+
def test_bad_subclass(self):
# check that we get an error message instead of a segfault
# for badly written subclasses.
diff --git a/tests/test_module.py b/tests/test_module.py
index 717cf50..5b47ba2 100755
--- a/tests/test_module.py
+++ b/tests/test_module.py
@@ -50,12 +50,22 @@ class ConnectTestCase(unittest.TestCase):
def tearDown(self):
psycopg2._connect = self._connect_orig
- def test_there_has_to_be_something(self):
- self.assertRaises(TypeError, psycopg2.connect)
- self.assertRaises(TypeError, psycopg2.connect,
+ def test_there_might_be_nothing(self):
+ psycopg2.connect()
+ self.assertEqual(self.args[0], '')
+ self.assertEqual(self.args[1], None)
+ self.assertEqual(self.args[2], False)
+
+ psycopg2.connect(
connection_factory=lambda dsn, async_=False: None)
- self.assertRaises(TypeError, psycopg2.connect,
- async_=True)
+ self.assertEqual(self.args[0], '')
+ self.assertNotEqual(self.args[1], None)
+ self.assertEqual(self.args[2], False)
+
+ psycopg2.connect(async_=True)
+ self.assertEqual(self.args[0], '')
+ self.assertEqual(self.args[1], None)
+ self.assertEqual(self.args[2], True)
def test_no_keywords(self):
psycopg2.connect('')
@@ -280,6 +290,7 @@ class ExceptionsTestCase(ConnectingTestCase):
self.assertEqual(e.diag.constraint_name, "chk_eq1")
self.assertEqual(e.diag.datatype_name, None)
+ @skip_if_crdb("diagnostic")
@skip_before_postgres(9, 6)
def test_9_6_diagnostics(self):
cur = self.conn.cursor()
diff --git a/tests/testutils.py b/tests/testutils.py
index 865416c..f0c3264 100644
--- a/tests/testutils.py
+++ b/tests/testutils.py
@@ -478,6 +478,7 @@ crdb_reasons = {
"named cursor": 41412,
"nested array": 32552,
"notify": 41522,
+ "password_encryption": 42519,
"range": 41282,
"stored procedure": 1751,
}