From: Daniele Varrazzo Date: Sat, 25 Jul 2020 23:54:32 +0000 (+0100) Subject: Create two different python distributions in the project X-Git-Tag: 3.0.dev0~470 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=609c99c3df702cf19875805b62645669a6ba09d3;p=thirdparty%2Fpsycopg.git Create two different python distributions in the project The psycopg3 package is pure Python and doesn't depend on Cython, the psycopg3_c package is entirely optional and depends on the former. Tox had to be split, because it gets confused by the presence of the top-level pyproject.toml, which is there only to configure black. --- diff --git a/.gitignore b/.gitignore index ce69c0448..54ca4839a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -/psycopg3.egg-info -/.tox -/.eggs +/*.egg-info/ +.tox +/.eggs/ /build /dist *.pstats diff --git a/.travis.yml b/.travis.yml index a23c2b4dd..0520f9d29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,13 +9,19 @@ env: matrix: include: - - env: TOXENV=black + - env: + - TOXENV=black + - TOXDIR=. python: 3.6 - - env: TOXENV=flake8 + - env: + - TOXENV=flake8 + - TOXDIR=. python: 3.6 - - env: TOXENV=mypy + - env: + - TOXENV=mypy + - TOXDIR=. python: 3.6 - python: 3.6 @@ -26,6 +32,7 @@ matrix: - postgresql-client-9.5 env: - TOXENV=py36 + - TOXDIR=psycopg3_c - PGVER=9.5 - PSYCOPG3_IMPL=c - PGPORT=5432 @@ -38,6 +45,7 @@ matrix: - postgresql-client-9.6 env: - TOXENV=py36 + - TOXDIR=psycopg3 - PGVER=9.6 - PSYCOPG3_IMPL=ctypes - PGPORT=5432 @@ -50,6 +58,7 @@ matrix: - postgresql-client-10 env: - TOXENV=py37 + - TOXDIR=psycopg3_c - PGVER=10 - PSYCOPG3_IMPL=c - PGPORT=5432 @@ -63,6 +72,7 @@ matrix: - postgresql-client-11 env: - TOXENV=py37 + - TOXDIR=psycopg3 - PGVER=11 - PSYCOPG3_IMPL=ctypes - PGPORT=5433 @@ -76,6 +86,7 @@ matrix: - postgresql-client-12 env: - TOXENV=py38 + - TOXDIR=psycopg3_c - PGVER=12 - PSYCOPG3_IMPL=c - PGPORT=5433 @@ -89,6 +100,7 @@ matrix: - postgresql-client-12 env: - TOXENV=py38 + - TOXDIR=psycopg3 - PGVER=12 - PSYCOPG3_IMPL=ctypes - PGPORT=5433 @@ -98,4 +110,4 @@ install: - test ${TOXENV:0:2} != py || psql -c 'create database psycopg3_test' script: - - tox + - tox -c $TOXDIR diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 10984ce53..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include README.rst LICENSE.txt BACKERS.md tox.ini -recursive-include psycopg3 *.pyx *.pxd diff --git a/README.rst b/README.rst index 162debd06..51ca1d1e6 100644 --- a/README.rst +++ b/README.rst @@ -3,6 +3,15 @@ psycopg3 -- PostgreSQL database adapter for Python psycopg3 is a modern implementation of a PostgreSQL adapter for Python. +The package is split in different parts, with different requirements. + +- The pure python package only depends on the **libpq**, the PostgreSQL client + library. The code is in the ``psycopg3`` directory. + +- The optional C optimization: in order to build it requires the **libpq-dev** + packages, a C compiler and Cython. The code is in the ``psycopg3_c`` + directory. + Installation ------------ @@ -10,7 +19,10 @@ Installation The library is still in early development stage. If you want to try it out you can install it from source using:: - pip install -e git+https://github.com/psycopg/psycopg3.git#egg=psycopg3 + git clone https://github.com/psycopg/psycopg3.git + cd psycopg3 + python psycopg3/setup.py install # for the base Python package + python psycopg3_c/setup.py install # for the C extension module Hacking @@ -19,16 +31,20 @@ Hacking We assume you have built your virtualenv and ``pip`` just works and ``python`` refers to Python 3. You can set up a dev environment with:: - python setup.py develop + python psycopg3/setup.py develop # for the base Python pacakge + python psycopg3_c/setup.py develop # for the C extension module -All the available tests and dev support are defined in ``tox.ini``: please -refer to `tox documentation`__ for its usage. You can run all the tests with:: +All the available tests and dev support are defined in the ``tox.ini`` files +in this directory and in the package directories: please refer to `tox +documentation`__ for its usage. You can run all the tests with:: psql -c 'create database psycopg3_test' export PSYCOPG3_TEST_DSN="dbname=psycopg3_test" - tox -s + tox -c psycopg3 -s + tox -c psycopg3_c -s + +and validate the code before submission running:: -You can also install the test dependencies in your virtualenv to run tests -faster: please look at the ``tox.ini`` comments for instructions. + tox -p4 .. __: https://tox.readthedocs.io/ diff --git a/psycopg3/.gitignore b/psycopg3/.gitignore index f14a44ed8..4bba7db84 100644 --- a/psycopg3/.gitignore +++ b/psycopg3/.gitignore @@ -1,3 +1,3 @@ -_psycopg3.c -_psycopg3.*.so -*.html +/psycopg3.egg-info/ +/build +/dist diff --git a/.mypy.ini b/psycopg3/.mypy.ini similarity index 87% rename from .mypy.ini rename to psycopg3/.mypy.ini index 793fbaadb..b62d8e3d8 100644 --- a/.mypy.ini +++ b/psycopg3/.mypy.ini @@ -3,6 +3,7 @@ files = psycopg3 warn_unused_ignores = True show_error_codes = True strict = True +mypy_path = ../psycopg3_c [mypy-pytest] ignore_missing_imports = True diff --git a/psycopg3/LICENSE.txt b/psycopg3/LICENSE.txt new file mode 120000 index 000000000..4ab43736a --- /dev/null +++ b/psycopg3/LICENSE.txt @@ -0,0 +1 @@ +../LICENSE.txt \ No newline at end of file diff --git a/psycopg3/MANIFEST.in b/psycopg3/MANIFEST.in new file mode 100644 index 000000000..88629c900 --- /dev/null +++ b/psycopg3/MANIFEST.in @@ -0,0 +1 @@ +include README.rst LICENSE.txt diff --git a/psycopg3/README.rst b/psycopg3/README.rst new file mode 100644 index 000000000..36ee00dc2 --- /dev/null +++ b/psycopg3/README.rst @@ -0,0 +1,17 @@ +PostgreSQL database adapter for Python +====================================== + +This distribution contains the pure Python package ``psycopg3``. + +Installation:: + + pip install psycopg3 + +Even if the package is pure Python, the PostgreSQL client library libpq must +be available in the system. + +Please read `the project readme`__ for more details. + +.. __: https://github.com/psycopg/psycopg3#readme + +Copyright (C) 2020 The Psycopg Team diff --git a/psycopg3/consts.py b/psycopg3/consts.py deleted file mode 100644 index ae4038794..000000000 --- a/psycopg3/consts.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -psycopg3 package constants -""" - -# Copyright (C) 2020 The Psycopg Team - -VERSION = "2.99.0" diff --git a/psycopg3/pq/.gitignore b/psycopg3/pq/.gitignore deleted file mode 100644 index 7b4389339..000000000 --- a/psycopg3/pq/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -pq_cython.c -pq_cython.*.so -pq_cython.html diff --git a/psycopg3/__init__.py b/psycopg3/psycopg3/__init__.py similarity index 92% rename from psycopg3/__init__.py rename to psycopg3/psycopg3/__init__.py index 09c7fa173..aeb87d83b 100644 --- a/psycopg3/__init__.py +++ b/psycopg3/psycopg3/__init__.py @@ -5,7 +5,6 @@ psycopg3 -- PostgreSQL database adapter for Python # Copyright (C) 2020 The Psycopg Team from . import pq -from .consts import VERSION as __version__ # noqa from .connection import AsyncConnection, Connection from .errors import ( @@ -25,6 +24,8 @@ from .dbapi20 import BINARY, DATETIME, NUMBER, ROWID, STRING from .dbapi20 import Binary, Date, DateFromTicks, Time, TimeFromTicks from .dbapi20 import Timestamp, TimestampFromTicks +from .version import __version__ # noqa + # DBAPI compliancy connect = Connection.connect apilevel = "2.0" @@ -37,7 +38,7 @@ from . import types # noqa # Override adapters with fast version if available if pq.__impl__ == "c": - from ._psycopg3 import register_builtin_c_loaders + from psycopg3_c._psycopg3 import register_builtin_c_loaders register_builtin_c_loaders() diff --git a/psycopg3/adapt.py b/psycopg3/psycopg3/adapt.py similarity index 99% rename from psycopg3/adapt.py rename to psycopg3/psycopg3/adapt.py index d3fc9c78d..da173d6b7 100644 --- a/psycopg3/adapt.py +++ b/psycopg3/psycopg3/adapt.py @@ -156,7 +156,7 @@ Transformer: Type[proto.Transformer] # Override it with fast object if available if pq.__impl__ == "c": - from . import _psycopg3 + from psycopg3_c import _psycopg3 Transformer = _psycopg3.Transformer else: diff --git a/psycopg3/connection.py b/psycopg3/psycopg3/connection.py similarity index 99% rename from psycopg3/connection.py rename to psycopg3/psycopg3/connection.py index 597a1d430..0f0e320da 100644 --- a/psycopg3/connection.py +++ b/psycopg3/psycopg3/connection.py @@ -29,7 +29,7 @@ connect: Callable[[str], proto.PQGen[pq.proto.PGconn]] execute: Callable[[pq.proto.PGconn], proto.PQGen[List[pq.proto.PGresult]]] if pq.__impl__ == "c": - from . import _psycopg3 + from psycopg3_c import _psycopg3 connect = _psycopg3.connect execute = _psycopg3.execute diff --git a/psycopg3/conninfo.py b/psycopg3/psycopg3/conninfo.py similarity index 100% rename from psycopg3/conninfo.py rename to psycopg3/psycopg3/conninfo.py diff --git a/psycopg3/copy.py b/psycopg3/psycopg3/copy.py similarity index 100% rename from psycopg3/copy.py rename to psycopg3/psycopg3/copy.py diff --git a/psycopg3/cursor.py b/psycopg3/psycopg3/cursor.py similarity index 99% rename from psycopg3/cursor.py rename to psycopg3/psycopg3/cursor.py index fd4e60252..3f8cb74b4 100644 --- a/psycopg3/cursor.py +++ b/psycopg3/psycopg3/cursor.py @@ -20,7 +20,7 @@ if TYPE_CHECKING: execute: Callable[[pq.proto.PGconn], PQGen[List[pq.proto.PGresult]]] if pq.__impl__ == "c": - from . import _psycopg3 + from psycopg3_c import _psycopg3 execute = _psycopg3.execute diff --git a/psycopg3/dbapi20.py b/psycopg3/psycopg3/dbapi20.py similarity index 100% rename from psycopg3/dbapi20.py rename to psycopg3/psycopg3/dbapi20.py diff --git a/psycopg3/errors.py b/psycopg3/psycopg3/errors.py similarity index 100% rename from psycopg3/errors.py rename to psycopg3/psycopg3/errors.py diff --git a/psycopg3/generators.py b/psycopg3/psycopg3/generators.py similarity index 100% rename from psycopg3/generators.py rename to psycopg3/psycopg3/generators.py diff --git a/psycopg3/pq/__init__.py b/psycopg3/psycopg3/pq/__init__.py similarity index 97% rename from psycopg3/pq/__init__.py rename to psycopg3/psycopg3/pq/__init__.py index f4b12889e..f13d240d3 100644 --- a/psycopg3/pq/__init__.py +++ b/psycopg3/psycopg3/pq/__init__.py @@ -48,7 +48,7 @@ def import_from_libpq() -> None: if not impl or impl == "c": try: # TODO: extension module not recognised by mypy? - from . import pq_cython # type: ignore + from psycopg3_c import pq_cython # type: ignore except Exception as e: if not impl: logger.debug("C pq wrapper not available: %s", e) diff --git a/psycopg3/pq/_pq_ctypes.py b/psycopg3/psycopg3/pq/_pq_ctypes.py similarity index 100% rename from psycopg3/pq/_pq_ctypes.py rename to psycopg3/psycopg3/pq/_pq_ctypes.py diff --git a/psycopg3/pq/_pq_ctypes.pyi b/psycopg3/psycopg3/pq/_pq_ctypes.pyi similarity index 100% rename from psycopg3/pq/_pq_ctypes.pyi rename to psycopg3/psycopg3/pq/_pq_ctypes.pyi diff --git a/psycopg3/pq/encodings.py b/psycopg3/psycopg3/pq/encodings.py similarity index 100% rename from psycopg3/pq/encodings.py rename to psycopg3/psycopg3/pq/encodings.py diff --git a/psycopg3/pq/enums.py b/psycopg3/psycopg3/pq/enums.py similarity index 100% rename from psycopg3/pq/enums.py rename to psycopg3/psycopg3/pq/enums.py diff --git a/psycopg3/pq/misc.py b/psycopg3/psycopg3/pq/misc.py similarity index 100% rename from psycopg3/pq/misc.py rename to psycopg3/psycopg3/pq/misc.py diff --git a/psycopg3/pq/pq_ctypes.py b/psycopg3/psycopg3/pq/pq_ctypes.py similarity index 100% rename from psycopg3/pq/pq_ctypes.py rename to psycopg3/psycopg3/pq/pq_ctypes.py diff --git a/psycopg3/pq/proto.py b/psycopg3/psycopg3/pq/proto.py similarity index 100% rename from psycopg3/pq/proto.py rename to psycopg3/psycopg3/pq/proto.py diff --git a/psycopg3/proto.py b/psycopg3/psycopg3/proto.py similarity index 100% rename from psycopg3/proto.py rename to psycopg3/psycopg3/proto.py diff --git a/psycopg3/transform.py b/psycopg3/psycopg3/transform.py similarity index 100% rename from psycopg3/transform.py rename to psycopg3/psycopg3/transform.py diff --git a/psycopg3/types/__init__.py b/psycopg3/psycopg3/types/__init__.py similarity index 100% rename from psycopg3/types/__init__.py rename to psycopg3/psycopg3/types/__init__.py diff --git a/psycopg3/types/array.py b/psycopg3/psycopg3/types/array.py similarity index 100% rename from psycopg3/types/array.py rename to psycopg3/psycopg3/types/array.py diff --git a/psycopg3/types/composite.py b/psycopg3/psycopg3/types/composite.py similarity index 100% rename from psycopg3/types/composite.py rename to psycopg3/psycopg3/types/composite.py diff --git a/psycopg3/types/numeric.py b/psycopg3/psycopg3/types/numeric.py similarity index 100% rename from psycopg3/types/numeric.py rename to psycopg3/psycopg3/types/numeric.py diff --git a/psycopg3/types/oids.py b/psycopg3/psycopg3/types/oids.py similarity index 100% rename from psycopg3/types/oids.py rename to psycopg3/psycopg3/types/oids.py diff --git a/psycopg3/types/text.py b/psycopg3/psycopg3/types/text.py similarity index 100% rename from psycopg3/types/text.py rename to psycopg3/psycopg3/types/text.py diff --git a/psycopg3/utils/__init__.py b/psycopg3/psycopg3/utils/__init__.py similarity index 100% rename from psycopg3/utils/__init__.py rename to psycopg3/psycopg3/utils/__init__.py diff --git a/psycopg3/utils/queries.py b/psycopg3/psycopg3/utils/queries.py similarity index 100% rename from psycopg3/utils/queries.py rename to psycopg3/psycopg3/utils/queries.py diff --git a/psycopg3/psycopg3/version.py b/psycopg3/psycopg3/version.py new file mode 100644 index 000000000..e5a76325d --- /dev/null +++ b/psycopg3/psycopg3/version.py @@ -0,0 +1,7 @@ +""" +psycopg3 distribution version file. +""" + +# Copyright (C) 2020 The Psycopg Team + +__version__ = "2.99.0" diff --git a/psycopg3/waiting.py b/psycopg3/psycopg3/waiting.py similarity index 100% rename from psycopg3/waiting.py rename to psycopg3/psycopg3/waiting.py diff --git a/psycopg3/pyproject.toml b/psycopg3/pyproject.toml new file mode 100644 index 000000000..fb4f1f4f2 --- /dev/null +++ b/psycopg3/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = ["setuptools>=49.2.0", "wheel>=0.34.2"] +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 79 diff --git a/psycopg3/setup.cfg b/psycopg3/setup.cfg new file mode 100644 index 000000000..fef979d3f --- /dev/null +++ b/psycopg3/setup.cfg @@ -0,0 +1,34 @@ +[metadata] +name = psycopg3 +description = PostgreSQL database adapter for Python +url = https://psycopg.org/psycopg3/ +author = Daniele Varrazzo +author_email = daniele.varrazzo@gmail.com +license = GNU Lesser General Public License v3 (LGPLv3) + +project_urls = + Homepage = https://psycopg.org/ + Code = https://github.com/psycopg/psycopg3 + Issue Tracker = https://github.com/psycopg/psycopg3/issues + Download = https://pypi.org/project/psycopg3/ + +classifiers = + Intended Audience :: Developers + Programming Language :: Python :: 3 + License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) + Topic :: Database + Topic :: Database :: Front-Ends + Topic :: Software Development + Topic :: Software Development :: Libraries :: Python Modules + +long_description = file: README.rst +long_description_content_type = text/x-rst +license_file = LICENSE.txt + +[options] +python_requires = >= 3.6 +packages = find: +zip_safe = False +include_package_data = True +install_requires = + typing_extensions diff --git a/psycopg3/setup.py b/psycopg3/setup.py new file mode 100644 index 000000000..80bb67feb --- /dev/null +++ b/psycopg3/setup.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +""" +PostgreSQL database adapter for Python - pure Python package +""" + +# Copyright (C) 2020 The Psycopg Team + +import re +import os + +from setuptools import setup + +# Move to the directory of setup.py: executing this file from another location +# (e.g. from the project root) will fail +here = os.path.abspath(os.path.dirname(__file__)) +if os.path.abspath(os.getcwd()) != here: + os.chdir(here) + +with open("psycopg3/version.py") as f: + data = f.read() + m = re.search(r"""(?m)^__version__\s*=\s*['"]([^'"]+)['"]""", data) + if m is None: + raise Exception(f"cannot find version in {f.name}") + version = m.group(1) + +setup(version=version) diff --git a/psycopg3/tox.ini b/psycopg3/tox.ini new file mode 100644 index 000000000..f59f74e60 --- /dev/null +++ b/psycopg3/tox.ini @@ -0,0 +1,11 @@ +[tox] +envlist = py{36,37,38} +isolated_build = True + +[testenv:py{36,37,38}] +commands = + pytest ../tests +passenv = PG* PSYCOPG3_TEST_DSN PYTEST_ADDOPTS PSYCOPG3_IMPL +deps = + pytest >= 5.3, < 6 + pytest-asyncio >= 0.12.0, < 0.13 diff --git a/psycopg3_c/.gitignore b/psycopg3_c/.gitignore new file mode 100644 index 000000000..c2197d4ee --- /dev/null +++ b/psycopg3_c/.gitignore @@ -0,0 +1,4 @@ +/.eggs +/build +/dist +/psycopg3_c.egg-info diff --git a/psycopg3_c/LICENSE.txt b/psycopg3_c/LICENSE.txt new file mode 120000 index 000000000..4ab43736a --- /dev/null +++ b/psycopg3_c/LICENSE.txt @@ -0,0 +1 @@ +../LICENSE.txt \ No newline at end of file diff --git a/psycopg3_c/MANIFEST.in b/psycopg3_c/MANIFEST.in new file mode 100644 index 000000000..88629c900 --- /dev/null +++ b/psycopg3_c/MANIFEST.in @@ -0,0 +1 @@ +include README.rst LICENSE.txt diff --git a/psycopg3_c/README.rst b/psycopg3_c/README.rst new file mode 100644 index 000000000..9eec2e404 --- /dev/null +++ b/psycopg3_c/README.rst @@ -0,0 +1,19 @@ +PostgreSQL database adapter for Python - optimisation package +============================================================= + +This distribution contains the optional optimization package ``psycopg3_c``. + +Installation:: + + pip install psycopg3-c + +Installing this distribution requires the ``libpq-dev`` package and other +packages normally used to build Python C extensions. If you cannot meet these +dependencies, don't worry: you don't need the package: please install the +``psycopg3`` package only. + +Please read `the project readme`__ for more details. + +.. __: https://github.com/psycopg/psycopg3#readme + +Copyright (C) 2020 The Psycopg Team diff --git a/psycopg3_c/psycopg3_c/.gitignore b/psycopg3_c/psycopg3_c/.gitignore new file mode 100644 index 000000000..5905a6773 --- /dev/null +++ b/psycopg3_c/psycopg3_c/.gitignore @@ -0,0 +1,3 @@ +/*.so +_psycopg3.c +pq_cython.c diff --git a/psycopg3_c/psycopg3_c/__init__.py b/psycopg3_c/psycopg3_c/__init__.py new file mode 100644 index 000000000..8ab3af86f --- /dev/null +++ b/psycopg3_c/psycopg3_c/__init__.py @@ -0,0 +1,7 @@ +""" +psycopg3 -- PostgreSQL database adapter for Python -- C optimization package +""" + +# Copyright (C) 2020 The Psycopg Team + +from .version import __version__ # noqa diff --git a/psycopg3/_psycopg3.pyi b/psycopg3_c/psycopg3_c/_psycopg3.pyi similarity index 89% rename from psycopg3/_psycopg3.pyi rename to psycopg3_c/psycopg3_c/_psycopg3.pyi index 87cd90596..aaa298834 100644 --- a/psycopg3/_psycopg3.pyi +++ b/psycopg3_c/psycopg3_c/_psycopg3.pyi @@ -10,10 +10,10 @@ information. Will submit a bug. import codecs from typing import Any, Iterable, List, Optional, Sequence, Tuple -from .proto import AdaptContext, DumpFunc, DumpersMap, DumperType -from .proto import LoadFunc, LoadersMap, LoaderType, MaybeOid, PQGen -from .connection import BaseConnection -from . import pq +from psycopg3.proto import AdaptContext, DumpFunc, DumpersMap, DumperType +from psycopg3.proto import LoadFunc, LoadersMap, LoaderType, MaybeOid, PQGen +from psycopg3.connection import BaseConnection +from psycopg3 import pq class Transformer: def __init__(self, context: AdaptContext = None): ... diff --git a/psycopg3/_psycopg3.pyx b/psycopg3_c/psycopg3_c/_psycopg3.pyx similarity index 100% rename from psycopg3/_psycopg3.pyx rename to psycopg3_c/psycopg3_c/_psycopg3.pyx diff --git a/psycopg3/adapt.pxd b/psycopg3_c/psycopg3_c/adapt.pxd similarity index 100% rename from psycopg3/adapt.pxd rename to psycopg3_c/psycopg3_c/adapt.pxd diff --git a/psycopg3/adapt.pyx b/psycopg3_c/psycopg3_c/adapt.pyx similarity index 95% rename from psycopg3/adapt.pyx rename to psycopg3_c/psycopg3_c/adapt.pyx index 0cd43da68..08f6409bd 100644 --- a/psycopg3/adapt.pyx +++ b/psycopg3_c/psycopg3_c/adapt.pyx @@ -13,7 +13,7 @@ equivalent C implementations. # Copyright (C) 2020 The Psycopg Team -from psycopg3.adapt cimport cloader_func, get_context_func +from psycopg3_c.adapt cimport cloader_func, get_context_func import logging logger = logging.getLogger("psycopg3.adapt") diff --git a/psycopg3/types/endian.pxd b/psycopg3_c/psycopg3_c/endian.pxd similarity index 100% rename from psycopg3/types/endian.pxd rename to psycopg3_c/psycopg3_c/endian.pxd diff --git a/psycopg3/generators.pyx b/psycopg3_c/psycopg3_c/generators.pyx similarity index 95% rename from psycopg3/generators.pyx rename to psycopg3_c/psycopg3_c/generators.pyx index b11f5be2c..58fffc95e 100644 --- a/psycopg3/generators.pyx +++ b/psycopg3_c/psycopg3_c/generators.pyx @@ -7,12 +7,12 @@ C implementation of generators for the communication protocols with the libpq import logging from typing import List -from . import errors as e -from .proto import PQGen -from .waiting import Wait, Ready +from psycopg3 import errors as e +from psycopg3.proto import PQGen +from psycopg3.waiting import Wait, Ready from psycopg3 import pq -from psycopg3.pq cimport libpq -from psycopg3.pq.pq_cython cimport PGconn, PGresult +from psycopg3_c cimport libpq +from psycopg3_c.pq_cython cimport PGconn, PGresult cdef object WAIT_W = Wait.W cdef object WAIT_R = Wait.R diff --git a/psycopg3/pq/libpq.pxd b/psycopg3_c/psycopg3_c/libpq.pxd similarity index 100% rename from psycopg3/pq/libpq.pxd rename to psycopg3_c/psycopg3_c/libpq.pxd diff --git a/psycopg3/pq/pq_cython.pxd b/psycopg3_c/psycopg3_c/pq_cython.pxd similarity index 95% rename from psycopg3/pq/pq_cython.pxd rename to psycopg3_c/psycopg3_c/pq_cython.pxd index 289aea2e0..edfe82c8c 100644 --- a/psycopg3/pq/pq_cython.pxd +++ b/psycopg3_c/psycopg3_c/pq_cython.pxd @@ -1,5 +1,5 @@ from posix.fcntl cimport pid_t -from psycopg3.pq cimport libpq as impl +from psycopg3_c cimport libpq as impl ctypedef char *(*conn_bytes_f) (const impl.PGconn *) ctypedef int(*conn_int_f) (const impl.PGconn *) diff --git a/psycopg3/pq/pq_cython.pyx b/psycopg3_c/psycopg3_c/pq_cython.pyx similarity index 99% rename from psycopg3/pq/pq_cython.pyx rename to psycopg3_c/psycopg3_c/pq_cython.pyx index 903e332d6..a1daa8ee8 100644 --- a/psycopg3/pq/pq_cython.pyx +++ b/psycopg3_c/psycopg3_c/pq_cython.pyx @@ -11,9 +11,8 @@ from cpython.bytes cimport PyBytes_AsString import logging from typing import List, Optional, Sequence, Tuple -from psycopg3.pq cimport libpq as impl -from psycopg3.pq.libpq cimport Oid -from psycopg3.errors import OperationalError +from psycopg3_c cimport libpq as impl +from psycopg3_c.libpq cimport Oid from psycopg3.pq.misc import PGnotify, ConninfoOption, PQerror, PGresAttDesc from psycopg3.pq.misc import error_message diff --git a/psycopg3/transform.pyx b/psycopg3_c/psycopg3_c/transform.pyx similarity index 98% rename from psycopg3/transform.pyx rename to psycopg3_c/psycopg3_c/transform.pyx index 63205cb86..28411b64f 100644 --- a/psycopg3/transform.pyx +++ b/psycopg3_c/psycopg3_c/transform.pyx @@ -17,12 +17,11 @@ from cpython.tuple cimport PyTuple_New, PyTuple_SET_ITEM import codecs from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple -from psycopg3.pq cimport libpq -from psycopg3.pq.pq_cython cimport PGresult +from psycopg3_c cimport libpq +from psycopg3_c.pq_cython cimport PGresult from psycopg3 import errors as e from psycopg3.pq.enums import Format -# from psycopg3.types.oids import builtins, INVALID_OID TEXT_OID = 25 diff --git a/psycopg3/types/numeric.pyx b/psycopg3_c/psycopg3_c/types/numeric.pyx similarity index 96% rename from psycopg3/types/numeric.pyx rename to psycopg3_c/psycopg3_c/types/numeric.pyx index 6192412e1..642c98307 100644 --- a/psycopg3/types/numeric.pyx +++ b/psycopg3_c/psycopg3_c/types/numeric.pyx @@ -5,7 +5,7 @@ Cython adapters for numeric types. # Copyright (C) 2020 The Psycopg Team from libc.stdint cimport * -from psycopg3.types.endian cimport be16toh, be32toh, be64toh +from psycopg3_c.endian cimport be16toh, be32toh, be64toh from cpython.long cimport ( diff --git a/psycopg3/types/text.pyx b/psycopg3_c/psycopg3_c/types/text.pyx similarity index 98% rename from psycopg3/types/text.pyx rename to psycopg3_c/psycopg3_c/types/text.pyx index 27f0ef3af..d3738fc0b 100644 --- a/psycopg3/types/text.pyx +++ b/psycopg3_c/psycopg3_c/types/text.pyx @@ -8,7 +8,7 @@ from cpython.bytes cimport PyBytes_FromStringAndSize from cpython.mem cimport PyMem_Malloc from cpython.object cimport PyObject from cpython.unicode cimport PyUnicode_DecodeUTF8 -from psycopg3.pq cimport libpq +from psycopg3_c cimport libpq cdef struct TextContext: diff --git a/psycopg3_c/psycopg3_c/version.py b/psycopg3_c/psycopg3_c/version.py new file mode 100644 index 000000000..34a6c9b12 --- /dev/null +++ b/psycopg3_c/psycopg3_c/version.py @@ -0,0 +1,7 @@ +""" +psycopg3-c distribution version file. +""" + +# Copyright (C) 2020 The Psycopg Team + +__version__ = "2.99.0" diff --git a/psycopg3_c/pyproject.toml b/psycopg3_c/pyproject.toml new file mode 100644 index 000000000..10e35480c --- /dev/null +++ b/psycopg3_c/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = ["setuptools>=49.2.0", "wheel>=0.34.2", "Cython>=3.0a5"] +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 79 diff --git a/psycopg3_c/setup.cfg b/psycopg3_c/setup.cfg new file mode 100644 index 000000000..90aed8d1b --- /dev/null +++ b/psycopg3_c/setup.cfg @@ -0,0 +1,34 @@ +[metadata] +name = psycopg3-c +description = PostgreSQL database adapter for Python -- C optimisation distribution +url = https://psycopg.org/psycopg3/ +author = Daniele Varrazzo +author_email = daniele.varrazzo@gmail.com +license = GNU Lesser General Public License v3 (LGPLv3) + +project_urls = + Homepage = https://psycopg.org/ + Code = https://github.com/psycopg/psycopg3 + Issue Tracker = https://github.com/psycopg/psycopg3/issues + Download = https://pypi.org/project/psycopg3-c/ + +# TODO: classifiers +classifiers = + Intended Audience :: Developers + Programming Language :: Python :: 3 + License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) + Topic :: Database + Topic :: Database :: Front-Ends + Topic :: Software Development + Topic :: Software Development :: Libraries :: Python Modules + +long_description = file: README.rst +long_description_content_type = text/x-rst +license_file = LICENSE.txt + +[options] +python_requires = >= 3.6 +setup_requires = Cython >= 3.0a5 +packages = find: +zip_safe = False +include_package_data = True diff --git a/psycopg3_c/setup.py b/psycopg3_c/setup.py new file mode 100644 index 000000000..30be45611 --- /dev/null +++ b/psycopg3_c/setup.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +""" +PostgreSQL database adapter for Python - optimisation package +""" + +# Copyright (C) 2020 The Psycopg Team + + +import os +import re +import subprocess as sp + +from setuptools import setup, Extension +from distutils.command.build_ext import build_ext +from distutils import log + +# Move to the directory of setup.py: executing this file from another location +# (e.g. from the project root) will fail +here = os.path.abspath(os.path.dirname(__file__)) +if os.path.abspath(os.getcwd()) != here: + os.chdir(here) + +with open("psycopg3_c/version.py") as f: + data = f.read() + m = re.search(r"""(?m)^__version__\s*=\s*['"]([^'"]+)['"]""", data) + if m is None: + raise Exception(f"cannot find version in {f.name}") + version = m.group(1) + + +class psycopg3_build_ext(build_ext): + def finalize_options(self) -> None: + self._setup_ext_build() + super().finalize_options() + + def _setup_ext_build(self) -> None: + cythonize = None + + # In the sdist there are not .pyx, only c, so we don't need Cython + # Otherwise Cython is a requirement and is be used to compile pyx to c + if os.path.exists("psycopg3_c/_psycopg3.pyx"): + from Cython.Build import cythonize + + # Add the include dir for the libpq. + try: + out = sp.run( + ["pg_config", "--includedir"], stdout=sp.PIPE, check=True + ) + except Exception as e: + log.error("cannot build C module: %s", e) + raise + + includedir = out.stdout.strip().decode("utf8") + for ext in self.distribution.ext_modules: + ext.include_dirs.append(includedir) + + if cythonize is not None: + for ext in self.distribution.ext_modules: + ext.sources[0] = os.path.splitext(ext.sources[0])[0] + ".pyx" + + self.distribution.ext_modules = cythonize( + self.distribution.ext_modules, + language_level=3, + annotate=False, # enable to get an html view of the C module + ) + else: + self.distribution.ext_modules = [pgext, pqext] + + +# Some details missing, to be finished by psycopg3_build_ext.finalize_options +pgext = Extension( + "psycopg3_c._psycopg3", + ["psycopg3_c/_psycopg3.c"], + libraries=["pq"], + include_dirs=[], +) + +pqext = Extension( + "psycopg3_c.pq_cython", + ["psycopg3_c/pq_cython.c"], + libraries=["pq"], + include_dirs=[], +) + +setup( + version=version, + # TODO: might use a range + install_requires=[f"psycopg3=={version}"], + ext_modules=[pgext, pqext], + cmdclass={"build_ext": psycopg3_build_ext}, +) diff --git a/psycopg3_c/tox.ini b/psycopg3_c/tox.ini new file mode 100644 index 000000000..2d4b7310f --- /dev/null +++ b/psycopg3_c/tox.ini @@ -0,0 +1,13 @@ +[tox] +envlist = py{36,37,38} +isolated_build = True + +[testenv] +commands = + python ../psycopg3/setup.py develop + pytest ../tests {posargs} +passenv = PG* PSYCOPG3_TEST_DSN PYTEST_ADDOPTS PSYCOPG3_IMPL +deps = + pytest >= 5.3, < 6 + pytest-asyncio >= 0.12.0, < 0.13 + -e {toxinidir}/../psycopg3 diff --git a/pyproject.toml b/pyproject.toml index a8f43fefd..372ef2d60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,11 @@ +[build-system] +requires = ["setuptools>=49.2.0", "wheel>=0.34.2"] +build-backend = "setuptools.build_meta" + [tool.black] line-length = 79 + +[tool.pytest.ini_options] +testpaths=[ + "tests", +] diff --git a/setup.py b/setup.py deleted file mode 100644 index ab371e15d..000000000 --- a/setup.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python3 -""" -psycopg3 -- PostgreSQL database adapter for Python -""" - -# Copyright (C) 2020 The Psycopg Team - - -import re -import os -import subprocess as sp -from setuptools import setup, find_packages, Extension -from distutils.command.build_ext import build_ext -from distutils import log - -try: - from Cython.Build import cythonize -except ImportError: - cythonize = None - -# Grab the version without importing the module -# or we will get import errors on install if prerequisites are still missing -fn = os.path.join(os.path.dirname(__file__), "psycopg3/consts.py") -with open(fn) as f: - m = re.search(r"""(?mi)^VERSION\s*=\s*["']+([^'"]+)["']+""", f.read()) -if m: - version = m.group(1) -else: - raise ValueError("cannot find VERSION in the consts module") - -# Read the description from the README -with open("README.rst") as f: - readme = f.read() - -# TODO: classifiers -classifiers = """ -Intended Audience :: Developers -Programming Language :: Python :: 3 -License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) -Topic :: Database -Topic :: Database :: Front-Ends -Topic :: Software Development -Topic :: Software Development :: Libraries :: Python Modules -""" - - -class psycopg3_build_ext(build_ext): - def finalize_options(self) -> None: - self._setup_ext_build() - super().finalize_options() - - def _setup_ext_build(self) -> None: - # Clear the dummy so if we can't build it's no drama - self.distribution.ext_modules = None - - try: - from Cython.Build import cythonize - except ImportError: - log.warn("Cython is not available: the C module will not be built") - return - - try: - out = sp.run( - ["pg_config", "--includedir"], stdout=sp.PIPE, check=True - ) - except Exception as e: - log.warn("cannot build C module: %s", e) - return - - includedir = out.stdout.strip().decode("utf8") - - pgext = Extension( - "psycopg3._psycopg3", - ["psycopg3/_psycopg3.pyx"], - libraries=["pq"], - include_dirs=[includedir], - ) - pqext = Extension( - "psycopg3.pq.pq_cython", - ["psycopg3/pq/pq_cython.pyx"], - libraries=["pq"], - include_dirs=[includedir], - ) - self.distribution.ext_modules = cythonize( - [pgext, pqext], - language_level=3, - # annotate=True, # enable to get an html view of the C module - ) - - -setup( - name="psycopg3", - description=readme.splitlines()[0], - long_description="\n".join(readme.splitlines()[2:]).lstrip(), - author="Daniele Varrazzo", - author_email="daniele.varrazzo@gmail.com", - url="https://psycopg.org/psycopg3/", - python_requires=">=3.6", - packages=find_packages(exclude=["tests"]), - classifiers=[x for x in classifiers.split("\n") if x], - setup_requires=["Cython>=3.0a2"], - install_requires=["typing_extensions"], - zip_safe=False, - include_package_data=True, - version=version, - project_urls={ - "Homepage": "https://psycopg.org/", - "Code": "https://github.com/psycopg/psycopg3", - "Issue Tracker": "https://github.com/psycopg/psycopg3/issues", - "Download": "https://pypi.org/project/psycopg3/", - }, - cmdclass={"build_ext": psycopg3_build_ext}, - # hack to run build_ext. It will be replaced by real the stuff - ext_modules=[Extension("psycopg3.dummy", ["dummy.c"])], -) diff --git a/tests/fix_db.py b/tests/fix_db.py index 2eb890259..f17f16e0b 100644 --- a/tests/fix_db.py +++ b/tests/fix_db.py @@ -1,8 +1,6 @@ import os import pytest -from psycopg3 import pq - def pytest_addoption(parser): parser.addoption( @@ -26,6 +24,8 @@ def dsn(request): @pytest.fixture def pgconn(dsn): """Return a PGconn connection open to `--test-dsn`.""" + from psycopg3 import pq + conn = pq.PGconn.connect(dsn.encode("utf8")) if conn.status != pq.ConnStatus.OK: pytest.fail( diff --git a/tests/fix_pq.py b/tests/fix_pq.py index ae1e2a399..fa0a566e8 100644 --- a/tests/fix_pq.py +++ b/tests/fix_pq.py @@ -2,10 +2,13 @@ import re import operator import pytest -from psycopg3 import pq - def pytest_report_header(config): + try: + from psycopg3 import pq + except ImportError: + return [] + return [ f"libpq available: {pq.version()}", f"libpq wrapper implementation: {pq.__impl__}", @@ -22,6 +25,8 @@ def pytest_configure(config): def pytest_runtest_setup(item): + from psycopg3 import pq + for m in item.iter_markers(name="libpq"): check_libpq_version(pq.version(), m.args) diff --git a/tests/pq/test_pgconn.py b/tests/pq/test_pgconn.py index 3753dde4f..e0d920964 100644 --- a/tests/pq/test_pgconn.py +++ b/tests/pq/test_pgconn.py @@ -194,7 +194,7 @@ def test_host(pgconn): pgconn.host -# TODO: to implement in psycopg3.pq.pq_cython +# TODO: to implement in pq_cython @pytest.mark.xfail @pytest.mark.libpq(">= 12") def test_hostaddr(pgconn): diff --git a/tests/test_concurrency.py b/tests/test_concurrency.py index 509c9962c..aafbdd270 100644 --- a/tests/test_concurrency.py +++ b/tests/test_concurrency.py @@ -99,6 +99,8 @@ t.join() f.write(module) env = dict(os.environ) env["PYTHONPATH"] = dir + os.pathsep + env.get("PYTHONPATH", "") + # TODO: debug this. Importing c module fails on travis in this scenario + env.pop("PSYCOPG3_IMPL", None) out = sp.check_output( [sys.executable, "-c", script], stderr=sp.STDOUT, env=env ).decode("utf8", "replace") diff --git a/tox.ini b/tox.ini index 72c710444..db270ab32 100644 --- a/tox.ini +++ b/tox.ini @@ -1,44 +1,22 @@ -# Tox is nice, but rebuilding the environment every time is kinda slow. -# If you want to install the test environments defined here into your current -# virtualenv you can use: -# -# pip install tox tox-current-env -# tox --print-deps-to-file /tmp/requirements.txt -# pip install -r /tmp/requirements.txt -# -# After which you can run the tests with: -# -# tox --current-env -e ENV -# -# or just run manually the ``commands`` defined here. - [tox] -envlist = py{36,37,38}, black, flake8, mypy - -[testenv] -# run setup.py develop to build the c extension in place. -# if this doesn't happen, psycopg3 will be imported from the root directory -# anyway rather than from the tox environment, because pytest adds the -# root dir to the pythonpath. It sucks but I don't see a way around. -commands = - python setup.py develop - pytest {posargs} -passenv = PG* PSYCOPG3_TEST_DSN PYTEST_ADDOPTS PSYCOPG3_IMPL -deps = - pytest >= 5.3, < 6 - pytest-asyncio >= 0.12.0, < 0.13 +envlist = black, flake8, mypy +isolated_build = True [testenv:black] commands = black --check --diff . deps = black +skip_install = true [testenv:flake8] commands = flake8 deps = flake8 >= 3.8, < 3.9 +skip_install = true [testenv:mypy] commands = mypy deps = mypy >= 0.782 +changedir = psycopg3 +skip_install = true [flake8] max-line-length = 85