summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>2021-05-26 17:29:03 +0100
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>2021-05-26 17:29:03 +0100
commit06c3c3a55739ff145fb196bc9bc2dde6ab66d78f (patch)
tree770ac470a4d5fa214b7da7fe1ddc1bd8da19be2a
parentec531bee31556ae1a1e42ced364d97b56a493a5d (diff)
parent808007456dd1c498028e908f07fd8b13e9953595 (diff)
downloadpsycopg2-06c3c3a55739ff145fb196bc9bc2dde6ab66d78f.tar.gz
Merge branch 'packages'
-rw-r--r--.appveyor/packages.yml88
-rw-r--r--.appveyor/tests.yml (renamed from .appveyor.yml)7
-rw-r--r--.github/workflows/packages.yml87
-rw-r--r--.gitignore1
-rw-r--r--NEWS9
-rw-r--r--doc/release.rst53
-rwxr-xr-xscripts/appveyor.py16
-rwxr-xr-xscripts/build/build_macos.sh77
-rwxr-xr-xscripts/build/build_manylinux_2_24.sh75
-rwxr-xr-xscripts/build/download_packages.py77
-rwxr-xr-xscripts/build/download_packages_appveyor.py77
-rw-r--r--setup.py10
-rw-r--r--tests/testutils.py5
13 files changed, 528 insertions, 54 deletions
diff --git a/.appveyor/packages.yml b/.appveyor/packages.yml
new file mode 100644
index 0000000..628475c
--- /dev/null
+++ b/.appveyor/packages.yml
@@ -0,0 +1,88 @@
+version : 2.x.{build}
+
+clone_folder: C:\Project
+
+# We use the configuration to specify the package name
+configuration:
+ - psycopg2
+ - psycopg2-binary
+
+environment:
+ matrix:
+ # For Python versions available on Appveyor, see
+ # https://www.appveyor.com/docs/windows-images-software/#python
+ - {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019, PY_VER: "39", PY_ARCH: "32"}
+ - {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019, PY_VER: "39", PY_ARCH: "64"}
+ - {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015, PY_VER: "38", PY_ARCH: "32"}
+ - {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015, PY_VER: "38", PY_ARCH: "64"}
+ - {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015, PY_VER: "37", PY_ARCH: "32"}
+ - {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015, PY_VER: "37", PY_ARCH: "64"}
+ - {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015, PY_VER: "36", PY_ARCH: "32"}
+ - {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015, PY_VER: "36", PY_ARCH: "64"}
+
+ WORKFLOW: packages
+
+ OPENSSL_VERSION: "1_1_1h"
+ POSTGRES_VERSION: "13_0"
+
+ PSYCOPG2_TESTDB: psycopg2_test
+ PSYCOPG2_TESTDB_USER: postgres
+ PSYCOPG2_TESTDB_HOST: localhost
+
+ PGUSER: postgres
+ PGPASSWORD: Password12!
+ PGSSLMODE: require
+
+ # Add CWD to perl library path for PostgreSQL build on VS2019
+ PERL5LIB: .
+
+ # Select according to the service enabled
+ POSTGRES_DIR: C:\Program Files\PostgreSQL\9.6\
+
+ # The python used in the build process, not the one packages are built for
+ PYEXE: C:\Python36\python.exe
+
+matrix:
+ fast_finish: false
+
+services:
+ # Note: if you change this service also change POSTGRES_DIR
+ - postgresql96
+
+cache:
+ # Rebuild cache if following file changes
+ # (See the file to zap the cache manually)
+ - C:\Others -> scripts\appveyor.cache_rebuild
+
+# Script called before repo cloning
+# init:
+
+# Repository gets cloned, Cache is restored
+
+install:
+ - "%PYEXE% scripts\\appveyor.py install"
+
+# PostgreSQL server starts now
+
+build: off
+
+build_script:
+ - "%PYEXE% scripts\\appveyor.py build_script"
+
+after_build:
+ - "%PYEXE% scripts\\appveyor.py after_build"
+
+before_test:
+ - "%PYEXE% scripts\\appveyor.py before_test"
+
+test_script:
+ - "%PYEXE% scripts\\appveyor.py test_script"
+
+artifacts:
+ - path: dist\psycopg2-*\*.whl
+ name: wheel
+ - path: dist\psycopg2-*\*.exe
+ name: exe
+
+
+# vim: set ts=4 sts=4 sw=4:
diff --git a/.appveyor.yml b/.appveyor/tests.yml
index d7edc0d..e1b7c52 100644
--- a/.appveyor.yml
+++ b/.appveyor/tests.yml
@@ -3,11 +3,6 @@ version : 2.x.{build}
clone_folder: C:\Project
environment:
- global:
- # MSVC Express 2008's setenv.cmd failes if /E:ON and /V:ON are not
- # enabled in the batch script interpreter
- CMD_IN_ENV: cmd /E:ON /V:ON /C .\appveyor\run_with_env.cmd
-
matrix:
# For Python versions available on Appveyor, see
# https://www.appveyor.com/docs/windows-images-software/#python
@@ -20,6 +15,8 @@ environment:
- {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015, PY_VER: "36", PY_ARCH: "32"}
- {APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015, PY_VER: "36", PY_ARCH: "64"}
+ WORKFLOW: tests
+
OPENSSL_VERSION: "1_1_1h"
POSTGRES_VERSION: "13_0"
diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml
index aa0f9c5..95d11ff 100644
--- a/.github/workflows/packages.yml
+++ b/.github/workflows/packages.yml
@@ -50,3 +50,90 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5
+
+
+ build-manylinux_2_24:
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - platform: manylinux_2_24_x86_64
+ - platform: manylinux_2_24_i686
+ - platform: manylinux_2_24_aarch64
+ - platform: manylinux_2_24_ppc64le
+
+ runs-on: ubuntu-20.04
+ steps:
+ - name: Checkout repos
+ uses: actions/checkout@v2
+
+ - name: Set up QEMU for multi-arch build
+ uses: docker/setup-qemu-action@v1
+
+ - name: Build packages
+ run: >-
+ docker run --rm
+ -e PLAT=${{ matrix.platform }}
+ -e PACKAGE_NAME=psycopg2-binary
+ -e PYVERS="cp36-cp36m cp37-cp37m cp38-cp38 cp39-cp39 cp310-cp310"
+ -e PSYCOPG2_TESTDB=postgres
+ -e PSYCOPG2_TESTDB_HOST=172.17.0.1
+ -e PSYCOPG2_TESTDB_USER=postgres
+ -e PSYCOPG2_TESTDB_PASSWORD=password
+ -e PSYCOPG2_TEST_FAST=1
+ -v `pwd`:/src
+ --workdir /src
+ quay.io/pypa/${{ matrix.platform }}
+ ./scripts/build/build_manylinux_2_24.sh
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v2
+ with:
+ name: packages_${{ matrix.platform }}
+ path: |
+ dist/*/*${{ matrix.platform }}.whl
+
+ services:
+ postgresql:
+ image: postgres:13
+ env:
+ POSTGRES_PASSWORD: password
+ ports:
+ - 5432:5432
+ # Set health checks to wait until postgres has started
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+
+ build-macos:
+ runs-on: macos-10.15
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: ['3.6', '3.7', '3.8', '3.9']
+
+ steps:
+ - name: Checkout repos
+ uses: actions/checkout@v2
+
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Build packages
+ run: ./scripts/build/build_macos.sh
+ env:
+ PACKAGE_NAME: psycopg2-binary
+ PSYCOPG2_TESTDB: postgres
+ PSYCOPG2_TEST_FAST: 1
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v2
+ with:
+ name: packages_macos
+ path: |
+ dist/*/*${{ matrix.platform }}.whl
diff --git a/.gitignore b/.gitignore
index 9a3bb03..457c9ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@ env?
.vscode/
/rel
/wheels
+/packages
diff --git a/NEWS b/NEWS
index e2c7a62..5967927 100644
--- a/NEWS
+++ b/NEWS
@@ -4,7 +4,6 @@ Current release
What's new in psycopg 2.9
-------------------------
-- Dropped support for Python 2.7, 3.4, 3.5 (:tickets:`#1198, #1000, #1197`).
- ``with connection`` starts a transaction on autocommit transactions too
(:ticket:`#941`).
- Escape table and column names in `~cursor.copy_from()` and
@@ -12,6 +11,14 @@ What's new in psycopg 2.9
- Connection exceptions with sqlstate ``08XXX`` reclassified as
`~psycopg2.OperationalError` (a subclass of the previously used
`~psycopg2.DatabaseError`) (:ticket:`#1148`).
+- Include library dirs required from libpq to work around MacOS build problems
+ (:ticket:`#1200`).
+
+Other changes:
+
+- Dropped support for Python 2.7, 3.4, 3.5 (:tickets:`#1198, #1000, #1197`).
+- Build system for Linux/MacOS binary packages moved to GitHub action, now
+ providing :pep:`600`\-style wheels packages.
What's new in psycopg 2.8.7
diff --git a/doc/release.rst b/doc/release.rst
index 66c03a4..87a2875 100644
--- a/doc/release.rst
+++ b/doc/release.rst
@@ -15,24 +15,12 @@ How to make a psycopg2 release
$ export VERSION=2.8.4
-- In the `Travis settings`__ you may want to be sure that the variables
- ``TEST_PAST`` and ``TEST_FUTURE`` are set to 1 to check all
- the supported postgres version.
+- Push psycopg2 to master or to the maint branch. Make sure tests on `GitHub
+ Actions`__ and AppVeyor__ pass.
-.. __: https://travis-ci.org/psycopg/psycopg2/settings
-
-- Push psycopg2 to master or to the maint branch. Make sure tests on Travis__
- and AppVeyor__ pass.
-
-.. __: https://travis-ci.org/psycopg/psycopg2
+.. __: https://github.com/psycopg/psycopg2/actions/workflows/tests.yml
.. __: https://ci.appveyor.com/project/psycopg/psycopg2
-- For an extra test merge or rebase the `test_i686`__ branch on the commit to
- release and push it too: this will test with Python 32 bits and debug
- versions.
-
-.. __: https://github.com/psycopg/psycopg2/tree/test_i686
-
- Create a signed tag with the content of the relevant NEWS bit and push it.
E.g.::
@@ -49,34 +37,31 @@ How to make a psycopg2 release
- Fixed bug blah (:ticket:`#42`).
...
-- Update the `psycopg2-wheels`_ submodule to the tag version and push. This
- will build the packages on `Travis CI`__ and `AppVeyor`__ and upload them to
- https://upload.psycopg.org/.
-
-.. _psycopg2-wheels: https://github.com/psycopg/psycopg2-wheels
-.. __: https://travis-ci.org/psycopg/psycopg2-wheels
-.. __: https://ci.appveyor.com/project/psycopg/psycopg2-wheels
-
-- Download the packages generated (this assumes ssh configured properly)::
+- Create the packages:
- $ rsync -arv psycopg-upload:psycopg2-${VERSION} .
+ - On GitHub Actions run manually a `package build workflow`__.
-- Sign the packages and upload the signatures back::
+ - On Appveyor change the `build settings`__ and replace the custom
+ configuration file name from ``.appveyor/tests.yml`` to
+ ``.appveyor/packages.yml`` (yeah, that sucks a bit. Remember to put it
+ back to testing).
- $ for f in psycopg2-${VERSION}/*.{exe,tar.gz,whl}; do \
- gpg --armor --detach-sign $f;
- done
+.. __: https://github.com/psycopg/psycopg2/actions/workflows/packages.yml
+.. __: https://ci.appveyor.com/project/psycopg/psycopg2/settings
- $ rsync -arv psycopg2-${VERSION} psycopg-upload:
+- When the workflows have finished download the packages using the
+ ``download_packages.py`` and ``download_packages_appveyor.py`` scripts from
+ the ``scripts/build`` directory. They will be saved in a
+ ``psycopg2-${VERSION}`` directory.
- Remove the ``.exe`` from the dir, because we don't want to upload them on
PyPI::
- $ rm -v psycopg2-${VERSION}/*.exe{,.asc}
+ $ rm -v psycopg2-${VERSION}/*.exe
-- Only for stable packages: upload the packages and signatures on PyPI::
+- Only for stable packages: upload the signed packages on PyPI::
- $ twine upload psycopg2-${VERSION}/*
+ $ twine upload -s psycopg2-${VERSION}/*
- Create a release and release notes in the psycopg website, announce to
psycopg and pgsql-announce mailing lists.
@@ -89,7 +74,7 @@ Releasing test packages
Test packages may be uploaded on the `PyPI testing site`__ using::
- $ twine upload -r testpypi psycopg2-${VERSION}/*
+ $ twine upload -s -r testpypi psycopg2-${VERSION}/*
assuming `proper configuration`__ of ``~/.pypirc``.
diff --git a/scripts/appveyor.py b/scripts/appveyor.py
index 428a6b4..39b3ebe 100755
--- a/scripts/appveyor.py
+++ b/scripts/appveyor.py
@@ -699,13 +699,8 @@ class Options:
@property
def is_wheel(self):
"""Are we building the wheel packages or just the extension?"""
- project_name = os.environ['APPVEYOR_PROJECT_NAME']
- if project_name == 'psycopg2':
- return False
- elif project_name == 'psycopg2-wheels':
- return True
- else:
- raise Exception(f"unexpected project name: {project_name}")
+ workflow = os.environ["WORKFLOW"]
+ return workflow == "packages"
@property
def py_dir(self):
@@ -801,12 +796,7 @@ class Options:
@property
def package_dir(self):
- """
- The directory containing the psycopg code checkout dir.
-
- Building psycopg it is clone_dir, building the wheels it is a submodule.
- """
- return self.clone_dir / 'psycopg2' if self.is_wheel else self.clone_dir
+ return self.clone_dir
@property
def dist_dir(self):
diff --git a/scripts/build/build_macos.sh b/scripts/build/build_macos.sh
new file mode 100755
index 0000000..4841ee7
--- /dev/null
+++ b/scripts/build/build_macos.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+# Create macOS wheels for psycopg2
+#
+# Following instructions from https://github.com/MacPython/wiki/wiki/Spinning-wheels
+# Cargoculting pieces of implementation from https://github.com/matthew-brett/multibuild
+
+set -euo pipefail
+set -x
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PRJDIR="$( cd "${DIR}/../.." && pwd )"
+
+brew install gnu-sed postgresql@13
+
+# Start the database for testing
+brew services start postgresql
+
+for i in $(seq 10 -1 0); do
+ eval pg_isready && break
+ if [ $i == 0 ]; then
+ echo "PostgreSQL service not ready, giving up"
+ exit 1
+ fi
+ echo "PostgreSQL service not ready, waiting a bit, attempts left: $i"
+ sleep 5
+done
+
+# Find psycopg version
+VERSION=$(grep -e ^PSYCOPG_VERSION "${PRJDIR}/setup.py" | gsed "s/.*'\(.*\)'/\1/")
+# A gratuitous comment to fix broken vim syntax file: '")
+DISTDIR="${PRJDIR}/dist/psycopg2-$VERSION"
+mkdir -p "$DISTDIR"
+
+# Install required python packages
+pip install -U pip wheel delocate
+
+# Replace the package name
+gsed -i "s/^setup(name=\"psycopg2\"/setup(name=\"${PACKAGE_NAME}\"/" \
+ "${PRJDIR}/setup.py"
+
+# Build the wheels
+WHEELDIR="${PRJDIR}/wheels"
+pip wheel -w ${WHEELDIR} .
+delocate-listdeps ${WHEELDIR}/*.whl
+
+# Check where is the libpq. I'm gonna kill it for testing
+if [[ -z "${LIBPQ:-}" ]]; then
+ export LIBPQ=$(delocate-listdeps ${WHEELDIR}/*.whl | grep libpq)
+fi
+
+delocate-wheel ${WHEELDIR}/*.whl
+# https://github.com/MacPython/wiki/wiki/Spinning-wheels#question-will-pip-give-me-a-broken-wheel
+delocate-addplat --rm-orig -x 10_9 -x 10_10 ${WHEELDIR}/*.whl
+cp ${WHEELDIR}/*.whl ${DISTDIR}
+
+# kill the libpq to make sure tests don't depend on it
+mv "$LIBPQ" "${LIBPQ}-bye"
+
+# Install and test the built wheel
+pip install ${PACKAGE_NAME} --no-index -f "$DISTDIR"
+
+# Print psycopg and libpq versions
+python -c "import psycopg2; print(psycopg2.__version__)"
+python -c "import psycopg2; print(psycopg2.__libpq_version__)"
+python -c "import psycopg2; print(psycopg2.extensions.libpq_version())"
+
+# fail if we are not using the expected libpq library
+# Disabled as we just use what's available on the system on macOS
+# if [[ "${WANT_LIBPQ:-}" ]]; then
+# python -c "import psycopg2, sys; sys.exit(${WANT_LIBPQ} != psycopg2.extensions.libpq_version())"
+# fi
+
+python -c "import tests; tests.unittest.main(defaultTest='tests.test_suite')"
+
+# just because I'm a boy scout
+mv "${LIBPQ}-bye" "$LIBPQ"
diff --git a/scripts/build/build_manylinux_2_24.sh b/scripts/build/build_manylinux_2_24.sh
new file mode 100755
index 0000000..2d247da
--- /dev/null
+++ b/scripts/build/build_manylinux_2_24.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+# Create manylinux_2_24 wheels for psycopg2
+#
+# Look at the .github/workflows/packages.yml file for hints about how to use it.
+
+set -euo pipefail
+set -x
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PRJDIR="$( cd "${DIR}/../.." && pwd )"
+
+# Build all the available versions, or just the ones specified in PYVERS
+if [ ! "${PYVERS:-}" ]; then
+ PYVERS="$(ls /opt/python/)"
+fi
+
+# Find psycopg version
+VERSION=$(grep -e ^PSYCOPG_VERSION "${PRJDIR}/setup.py" | sed "s/.*'\(.*\)'/\1/")
+# A gratuitous comment to fix broken vim syntax file: '")
+DISTDIR="${PRJDIR}/dist/psycopg2-$VERSION"
+
+# Replace the package name
+if [[ "${PACKAGE_NAME:-}" ]]; then
+ sed -i "s/^setup(name=\"psycopg2\"/setup(name=\"${PACKAGE_NAME}\"/" \
+ "${PRJDIR}/setup.py"
+fi
+
+# Install prerequisite libraries
+curl -s https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
+echo "deb http://apt.postgresql.org/pub/repos/apt stretch-pgdg main" \
+ > /etc/apt/sources.list.d/pgdg.list
+apt-get -y update
+apt-get install -y libpq-dev
+
+# Create the wheel packages
+for PYVER in $PYVERS; do
+ PYBIN="/opt/python/${PYVER}/bin"
+ "${PYBIN}/pip" wheel "${PRJDIR}" -w "${PRJDIR}/dist/"
+done
+
+# Bundle external shared libraries into the wheels
+for WHL in "${PRJDIR}"/dist/*.whl; do
+ auditwheel repair "$WHL" -w "$DISTDIR"
+done
+
+# Make sure the libpq is not in the system
+for f in $(find /usr/lib /usr/lib64 -name libpq\*) ; do
+ mkdir -pv "/libpqbak/$(dirname $f)"
+ mv -v "$f" "/libpqbak/$(dirname $f)"
+done
+
+# Install packages and test
+cd "${PRJDIR}"
+for PYVER in $PYVERS; do
+ PYBIN="/opt/python/${PYVER}/bin"
+ "${PYBIN}/pip" install ${PACKAGE_NAME} --no-index -f "$DISTDIR"
+
+ # Print psycopg and libpq versions
+ "${PYBIN}/python" -c "import psycopg2; print(psycopg2.__version__)"
+ "${PYBIN}/python" -c "import psycopg2; print(psycopg2.__libpq_version__)"
+ "${PYBIN}/python" -c "import psycopg2; print(psycopg2.extensions.libpq_version())"
+
+ # Fail if we are not using the expected libpq library
+ if [[ "${WANT_LIBPQ:-}" ]]; then
+ "${PYBIN}/python" -c "import psycopg2, sys; sys.exit(${WANT_LIBPQ} != psycopg2.extensions.libpq_version())"
+ fi
+
+ "${PYBIN}/python" -c "import tests; tests.unittest.main(defaultTest='tests.test_suite')"
+done
+
+# Restore the libpq packages
+for f in $(cd /libpqbak/ && find . -not -type d); do
+ mv -v "/libpqbak/$f" "/$f"
+done
diff --git a/scripts/build/download_packages.py b/scripts/build/download_packages.py
new file mode 100755
index 0000000..46ce149
--- /dev/null
+++ b/scripts/build/download_packages.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+"""Download packages from github actions artifacts
+"""
+
+import io
+import os
+import sys
+import logging
+from pathlib import Path
+from zipfile import ZipFile
+
+import requests
+
+logger = logging.getLogger()
+logging.basicConfig(
+ level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s"
+)
+
+REPOS = "psycopg/psycopg2"
+WORKFLOW_NAME = "Build packages"
+
+
+class ScriptError(Exception):
+ """Controlled exception raised by the script."""
+
+
+def main():
+ try:
+ token = os.environ["GITHUB_TOKEN"]
+ except KeyError:
+ raise ScriptError("please set a GITHUB_TOKEN to download artifacts")
+
+ s = requests.Session()
+ s.headers["Accept"] = "application/vnd.github.v3+json"
+ s.headers["Authorization"] = f"token {token}"
+
+ logger.info("looking for recent runs")
+ resp = s.get(f"https://api.github.com/repos/{REPOS}/actions/runs?per_page=10")
+ resp.raise_for_status()
+ for run in resp.json()["workflow_runs"]:
+ if run["name"] == WORKFLOW_NAME:
+ break
+ else:
+ raise ScriptError(f"couldn't find {WORKFLOW_NAME!r} in recent runs")
+
+ logger.info(f"looking for run {run['id']} artifacts")
+ resp = s.get(f"{run['url']}/artifacts")
+ resp.raise_for_status()
+ artifacts = resp.json()["artifacts"]
+
+ dest = Path("packages")
+ if not dest.exists():
+ logger.info(f"creating dir {dest}")
+ dest.mkdir()
+
+ for artifact in artifacts:
+ logger.info(f"downloading {artifact['name']} archive")
+ zip_url = artifact["archive_download_url"]
+ resp = s.get(zip_url)
+ with ZipFile(io.BytesIO(resp.content)) as zf:
+ logger.info("extracting archive content")
+ zf.extractall(dest)
+
+ logger.info(f"now you can run: 'twine upload -s {dest}/*'")
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+
+ except ScriptError as e:
+ logger.error("%s", e)
+ sys.exit(1)
+
+ except KeyboardInterrupt:
+ logger.info("user interrupt")
+ sys.exit(1)
diff --git a/scripts/build/download_packages_appveyor.py b/scripts/build/download_packages_appveyor.py
new file mode 100755
index 0000000..7ac55b4
--- /dev/null
+++ b/scripts/build/download_packages_appveyor.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+"""Download packages from github actions artifacts
+"""
+
+import os
+import sys
+import logging
+from pathlib import Path
+
+import requests
+
+logger = logging.getLogger()
+logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
+
+API_URL = "https://ci.appveyor.com/api"
+REPOS = "psycopg/psycopg2"
+WORKFLOW_NAME = "Build packages"
+
+
+class ScriptError(Exception):
+ """Controlled exception raised by the script."""
+
+
+def main():
+ try:
+ token = os.environ["APPVEYOR_TOKEN"]
+ except KeyError:
+ raise ScriptError("please set a APPVEYOR_TOKEN to download artifacts")
+
+ s = requests.Session()
+ s.headers["Content-Type"] = "application/json"
+ s.headers["Authorization"] = f"Bearer {token}"
+
+ logger.info("fetching last run")
+ resp = s.get(f"{API_URL}/projects/{REPOS}/")
+ resp.raise_for_status()
+ data = resp.json()
+ jobs = data["build"]["jobs"]
+ for job in jobs:
+ if job["status"] != "success":
+ raise ScriptError("status for job {job['jobId']} is {job['status']}")
+
+ logger.info(f"fetching artifacts info for {job['name']}")
+ resp = s.get(f"{API_URL}/buildjobs/{job['jobId']}/artifacts/")
+ resp.raise_for_status()
+ afs = resp.json()
+ for af in afs:
+ fn = af["fileName"]
+ if fn.startswith("dist/"):
+ fn = fn.split("/", 1)[1]
+ dest = Path("packages") / fn
+ logger.info(f"downloading {dest}")
+ resp = s.get(
+ f"{API_URL}/buildjobs/{job['jobId']}/artifacts/{af['fileName']}"
+ )
+ resp.raise_for_status()
+ if not dest.parent.exists():
+ dest.parent.mkdir()
+
+ with dest.open("wb") as f:
+ f.write(resp.content)
+
+ logger.info("now you can run: 'twine upload -s packages/*'")
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+
+ except ScriptError as e:
+ logger.error("%s", e)
+ sys.exit(1)
+
+ except KeyboardInterrupt:
+ logger.info("user interrupt")
+ sys.exit(1)
+
diff --git a/setup.py b/setup.py
index a563fd1..2cdb7c2 100644
--- a/setup.py
+++ b/setup.py
@@ -376,6 +376,16 @@ For further information please check the 'doc/src/install.rst' file (also at
self.library_dirs.append(pg_config_helper.query("libdir"))
self.include_dirs.append(pg_config_helper.query("includedir"))
self.include_dirs.append(pg_config_helper.query("includedir-server"))
+
+ # add includedirs from cppflags, libdirs from ldflags
+ for token in pg_config_helper.query("ldflags").split():
+ if token.startswith("-L"):
+ self.library_dirs.append(token[2:])
+
+ for token in pg_config_helper.query("cppflags").split():
+ if token.startswith("-I"):
+ self.include_dirs.append(token[2:])
+
pgversion = pg_config_helper.query("version").split()[1]
verre = re.compile(
diff --git a/tests/testutils.py b/tests/testutils.py
index f0c3264..3f8ceb3 100644
--- a/tests/testutils.py
+++ b/tests/testutils.py
@@ -178,7 +178,10 @@ class ConnectingTestCase(unittest.TestCase):
if libname is None and platform.system() == 'Windows':
raise self.skipTest("can't import libpq on windows")
- rv = ConnectingTestCase._libpq = ctypes.pydll.LoadLibrary(libname)
+ try:
+ rv = ConnectingTestCase._libpq = ctypes.pydll.LoadLibrary(libname)
+ except OSError as e:
+ raise self.skipTest("couldn't open libpq for testing: %s" % e)
return rv