nixpkgs/pkgs/development/python-modules/psycopg/default.nix
Wolfgang Walther 88dfade94b
postgresql: replace pg_config with custom script
By replacing upstream's pg_config binary with a shell script, we:
- gain the ability to run pg_config easily when cross-compiling,
- can remove the fake pg_config in the default output,
- can remove the pg_config wrapper script dealing with special cases.

Some 20 years ago, pg_config *was* a shell script upstream, too. It was
changed to a binary, when it was made "relocatable", so it would return
paths depending on the location of the "postgres" binary. However, this
is exactly the thing that just hurts us in nixpkgs - we don't want those
paths to change, we want them to always point at the right outputs. By
writing the script ourselves, this becomes a lot less painful.

This approach means more lines of codes, but all of them are dead simple
and we have a lot less complexity overall.

Additionally, pg_config is now made a separate derivation, only exposed
as "postgresql.pg_config". This has the nice side-effect, that all users
of postgresql and libpq in nixpkgs must be very *explicit* about their
dependency on pg_config. This gives a lot more visibility into the state
of affairs regarding pkg-config support for libpq, which ultimately is
the much better solution.
2025-03-21 18:05:38 +01:00

240 lines
4.6 KiB
Nix

{
lib,
stdenv,
buildPythonPackage,
fetchFromGitHub,
fetchurl,
pythonOlder,
replaceVars,
# build
libpq,
setuptools,
# propagates
typing-extensions,
# psycopg-c
cython,
tomli,
# docs
furo,
shapely,
sphinxHook,
sphinx-autodoc-typehints,
# tests
anyio,
pproxy,
pytest-randomly,
pytestCheckHook,
postgresql,
postgresqlTestHook,
}:
let
pname = "psycopg";
version = "3.2.6";
src = fetchFromGitHub {
owner = "psycopg";
repo = "psycopg";
tag = version;
hash = "sha256-fCiTu6lKFqY7Yl9KfmhRZQIDg5sEkXkQ95kPfIDSGn8=";
};
patches = [
(replaceVars ./ctypes.patch {
libpq = "${libpq}/lib/libpq${stdenv.hostPlatform.extensions.sharedLibrary}";
libc = "${stdenv.cc.libc}/lib/libc.so.6";
})
];
baseMeta = {
changelog = "https://github.com/psycopg/psycopg/blob/${version}/docs/news.rst#current-release";
homepage = "https://github.com/psycopg/psycopg";
license = lib.licenses.lgpl3Plus;
maintainers = with lib.maintainers; [ hexa ];
};
psycopg-c = buildPythonPackage {
pname = "${pname}-c";
inherit version src;
format = "pyproject";
# apply patches to base repo
inherit patches;
# move into source root after patching
postPatch = ''
cd psycopg_c
'';
nativeBuildInputs = [
cython
libpq.pg_config
setuptools
tomli
];
buildInputs = [
libpq
];
# tested in psycopg
doCheck = false;
meta = baseMeta // {
description = "C optimisation distribution for Psycopg";
};
};
psycopg-pool = buildPythonPackage {
pname = "${pname}-pool";
inherit version src;
format = "setuptools";
# apply patches to base repo
inherit patches;
# move into source root after patching
postPatch = ''
cd psycopg_pool
'';
propagatedBuildInputs = [ typing-extensions ];
# tested in psycopg
doCheck = false;
meta = baseMeta // {
description = "Connection Pool for Psycopg";
};
};
in
buildPythonPackage rec {
inherit pname version src;
format = "pyproject";
disabled = pythonOlder "3.7";
outputs =
[
"out"
]
++ lib.optionals (stdenv.hostPlatform == stdenv.buildPlatform) [
"doc"
];
sphinxRoot = "../docs";
# Introduce this file necessary for the docs build via environment var
LIBPQ_DOCS_FILE = fetchurl {
url = "https://raw.githubusercontent.com/postgres/postgres/496a1dc44bf1261053da9b3f7e430769754298b4/doc/src/sgml/libpq.sgml";
hash = "sha256-JwtCngkoi9pb0pqIdNgukY8GbG5pUDZvrGAHZqjFOw4";
};
inherit patches;
# only move to sourceRoot after patching, makes patching easier
postPatch = ''
cd psycopg
'';
nativeBuildInputs =
[
furo
setuptools
shapely
]
# building the docs fails with the following error when cross compiling
# AttributeError: module 'psycopg_c.pq' has no attribute '__impl__'
++ lib.optionals (stdenv.hostPlatform == stdenv.buildPlatform) [
sphinx-autodoc-typehints
sphinxHook
];
propagatedBuildInputs = [
psycopg-c
typing-extensions
];
pythonImportsCheck = [
"psycopg"
"psycopg_c"
"psycopg_pool"
];
optional-dependencies = {
c = [ psycopg-c ];
pool = [ psycopg-pool ];
};
nativeCheckInputs =
[
anyio
pproxy
pytest-randomly
pytestCheckHook
postgresql
]
++ lib.optional stdenv.hostPlatform.isLinux postgresqlTestHook
++ optional-dependencies.c
++ optional-dependencies.pool;
env = {
postgresqlEnableTCP = 1;
PGUSER = "psycopg";
PGDATABASE = "psycopg";
};
preCheck =
''
cd ..
''
+ lib.optionalString stdenv.hostPlatform.isLinux ''
export PSYCOPG_TEST_DSN="host=/build/run/postgresql user=$PGUSER"
'';
disabledTests = [
# don't depend on mypy for tests
"test_version"
"test_package_version"
];
disabledTestPaths = [
# Network access
"tests/test_dns.py"
"tests/test_dns_srv.py"
# Mypy typing test
"tests/test_typing.py"
"tests/crdb/test_typing.py"
# https://github.com/psycopg/psycopg/pull/915
"tests/test_notify.py"
"tests/test_notify_async.py"
];
pytestFlagsArray = [
"-o cache_dir=.cache"
"-m"
"'not refcount and not timing and not flakey'"
# pytest.PytestRemovedIn9Warning: Marks applied to fixtures have no effect
"-W"
"ignore::pytest.PytestRemovedIn9Warning"
];
postCheck = ''
cd psycopg
'';
passthru = {
c = psycopg-c;
pool = psycopg-pool;
};
meta = baseMeta // {
description = "PostgreSQL database adapter for Python";
};
}