From 78b83f8dbaf4a0b6ce637b52442d06f8abf53873 Mon Sep 17 00:00:00 2001 From: Elvis Pranskevichus Date: Tue, 16 Nov 2021 13:27:06 -0800 Subject: [PATCH 1/4] Fix `test_tls_version` in some environments The kinds of errors raised on invalid TLS configuration seem to differ between platforms. --- tests/test_connect.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/test_connect.py b/tests/test_connect.py index d66a087b..b78f4f48 100644 --- a/tests/test_connect.py +++ b/tests/test_connect.py @@ -1438,7 +1438,8 @@ async def test_executemany_uvloop_ssl_issue_700(self): await con.close() @unittest.skipIf( - sys.version_info < (3, 7), "Python < 3.7 doesn't have ssl.TLSVersion" + sys.version_info < (3, 7), + "Python < 3.7 doesn't have ssl.TLSVersion" ) async def test_tls_version(self): if self.cluster.get_pg_version() < (12, 0): @@ -1455,12 +1456,15 @@ async def test_tls_version(self): ) try: self.loop.set_exception_handler(lambda *args: None) - with self.assertRaisesRegex(ssl.SSLError, 'protocol version'): + with self.assertRaisesRegex( + ssl.SSLError, + '(protocol version)|(handshake failure)', + ): await self.connect( dsn='postgresql://ssl_user@localhost/postgres' '?sslmode=require&ssl_min_protocol_version=TLSv1.3' ) - with self.assertRaises(ssl.SSLError): + with self.assertRaises((ssl.SSLError, ConnectionResetError)): await self.connect( dsn='postgresql://ssl_user@localhost/postgres' '?sslmode=require' From 18f2aa4531dabf7bddd01fff5ebe03cfdac4d838 Mon Sep 17 00:00:00 2001 From: Elvis Pranskevichus Date: Tue, 16 Nov 2021 13:50:22 -0800 Subject: [PATCH 2/4] Fix compiler warnings --- asyncpg/pgproto | 2 +- asyncpg/protocol/codecs/range.pyx | 16 ++++++++++++++-- asyncpg/protocol/prepared_stmt.pyx | 4 ++-- asyncpg/protocol/protocol.pyx | 2 +- asyncpg/protocol/record/recordobj.c | 2 +- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/asyncpg/pgproto b/asyncpg/pgproto index 1720f8af..a4178145 160000 --- a/asyncpg/pgproto +++ b/asyncpg/pgproto @@ -1 +1 @@ -Subproject commit 1720f8af63725d79454884cfa787202a50eb5430 +Subproject commit a4178145cd7cc3a44eee20cfc9e8b94a7fed2053 diff --git a/asyncpg/protocol/codecs/range.pyx b/asyncpg/protocol/codecs/range.pyx index 4270d854..1038c18d 100644 --- a/asyncpg/protocol/codecs/range.pyx +++ b/asyncpg/protocol/codecs/range.pyx @@ -146,6 +146,8 @@ cdef multirange_encode(ConnectionSettings settings, WriteBuffer buf, encode_func_ex encoder, const void *encoder_arg): cdef: WriteBuffer elem_data + ssize_t elem_data_len + ssize_t elem_count if not isinstance(obj, SequenceABC): raise TypeError( @@ -157,10 +159,20 @@ cdef multirange_encode(ConnectionSettings settings, WriteBuffer buf, for elem in obj: range_encode(settings, elem_data, elem, elem_oid, encoder, encoder_arg) + elem_count = len(obj) + if elem_count > INT32_MAX: + raise OverflowError(f'too many elements in multirange value') + + elem_data_len = elem_data.len() + if elem_data_len > INT32_MAX - 4: + raise OverflowError( + f'size of encoded multirange datum exceeds the maximum allowed' + f' {INT32_MAX - 4} bytes') + # Datum length - buf.write_int32(4 + elem_data.len()) + buf.write_int32(4 + elem_data_len) # Number of elements in multirange - buf.write_int32(len(obj)) + buf.write_int32(elem_count) buf.write_buffer(elem_data) diff --git a/asyncpg/protocol/prepared_stmt.pyx b/asyncpg/protocol/prepared_stmt.pyx index 63466db8..b1f2a66d 100644 --- a/asyncpg/protocol/prepared_stmt.pyx +++ b/asyncpg/protocol/prepared_stmt.pyx @@ -151,7 +151,7 @@ cdef class PreparedStatementState: writer.write_int16(self.args_num) for idx in range(self.args_num): codec = (self.args_codecs[idx]) - writer.write_int16(codec.format) + writer.write_int16(codec.format) else: # All arguments are in binary format writer.write_int32(0x00010001) @@ -203,7 +203,7 @@ cdef class PreparedStatementState: writer.write_int16(self.cols_num) for idx in range(self.cols_num): codec = (self.rows_codecs[idx]) - writer.write_int16(codec.format) + writer.write_int16(codec.format) else: # All columns are in binary format writer.write_int32(0x00010001) diff --git a/asyncpg/protocol/protocol.pyx b/asyncpg/protocol/protocol.pyx index bb548962..3f512a81 100644 --- a/asyncpg/protocol/protocol.pyx +++ b/asyncpg/protocol/protocol.pyx @@ -38,7 +38,7 @@ from asyncpg.protocol cimport record from libc.stdint cimport int8_t, uint8_t, int16_t, uint16_t, \ int32_t, uint32_t, int64_t, uint64_t, \ - UINT32_MAX + INT32_MAX, UINT32_MAX from asyncpg.exceptions import _base as apg_exc_base from asyncpg import compat diff --git a/asyncpg/protocol/record/recordobj.c b/asyncpg/protocol/record/recordobj.c index e912782f..4bf34c8a 100644 --- a/asyncpg/protocol/record/recordobj.c +++ b/asyncpg/protocol/record/recordobj.c @@ -63,7 +63,7 @@ ApgRecord_New(PyTypeObject *type, PyObject *desc, Py_ssize_t size) return PyErr_NoMemory(); } o = (ApgRecordObject *)type->tp_alloc(type, size); - if (!_ApgObject_GC_IS_TRACKED(o)) { + if (!_ApgObject_GC_IS_TRACKED((PyObject *)o)) { PyErr_SetString( PyExc_TypeError, "record subclass is not tracked by GC" From 220d1d508a90a7db2a8172348561406a9316c3ca Mon Sep 17 00:00:00 2001 From: Elvis Pranskevichus Date: Tue, 16 Nov 2021 13:00:01 -0800 Subject: [PATCH 3/4] Release workflow updates * Add musllinux support * Build 32-bit packages for Windows (fixes #834) * Don't ship Cython-generated *.c files in wheels --- .github/workflows/install-postgres.sh | 4 ++++ .github/workflows/release.yml | 24 ++++++++---------------- Makefile | 1 + pyproject.toml | 24 ++++++++++++++++++++++++ setup.py | 10 +++++++--- tests/__init__.py | 2 +- 6 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 pyproject.toml diff --git a/.github/workflows/install-postgres.sh b/.github/workflows/install-postgres.sh index 70d42f60..c3f27186 100755 --- a/.github/workflows/install-postgres.sh +++ b/.github/workflows/install-postgres.sh @@ -38,7 +38,11 @@ elif [ "${ID}" = "centos" ]; then "postgresql${PGVERSION}-server" \ "postgresql${PGVERSION}-contrib" ln -s "/usr/pgsql-${PGVERSION}/bin/pg_config" "/usr/local/bin/pg_config" +elif [ "${ID}" = "alpine" ]; then + apk add shadow postgresql postgresql-dev postgresql-contrib else echo "install-postgres.sh: Unsupported distro: ${distro}" >&2 exit 1 fi + +useradd -m -s /bin/bash apgtest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e388e7bb..d1e2cfd5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,8 +74,13 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - cibw_python: ["cp37-*", "cp38-*", "cp39-*", "cp310-*"] - cibw_arch: ["auto64"] + cibw_python: ["cp36-*", "cp37-*", "cp38-*", "cp39-*", "cp310-*"] + cibw_arch: ["auto64", "auto32"] + exclude: + - os: macos-latest + cibw_arch: "auto32" + - os: ubuntu-latest + cibw_arch: "auto32" defaults: run: @@ -90,24 +95,11 @@ jobs: fetch-depth: 50 submodules: true - - uses: pypa/cibuildwheel@v2.1.1 + - uses: pypa/cibuildwheel@v2.2.2 env: CIBW_BUILD_VERBOSITY: 1 CIBW_BUILD: ${{ matrix.cibw_python }} CIBW_ARCHS: ${{ matrix.cibw_arch }} - CIBW_BEFORE_ALL_LINUX: > - yum -y install libffi-devel - && env PGVERSION=12 .github/workflows/install-postgres.sh - && useradd -m -s /bin/bash apgtest - CIBW_TEST_EXTRAS: "test" - CIBW_TEST_COMMAND: > - python {project}/tests/__init__.py - CIBW_TEST_COMMAND_WINDOWS: > - python {project}\tests\__init__.py - CIBW_TEST_COMMAND_LINUX: > - PY=`which python` - && chmod -R go+rX "$(dirname $(dirname $(dirname $PY)))" - && su -p -l apgtest -c "$PY {project}/tests/__init__.py" - uses: actions/upload-artifact@v2 with: diff --git a/Makefile b/Makefile index 9ad5d2e7..7a09181c 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ clean: rm -fr dist/ doc/_build/ rm -fr asyncpg/pgproto/*.c asyncpg/pgproto/*.html rm -fr asyncpg/pgproto/codecs/*.html + rm -fr asyncpg/pgproto/*.so rm -fr asyncpg/protocol/*.c asyncpg/protocol/*.html rm -fr asyncpg/protocol/*.so build *.egg-info rm -fr asyncpg/protocol/codecs/*.html diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..9e4ce7f9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,24 @@ +[project] +requires-python = ">=3.6" + +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.cibuildwheel] +build-frontend = "build" +test-extras = "test" + +[tool.cibuildwheel.macos] +test-command = "python {project}/tests/__init__.py" + +[tool.cibuildwheel.windows] +test-command = "python {project}\\tests\\__init__.py" + +[tool.cibuildwheel.linux] +before-all = ".github/workflows/install-postgres.sh" +test-command = """\ + PY=`which python` \ + && chmod -R go+rX "$(dirname $(dirname $(dirname $PY)))" \ + && su -l apgtest -c "$PY {project}/tests/__init__.py" \ + """ diff --git a/setup.py b/setup.py index 4da3fb25..332bad3f 100644 --- a/setup.py +++ b/setup.py @@ -274,9 +274,13 @@ def finalize_options(self): author_email='hello@magic.io', url='https://github.com/MagicStack/asyncpg', license='Apache License, Version 2.0', - packages=['asyncpg'], - provides=['asyncpg'], - include_package_data=True, + packages=setuptools.find_packages( + exclude=['tests', 'tools'], + ), + package_data={ + # Cython sources needed for tracebacks + "": ["*.pyx", "*.pxd", "*.pxi"], + }, ext_modules=[ setuptools.extension.Extension( "asyncpg.pgproto.pgproto", diff --git a/tests/__init__.py b/tests/__init__.py index 6282ebe5..c412aff7 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -18,6 +18,6 @@ def suite(): if __name__ == '__main__': - runner = unittest.runner.TextTestRunner() + runner = unittest.runner.TextTestRunner(verbosity=2) result = runner.run(suite()) sys.exit(not result.wasSuccessful()) From 7a2dfdc327b49e474b1c1e8857581a1bc7252e6f Mon Sep 17 00:00:00 2001 From: Elvis Pranskevichus Date: Tue, 16 Nov 2021 13:01:34 -0800 Subject: [PATCH 4/4] asyncpg v0.25.0 Changes ------- * Improve SSL option compatibility in URIs (by @fantix in 383c711e for #827) * Add `Pool` methods to determine its min, max, current and idle size (by @elprans in 603e3868 for #849) * Make it possible to specify a statement name in `Connection.prepare()` (by @elprans in 03a3d18f for #846) * Implement support for `multirange` types (by @elprans in d64a44a1 for #851) Fixes ----- * Make sure timeout callbacks always get cleaned up (by @elprans in dad26913 for #831) * Update `__all__` statements to a simpler form that is better supported by typecheckers (by @bschnurr in 0a3ae7f5 for #828) * Fix `test_timetz_encoding` on Python 3.10 (by @elprans in 3a90fef0) * Fix a bunch of `ResourceWarnings` in the test suite (by @elprans in 2f4fe539) * Fix `SSLContext` deprecation warnings (by @elprans in 4d39a052) * Fix the description of the database argument to `connect()` (by @elprans in a2a92374 for #847) * Fix parsing of IPv6 addresses in the connection URI (by @elprans in f900b737 for #845) * Improve diagnostics of invalid `executemany()` input (by @elprans in a8fc21e0 for #848) --- asyncpg/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asyncpg/_version.py b/asyncpg/_version.py index 2f106a98..bd1fc082 100644 --- a/asyncpg/_version.py +++ b/asyncpg/_version.py @@ -10,4 +10,4 @@ # supported platforms, publish the packages on PyPI, merge the PR # to the target branch, create a Git tag pointing to the commit. -__version__ = '0.24.0' +__version__ = '0.25.0'