Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-psycopg2 for openSUSE:Factory checked in at 2022-11-01 13:42:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-psycopg2 (Old) and /work/SRC/openSUSE:Factory/.python-psycopg2.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-psycopg2" Tue Nov 1 13:42:13 2022 rev:41 rq:1032498 version:2.9.5 Changes: -------- --- /work/SRC/openSUSE:Factory/python-psycopg2/python-psycopg2.changes 2021-12-30 15:56:07.036686774 +0100 +++ /work/SRC/openSUSE:Factory/.python-psycopg2.new.2275/python-psycopg2.changes 2022-11-01 13:42:23.991842340 +0100 @@ -1,0 +2,20 @@ +Fri Oct 28 19:56:31 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to 2.9.5 + * Add support for Python 3.11. + * Add support for rowcount in MERGE statements in binary packages + (ticket`#1497`). + * Wheel package compiled against OpenSSL 1.1.1r and PostgreSQL 15 libpq. + +- Update to 2.9.4 + * Fix `~psycopg2.extras.register_composite()`, + `~psycopg2.extras.register_range()` with customized search_path + (ticket`#1487`). + * Handle correctly composite types with names or in schemas requiring escape. + * Find ``pg_service.conf file in the ``/etc/postgresql-common`` directory in + binary packages (ticket`1365`). + * `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to + PostgreSQL 15. + * Wheel package compiled against OpenSSL 1.1.1q and PostgreSQL 14.4 + +------------------------------------------------------------------- Old: ---- psycopg2-2.9.3.tar.gz New: ---- psycopg2-2.9.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-psycopg2.spec ++++++ --- /var/tmp/diff_new_pack.es5zoI/_old 2022-11-01 13:42:24.419844618 +0100 +++ /var/tmp/diff_new_pack.es5zoI/_new 2022-11-01 13:42:24.423844640 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-psycopg2 # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-psycopg2 -Version: 2.9.3 +Version: 2.9.5 Release: 0 Summary: Python-PostgreSQL Database Adapter License: LGPL-3.0-or-later AND (LGPL-3.0-or-later OR ZPL-2.0) AND SUSE-GPL-2.0-with-openssl-exception ++++++ psycopg2-2.9.3.tar.gz -> psycopg2-2.9.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/NEWS new/psycopg2-2.9.5/NEWS --- old/psycopg2-2.9.3/NEWS 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/NEWS 2022-10-25 13:05:48.000000000 +0200 @@ -1,10 +1,34 @@ Current release --------------- +What's new in psycopg 2.9.5 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Add support for Python 3.11. +- Add support for rowcount in MERGE statements in binary packages + (:ticket:`#1497`). +- Wheel package compiled against OpenSSL 1.1.1r and PostgreSQL 15 libpq. + + +What's new in psycopg 2.9.4 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Fix `~psycopg2.extras.register_composite()`, + `~psycopg2.extras.register_range()` with customized :sql:`search_path` + (:ticket:`#1487`). +- Handle correctly composite types with names or in schemas requiring escape. +- Find ``pg_service.conf`` file in the ``/etc/postgresql-common`` directory in + binary packages (:ticket:`#1365`). +- `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to + PostgreSQL 15. +- Wheel package compiled against OpenSSL 1.1.1q and PostgreSQL 14.4 libpq. + + What's new in psycopg 2.9.3 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- Alpine (musl) wheels now available (:ticket:`#1148`). +- Alpine (musl) wheels now available (:ticket:`#1392`). +- macOS arm64 (Apple M1) wheels now available (:ticket:`1482`). What's new in psycopg 2.9.2 @@ -14,14 +38,14 @@ - `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to PostgreSQL 14. - Add preliminary support for Python 3.11 (:tickets:`#1376, #1386`). -- Wheel package compiled against OpenSSL 1.1.1l and PostgreSQL 14.1 +- Wheel package compiled against OpenSSL 1.1.1l and PostgreSQL 14.1 libpq (:ticket:`#1388`). What's new in psycopg 2.9.1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Fix regression with named `sql.Placeholder` (:ticket:`#1291`). +- Fix regression with named `~psycopg2.sql.Placeholder` (:ticket:`#1291`). What's new in psycopg 2.9 @@ -51,7 +75,7 @@ platforms. - Provide :pep:`600` wheels packages (manylinux_2_24 tag) for aarch64 and ppc64le platforms. -- Wheel package compiled against OpenSSL 1.1.1k and PostgreSQL 13.3. +- Wheel package compiled against OpenSSL 1.1.1k and PostgreSQL 13.3 libpq. - Build system for Linux/MacOS binary packages moved to GitHub Actions. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/PKG-INFO new/psycopg2-2.9.5/PKG-INFO --- old/psycopg2-2.9.3/PKG-INFO 2021-12-29 13:51:57.495733500 +0100 +++ new/psycopg2-2.9.5/PKG-INFO 2022-10-25 13:05:49.455371100 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: psycopg2 -Version: 2.9.3 +Version: 2.9.5 Summary: psycopg2 - Python-PostgreSQL Database Adapter Home-page: https://psycopg.org/ Author: Federico Di Gregorio @@ -95,6 +95,7 @@ Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: C diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/doc/requirements.txt new/psycopg2-2.9.5/doc/requirements.txt --- old/psycopg2-2.9.3/doc/requirements.txt 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/doc/requirements.txt 2022-10-25 13:05:48.000000000 +0200 @@ -1,8 +1,58 @@ -# Packages only needed to build the docs -Pygments>=2.2,<2.3 -Sphinx>=1.6,<=1.7 -sphinx-better-theme>=0.1.5,<0.2 - -# 0.15.2 affected by https://sourceforge.net/p/docutils/bugs/353/ -# Can update to 0.16 after release (currently in rc) but must update Sphinx too -docutils<0.15 +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile requirements.in +# +alabaster==0.7.12 + # via sphinx +babel==2.9.1 + # via sphinx +certifi==2021.10.8 + # via requests +charset-normalizer==2.0.12 + # via requests +docutils==0.17.1 + # via sphinx +idna==3.3 + # via requests +imagesize==1.3.0 + # via sphinx +importlib-metadata==4.11.3 + # via sphinx +jinja2==3.1.1 + # via sphinx +markupsafe==2.1.1 + # via jinja2 +packaging==21.3 + # via sphinx +pygments==2.11.2 + # via sphinx +pyparsing==3.0.7 + # via packaging +pytz==2022.1 + # via babel +requests==2.27.1 + # via sphinx +snowballstemmer==2.2.0 + # via sphinx +sphinx==4.4.0 + # via -r requirements.in +sphinx-better-theme==0.1.5 + # via -r requirements.in +sphinxcontrib-applehelp==1.0.2 + # via sphinx +sphinxcontrib-devhelp==1.0.2 + # via sphinx +sphinxcontrib-htmlhelp==2.0.0 + # via sphinx +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.3 + # via sphinx +sphinxcontrib-serializinghtml==1.1.5 + # via sphinx +urllib3==1.26.9 + # via requests +zipp==3.7.0 + # via importlib-metadata diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/cursor.rst new/psycopg2-2.9.5/doc/src/cursor.rst --- old/psycopg2-2.9.3/doc/src/cursor.rst 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/doc/src/cursor.rst 2022-10-25 13:05:48.000000000 +0200 @@ -208,6 +208,14 @@ Parameters are bounded to the query using the same rules described in the `~cursor.execute()` method. + .. code:: python + + >>> nums = ((1,), (5,), (10,)) + >>> cur.executemany("INSERT INTO test (num) VALUES (%s)", nums) + + >>> tuples = ((123, "foo"), (42, "bar"), (23, "baz")) + >>> cur.executemany("INSERT INTO test (num, data) VALUES (%s, %s)", tuples) + .. warning:: In its current implementation this method is not faster than executing `~cursor.execute()` in a loop. For better performance diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/errorcodes.rst new/psycopg2-2.9.5/doc/src/errorcodes.rst --- old/psycopg2-2.9.3/doc/src/errorcodes.rst 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/doc/src/errorcodes.rst 2022-10-25 13:05:48.000000000 +0200 @@ -50,7 +50,7 @@ '42P01' Constants representing all the error values defined by PostgreSQL versions -between 8.1 and 13 are included in the module. +between 8.1 and 15 are included in the module. .. autofunction:: lookup(code) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/errors.rst new/psycopg2-2.9.5/doc/src/errors.rst --- old/psycopg2-2.9.3/doc/src/errors.rst 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/doc/src/errors.rst 2022-10-25 13:05:48.000000000 +0200 @@ -14,11 +14,15 @@ .. versionchanged:: 2.8.6 added errors introduced in PostgreSQL 13 +.. versionchanged:: 2.9.2 added errors introduced in PostgreSQL 14 + +.. versionchanged:: 2.9.4 added errors introduced in PostgreSQL 15 + This module exposes the classes psycopg raises upon receiving an error from the database with a :sql:`SQLSTATE` value attached (available in the `~psycopg2.Error.pgcode` attribute). The content of the module is generated from the PostgreSQL source code and includes classes for every error defined -by PostgreSQL in versions between 9.1 and 13. +by PostgreSQL in versions between 9.1 and 15. Every class in the module is named after what referred as "condition name" `in the documentation`__, converted to CamelCase: e.g. the error 22012, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/extras.rst new/psycopg2-2.9.5/doc/src/extras.rst --- old/psycopg2-2.9.3/doc/src/extras.rst 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/doc/src/extras.rst 2022-10-25 13:05:48.000000000 +0200 @@ -1029,6 +1029,14 @@ .. autofunction:: execute_batch + .. code:: python + + >>> nums = ((1,), (5,), (10,)) + >>> execute_batch(cur, "INSERT INTO test (num) VALUES (%s)", nums) + + >>> tuples = ((123, "foo"), (42, "bar"), (23, "baz")) + >>> execute_batch(cur, "INSERT INTO test (num, data) VALUES (%s, %s)", tuples) + .. versionadded:: 2.7 .. note:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/install.rst new/psycopg2-2.9.5/doc/src/install.rst --- old/psycopg2-2.9.3/doc/src/install.rst 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/doc/src/install.rst 2022-10-25 13:05:48.000000000 +0200 @@ -131,10 +131,17 @@ .. NOTE: keep consistent with setup.py and the /features/ page. -- Python versions from 3.6 to 3.10 -- PostgreSQL server versions from 7.4 to 14 +- Python versions from 3.6 to 3.11 +- PostgreSQL server versions from 7.4 to 15 - PostgreSQL client library version from 9.1 +.. note:: + + Not all the psycopg2 versions support all the supported Python versions. + + Please see the :ref:`release notes <news>` to verify when the support for + a new Python version was added and when the support for an old Python + version was removed. .. _build-prerequisites: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/news.rst new/psycopg2-2.9.5/doc/src/news.rst --- old/psycopg2-2.9.3/doc/src/news.rst 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/doc/src/news.rst 2022-10-25 13:05:48.000000000 +0200 @@ -2,6 +2,8 @@ single: Release notes single: News +.. _news: + Release notes ============= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/sql.rst new/psycopg2-2.9.5/doc/src/sql.rst --- old/psycopg2-2.9.3/doc/src/sql.rst 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/doc/src/sql.rst 2022-10-25 13:05:48.000000000 +0200 @@ -33,7 +33,7 @@ # This works, but it is not optimal table_name = 'my_table' cur.execute( - "insert into %s values (%%s, %%s)" % ext.quote_ident(table_name), + "insert into %s values (%%s, %%s)" % ext.quote_ident(table_name, cur), [10, 20]) This is now safe, but it somewhat ad-hoc. In case, for some reason, it is diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/lib/_range.py new/psycopg2-2.9.5/lib/_range.py --- old/psycopg2-2.9.3/lib/_range.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/lib/_range.py 2022-10-25 13:05:48.000000000 +0200 @@ -143,10 +143,6 @@ def __bool__(self): return self._bounds is not None - def __nonzero__(self): - # Python 2 compatibility - return type(self).__bool__(self) - def __eq__(self, other): if not isinstance(other, Range): return False @@ -367,33 +363,54 @@ schema = 'public' # get the type oid and attributes - try: - curs.execute("""\ -select rngtypid, rngsubtype, - (select typarray from pg_type where oid = rngtypid) + curs.execute("""\ +select rngtypid, rngsubtype, typarray from pg_range r join pg_type t on t.oid = rngtypid join pg_namespace ns on ns.oid = typnamespace where typname = %s and ns.nspname = %s; """, (tname, schema)) + rec = curs.fetchone() - except ProgrammingError: - if not conn.autocommit: - conn.rollback() - raise - else: - rec = curs.fetchone() + if not rec: + # The above algorithm doesn't work for customized seach_path + # (#1487) The implementation below works better, but, to guarantee + # backwards compatibility, use it only if the original one failed. + try: + savepoint = False + # Because we executed statements earlier, we are either INTRANS + # or we are IDLE only if the transaction is autocommit, in + # which case we don't need the savepoint anyway. + if conn.status == STATUS_IN_TRANSACTION: + curs.execute("SAVEPOINT register_type") + savepoint = True - # revert the status of the connection as before the command - if (conn_status != STATUS_IN_TRANSACTION - and not conn.autocommit): - conn.rollback() + curs.execute("""\ +SELECT rngtypid, rngsubtype, typarray, typname, nspname +from pg_range r +join pg_type t on t.oid = rngtypid +join pg_namespace ns on ns.oid = typnamespace +WHERE t.oid = %s::regtype +""", (name, )) + except ProgrammingError: + pass + else: + rec = curs.fetchone() + if rec: + tname, schema = rec[3:] + finally: + if savepoint: + curs.execute("ROLLBACK TO SAVEPOINT register_type") + + # revert the status of the connection as before the command + if conn_status != STATUS_IN_TRANSACTION and not conn.autocommit: + conn.rollback() if not rec: raise ProgrammingError( - f"PostgreSQL type '{name}' not found") + f"PostgreSQL range '{name}' not found") - type, subtype, array = rec + type, subtype, array = rec[:3] return RangeCaster(name, pyrange, oid=type, subtype_oid=subtype, array_oid=array) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/lib/errorcodes.py new/psycopg2-2.9.5/lib/errorcodes.py --- old/psycopg2-2.9.3/lib/errorcodes.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/lib/errorcodes.py 2022-10-25 13:05:48.000000000 +0200 @@ -223,6 +223,7 @@ TOO_MANY_JSON_ARRAY_ELEMENTS = '2203D' TOO_MANY_JSON_OBJECT_MEMBERS = '2203E' SQL_JSON_SCALAR_REQUIRED = '2203F' +SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE = '2203G' FLOATING_POINT_EXCEPTION = '22P01' INVALID_TEXT_REPRESENTATION = '22P02' INVALID_BINARY_REPRESENTATION = '22P03' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/lib/extras.py new/psycopg2-2.9.5/lib/extras.py --- old/psycopg2-2.9.3/lib/extras.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/lib/extras.py 2022-10-25 13:05:48.000000000 +0200 @@ -357,10 +357,6 @@ except StopIteration: return - # ascii except alnum and underscore - _re_clean = _re.compile( - '[' + _re.escape(' !"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~') + ']') - def _make_nt(self): key = tuple(d[0] for d in self.description) if self.description else () return self._cached_make_nt(key) @@ -369,7 +365,7 @@ def _do_make_nt(cls, key): fields = [] for s in key: - s = cls._re_clean.sub('_', s) + s = _re_clean.sub('_', s) # Python identifier cannot start with numbers, namedtuple fields # cannot start with underscore. So... if s[0] == '_' or '0' <= s[0] <= '9': @@ -1061,6 +1057,7 @@ return rv def _create_type(self, name, attnames): + name = _re_clean.sub('_', name) self.type = namedtuple(name, attnames) self._ctor = self.type._make @@ -1098,9 +1095,41 @@ recs = curs.fetchall() + if not recs: + # The above algorithm doesn't work for customized seach_path + # (#1487) The implementation below works better, but, to guarantee + # backwards compatibility, use it only if the original one failed. + try: + savepoint = False + # Because we executed statements earlier, we are either INTRANS + # or we are IDLE only if the transaction is autocommit, in + # which case we don't need the savepoint anyway. + if conn.status == _ext.STATUS_IN_TRANSACTION: + curs.execute("SAVEPOINT register_type") + savepoint = True + + curs.execute("""\ +SELECT t.oid, %s, attname, atttypid, typname, nspname +FROM pg_type t +JOIN pg_namespace ns ON typnamespace = ns.oid +JOIN pg_attribute a ON attrelid = typrelid +WHERE t.oid = %%s::regtype + AND attnum > 0 AND NOT attisdropped +ORDER BY attnum; +""" % typarray, (name, )) + except psycopg2.ProgrammingError: + pass + else: + recs = curs.fetchall() + if recs: + tname = recs[0][4] + schema = recs[0][5] + finally: + if savepoint: + curs.execute("ROLLBACK TO SAVEPOINT register_type") + # revert the status of the connection as before the command - if (conn_status != _ext.STATUS_IN_TRANSACTION - and not conn.autocommit): + if conn_status != _ext.STATUS_IN_TRANSACTION and not conn.autocommit: conn.rollback() if not recs: @@ -1304,3 +1333,8 @@ raise ValueError("the query doesn't contain any '%s' placeholder") return pre, post + + +# ascii except alnum and underscore +_re_clean = _re.compile( + '[' + _re.escape(' !"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~') + ']') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/psycopg/sqlstate_errors.h new/psycopg2-2.9.5/psycopg/sqlstate_errors.h --- old/psycopg2-2.9.3/psycopg/sqlstate_errors.h 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/psycopg/sqlstate_errors.h 2022-10-25 13:05:48.000000000 +0200 @@ -111,6 +111,7 @@ {"2203D", "TooManyJsonArrayElements"}, {"2203E", "TooManyJsonObjectMembers"}, {"2203F", "SqlJsonScalarRequired"}, +{"2203G", "SqlJsonItemCannotBeCastToTargetType"}, {"22P01", "FloatingPointException"}, {"22P02", "InvalidTextRepresentation"}, {"22P03", "InvalidBinaryRepresentation"}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/psycopg2.egg-info/PKG-INFO new/psycopg2-2.9.5/psycopg2.egg-info/PKG-INFO --- old/psycopg2-2.9.3/psycopg2.egg-info/PKG-INFO 2021-12-29 13:51:57.000000000 +0100 +++ new/psycopg2-2.9.5/psycopg2.egg-info/PKG-INFO 2022-10-25 13:05:49.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: psycopg2 -Version: 2.9.3 +Version: 2.9.5 Summary: psycopg2 - Python-PostgreSQL Database Adapter Home-page: https://psycopg.org/ Author: Federico Di Gregorio @@ -95,6 +95,7 @@ Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: C diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/psycopg2.egg-info/SOURCES.txt new/psycopg2-2.9.5/psycopg2.egg-info/SOURCES.txt --- old/psycopg2-2.9.3/psycopg2.egg-info/SOURCES.txt 2021-12-29 13:51:57.000000000 +0100 +++ new/psycopg2-2.9.5/psycopg2.egg-info/SOURCES.txt 2022-10-25 13:05:49.000000000 +0200 @@ -138,12 +138,14 @@ scripts/build/appveyor.py scripts/build/build_libpq.sh scripts/build/build_macos.sh +scripts/build/build_macos_arm64.sh scripts/build/build_manylinux2014.sh scripts/build/build_manylinux_2_24.sh scripts/build/build_musllinux_1_1.sh scripts/build/build_sdist.sh scripts/build/download_packages_appveyor.py scripts/build/download_packages_github.py +scripts/build/run_build_macos_arm64.sh scripts/build/strip_wheel.sh tests/__init__.py tests/dbapi20.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/scripts/build/build_libpq.sh new/psycopg2-2.9.5/scripts/build/build_libpq.sh --- old/psycopg2-2.9.3/scripts/build/build_libpq.sh 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/scripts/build/build_libpq.sh 2022-10-25 13:05:48.000000000 +0200 @@ -5,10 +5,14 @@ set -euo pipefail set -x -openssl_version="1.1.1l" +# Last release: https://www.postgresql.org/ftp/source/ +postgres_version="15.0" +# last release: https://www.openssl.org/source/ +openssl_version="1.1.1r" +# last release: https://openldap.org/software/download/ ldap_version="2.4.59" -sasl_version="2.1.27" -postgres_version="14.1" +# last release: https://github.com/cyrusimap/cyrus-sasl/releases +sasl_version="2.1.28" yum install -y zlib-devel krb5-devel pam-devel @@ -113,7 +117,8 @@ fi ./configure --prefix=/usr/local --without-readline \ - --with-gssapi --with-openssl --with-pam --with-ldap + --with-gssapi --with-openssl --with-pam --with-ldap \ + --sysconfdir=/etc/postgresql-common make -C src/interfaces/libpq make -C src/bin/pg_config make -C src/include diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/scripts/build/build_macos_arm64.sh new/psycopg2-2.9.5/scripts/build/build_macos_arm64.sh --- old/psycopg2-2.9.3/scripts/build/build_macos_arm64.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/psycopg2-2.9.5/scripts/build/build_macos_arm64.sh 2022-10-25 13:05:48.000000000 +0200 @@ -0,0 +1,85 @@ +#!/bin/bash + +# Build psycopg2-binary wheel packages for Apple M1 (cpNNN-macosx_arm64) +# +# This script is designed to run on Scaleway Apple Silicon machines. +# +# The script cannot be run as sudo (installing brew fails), but requires sudo, +# so it can pretty much only be executed by a sudo user as it is. + +set -euo pipefail +set -x + +python_versions="3.8.10 3.9.13 3.10.5 3.11" +postgres_version=15 + +# Move to the root of the project +dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "${dir}/../../" + +# Add /usr/local/bin to the path. It seems it's not, in non-interactive sessions +if ! (echo $PATH | grep -q '/usr/local/bin'); then + export PATH=/usr/local/bin:$PATH +fi + +# Install brew, if necessary. Otherwise just make sure it's in the path +if [[ -x /opt/homebrew/bin/brew ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" +else + command -v brew > /dev/null || ( + # Not necessary: already installed + # xcode-select --install + NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL \ + https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + ) + eval "$(/opt/homebrew/bin/brew shellenv)" +fi + +# Install PostgreSQL, if necessary +command -v pg_config > /dev/null || ( + brew install postgresql@${postgres_version} + # Currently not working + # brew services start postgresql@${postgres_version} + pg_ctl \ + -D /opt/homebrew/var/postgresql@${postgres_version} \ + -l /opt/homebrew/var/log/postgresql@${postgres_version}.log \ + start +) + +# Install the Python versions we want to build +for ver3 in $python_versions; do + ver2=$(echo $ver3 | sed 's/\([^\.]*\)\(\.[^\.]*\)\(.*\)/\1\2/') + command -v python${ver2} > /dev/null || ( + (cd /tmp && + curl -fsSl -O \ + https://www.python.org/ftp/python/${ver3}/python-${ver3}-macos11.pkg) + sudo installer -pkg /tmp/python-${ver3}-macos11.pkg -target / + ) +done + +# Create a virtualenv where to work +if [[ ! -x .venv/bin/python ]]; then + python3 -m venv .venv +fi + +source .venv/bin/activate +pip install cibuildwheel + +# Build the binary packages +export CIBW_PLATFORM=macos +export CIBW_ARCHS=arm64 +export CIBW_BUILD='cp{38,39,310}-*' +export CIBW_TEST_COMMAND='python -c "import tests; tests.unittest.main(defaultTest=\"tests.test_suite\")"' + +export PSYCOPG2_TESTDB=postgres +export PYTHONPATH=$(pwd) + +# For some reason, cibuildwheel tests says that psycopg2 is already installed, +# refuses to install, then promptly fails import. So, please, seriously, +# install this thing. +export PIP_FORCE_REINSTALL=1 + +# Replace the package name +sed -i .bak 's/^setup(name="psycopg2"/setup(name="psycopg2-binary"/' setup.py + +cibuildwheel diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/scripts/build/download_packages_appveyor.py new/psycopg2-2.9.5/scripts/build/download_packages_appveyor.py --- old/psycopg2-2.9.3/scripts/build/download_packages_appveyor.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/scripts/build/download_packages_appveyor.py 2022-10-25 13:05:48.000000000 +0200 @@ -69,7 +69,7 @@ fn = af["fileName"] if fn.startswith("dist/"): fn = fn.split("/", 1)[1] - dest = Path("packages") / fn + dest = Path("wheelhouse") / fn logger.info(f"downloading {dest}") resp = s.get( f"{API_URL}/buildjobs/{job['jobId']}/artifacts/{af['fileName']}" @@ -81,7 +81,7 @@ with dest.open("wb") as f: f.write(resp.content) - logger.info("now you can run: 'twine upload -s packages/*'") + logger.info("now you can run: 'twine upload -s wheelhouse/*'") def parse_cmdline(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/scripts/build/download_packages_github.py new/psycopg2-2.9.5/scripts/build/download_packages_github.py --- old/psycopg2-2.9.3/scripts/build/download_packages_github.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/scripts/build/download_packages_github.py 2022-10-25 13:05:48.000000000 +0200 @@ -57,7 +57,7 @@ resp.raise_for_status() artifacts = resp.json()["artifacts"] - dest = Path("packages") + dest = Path("wheelhouse") if not dest.exists(): logger.info(f"creating dir {dest}") dest.mkdir(parents=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/scripts/build/run_build_macos_arm64.sh new/psycopg2-2.9.5/scripts/build/run_build_macos_arm64.sh --- old/psycopg2-2.9.3/scripts/build/run_build_macos_arm64.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/psycopg2-2.9.5/scripts/build/run_build_macos_arm64.sh 2022-10-25 13:05:48.000000000 +0200 @@ -0,0 +1,40 @@ +#!/bin/bash + +# Build psycopg2-binary wheel packages for Apple M1 (cpNNN-macosx_arm64) +# +# This script is designed to run on a local machine: it will clone the repos +# remotely and execute the `build_macos_arm64.sh` script remotely, then will +# download the built packages. A tag to build must be specified. +# +# In order to run the script, the `m1` host must be specified in +# `~/.ssh/config`; for instance: +# +# Host m1 +# User m1 +# HostName 1.2.3.4 + +set -euo pipefail +# set -x + +tag=${1:-} + +if [[ ! "${tag}" ]]; then + echo "Usage: $0 TAG" >&2 + exit 2 +fi + +rdir=psycobuild + +# Clone the repos +ssh m1 rm -rf "${rdir}" +ssh m1 git clone https://github.com/psycopg/psycopg2.git --branch ${tag} "${rdir}" + +# Allow sudoing without password, to allow brew to install +ssh -t m1 bash -c \ + 'test -f /etc/sudoers.d/m1 || echo "m1 ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/m1' + +# Build the wheel packages +ssh m1 "${rdir}/scripts/build/build_macos_arm64.sh" + +# Transfer the packages locally +scp -r "m1:${rdir}/wheelhouse" . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/scripts/make_errorcodes.py new/psycopg2-2.9.5/scripts/make_errorcodes.py --- old/psycopg2-2.9.3/scripts/make_errorcodes.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/scripts/make_errorcodes.py 2022-10-25 13:05:48.000000000 +0200 @@ -33,7 +33,7 @@ file_start = read_base_file(filename) # If you add a version to the list fix the docs (in errorcodes.rst) classes, errors = fetch_errors( - ['9.1', '9.2', '9.3', '9.4', '9.5', '9.6', '10', '11', '12', '13', '14']) + '9.1 9.2 9.3 9.4 9.5 9.6 10 11 12 13 14 15'.split()) disambiguate(errors) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/scripts/make_errors.py new/psycopg2-2.9.5/scripts/make_errors.py --- old/psycopg2-2.9.3/scripts/make_errors.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/scripts/make_errors.py 2022-10-25 13:05:48.000000000 +0200 @@ -30,7 +30,7 @@ # If you add a version to the list fix the docs (in errors.rst) classes, errors = fetch_errors( - ['9.1', '9.2', '9.3', '9.4', '9.5', '9.6', '10', '11', '12', '13', '14']) + '9.1 9.2 9.3 9.4 9.5 9.6 10 11 12 13 14 15'.split()) f = open(filename, "w") print("/*\n * Autogenerated by 'scripts/make_errors.py'.\n */\n", file=f) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/setup.py new/psycopg2-2.9.5/setup.py --- old/psycopg2-2.9.3/setup.py 2021-12-29 13:51:57.000000000 +0100 +++ new/psycopg2-2.9.5/setup.py 2022-10-25 13:05:48.000000000 +0200 @@ -44,7 +44,7 @@ # Take a look at https://www.python.org/dev/peps/pep-0440/ # for a consistent versioning pattern. -PSYCOPG_VERSION = '2.9.3' +PSYCOPG_VERSION = '2.9.5' # note: if you are changing the list of supported Python version please fix @@ -60,6 +60,7 @@ Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 +Programming Language :: Python :: 3.11 Programming Language :: Python :: 3 :: Only Programming Language :: Python :: Implementation :: CPython Programming Language :: C diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_async.py new/psycopg2-2.9.5/tests/test_async.py --- old/psycopg2-2.9.3/tests/test_async.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/test_async.py 2022-10-25 13:05:48.000000000 +0200 @@ -390,6 +390,7 @@ # fetching from the correct cursor works self.assertEquals(cur1.fetchone()[0], 1) + @skip_if_crdb("batch statements", version="< 22.1") def test_error(self): cur = self.conn.cursor() cur.execute("insert into table1 values (%s)", (1, )) @@ -402,9 +403,8 @@ # this should fail as well (Postgres behaviour) self.assertRaises(psycopg2.IntegrityError, self.wait, cur) # but this should work - if crdb_version(self.sync_conn) is None: - cur.execute("insert into table1 values (%s)", (2, )) - self.wait(cur) + cur.execute("insert into table1 values (%s)", (2, )) + self.wait(cur) # and the cursor should be usable afterwards cur.execute("insert into table1 values (%s)", (3, )) self.wait(cur) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_connection.py new/psycopg2-2.9.5/tests/test_connection.py --- old/psycopg2-2.9.3/tests/test_connection.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/test_connection.py 2022-10-25 13:05:48.000000000 +0200 @@ -1928,11 +1928,16 @@ self.assertIsInstance(self.conn.info.ssl_attribute(attrib), str) else: for attrib in attribs: + # Behaviour changed in PostgreSQL 15 + if attrib == "library": + continue self.assertIsNone(self.conn.info.ssl_attribute(attrib)) self.assertIsNone(self.conn.info.ssl_attribute('wat')) for attrib in attribs: + if attrib == "library": + continue self.assertIsNone(self.bconn.info.ssl_attribute(attrib)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_cursor.py new/psycopg2-2.9.5/tests/test_cursor.py --- old/psycopg2-2.9.3/tests/test_cursor.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/test_cursor.py 2022-10-25 13:05:48.000000000 +0200 @@ -379,6 +379,12 @@ @skip_before_postgres(8, 2) def test_rowcount_on_executemany_returning(self): cur = self.conn.cursor() + try: + cur.execute("drop table execmany") + self.conn.commit() + except psycopg2.DatabaseError: + self.conn.rollback() + cur.execute("create table execmany(id serial primary key, data int)") cur.executemany( "insert into execmany (data) values (%s)", @@ -412,7 +418,7 @@ self.assert_(curs.pgresult_ptr is None) -@skip_if_crdb("named cursor") +@skip_if_crdb("named cursor", version="< 22.1") class NamedCursorTests(ConnectingTestCase): def test_invalid_name(self): curs = self.conn.cursor() @@ -436,6 +442,7 @@ curs.execute("insert into withhold values (%s)", (i,)) curs.close() + @skip_if_crdb("cursor with hold") def test_withhold(self): self.assertRaises(psycopg2.ProgrammingError, self.conn.cursor, withhold=True) @@ -460,6 +467,7 @@ curs.execute("drop table withhold") self.conn.commit() + @skip_if_crdb("cursor with hold") def test_withhold_no_begin(self): self._create_withhold_table() curs = self.conn.cursor("w", withhold=True) @@ -484,6 +492,7 @@ self.assertEqual(self.conn.info.transaction_status, psycopg2.extensions.TRANSACTION_STATUS_IDLE) + @skip_if_crdb("cursor with hold") def test_withhold_autocommit(self): self._create_withhold_table() self.conn.commit() @@ -506,6 +515,7 @@ self.assertEqual(self.conn.info.transaction_status, psycopg2.extensions.TRANSACTION_STATUS_IDLE) + @skip_if_crdb("scroll cursor") def test_scrollable(self): self.assertRaises(psycopg2.ProgrammingError, self.conn.cursor, scrollable=True) @@ -679,6 +689,7 @@ self.assertRaises((IndexError, psycopg2.ProgrammingError), cur.scroll, 1) + @skip_if_crdb("scroll cursor") @skip_before_postgres(8, 0) def test_scroll_named(self): cur = self.conn.cursor('tmp', scrollable=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_extras_dictcursor.py new/psycopg2-2.9.5/tests/test_extras_dictcursor.py --- old/psycopg2-2.9.3/tests/test_extras_dictcursor.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/test_extras_dictcursor.py 2022-10-25 13:05:48.000000000 +0200 @@ -64,7 +64,7 @@ class ExtrasDictCursorTests(_DictCursorBase): """Test if DictCursor extension class works.""" - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def testDictConnCursorArgs(self): self.conn.close() self.conn = self.connect(connection_factory=psycopg2.extras.DictConnection) @@ -132,19 +132,19 @@ return row self._testWithNamedCursor(getter) - @skip_if_crdb("named cursor") + @skip_if_crdb("greedy cursor") @skip_before_postgres(8, 2) def testDictCursorWithNamedCursorNotGreedy(self): curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.DictCursor) self._testNamedCursorNotGreedy(curs) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") @skip_before_postgres(8, 0) def testDictCursorWithNamedCursorIterRowNumber(self): curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.DictCursor) self._testIterRowNumber(curs) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def _testWithNamedCursor(self, getter): curs = self.conn.cursor('aname', cursor_factory=psycopg2.extras.DictCursor) curs.execute("SELECT * FROM ExtrasDictCursorTests") @@ -285,19 +285,19 @@ return row self._testWithNamedCursorReal(getter) - @skip_if_crdb("named cursor") + @skip_if_crdb("greedy cursor") @skip_before_postgres(8, 2) def testDictCursorRealWithNamedCursorNotGreedy(self): curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.RealDictCursor) self._testNamedCursorNotGreedy(curs) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") @skip_before_postgres(8, 0) def testDictCursorRealWithNamedCursorIterRowNumber(self): curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.RealDictCursor) self._testIterRowNumber(curs) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def _testWithNamedCursorReal(self, getter): curs = self.conn.cursor('aname', cursor_factory=psycopg2.extras.RealDictCursor) @@ -376,7 +376,7 @@ curs.execute("INSERT INTO nttest VALUES (3, 'baz')") self.conn.commit() - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def test_cursor_args(self): cur = self.conn.cursor('foo', cursor_factory=psycopg2.extras.DictCursor) self.assertEqual(cur.name, 'foo') @@ -533,7 +533,7 @@ finally: NamedTupleCursor._make_nt = f_orig - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") @skip_before_postgres(8, 0) def test_named(self): curs = self.conn.cursor('tmp') @@ -544,28 +544,28 @@ recs.extend(curs.fetchall()) self.assertEqual(list(range(10)), [t.i for t in recs]) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def test_named_fetchone(self): curs = self.conn.cursor('tmp') curs.execute("""select 42 as i""") t = curs.fetchone() self.assertEqual(t.i, 42) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def test_named_fetchmany(self): curs = self.conn.cursor('tmp') curs.execute("""select 42 as i""") recs = curs.fetchmany(10) self.assertEqual(recs[0].i, 42) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def test_named_fetchall(self): curs = self.conn.cursor('tmp') curs.execute("""select 42 as i""") recs = curs.fetchall() self.assertEqual(recs[0].i, 42) - @skip_if_crdb("named cursor") + @skip_if_crdb("greedy cursor") @skip_before_postgres(8, 2) def test_not_greedy(self): curs = self.conn.cursor('tmp') @@ -580,7 +580,7 @@ self.assert_(recs[1].ts - recs[0].ts < timedelta(seconds=0.005)) self.assert_(recs[2].ts - recs[1].ts > timedelta(seconds=0.0099)) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") @skip_before_postgres(8, 0) def test_named_rownumber(self): curs = self.conn.cursor('tmp') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_green.py new/psycopg2-2.9.5/tests/test_green.py --- old/psycopg2-2.9.3/tests/test_green.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/test_green.py 2022-10-25 13:05:48.000000000 +0200 @@ -219,7 +219,7 @@ self.fail("you should have had a success or an error by now") - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def test_errors_named_cursor(self): for i in range(100): self.to_error = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_types_basic.py new/psycopg2-2.9.5/tests/test_types_basic.py --- old/psycopg2-2.9.3/tests/test_types_basic.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/test_types_basic.py 2022-10-25 13:05:48.000000000 +0200 @@ -272,6 +272,8 @@ ]: curs.execute("select %s::int[]", (a,)) self.assertEqual(curs.fetchone()[0], a) + curs.execute("select array[%s::int[]]", (a,)) + self.assertEqual(curs.fetchone()[0], [a]) def testTypeRoundtripBytes(self): o1 = bytes(range(256)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_types_extras.py new/psycopg2-2.9.5/tests/test_types_extras.py --- old/psycopg2-2.9.3/tests/test_types_extras.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/test_types_extras.py 2022-10-25 13:05:48.000000000 +0200 @@ -585,6 +585,68 @@ self.assertEqual(curs.fetchone()[0], (4, 8)) @skip_if_no_composite + def test_composite_namespace_path(self): + curs = self.conn.cursor() + curs.execute(""" + select nspname from pg_namespace + where nspname = 'typens'; + """) + if not curs.fetchone(): + curs.execute("create schema typens;") + self.conn.commit() + + self._create_type("typens.typensp_ii", + [("a", "integer"), ("b", "integer")]) + curs.execute("set search_path=typens,public") + t = psycopg2.extras.register_composite( + "typensp_ii", self.conn) + self.assertEqual(t.schema, 'typens') + curs.execute("select (4,8)::typensp_ii") + self.assertEqual(curs.fetchone()[0], (4, 8)) + + @skip_if_no_composite + def test_composite_weird_name(self): + curs = self.conn.cursor() + curs.execute(""" + select nspname from pg_namespace + where nspname = 'qux.quux'; + """) + if not curs.fetchone(): + curs.execute('create schema "qux.quux";') + + self._create_type('"qux.quux"."foo.bar"', + [("a", "integer"), ("b", "integer")]) + t = psycopg2.extras.register_composite( + '"qux.quux"."foo.bar"', self.conn) + self.assertEqual(t.name, 'foo.bar') + self.assertEqual(t.schema, 'qux.quux') + curs.execute('select (4,8)::"qux.quux"."foo.bar"') + self.assertEqual(curs.fetchone()[0], (4, 8)) + + @skip_if_no_composite + def test_composite_not_found(self): + + self.assertRaises( + psycopg2.ProgrammingError, psycopg2.extras.register_composite, + "nosuchtype", self.conn) + self.assertEqual(self.conn.status, ext.STATUS_READY) + + cur = self.conn.cursor() + cur.execute("select 1") + self.assertRaises( + psycopg2.ProgrammingError, psycopg2.extras.register_composite, + "nosuchtype", self.conn) + + self.assertEqual(self.conn.status, ext.STATUS_IN_TRANSACTION) + + self.conn.rollback() + self.conn.autocommit = True + self.assertRaises( + psycopg2.ProgrammingError, psycopg2.extras.register_composite, + "nosuchtype", self.conn) + self.assertEqual(self.conn.status, ext.STATUS_READY) + + @skip_if_no_composite @skip_before_postgres(8, 4) def test_composite_array(self): self._create_type("type_isd", @@ -710,22 +772,15 @@ def _create_type(self, name, fields): curs = self.conn.cursor() try: + curs.execute("savepoint x") curs.execute(f"drop type {name} cascade;") except psycopg2.ProgrammingError: - self.conn.rollback() + curs.execute("rollback to savepoint x") curs.execute("create type {} as ({});".format(name, ", ".join(["%s %s" % p for p in fields]))) - if '.' in name: - schema, name = name.split('.') - else: - schema = 'public' - - curs.execute("""\ - SELECT t.oid - FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid - WHERE typname = %s and nspname = %s; - """, (name, schema)) + + curs.execute("SELECT %s::regtype::oid", (name, )) oid = curs.fetchone()[0] self.conn.commit() return oid @@ -1560,6 +1615,18 @@ cur = self.conn.cursor() self.assertRaises(psycopg2.ProgrammingError, register_range, 'nosuchrange', 'FailRange', cur) + self.assertEqual(self.conn.status, ext.STATUS_READY) + + cur.execute("select 1") + self.assertRaises(psycopg2.ProgrammingError, + register_range, 'nosuchrange', 'FailRange', cur) + + self.assertEqual(self.conn.status, ext.STATUS_IN_TRANSACTION) + + self.conn.rollback() + self.conn.autocommit = True + self.assertRaises(psycopg2.ProgrammingError, + register_range, 'nosuchrange', 'FailRange', cur) @restore_types def test_schema_range(self): @@ -1574,7 +1641,7 @@ register_range('r1', 'r1', cur) ra2 = register_range('r2', 'r2', cur) rars2 = register_range('rs.r2', 'r2', cur) - register_range('rs.r3', 'r3', cur) + rars3 = register_range('rs.r3', 'r3', cur) self.assertNotEqual( ra2.typecaster.values[0], @@ -1588,6 +1655,27 @@ register_range, 'rs.r1', 'FailRange', cur) cur.execute("rollback to savepoint x;") + cur2 = self.conn.cursor() + cur2.execute("set local search_path to rs,public") + ra3 = register_range('r3', 'r3', cur2) + self.assertEqual(ra3.typecaster.values[0], rars3.typecaster.values[0]) + + @skip_if_no_composite + def test_rang_weird_name(self): + cur = self.conn.cursor() + cur.execute(""" + select nspname from pg_namespace + where nspname = 'qux.quux'; + """) + if not cur.fetchone(): + cur.execute('create schema "qux.quux";') + + cur.execute('create type "qux.quux"."foo.range" as range (subtype=text)') + r = psycopg2.extras.register_range( + '"qux.quux"."foo.range"', "foorange", cur) + cur.execute('''select '[a,z]'::"qux.quux"."foo.range"''') + self.assertEqual(cur.fetchone()[0], r.range('a', 'z', '[]')) + def test_suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_with.py new/psycopg2-2.9.5/tests/test_with.py --- old/psycopg2-2.9.3/tests/test_with.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/test_with.py 2022-10-25 13:05:48.000000000 +0200 @@ -290,7 +290,7 @@ self.assert_(curs.closed) self.assert_(closes) - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") def test_exception_swallow(self): # bug #262: __exit__ calls cur.close() that hides the exception # with another error. @@ -304,7 +304,7 @@ else: self.fail("where is my exception?") - @skip_if_crdb("named cursor") + @skip_if_crdb("named cursor", version="< 22.1") @skip_before_postgres(8, 2) def test_named_with_noop(self): with self.conn.cursor('named'): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/psycopg2-2.9.3/tests/testutils.py new/psycopg2-2.9.5/tests/testutils.py --- old/psycopg2-2.9.3/tests/testutils.py 2021-12-29 13:51:56.000000000 +0100 +++ new/psycopg2-2.9.5/tests/testutils.py 2022-10-25 13:05:48.000000000 +0200 @@ -467,11 +467,13 @@ crdb_reasons = { "2-phase commit": 22329, "backend pid": 35897, + "batch statements": 44803, "cancel": 41335, "cast adds tz": 51692, "cidr": 18846, "composite": 27792, "copy": 41608, + "cursor with hold": 77101, "deferrable": 48307, "encoding": 35882, "hstore": 41284, @@ -483,6 +485,7 @@ "notify": 41522, "password_encryption": 42519, "range": 41282, + "scroll cursor": 77102, "stored procedure": 1751, }