asyncpg 0.28.0__tar.gz → 0.30.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- asyncpg-0.30.0/.flake8 +5 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/MANIFEST.in +1 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/PKG-INFO +33 -12
- {asyncpg-0.28.0 → asyncpg-0.30.0}/README.rst +14 -7
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/__init__.py +6 -1
- asyncpg-0.30.0/asyncpg/_asyncio_compat.py +94 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/_testbase/__init__.py +30 -14
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/_version.py +5 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/cluster.py +49 -8
- asyncpg-0.30.0/asyncpg/compat.py +88 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/connect_utils.py +130 -66
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/connection.py +405 -80
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/cursor.py +15 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/exceptions/__init__.py +24 -6
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/exceptions/_base.py +11 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/introspection.py +16 -6
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/__init__.pxd +4 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/context.pyx +12 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/json.pyx +29 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/numeric.pyx +17 -2
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/text.pyx +2 -2
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/frb.pxd +1 -2
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/hton.h +1 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/pgproto.c +40501 -30317
- asyncpg-0.30.0/asyncpg/pgproto/pgproto.pyi +13 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/types.py +3 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/uuid.pyx +24 -10
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pool.py +109 -52
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/prepared_stmt.py +29 -3
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/__init__.py +2 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/codecs/base.pxd +3 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/codecs/base.pyx +63 -29
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/coreproto.pxd +10 -12
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/coreproto.pyx +115 -19
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/prepared_stmt.pxd +1 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/prepared_stmt.pyx +8 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/protocol.c +88456 -68478
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/protocol.pxd +0 -3
- asyncpg-0.30.0/asyncpg/protocol/protocol.pyi +300 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/protocol.pyx +57 -19
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/record/recordobj.c +2 -2
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/settings.pxd +1 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/settings.pyx +6 -4
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/serverversion.py +17 -7
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/types.py +74 -28
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/utils.py +8 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg.egg-info/PKG-INFO +33 -12
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg.egg-info/SOURCES.txt +5 -0
- asyncpg-0.30.0/asyncpg.egg-info/requires.txt +31 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/docs/api/index.rst +1 -2
- {asyncpg-0.28.0 → asyncpg-0.30.0}/docs/conf.py +1 -2
- {asyncpg-0.28.0 → asyncpg-0.30.0}/docs/index.rst +2 -2
- asyncpg-0.30.0/docs/installation.rst +74 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/docs/usage.rst +57 -13
- {asyncpg-0.28.0 → asyncpg-0.30.0}/pyproject.toml +54 -10
- {asyncpg-0.28.0 → asyncpg-0.30.0}/setup.py +4 -4
- asyncpg-0.30.0/tests/certs/ca.cert.pem +35 -0
- asyncpg-0.30.0/tests/certs/ca.key.pem +51 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/certs/gen.py +15 -1
- asyncpg-0.30.0/tests/certs/server.cert.pem +39 -0
- asyncpg-0.30.0/tests/certs/server.crl.pem +19 -0
- asyncpg-0.30.0/tests/certs/server.key.pem +51 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test__sourcecode.py +32 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_adversity.py +19 -4
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_codecs.py +73 -28
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_connect.py +402 -50
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_copy.py +38 -5
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_cursor.py +15 -5
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_exceptions.py +13 -7
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_execute.py +39 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_introspection.py +7 -1
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_listeners.py +2 -4
- asyncpg-0.30.0/tests/test_logging.py +51 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_pool.py +102 -2
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_prepare.py +14 -0
- asyncpg-0.28.0/.flake8 +0 -3
- asyncpg-0.28.0/asyncpg/compat.py +0 -65
- asyncpg-0.28.0/asyncpg.egg-info/requires.txt +0 -14
- asyncpg-0.28.0/docs/installation.rst +0 -59
- asyncpg-0.28.0/tests/certs/ca.cert.pem +0 -35
- asyncpg-0.28.0/tests/certs/ca.key.pem +0 -51
- asyncpg-0.28.0/tests/certs/server.cert.pem +0 -39
- asyncpg-0.28.0/tests/certs/server.key.pem +0 -51
- {asyncpg-0.28.0 → asyncpg-0.30.0}/AUTHORS +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/LICENSE +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/Makefile +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/_testbase/fuzzer.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/connresource.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/__init__.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/__init__.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/buffer.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/buffer.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/bits.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/bytea.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/datetime.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/float.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/geometry.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/hstore.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/int.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/jsonpath.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/misc.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/network.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/pg_snapshot.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/tid.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/codecs/uuid.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/consts.pxi +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/cpythonx.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/debug.h +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/debug.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/frb.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/hton.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/pgproto.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/pgproto.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/tohex.h +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/pgproto/tohex.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/codecs/__init__.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/codecs/array.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/codecs/pgproto.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/codecs/range.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/codecs/record.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/codecs/textutils.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/consts.pxi +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/cpythonx.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/encodings.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/pgtypes.pxi +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/record/__init__.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/record/recordobj.h +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/scram.pxd +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/protocol/scram.pyx +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg/transaction.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg.egg-info/dependency_links.txt +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg.egg-info/not-zip-safe +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/asyncpg.egg-info/top_level.txt +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/docs/Makefile +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/docs/_static/theme_overrides.css +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/docs/faq.rst +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/performance.png +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/setup.cfg +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/__init__.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/certs/ca.crl.pem +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/certs/client.cert.pem +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/certs/client.csr.pem +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/certs/client.key.pem +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/certs/client.key.protected.pem +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/certs/client_ca.cert.pem +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/certs/client_ca.key.pem +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test__environment.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_cache_invalidation.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_cancellation.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_record.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_test.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_timeout.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_transaction.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_types.py +0 -0
- {asyncpg-0.28.0 → asyncpg-0.30.0}/tests/test_utils.py +0 -0
asyncpg-0.30.0/.flake8
ADDED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
recursive-include docs *.py *.rst Makefile *.css
|
|
2
2
|
recursive-include examples *.py
|
|
3
3
|
recursive-include tests *.py *.pem
|
|
4
|
-
recursive-include asyncpg *.pyx *.pxd *.pxi *.py *.c *.h
|
|
4
|
+
recursive-include asyncpg *.pyx *.pxd *.pxi *.py *.pyi *.c *.h
|
|
5
5
|
include LICENSE README.rst Makefile performance.png .flake8
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: asyncpg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.30.0
|
|
4
4
|
Summary: An asyncio PostgreSQL driver
|
|
5
5
|
Author-email: MagicStack Inc <hello@magic.io>
|
|
6
6
|
License: Apache License, Version 2.0
|
|
@@ -14,19 +14,33 @@ Classifier: Operating System :: POSIX
|
|
|
14
14
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
15
15
|
Classifier: Operating System :: Microsoft :: Windows
|
|
16
16
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.8
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
23
|
Classifier: Topic :: Database :: Front-Ends
|
|
24
|
-
Requires-Python: >=3.
|
|
24
|
+
Requires-Python: >=3.8.0
|
|
25
25
|
Description-Content-Type: text/x-rst
|
|
26
|
-
Provides-Extra: test
|
|
27
|
-
Provides-Extra: docs
|
|
28
26
|
License-File: LICENSE
|
|
29
27
|
License-File: AUTHORS
|
|
28
|
+
Requires-Dist: async_timeout>=4.0.3; python_version < "3.11.0"
|
|
29
|
+
Provides-Extra: gssauth
|
|
30
|
+
Requires-Dist: gssapi; platform_system != "Windows" and extra == "gssauth"
|
|
31
|
+
Requires-Dist: sspilib; platform_system == "Windows" and extra == "gssauth"
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: flake8~=6.1; extra == "test"
|
|
34
|
+
Requires-Dist: flake8-pyi~=24.1.0; extra == "test"
|
|
35
|
+
Requires-Dist: distro~=1.9.0; extra == "test"
|
|
36
|
+
Requires-Dist: uvloop>=0.15.3; (platform_system != "Windows" and python_version < "3.14.0") and extra == "test"
|
|
37
|
+
Requires-Dist: gssapi; platform_system == "Linux" and extra == "test"
|
|
38
|
+
Requires-Dist: k5test; platform_system == "Linux" and extra == "test"
|
|
39
|
+
Requires-Dist: sspilib; platform_system == "Windows" and extra == "test"
|
|
40
|
+
Requires-Dist: mypy~=1.8.0; extra == "test"
|
|
41
|
+
Provides-Extra: docs
|
|
42
|
+
Requires-Dist: Sphinx~=8.1.3; extra == "docs"
|
|
43
|
+
Requires-Dist: sphinx_rtd_theme>=1.2.2; extra == "docs"
|
|
30
44
|
|
|
31
45
|
asyncpg -- A fast PostgreSQL Database Client Library for Python/asyncio
|
|
32
46
|
=======================================================================
|
|
@@ -43,9 +57,10 @@ of PostgreSQL server binary protocol for use with Python's ``asyncio``
|
|
|
43
57
|
framework. You can read more about asyncpg in an introductory
|
|
44
58
|
`blog post <http://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/>`_.
|
|
45
59
|
|
|
46
|
-
asyncpg requires Python 3.
|
|
47
|
-
versions 9.5 to
|
|
48
|
-
the PostgreSQL protocol *may* work, but are not being
|
|
60
|
+
asyncpg requires Python 3.8 or later and is supported for PostgreSQL
|
|
61
|
+
versions 9.5 to 17. Other PostgreSQL versions or other databases
|
|
62
|
+
implementing the PostgreSQL protocol *may* work, but are not being
|
|
63
|
+
actively tested.
|
|
49
64
|
|
|
50
65
|
|
|
51
66
|
Documentation
|
|
@@ -88,11 +103,18 @@ This enables asyncpg to have easy-to-use support for:
|
|
|
88
103
|
Installation
|
|
89
104
|
------------
|
|
90
105
|
|
|
91
|
-
asyncpg is available on PyPI
|
|
92
|
-
Use pip to install::
|
|
106
|
+
asyncpg is available on PyPI. When not using GSSAPI/SSPI authentication it
|
|
107
|
+
has no dependencies. Use pip to install::
|
|
93
108
|
|
|
94
109
|
$ pip install asyncpg
|
|
95
110
|
|
|
111
|
+
If you need GSSAPI/SSPI authentication, use::
|
|
112
|
+
|
|
113
|
+
$ pip install 'asyncpg[gssauth]'
|
|
114
|
+
|
|
115
|
+
For more details, please `see the documentation
|
|
116
|
+
<https://magicstack.github.io/asyncpg/current/installation.html>`_.
|
|
117
|
+
|
|
96
118
|
|
|
97
119
|
Basic Usage
|
|
98
120
|
-----------
|
|
@@ -111,8 +133,7 @@ Basic Usage
|
|
|
111
133
|
)
|
|
112
134
|
await conn.close()
|
|
113
135
|
|
|
114
|
-
|
|
115
|
-
loop.run_until_complete(run())
|
|
136
|
+
asyncio.run(run())
|
|
116
137
|
|
|
117
138
|
|
|
118
139
|
License
|
|
@@ -13,9 +13,10 @@ of PostgreSQL server binary protocol for use with Python's ``asyncio``
|
|
|
13
13
|
framework. You can read more about asyncpg in an introductory
|
|
14
14
|
`blog post <http://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/>`_.
|
|
15
15
|
|
|
16
|
-
asyncpg requires Python 3.
|
|
17
|
-
versions 9.5 to
|
|
18
|
-
the PostgreSQL protocol *may* work, but are not being
|
|
16
|
+
asyncpg requires Python 3.8 or later and is supported for PostgreSQL
|
|
17
|
+
versions 9.5 to 17. Other PostgreSQL versions or other databases
|
|
18
|
+
implementing the PostgreSQL protocol *may* work, but are not being
|
|
19
|
+
actively tested.
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
Documentation
|
|
@@ -58,11 +59,18 @@ This enables asyncpg to have easy-to-use support for:
|
|
|
58
59
|
Installation
|
|
59
60
|
------------
|
|
60
61
|
|
|
61
|
-
asyncpg is available on PyPI
|
|
62
|
-
Use pip to install::
|
|
62
|
+
asyncpg is available on PyPI. When not using GSSAPI/SSPI authentication it
|
|
63
|
+
has no dependencies. Use pip to install::
|
|
63
64
|
|
|
64
65
|
$ pip install asyncpg
|
|
65
66
|
|
|
67
|
+
If you need GSSAPI/SSPI authentication, use::
|
|
68
|
+
|
|
69
|
+
$ pip install 'asyncpg[gssauth]'
|
|
70
|
+
|
|
71
|
+
For more details, please `see the documentation
|
|
72
|
+
<https://magicstack.github.io/asyncpg/current/installation.html>`_.
|
|
73
|
+
|
|
66
74
|
|
|
67
75
|
Basic Usage
|
|
68
76
|
-----------
|
|
@@ -81,8 +89,7 @@ Basic Usage
|
|
|
81
89
|
)
|
|
82
90
|
await conn.close()
|
|
83
91
|
|
|
84
|
-
|
|
85
|
-
loop.run_until_complete(run())
|
|
92
|
+
asyncio.run(run())
|
|
86
93
|
|
|
87
94
|
|
|
88
95
|
License
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# This module is part of asyncpg and is released under
|
|
5
5
|
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
7
8
|
|
|
8
9
|
from .connection import connect, Connection # NOQA
|
|
9
10
|
from .exceptions import * # NOQA
|
|
@@ -14,6 +15,10 @@ from .types import * # NOQA
|
|
|
14
15
|
|
|
15
16
|
from ._version import __version__ # NOQA
|
|
16
17
|
|
|
18
|
+
from . import exceptions
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
|
|
21
|
+
__all__: tuple[str, ...] = (
|
|
22
|
+
'connect', 'create_pool', 'Pool', 'Record', 'Connection'
|
|
23
|
+
)
|
|
19
24
|
__all__ += exceptions.__all__ # NOQA
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Backports from Python/Lib/asyncio for older Pythons
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2001-2023 Python Software Foundation; All Rights Reserved
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: PSF-2.0
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import functools
|
|
11
|
+
import sys
|
|
12
|
+
import typing
|
|
13
|
+
|
|
14
|
+
if typing.TYPE_CHECKING:
|
|
15
|
+
from . import compat
|
|
16
|
+
|
|
17
|
+
if sys.version_info < (3, 11):
|
|
18
|
+
from async_timeout import timeout as timeout_ctx
|
|
19
|
+
else:
|
|
20
|
+
from asyncio import timeout as timeout_ctx
|
|
21
|
+
|
|
22
|
+
_T = typing.TypeVar('_T')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def wait_for(fut: compat.Awaitable[_T], timeout: float | None) -> _T:
|
|
26
|
+
"""Wait for the single Future or coroutine to complete, with timeout.
|
|
27
|
+
|
|
28
|
+
Coroutine will be wrapped in Task.
|
|
29
|
+
|
|
30
|
+
Returns result of the Future or coroutine. When a timeout occurs,
|
|
31
|
+
it cancels the task and raises TimeoutError. To avoid the task
|
|
32
|
+
cancellation, wrap it in shield().
|
|
33
|
+
|
|
34
|
+
If the wait is cancelled, the task is also cancelled.
|
|
35
|
+
|
|
36
|
+
If the task supresses the cancellation and returns a value instead,
|
|
37
|
+
that value is returned.
|
|
38
|
+
|
|
39
|
+
This function is a coroutine.
|
|
40
|
+
"""
|
|
41
|
+
# The special case for timeout <= 0 is for the following case:
|
|
42
|
+
#
|
|
43
|
+
# async def test_waitfor():
|
|
44
|
+
# func_started = False
|
|
45
|
+
#
|
|
46
|
+
# async def func():
|
|
47
|
+
# nonlocal func_started
|
|
48
|
+
# func_started = True
|
|
49
|
+
#
|
|
50
|
+
# try:
|
|
51
|
+
# await asyncio.wait_for(func(), 0)
|
|
52
|
+
# except asyncio.TimeoutError:
|
|
53
|
+
# assert not func_started
|
|
54
|
+
# else:
|
|
55
|
+
# assert False
|
|
56
|
+
#
|
|
57
|
+
# asyncio.run(test_waitfor())
|
|
58
|
+
|
|
59
|
+
if timeout is not None and timeout <= 0:
|
|
60
|
+
fut = asyncio.ensure_future(fut)
|
|
61
|
+
|
|
62
|
+
if fut.done():
|
|
63
|
+
return fut.result()
|
|
64
|
+
|
|
65
|
+
await _cancel_and_wait(fut)
|
|
66
|
+
try:
|
|
67
|
+
return fut.result()
|
|
68
|
+
except asyncio.CancelledError as exc:
|
|
69
|
+
raise TimeoutError from exc
|
|
70
|
+
|
|
71
|
+
async with timeout_ctx(timeout):
|
|
72
|
+
return await fut
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async def _cancel_and_wait(fut: asyncio.Future[_T]) -> None:
|
|
76
|
+
"""Cancel the *fut* future or task and wait until it completes."""
|
|
77
|
+
|
|
78
|
+
loop = asyncio.get_running_loop()
|
|
79
|
+
waiter = loop.create_future()
|
|
80
|
+
cb = functools.partial(_release_waiter, waiter)
|
|
81
|
+
fut.add_done_callback(cb)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
fut.cancel()
|
|
85
|
+
# We cannot wait on *fut* directly to make
|
|
86
|
+
# sure _cancel_and_wait itself is reliably cancellable.
|
|
87
|
+
await waiter
|
|
88
|
+
finally:
|
|
89
|
+
fut.remove_done_callback(cb)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _release_waiter(waiter: asyncio.Future[typing.Any], *args: object) -> None:
|
|
93
|
+
if not waiter.done():
|
|
94
|
+
waiter.set_result(None)
|
|
@@ -117,10 +117,22 @@ class TestCase(unittest.TestCase, metaclass=TestCaseMeta):
|
|
|
117
117
|
self.__unhandled_exceptions = []
|
|
118
118
|
|
|
119
119
|
def tearDown(self):
|
|
120
|
-
|
|
120
|
+
excs = []
|
|
121
|
+
for exc in self.__unhandled_exceptions:
|
|
122
|
+
if isinstance(exc, ConnectionResetError):
|
|
123
|
+
texc = traceback.TracebackException.from_exception(
|
|
124
|
+
exc, lookup_lines=False)
|
|
125
|
+
if texc.stack[-1].name == "_call_connection_lost":
|
|
126
|
+
# On Windows calling socket.shutdown may raise
|
|
127
|
+
# ConnectionResetError, which happens in the
|
|
128
|
+
# finally block of _call_connection_lost.
|
|
129
|
+
continue
|
|
130
|
+
excs.append(exc)
|
|
131
|
+
|
|
132
|
+
if excs:
|
|
121
133
|
formatted = []
|
|
122
134
|
|
|
123
|
-
for i, context in enumerate(
|
|
135
|
+
for i, context in enumerate(excs):
|
|
124
136
|
formatted.append(self._format_loop_exception(context, i + 1))
|
|
125
137
|
|
|
126
138
|
self.fail(
|
|
@@ -214,13 +226,6 @@ def _init_cluster(ClusterCls, cluster_kwargs, initdb_options=None):
|
|
|
214
226
|
return cluster
|
|
215
227
|
|
|
216
228
|
|
|
217
|
-
def _start_cluster(ClusterCls, cluster_kwargs, server_settings,
|
|
218
|
-
initdb_options=None):
|
|
219
|
-
cluster = _init_cluster(ClusterCls, cluster_kwargs, initdb_options)
|
|
220
|
-
cluster.start(port='dynamic', server_settings=server_settings)
|
|
221
|
-
return cluster
|
|
222
|
-
|
|
223
|
-
|
|
224
229
|
def _get_initdb_options(initdb_options=None):
|
|
225
230
|
if not initdb_options:
|
|
226
231
|
initdb_options = {}
|
|
@@ -244,8 +249,12 @@ def _init_default_cluster(initdb_options=None):
|
|
|
244
249
|
_default_cluster = pg_cluster.RunningCluster()
|
|
245
250
|
else:
|
|
246
251
|
_default_cluster = _init_cluster(
|
|
247
|
-
pg_cluster.TempCluster,
|
|
248
|
-
|
|
252
|
+
pg_cluster.TempCluster,
|
|
253
|
+
cluster_kwargs={
|
|
254
|
+
"data_dir_suffix": ".apgtest",
|
|
255
|
+
},
|
|
256
|
+
initdb_options=_get_initdb_options(initdb_options),
|
|
257
|
+
)
|
|
249
258
|
|
|
250
259
|
return _default_cluster
|
|
251
260
|
|
|
@@ -262,6 +271,7 @@ def create_pool(dsn=None, *,
|
|
|
262
271
|
max_size=10,
|
|
263
272
|
max_queries=50000,
|
|
264
273
|
max_inactive_connection_lifetime=60.0,
|
|
274
|
+
connect=None,
|
|
265
275
|
setup=None,
|
|
266
276
|
init=None,
|
|
267
277
|
loop=None,
|
|
@@ -271,12 +281,18 @@ def create_pool(dsn=None, *,
|
|
|
271
281
|
**connect_kwargs):
|
|
272
282
|
return pool_class(
|
|
273
283
|
dsn,
|
|
274
|
-
min_size=min_size,
|
|
275
|
-
|
|
284
|
+
min_size=min_size,
|
|
285
|
+
max_size=max_size,
|
|
286
|
+
max_queries=max_queries,
|
|
287
|
+
loop=loop,
|
|
288
|
+
connect=connect,
|
|
289
|
+
setup=setup,
|
|
290
|
+
init=init,
|
|
276
291
|
max_inactive_connection_lifetime=max_inactive_connection_lifetime,
|
|
277
292
|
connection_class=connection_class,
|
|
278
293
|
record_class=record_class,
|
|
279
|
-
**connect_kwargs
|
|
294
|
+
**connect_kwargs,
|
|
295
|
+
)
|
|
280
296
|
|
|
281
297
|
|
|
282
298
|
class ClusterTestCase(TestCase):
|
|
@@ -10,4 +10,8 @@
|
|
|
10
10
|
# supported platforms, publish the packages on PyPI, merge the PR
|
|
11
11
|
# to the target branch, create a Git tag pointing to the commit.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import typing
|
|
16
|
+
|
|
17
|
+
__version__: typing.Final = '0.30.0'
|
|
@@ -9,9 +9,11 @@ import asyncio
|
|
|
9
9
|
import os
|
|
10
10
|
import os.path
|
|
11
11
|
import platform
|
|
12
|
+
import random
|
|
12
13
|
import re
|
|
13
14
|
import shutil
|
|
14
15
|
import socket
|
|
16
|
+
import string
|
|
15
17
|
import subprocess
|
|
16
18
|
import sys
|
|
17
19
|
import tempfile
|
|
@@ -45,6 +47,29 @@ def find_available_port():
|
|
|
45
47
|
sock.close()
|
|
46
48
|
|
|
47
49
|
|
|
50
|
+
def _world_readable_mkdtemp(suffix=None, prefix=None, dir=None):
|
|
51
|
+
name = "".join(random.choices(string.ascii_lowercase, k=8))
|
|
52
|
+
if dir is None:
|
|
53
|
+
dir = tempfile.gettempdir()
|
|
54
|
+
if prefix is None:
|
|
55
|
+
prefix = tempfile.gettempprefix()
|
|
56
|
+
if suffix is None:
|
|
57
|
+
suffix = ""
|
|
58
|
+
fn = os.path.join(dir, prefix + name + suffix)
|
|
59
|
+
os.mkdir(fn, 0o755)
|
|
60
|
+
return fn
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _mkdtemp(suffix=None, prefix=None, dir=None):
|
|
64
|
+
if _system == 'Windows' and os.environ.get("GITHUB_ACTIONS"):
|
|
65
|
+
# Due to mitigations introduced in python/cpython#118486
|
|
66
|
+
# when Python runs in a session created via an SSH connection
|
|
67
|
+
# tempfile.mkdtemp creates directories that are not accessible.
|
|
68
|
+
return _world_readable_mkdtemp(suffix, prefix, dir)
|
|
69
|
+
else:
|
|
70
|
+
return tempfile.mkdtemp(suffix, prefix, dir)
|
|
71
|
+
|
|
72
|
+
|
|
48
73
|
class ClusterError(Exception):
|
|
49
74
|
pass
|
|
50
75
|
|
|
@@ -122,9 +147,13 @@ class Cluster:
|
|
|
122
147
|
else:
|
|
123
148
|
extra_args = []
|
|
124
149
|
|
|
150
|
+
os.makedirs(self._data_dir, exist_ok=True)
|
|
125
151
|
process = subprocess.run(
|
|
126
152
|
[self._pg_ctl, 'init', '-D', self._data_dir] + extra_args,
|
|
127
|
-
stdout=subprocess.PIPE,
|
|
153
|
+
stdout=subprocess.PIPE,
|
|
154
|
+
stderr=subprocess.STDOUT,
|
|
155
|
+
cwd=self._data_dir,
|
|
156
|
+
)
|
|
128
157
|
|
|
129
158
|
output = process.stdout
|
|
130
159
|
|
|
@@ -199,7 +228,10 @@ class Cluster:
|
|
|
199
228
|
process = subprocess.run(
|
|
200
229
|
[self._pg_ctl, 'start', '-D', self._data_dir,
|
|
201
230
|
'-o', ' '.join(extra_args)],
|
|
202
|
-
stdout=stdout,
|
|
231
|
+
stdout=stdout,
|
|
232
|
+
stderr=subprocess.STDOUT,
|
|
233
|
+
cwd=self._data_dir,
|
|
234
|
+
)
|
|
203
235
|
|
|
204
236
|
if process.returncode != 0:
|
|
205
237
|
if process.stderr:
|
|
@@ -218,7 +250,10 @@ class Cluster:
|
|
|
218
250
|
self._daemon_process = \
|
|
219
251
|
subprocess.Popen(
|
|
220
252
|
[self._postgres, '-D', self._data_dir, *extra_args],
|
|
221
|
-
stdout=stdout,
|
|
253
|
+
stdout=stdout,
|
|
254
|
+
stderr=subprocess.STDOUT,
|
|
255
|
+
cwd=self._data_dir,
|
|
256
|
+
)
|
|
222
257
|
|
|
223
258
|
self._daemon_pid = self._daemon_process.pid
|
|
224
259
|
|
|
@@ -232,7 +267,10 @@ class Cluster:
|
|
|
232
267
|
|
|
233
268
|
process = subprocess.run(
|
|
234
269
|
[self._pg_ctl, 'reload', '-D', self._data_dir],
|
|
235
|
-
stdout=subprocess.PIPE,
|
|
270
|
+
stdout=subprocess.PIPE,
|
|
271
|
+
stderr=subprocess.PIPE,
|
|
272
|
+
cwd=self._data_dir,
|
|
273
|
+
)
|
|
236
274
|
|
|
237
275
|
stderr = process.stderr
|
|
238
276
|
|
|
@@ -245,7 +283,10 @@ class Cluster:
|
|
|
245
283
|
process = subprocess.run(
|
|
246
284
|
[self._pg_ctl, 'stop', '-D', self._data_dir, '-t', str(wait),
|
|
247
285
|
'-m', 'fast'],
|
|
248
|
-
stdout=subprocess.PIPE,
|
|
286
|
+
stdout=subprocess.PIPE,
|
|
287
|
+
stderr=subprocess.PIPE,
|
|
288
|
+
cwd=self._data_dir,
|
|
289
|
+
)
|
|
249
290
|
|
|
250
291
|
stderr = process.stderr
|
|
251
292
|
|
|
@@ -583,9 +624,9 @@ class TempCluster(Cluster):
|
|
|
583
624
|
def __init__(self, *,
|
|
584
625
|
data_dir_suffix=None, data_dir_prefix=None,
|
|
585
626
|
data_dir_parent=None, pg_config_path=None):
|
|
586
|
-
self._data_dir =
|
|
587
|
-
|
|
588
|
-
|
|
627
|
+
self._data_dir = _mkdtemp(suffix=data_dir_suffix,
|
|
628
|
+
prefix=data_dir_prefix,
|
|
629
|
+
dir=data_dir_parent)
|
|
589
630
|
super().__init__(self._data_dir, pg_config_path=pg_config_path)
|
|
590
631
|
|
|
591
632
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Copyright (C) 2016-present the asyncpg authors and contributors
|
|
2
|
+
# <see AUTHORS file>
|
|
3
|
+
#
|
|
4
|
+
# This module is part of asyncpg and is released under
|
|
5
|
+
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import enum
|
|
10
|
+
import pathlib
|
|
11
|
+
import platform
|
|
12
|
+
import typing
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
if typing.TYPE_CHECKING:
|
|
16
|
+
import asyncio
|
|
17
|
+
|
|
18
|
+
SYSTEM: typing.Final = platform.uname().system
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if sys.platform == 'win32':
|
|
22
|
+
import ctypes.wintypes
|
|
23
|
+
|
|
24
|
+
CSIDL_APPDATA: typing.Final = 0x001a
|
|
25
|
+
|
|
26
|
+
def get_pg_home_directory() -> pathlib.Path | None:
|
|
27
|
+
# We cannot simply use expanduser() as that returns the user's
|
|
28
|
+
# home directory, whereas Postgres stores its config in
|
|
29
|
+
# %AppData% on Windows.
|
|
30
|
+
buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
|
|
31
|
+
r = ctypes.windll.shell32.SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, buf)
|
|
32
|
+
if r:
|
|
33
|
+
return None
|
|
34
|
+
else:
|
|
35
|
+
return pathlib.Path(buf.value) / 'postgresql'
|
|
36
|
+
|
|
37
|
+
else:
|
|
38
|
+
def get_pg_home_directory() -> pathlib.Path | None:
|
|
39
|
+
try:
|
|
40
|
+
return pathlib.Path.home()
|
|
41
|
+
except (RuntimeError, KeyError):
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
async def wait_closed(stream: asyncio.StreamWriter) -> None:
|
|
46
|
+
# Not all asyncio versions have StreamWriter.wait_closed().
|
|
47
|
+
if hasattr(stream, 'wait_closed'):
|
|
48
|
+
try:
|
|
49
|
+
await stream.wait_closed()
|
|
50
|
+
except ConnectionResetError:
|
|
51
|
+
# On Windows wait_closed() sometimes propagates
|
|
52
|
+
# ConnectionResetError which is totally unnecessary.
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if sys.version_info < (3, 12):
|
|
57
|
+
def markcoroutinefunction(c): # type: ignore
|
|
58
|
+
pass
|
|
59
|
+
else:
|
|
60
|
+
from inspect import markcoroutinefunction # noqa: F401
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if sys.version_info < (3, 12):
|
|
64
|
+
from ._asyncio_compat import wait_for as wait_for # noqa: F401
|
|
65
|
+
else:
|
|
66
|
+
from asyncio import wait_for as wait_for # noqa: F401
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if sys.version_info < (3, 11):
|
|
70
|
+
from ._asyncio_compat import timeout_ctx as timeout # noqa: F401
|
|
71
|
+
else:
|
|
72
|
+
from asyncio import timeout as timeout # noqa: F401
|
|
73
|
+
|
|
74
|
+
if sys.version_info < (3, 9):
|
|
75
|
+
from typing import ( # noqa: F401
|
|
76
|
+
Awaitable as Awaitable,
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
from collections.abc import ( # noqa: F401
|
|
80
|
+
Awaitable as Awaitable,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if sys.version_info < (3, 11):
|
|
84
|
+
class StrEnum(str, enum.Enum):
|
|
85
|
+
__str__ = str.__str__
|
|
86
|
+
__repr__ = enum.Enum.__repr__
|
|
87
|
+
else:
|
|
88
|
+
from enum import StrEnum as StrEnum # noqa: F401
|