diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 039a366..7ba10ca 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,7 +30,7 @@ jobs: tests-psycopg-version: strategy: matrix: - psycopg: ["psycopg2", "psycopg"] + psycopg: ["psycopg2-binary", "psycopg2-binary==2.9.3", "psycopg-binary", "psycopg-binary==3.1"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/README.md b/README.md index f35e803..f41c182 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,9 @@ Key features: ## Requirements Python 3.9+ - SQLAlchemy 1.4 or 2+ - PostgreSQL 12+ +Psycopg (Version 2 >= 2.9.3 or Version 3 >= 3.1) ## Installation diff --git a/depeche_db/_compat.py b/depeche_db/_compat.py index 9632195..667ca85 100644 --- a/depeche_db/_compat.py +++ b/depeche_db/_compat.py @@ -58,6 +58,7 @@ def get_union_members(union_or_type) -> typing.Generator[typing.Type, None, None if os.environ.get("DEPECHE_DB_FORCE_PSYCOPG3", "0") != "1": import psycopg2 as psycopg # noqa from psycopg2.errors import LockNotAvailable as PsycoPgLockNotAvailable # noqa + from psycopg2.errors import RaiseException as PsycoPgRaiseException # noqa from psycopg2.extras import Json as PsycoPgJson # noqa PSYCOPG_VERSION = "2" @@ -68,7 +69,8 @@ def get_union_members(union_or_type) -> typing.Generator[typing.Type, None, None try: import psycopg # noqa from psycopg.errors import LockNotAvailable as PsycoPgLockNotAvailable # noqa - from psycopg.types.json import Jsonb as PsycoPgJson # noqa + from psycopg.errors import RaiseException as PsycoPgRaiseException # noqa + from psycopg.types.json import Json as PsycoPgJson # noqa PSYCOPG_VERSION = "3" except ImportError: diff --git a/depeche_db/_storage.py b/depeche_db/_storage.py index bb570a3..40d58f8 100644 --- a/depeche_db/_storage.py +++ b/depeche_db/_storage.py @@ -84,7 +84,7 @@ def add_all( try: for idx, (message_id, message) in enumerate(messages): _expected_version = ( - expected_version + idx if expected_version is not None else None, + expected_version + idx if expected_version is not None else None ) result: Any = conn.execute( _sa.select( @@ -95,8 +95,24 @@ def add_all( ).alias() ) ) - except _sa.exc.InternalError: - raise OptimisticConcurrencyError("optimistic concurrency failure") + except _sa.exc.InternalError as exc: + # psycopg2 + from depeche_db._compat import PsycoPgRaiseException + + if isinstance(exc.orig, PsycoPgRaiseException): + raise OptimisticConcurrencyError( + f"optimistic concurrency failure: {exc.orig}" + ) + raise + except _sa.exc.ProgrammingError as exc: + # psycopg3 + from depeche_db._compat import PsycoPgRaiseException + + if isinstance(exc.orig, PsycoPgRaiseException): + raise OptimisticConcurrencyError( + f"optimistic concurrency failure: {exc.orig}" + ) + raise row = result.fetchone() return MessagePosition( stream=stream, diff --git a/depeche_db/tools/pg_notification_listener.py b/depeche_db/tools/pg_notification_listener.py index 8bc3808..f8f099e 100644 --- a/depeche_db/tools/pg_notification_listener.py +++ b/depeche_db/tools/pg_notification_listener.py @@ -6,6 +6,7 @@ import threading from typing import Iterator, Sequence +from depeche_db._compat import PSYCOPG_VERSION from depeche_db._compat import psycopg as _psycopg logger = logging.getLogger(__name__) @@ -48,8 +49,24 @@ def stop(self): self._keep_running = False self._thread.join() + def _parse_dsn(self, dsn: str) -> tuple[str, str]: + import urllib.parse as _urlparse + + parts = list(_urlparse.urlparse(dsn)) + expected_psycopg_version = "2" + if parts[0] == "postgresql+psycopg": + parts[0] = "postgresql" + expected_psycopg_version = "3" + if parts[0] == "postgresql+psycopg2": + parts[0] = "postgresql" + dsn = _urlparse.urlunparse(parts) + + return dsn, expected_psycopg_version + def _loop(self): - conn = _psycopg.connect(self.dsn) + dsn, expected_psycopg_version = self._parse_dsn(self.dsn) + assert expected_psycopg_version == PSYCOPG_VERSION, "Invalid psycopg version" + conn = _psycopg.connect(dsn) try: curs = conn.cursor() @@ -61,21 +78,28 @@ def _loop(self): if select.select([conn], [], [], self._select_timeout) == ([], [], []): pass else: - conn.poll() - while conn.notifies: - notification = conn.notifies.pop(0) - try: - if self._ignore_payload: - payload = {} - else: - payload = json.loads(notification.payload) - self._queue.put( - PgNotification(notification.channel, payload) - ) - except Exception: - logger.exception( - f"Error processing notification payload: {notification}" - ) - + if PSYCOPG_VERSION == "3": + self._psycopg3_loop(conn) + else: + self._psycopg2_loop(conn) finally: conn.close() + + def _psycopg3_loop(self, conn): + for notification in conn.notifies(timeout=0.2): + self._process_notification(notification) + + def _psycopg2_loop(self, conn): + conn.poll() + while conn.notifies: + self._process_notification(conn.notifies.pop(0)) + + def _process_notification(self, notification): + try: + if self._ignore_payload: + payload = {} + else: + payload = json.loads(notification.payload) + self._queue.put(PgNotification(notification.channel, payload)) + except Exception: + logger.exception(f"Error processing notification payload: {notification}") diff --git a/docs/generated/README.md b/docs/generated/README.md index c7679d6..95c6319 100644 --- a/docs/generated/README.md +++ b/docs/generated/README.md @@ -28,15 +28,15 @@ Key features: * Message store with optimistic concurrency control & strong ordering guarantees * Subscriptions with "at least once" semantics +* Parallel processing of (partitioned) subscriptions * No database polling ## Requirements Python 3.9+ - SQLAlchemy 1.4 or 2+ - PostgreSQL 12+ +Psycopg (Version 2 >= 2.9.3 or Version 3 >= 3.1) ## Installation diff --git a/docs/generated/getting_started.py b/docs/generated/getting_started.py index 04663e8..cff1161 100644 --- a/docs/generated/getting_started.py +++ b/docs/generated/getting_started.py @@ -13,6 +13,8 @@ from sqlalchemy import create_engine DB_DSN = "postgresql://depeche:depeche@localhost:4888/depeche_demo" +# If you are using psycopg 3, use the following DSN instead: +# DB_DSN = "postgresql+psycopg://depeche:depeche@localhost:4888/depeche_demo" db_engine = create_engine(DB_DSN) doc.md( @@ -262,7 +264,7 @@ def handle_event_a(msg: SubscriptionMessage[EventA]): ) subscription = aggregated_stream.subscription( - name="sub_example_docs_aggregate_me_with_handlers", + name="sub_example_docs_with_handlers", handlers=handlers, ) diff --git a/docs/generated/output/getting-started-subscription.md b/docs/generated/output/getting-started-subscription.md index 034fff3..7506008 100644 --- a/docs/generated/output/getting-started-subscription.md +++ b/docs/generated/output/getting-started-subscription.md @@ -64,7 +64,7 @@ Now we can create a new subscription with these handlers. ```python subscription = aggregated_stream.subscription( - name="sub_example_docs_aggregate_me_with_handlers", + name="sub_example_docs_with_handlers", handlers=handlers, ) ``` diff --git a/docs/generated/output/getting-started-write-read.md b/docs/generated/output/getting-started-write-read.md index eecb287..2a21379 100644 --- a/docs/generated/output/getting-started-write-read.md +++ b/docs/generated/output/getting-started-write-read.md @@ -6,6 +6,8 @@ First, create a SQLAlchemy engine with your database connection: from sqlalchemy import create_engine DB_DSN = "postgresql://depeche:depeche@localhost:4888/depeche_demo" +# If you are using psycopg 3, use the following DSN instead: +# DB_DSN = "postgresql+psycopg://depeche:depeche@localhost:4888/depeche_demo" db_engine = create_engine(DB_DSN) ``` diff --git a/poetry.lock b/poetry.lock index 5546eaa..93471a5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1046,114 +1046,14 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "psycopg" -version = "3.2.4" -description = "PostgreSQL database adapter for Python" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "psycopg-3.2.4-py3-none-any.whl", hash = "sha256:43665368ccd48180744cab26b74332f46b63b7e06e8ce0775547a3533883d381"}, - {file = "psycopg-3.2.4.tar.gz", hash = "sha256:f26f1346d6bf1ef5f5ef1714dd405c67fb365cfd1c6cea07de1792747b167b92"}, -] - -[package.dependencies] -psycopg-binary = {version = "3.2.4", optional = true, markers = "implementation_name != \"pypy\" and extra == \"binary\""} -typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""} -tzdata = {version = "*", markers = "sys_platform == \"win32\""} - -[package.extras] -binary = ["psycopg-binary (==3.2.4)"] -c = ["psycopg-c (==3.2.4)"] -dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.14)", "pre-commit (>=4.0.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] -docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] -pool = ["psycopg-pool"] -test = ["anyio (>=4.0)", "mypy (>=1.14)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] - -[[package]] -name = "psycopg-binary" -version = "3.2.4" -description = "PostgreSQL database adapter for Python -- C optimisation distribution" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -markers = "implementation_name != \"pypy\"" -files = [ - {file = "psycopg_binary-3.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c716f75b5c0388fc5283b5124046292c727511dd8c6aa59ca2dc644b9a2ed0cd"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2e8050347018f596a63f5dccbb92fb68bca52b13912cb8fc40184b24c0e534f"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04171f9af9ab567c0fd339bac06f2c75836db839cebac5bd07824778dafa7f0e"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7ba7b2ff25a6405826f627fb7d0f1e06e5c08ae25ffabc74a5e9ec7b0a63b85"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e58eeba520d405b2ad72dffaafd04d0b592bef870e718bf37c261e89a75450a"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb18cfbb1cfc8172786ceefd314f0faa05c40ea93b3db7194d0f6bbbbfedb42a"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:769804b4f753ddec9403183a6d4577d5b696fc49c2451421013fb06d6fa2f288"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7d4f0c9b01eb933ce35bb32a54205f48d7bc36bf455565afe269cabcb7973955"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:26aed7ff8691ba810de95718d3bc81a43fd48a4036c3641ef711eb5f71fc7106"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8a4b65eaf44dfed0b47e6ebd392e88cd3cff62ea11652d92db6fefeb2608ed25"}, - {file = "psycopg_binary-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9fa48a2dc54c4e906d7dd781031d227d1b13966deff7e5ece5b037588643190"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d092b0aa80b8c3ee0701a7252cbfb0bdb742e1f74aaf0c1a13ef22c05c9266ab"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3955381dacc6d15f3838d5f25445ee99f80882876a163f8de0c01ffc54aeef4a"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04144d1963aa3309247980f1a742b98e15f60d68ea9745143c433f99aaeb70d7"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eac61931bc90c1c6fdc648452894d3a434a005ffefaf12819b4709548c894bf2"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c09b765960480c4586758a3c16f0ee0db6f7e2f31c88cccb5e7d7024215468cd"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:220de8efcc276e42ba7cc7ed613145b1274b6b5de321a1396fb6b6ce1758d34c"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b558d3de315d18819ce477908e27518cbdd3275717c6193b58dde36f0443e167"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3b4c9b9a112d43533f7dbdedbb1188107d4ddcd262e2a2af41b4de0caf7d053"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:870df866f789bb641a350897c1751c293b9420f46be4eb366d190ff5f2f2ffd8"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89506e268fb95428fb0f8f7abe48032e66cf47390469e11a4fe989f7407a5d88"}, - {file = "psycopg_binary-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:7ddf1494cc3bf60761c01265c44dfc7a7fd63f21308c403c14f5dd91702df84d"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ac24b3d421127ebe8662eba2c1e149a12f0f5b6795e66c1811a3f59111456bb"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f702f36204127984dd212eb57bb328676abdfe8a56f179e408a806d5e520aa11"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:610cd2013ee0849154fcff34b0cca17f720c91c7430ca094a61f1e5ff1d38e15"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95da59edd95f6b6488799c9710fafc2d5750e3ec6328ec991f7a9be04efe6886"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b71e98e3186f08473962e1ea4bfbc4387ecc398644b794cb112ad0a4276e3789"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ccf4f71c3a0d46bc74207bf7997f010a6586414161dd10f3dd026ec059942ef"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:244e1dd33b694792b7bc7a3d412a535ba39116218b07d8936b4591567f4121e9"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f8dc8f4de5130c6278dd5e34b18ad8324a74658a7adb72d4e67ca97f9aeaaf3c"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c336e58a48061a9189d3ba8c19f00fe5d9570219e6f7f954b923ad5c33e5bc71"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9633c5dc6796d11766d2475e62335b67e5f99f119f40ba1675c1d23208d7709d"}, - {file = "psycopg_binary-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:295c25e56b430d786a475c5c2cef266b0b27c0a6fcaadf9d83a4cdcfb76f971f"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:81ab801c0d35830c876bf0d1edc8e7dd2f73aa2b04fe24eb812159c0b054d149"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c09e02ce1124eb6638b3381df050a8cf88aedfad4522f939945cda49050a990c"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a249cdc6a5c2b5088a8677acba66b291e5237524739ab3d27498e1ef189312f5"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2960ba8a5c0ad75e184f6d8bf76bdf023708999efe75fe4e13445136c1cd206"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dae2e50b0d3425c167eebbedc3553f7c811dbc0dbfc737b6877f68a03be7daf"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03bf7ee7e0002c2cce43ecb923ec510358056eb2e44a96afaeb0424518f35206"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5f5c85eeb63b1a8a6b026eef57f5da36ff215ce9a6a3bb8e20a409670d6cfbda"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8c7b95899d4d6d23c5cc46cb3419e8e6ca68d867509432ee1487042564a1ea55"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fa4acea9ca20a567c3872a5afab2084751530bb57b8fb6b52820d5c54e7c8c3b"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c487f35a1905bb15da927c1fc05f70f3d29f0e21fb4ba21d360a0da9c755f20"}, - {file = "psycopg_binary-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:80297c3a9f7b5a6afdb0d8f220661ccd796e5c9128c44b32c41267f7daefd37f"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:22cf23d037310ae08feceea5e24f727b1ef816867188dbec2edde2e7237b0004"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3409151b91df85ef99a72d137aba289e1d7b5d4ac7750b37183674421903e04"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1145c3c038e6dbe7127309cc9bbe209bce5743f9f02a2a65c4f9478bd794598e"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21d369bac7606157ef2699a0ff65c8d43d274f0178fd03241babb5f86b7586f7"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:158fa0dbda433e0069bd2b6ffdf357c9fcdb84ec5e3b353fb8206636873b54f9"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4a56b55072a3e0629e6421a7f6fdd4eecc0eba4e9cedaaf2e7578ac62c336680"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:d993ecfa7f2ac30108d57e7418732d70aa399ccb4a8ca1cf415638679fb32e8b"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:a5b68ba52bdf3ed86a8a1f1ac809ecd775ffd7bb611438d3ab9e1ee572742f95"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:90423ff7a0c1f4001b8d54e6c7866f5bbb778f3f4272a70a7926878fe7d8763c"}, - {file = "psycopg_binary-3.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:5a462bdd427330418fa2a011b6494103edd94cacd4f5b00e598bcbd1c8d20fb9"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2ddec5deed4c93a1bd73f210bed6dadbabc470ac1f9ebf55fa260e48396fd61f"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8bd54787d894261ff48d5c4b7f23e281c05c9a5ac67355eff7d29cfbcde640cd"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ae8cf8694d01788be5f418f6cada813e2b86cef67efba9c60cb9371cee9eb9"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0958dd3bfffbdef86594a6fa45255d4389ade94d17572bdf5207a900166a3cba"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b9558f9d101907e412ea12c355e8989c811d382d893ba6a541c091e6d916164"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279faafe9a4cdaeeee7844c19cccb865328bd55a2bf4012fef8d7040223a5245"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:196d8426a9220d29c118eec6074034648267c176d220cb42c49b3c9c396f0dbc"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:166e68b1e42862b18570d636a7b615630552daeab8b129083aa094f848be64b0"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b84c3f51969d33266640c218ad5bb5f8487e6a991db7a95b2c3c46fbda37a77c"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:501113e4d84887c03f83c7d8886c0744fe088fd6b633b919ebf7af4f0f7186be"}, - {file = "psycopg_binary-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:e889fe21c578c6c533c8550e1b3ba5d2cc5d151890458fa5fbfc2ca3b2324cfa"}, -] - [[package]] name = "psycopg2-binary" version = "2.9.10" description = "psycopg2 - Python-PostgreSQL Database Adapter" -optional = false +optional = true python-versions = ">=3.8" -groups = ["dev"] +groups = ["main"] +markers = "extra == \"psycopg2\"" files = [ {file = "psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2"}, {file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f"}, @@ -1991,19 +1891,6 @@ files = [ ] markers = {docs = "python_version < \"3.10\""} -[[package]] -name = "tzdata" -version = "2025.1" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -groups = ["dev"] -markers = "sys_platform == \"win32\"" -files = [ - {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, - {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, -] - [[package]] name = "ujson" version = "5.8.0" @@ -2150,7 +2037,10 @@ files = [ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +[extras] +psycopg2 = ["psycopg2-binary"] + [metadata] lock-version = "2.1" python-versions = "^3.9" -content-hash = "bdbff29a7b63a3d047b9776250b95e45f3a6e0a15d65b1727c770ddb0bb89243" +content-hash = "0a5da13e7b3e057c2c857ba610ffa6af8bb7902c1cc71837c6021a52d7093a04" diff --git a/pyproject.toml b/pyproject.toml index 08cb46e..ab8f35e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,8 @@ sqlalchemy-utils = "^0.41.1" #iterators = "^0.2.0" #click = "^8.1.6" pals = "^0.3.5" +psycopg2-binary = { version = "^2.9", optional = true } + [tool.poetry.group.dev.dependencies] pytest = "^7.3.1" @@ -38,8 +40,6 @@ python-language-server = "^0.36.2" ruff = "^0.0.285" pydantic = "^2.4" pytest-cov = "^4.1.0" -psycopg2-binary = "^2.9.10" -psycopg = {extras = ["binary"], version = "^3.2.4"} [tool.poetry.group.docs.dependencies] @@ -52,6 +52,9 @@ mkdocstrings = {extras = ["python"], version = "^0.23.0"} mkdocs-alias-plugin = "^0.6.0" mkdocs-macros-plugin = "^1.0.4" +[tool.poetry.extras] +psycopg2 = ["psycopg2-binary"] + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/tests/conftest.py b/tests/conftest.py index fe6ff91..f8b9ea4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,7 +25,12 @@ @pytest.fixture(scope="session") def pg_db(): - dsn = f"postgresql+psycopg://depeche:depeche@localhost:4888/depeche_test_{_os.getpid()}" + from depeche_db import _compat + + if _compat.PSYCOPG_VERSION == "3": + dsn = f"postgresql+psycopg://depeche:depeche@localhost:4888/depeche_test_{_os.getpid()}" + else: + dsn = f"postgresql://depeche:depeche@localhost:4888/depeche_test_{_os.getpid()}" if _tools.pg_check_if_db_exists(dsn): _tools.pg_drop_db(dsn) _tools.pg_create_db(dsn)