1{
2 lib,
3 stdenv,
4 buildPythonPackage,
5 fetchFromGitHub,
6 fetchurl,
7 replaceVars,
8
9 # build
10 libpq,
11 setuptools,
12
13 # propagates
14 typing-extensions,
15
16 # psycopg-c
17 cython,
18 tomli,
19
20 # docs
21 furo,
22 shapely,
23 sphinxHook,
24 sphinx-autodoc-typehints,
25
26 # tests
27 anyio,
28 pproxy,
29 pytest-randomly,
30 pytestCheckHook,
31 postgresql,
32 postgresqlTestHook,
33}:
34
35let
36 pname = "psycopg";
37 version = "3.2.9";
38
39 src = fetchFromGitHub {
40 owner = "psycopg";
41 repo = "psycopg";
42 tag = version;
43 hash = "sha256-mMhfULdvqphwdEqynLNq+7XCNmqmf+zi1SGumC/6qAc=";
44 };
45
46 patches = [
47 (replaceVars ./ctypes.patch {
48 libpq = "${libpq}/lib/libpq${stdenv.hostPlatform.extensions.sharedLibrary}";
49 libc = "${stdenv.cc.libc}/lib/libc.so.6";
50 })
51 ];
52
53 baseMeta = {
54 changelog = "https://github.com/psycopg/psycopg/blob/${version}/docs/news.rst#current-release";
55 homepage = "https://github.com/psycopg/psycopg";
56 license = lib.licenses.lgpl3Plus;
57 maintainers = with lib.maintainers; [ hexa ];
58 };
59
60 psycopg-c = buildPythonPackage {
61 pname = "${pname}-c";
62 inherit version src;
63 format = "pyproject";
64
65 # apply patches to base repo
66 inherit patches;
67
68 # move into source root after patching
69 postPatch = ''
70 cd psycopg_c
71
72 substituteInPlace pyproject.toml \
73 --replace-fail "Cython >= 3.0.0, < 3.1.0" "Cython"
74 '';
75
76 nativeBuildInputs = [
77 cython
78 libpq.pg_config
79 setuptools
80 tomli
81 ];
82
83 buildInputs = [
84 libpq
85 ];
86
87 # tested in psycopg
88 doCheck = false;
89
90 meta = baseMeta // {
91 description = "C optimisation distribution for Psycopg";
92 };
93 };
94
95 psycopg-pool = buildPythonPackage {
96 pname = "${pname}-pool";
97 inherit version src;
98 format = "setuptools";
99
100 # apply patches to base repo
101 inherit patches;
102
103 # move into source root after patching
104 postPatch = ''
105 cd psycopg_pool
106 '';
107
108 propagatedBuildInputs = [ typing-extensions ];
109
110 # tested in psycopg
111 doCheck = false;
112
113 meta = baseMeta // {
114 description = "Connection Pool for Psycopg";
115 };
116 };
117in
118
119buildPythonPackage rec {
120 inherit pname version src;
121 pyproject = true;
122
123 outputs = [
124 "out"
125 ]
126 ++ lib.optionals (stdenv.hostPlatform == stdenv.buildPlatform) [
127 "doc"
128 ];
129
130 sphinxRoot = "../docs";
131
132 # Introduce this file necessary for the docs build via environment var
133 LIBPQ_DOCS_FILE = fetchurl {
134 url = "https://raw.githubusercontent.com/postgres/postgres/496a1dc44bf1261053da9b3f7e430769754298b4/doc/src/sgml/libpq.sgml";
135 hash = "sha256-JwtCngkoi9pb0pqIdNgukY8GbG5pUDZvrGAHZqjFOw4";
136 };
137
138 inherit patches;
139
140 # only move to sourceRoot after patching, makes patching easier
141 postPatch = ''
142 cd psycopg
143 '';
144
145 nativeBuildInputs = [
146 setuptools
147 ]
148 # building the docs fails with the following error when cross compiling
149 # AttributeError: module 'psycopg_c.pq' has no attribute '__impl__'
150 ++ lib.optionals (stdenv.hostPlatform == stdenv.buildPlatform) [
151 furo
152 sphinx-autodoc-typehints
153 sphinxHook
154 shapely
155 ];
156
157 propagatedBuildInputs = [
158 psycopg-c
159 typing-extensions
160 ];
161
162 pythonImportsCheck = [
163 "psycopg"
164 "psycopg_c"
165 "psycopg_pool"
166 ];
167
168 optional-dependencies = {
169 c = [ psycopg-c ];
170 pool = [ psycopg-pool ];
171 };
172
173 nativeCheckInputs = [
174 anyio
175 pproxy
176 pytest-randomly
177 pytestCheckHook
178 postgresql
179 ]
180 ++ lib.optional stdenv.hostPlatform.isLinux postgresqlTestHook
181 ++ optional-dependencies.c
182 ++ optional-dependencies.pool;
183
184 env = {
185 postgresqlEnableTCP = 1;
186 PGUSER = "psycopg";
187 PGDATABASE = "psycopg";
188 };
189
190 preCheck = ''
191 cd ..
192 ''
193 + lib.optionalString stdenv.hostPlatform.isLinux ''
194 export PSYCOPG_TEST_DSN="host=/build/run/postgresql user=$PGUSER"
195 '';
196
197 disabledTests = [
198 # don't depend on mypy for tests
199 "test_version"
200 "test_package_version"
201 # expects timeout, but we have no route in the sandbox
202 "test_connect_error_multi_hosts_each_message_preserved"
203 ];
204
205 disabledTestPaths = [
206 # Network access
207 "tests/test_dns.py"
208 "tests/test_dns_srv.py"
209 # Mypy typing test
210 "tests/test_typing.py"
211 "tests/crdb/test_typing.py"
212 ];
213
214 pytestFlags = [
215 "-ocache_dir=.cache"
216 ];
217
218 disabledTestMarks = [
219 "refcount"
220 "timing"
221 "flakey"
222 ];
223
224 postCheck = ''
225 cd psycopg
226 '';
227
228 passthru = {
229 c = psycopg-c;
230 pool = psycopg-pool;
231 };
232
233 meta = baseMeta // {
234 description = "PostgreSQL database adapter for Python";
235 };
236}