pgdevkit 0.7.2__py3-none-any.whl → 0.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pgdevkit/testdb/_docker.py +33 -0
- pgdevkit/testdb/constants.py +8 -1
- pgdevkit/testdb/container.py +11 -1
- pgdevkit/testdb/mssql/constants.py +9 -0
- pgdevkit/testdb/mssql/container.py +9 -0
- {pgdevkit-0.7.2.dist-info → pgdevkit-0.8.0.dist-info}/METADATA +31 -6
- {pgdevkit-0.7.2.dist-info → pgdevkit-0.8.0.dist-info}/RECORD +9 -9
- {pgdevkit-0.7.2.dist-info → pgdevkit-0.8.0.dist-info}/WHEEL +0 -0
- {pgdevkit-0.7.2.dist-info → pgdevkit-0.8.0.dist-info}/entry_points.txt +0 -0
pgdevkit/testdb/_docker.py
CHANGED
|
@@ -39,3 +39,36 @@ def client() -> docker.DockerClient:
|
|
|
39
39
|
"Could not reach a Docker-compatible API. Set DOCKER_HOST, or make sure "
|
|
40
40
|
"Docker or Podman's API socket is running."
|
|
41
41
|
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _parse_tmpfs(spec: str) -> dict[str, str]:
|
|
45
|
+
"""Parse a docker-CLI-style --tmpfs spec into the dict shape docker-py's
|
|
46
|
+
`containers.run(tmpfs=...)` expects. Multiple mounts are semicolon-separated
|
|
47
|
+
(commas are already used by docker's own comma-separated mount options),
|
|
48
|
+
e.g. "/path:rw,size=64m;/other/path:ro,size=32m", matching `docker run
|
|
49
|
+
--tmpfs /path:rw,size=64m --tmpfs /other/path:ro,size=32m`."""
|
|
50
|
+
mounts: dict[str, str] = {}
|
|
51
|
+
for entry in spec.split(";"):
|
|
52
|
+
entry = entry.strip()
|
|
53
|
+
if not entry:
|
|
54
|
+
continue
|
|
55
|
+
path, _, options = entry.partition(":")
|
|
56
|
+
mounts[path] = options
|
|
57
|
+
return mounts
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def resource_kwargs(*, tmpfs: str, shm_size: str, mem_limit: str, cpus: str) -> dict:
|
|
61
|
+
"""Build the `containers.run()` kwargs for the tmpfs/shm_size/mem_limit/cpus
|
|
62
|
+
overrides, omitting any that aren't set so Docker's own defaults apply.
|
|
63
|
+
Shared by the Postgres and MSSQL container modules -- these are Docker-level
|
|
64
|
+
resource knobs, not anything specific to either engine."""
|
|
65
|
+
kwargs: dict = {}
|
|
66
|
+
if tmpfs:
|
|
67
|
+
kwargs["tmpfs"] = _parse_tmpfs(tmpfs)
|
|
68
|
+
if shm_size:
|
|
69
|
+
kwargs["shm_size"] = shm_size
|
|
70
|
+
if mem_limit:
|
|
71
|
+
kwargs["mem_limit"] = mem_limit
|
|
72
|
+
if cpus:
|
|
73
|
+
kwargs["nano_cpus"] = int(float(cpus) * 1_000_000_000)
|
|
74
|
+
return kwargs
|
pgdevkit/testdb/constants.py
CHANGED
|
@@ -5,11 +5,18 @@ import os
|
|
|
5
5
|
from psycopg.conninfo import make_conninfo
|
|
6
6
|
|
|
7
7
|
CONTAINER_NAME = "pgdevkit-postgres"
|
|
8
|
-
IMAGE = "pgvector/pgvector:pg18-trixie"
|
|
8
|
+
IMAGE = os.environ.get("PGDEVKIT_TESTDB_IMAGE", "pgvector/pgvector:pg18-trixie")
|
|
9
9
|
HOST = os.environ.get("PGDEVKIT_TESTDB_HOST", "localhost")
|
|
10
10
|
PORT = int(os.environ.get("PGDEVKIT_TESTDB_PORT", "54322"))
|
|
11
11
|
USER = os.environ.get("PGDEVKIT_TESTDB_USER", "postgres")
|
|
12
12
|
PASSWORD = os.environ.get("PGDEVKIT_TESTDB_PASSWORD", "testpwd")
|
|
13
|
+
# Docker-level resource overrides, passed through to `containers.run()` --
|
|
14
|
+
# unset (the default) means "let Docker/Podman use their own defaults".
|
|
15
|
+
# TMPFS uses docker-CLI --tmpfs syntax; see _docker._parse_tmpfs().
|
|
16
|
+
TMPFS = os.environ.get("PGDEVKIT_TESTDB_TMPFS", "")
|
|
17
|
+
SHM_SIZE = os.environ.get("PGDEVKIT_TESTDB_SHM_SIZE", "")
|
|
18
|
+
MEM_LIMIT = os.environ.get("PGDEVKIT_TESTDB_MEM_LIMIT", "")
|
|
19
|
+
CPUS = os.environ.get("PGDEVKIT_TESTDB_CPUS", "")
|
|
13
20
|
PG_SPEED_FLAGS = ["-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
|
14
21
|
# Production connects with session timezone=UTC; the container image's own default
|
|
15
22
|
# (baked into its base OS, not something pgdevkit ever set) can differ, silently
|
pgdevkit/testdb/container.py
CHANGED
|
@@ -7,7 +7,7 @@ import docker
|
|
|
7
7
|
import docker.errors
|
|
8
8
|
import psycopg
|
|
9
9
|
|
|
10
|
-
from . import constants
|
|
10
|
+
from . import _docker, constants
|
|
11
11
|
from ._docker import client as _client
|
|
12
12
|
|
|
13
13
|
|
|
@@ -43,6 +43,12 @@ def _create_container(client: docker.DockerClient) -> None:
|
|
|
43
43
|
"PGTZ": "UTC",
|
|
44
44
|
},
|
|
45
45
|
command=["postgres", *constants.PG_STARTUP_FLAGS],
|
|
46
|
+
**_docker.resource_kwargs(
|
|
47
|
+
tmpfs=constants.TMPFS,
|
|
48
|
+
shm_size=constants.SHM_SIZE,
|
|
49
|
+
mem_limit=constants.MEM_LIMIT,
|
|
50
|
+
cpus=constants.CPUS,
|
|
51
|
+
),
|
|
46
52
|
)
|
|
47
53
|
except docker.errors.APIError as e:
|
|
48
54
|
if getattr(e, "status_code", None) == 409 or "already in use" in str(e):
|
|
@@ -79,6 +85,10 @@ def ensure_container() -> None:
|
|
|
79
85
|
except docker.errors.NotFound:
|
|
80
86
|
container = None
|
|
81
87
|
if container is not None:
|
|
88
|
+
# An existing container (even stopped) is just restarted as-is --
|
|
89
|
+
# constants like TMPFS/SHM_SIZE/IMAGE/etc. only take effect via
|
|
90
|
+
# _create_container(), so changing them has no effect here until
|
|
91
|
+
# the stale container is removed. Documented in the README.
|
|
82
92
|
if container.status != "running":
|
|
83
93
|
container.start()
|
|
84
94
|
else:
|
|
@@ -22,6 +22,15 @@ USER = os.environ.get("PGDEVKIT_TESTDB_MSSQL_USER", "sa")
|
|
|
22
22
|
# default -- see validate_sa_password().
|
|
23
23
|
PASSWORD = os.environ.get("PGDEVKIT_TESTDB_MSSQL_PASSWORD", "TestPwd!2026")
|
|
24
24
|
MEMORY_LIMIT_MB = int(os.environ.get("PGDEVKIT_TESTDB_MSSQL_MEMORY_LIMIT_MB", "2048"))
|
|
25
|
+
# Docker-level resource overrides, passed through to `containers.run()` --
|
|
26
|
+
# unset (the default) means "let Docker/Podman use their own defaults". Distinct
|
|
27
|
+
# from MEMORY_LIMIT_MB above, which only controls SQL Server's own internal memory
|
|
28
|
+
# management, not the container's actual cgroup limit. TMPFS uses docker-CLI
|
|
29
|
+
# --tmpfs syntax; see _docker._parse_tmpfs().
|
|
30
|
+
TMPFS = os.environ.get("PGDEVKIT_TESTDB_MSSQL_TMPFS", "")
|
|
31
|
+
SHM_SIZE = os.environ.get("PGDEVKIT_TESTDB_MSSQL_SHM_SIZE", "")
|
|
32
|
+
MEM_LIMIT = os.environ.get("PGDEVKIT_TESTDB_MSSQL_MEM_LIMIT", "")
|
|
33
|
+
CPUS = os.environ.get("PGDEVKIT_TESTDB_MSSQL_CPUS", "")
|
|
25
34
|
|
|
26
35
|
|
|
27
36
|
def validate_sa_password(password: str) -> None:
|
|
@@ -40,6 +40,12 @@ def _create_container(client: docker.DockerClient) -> None:
|
|
|
40
40
|
"MSSQL_PID": "Developer",
|
|
41
41
|
"MSSQL_MEMORY_LIMIT_MB": str(constants.MEMORY_LIMIT_MB),
|
|
42
42
|
},
|
|
43
|
+
**_docker.resource_kwargs(
|
|
44
|
+
tmpfs=constants.TMPFS,
|
|
45
|
+
shm_size=constants.SHM_SIZE,
|
|
46
|
+
mem_limit=constants.MEM_LIMIT,
|
|
47
|
+
cpus=constants.CPUS,
|
|
48
|
+
),
|
|
43
49
|
)
|
|
44
50
|
except docker.errors.APIError as e:
|
|
45
51
|
if getattr(e, "status_code", None) == 409 or "already in use" in str(e):
|
|
@@ -83,6 +89,9 @@ def ensure_mssql_container() -> None:
|
|
|
83
89
|
except docker.errors.NotFound:
|
|
84
90
|
container = None
|
|
85
91
|
if container is not None:
|
|
92
|
+
# See the Postgres container's ensure_container() -- an existing
|
|
93
|
+
# (even stopped) container is just restarted as-is, so config
|
|
94
|
+
# constants only take effect via _create_container().
|
|
86
95
|
if container.status != "running":
|
|
87
96
|
container.start()
|
|
88
97
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pgdevkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: A helper for developing with Postgres
|
|
5
5
|
Requires-Python: >=3.14
|
|
6
6
|
Requires-Dist: docker>=7.1.0
|
|
@@ -261,11 +261,25 @@ worktree and wants to know exactly which DB(s) go with it.
|
|
|
261
261
|
|
|
262
262
|
Container connection defaults (`localhost:54322`, `postgres`/`testpwd`) can
|
|
263
263
|
be overridden with `PGDEVKIT_TESTDB_HOST`, `PGDEVKIT_TESTDB_PORT`,
|
|
264
|
-
`PGDEVKIT_TESTDB_USER`, `PGDEVKIT_TESTDB_PASSWORD
|
|
265
|
-
Docker API, pgdevkit first
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
that check too.
|
|
264
|
+
`PGDEVKIT_TESTDB_USER`, `PGDEVKIT_TESTDB_PASSWORD`, and the image with
|
|
265
|
+
`PGDEVKIT_TESTDB_IMAGE`. Before touching the Docker API, pgdevkit first
|
|
266
|
+
checks (with a short timeout) whether Postgres is already reachable at that
|
|
267
|
+
address and skips container management if so. Set `PGDEVKIT_SKIP_CONTAINER=1`
|
|
268
|
+
to always assume it's already there and skip that check too.
|
|
269
|
+
|
|
270
|
+
Docker-level resource knobs are unset by default (Docker/Podman's own
|
|
271
|
+
defaults apply) and can be overridden with `PGDEVKIT_TESTDB_SHM_SIZE` (e.g.
|
|
272
|
+
`256m`, useful when Docker's 64MB default shared-memory size is too small
|
|
273
|
+
for parallel query workers), `PGDEVKIT_TESTDB_MEM_LIMIT` (e.g. `1g`),
|
|
274
|
+
`PGDEVKIT_TESTDB_CPUS` (e.g. `2` or `0.5`), and `PGDEVKIT_TESTDB_TMPFS` —
|
|
275
|
+
docker-CLI `--tmpfs` syntax (`/path:options`), semicolon-separated for
|
|
276
|
+
multiple mounts, e.g. `/var/lib/postgresql/data:size=512m`.
|
|
277
|
+
|
|
278
|
+
All of the above (including `_HOST`/`_PORT`/`_USER`/`_PASSWORD`/`_IMAGE`)
|
|
279
|
+
only take effect when pgdevkit actually creates the container, not when it
|
|
280
|
+
finds and restarts an existing stopped one with the same name — remove the
|
|
281
|
+
existing container (`docker rm -f pgdevkit-postgres`) first if you've
|
|
282
|
+
changed any of these on a machine that already has one.
|
|
269
283
|
|
|
270
284
|
Container management goes through the Docker API (the `docker` package,
|
|
271
285
|
`docker.from_env()`, falling back to Podman's rootful/rootless socket) — it
|
|
@@ -291,6 +305,17 @@ Container defaults (`localhost:14330`, `sa`/a generated complexity-valid
|
|
|
291
305
|
password) can be overridden with `PGDEVKIT_TESTDB_MSSQL_HOST`, `_PORT`,
|
|
292
306
|
`_USER`, `_PASSWORD`, `_IMAGE`, `_MEMORY_LIMIT_MB`. The container only
|
|
293
307
|
bootstraps the `sa` login — additional logins are a known limitation.
|
|
308
|
+
|
|
309
|
+
The same Docker-level resource knobs as the Postgres container are
|
|
310
|
+
available here too: `PGDEVKIT_TESTDB_MSSQL_SHM_SIZE`,
|
|
311
|
+
`PGDEVKIT_TESTDB_MSSQL_MEM_LIMIT` (a container-level cgroup limit, distinct
|
|
312
|
+
from `_MEMORY_LIMIT_MB` above which only tunes SQL Server's own internal
|
|
313
|
+
memory management), `PGDEVKIT_TESTDB_MSSQL_CPUS`, and
|
|
314
|
+
`PGDEVKIT_TESTDB_MSSQL_TMPFS`. As with the Postgres container, these only
|
|
315
|
+
take effect when pgdevkit creates the container, not when restarting an
|
|
316
|
+
existing stopped one (`docker rm -f pgdevkit-mssql` first if you've changed
|
|
317
|
+
any of them).
|
|
318
|
+
|
|
294
319
|
`pgdb testdb shell` execs into
|
|
295
320
|
[`sqlcmd`](https://github.com/microsoft/go-sqlcmd) (an external prerequisite,
|
|
296
321
|
the same category as `psql` for the Postgres path) rather than a Python
|
|
@@ -27,23 +27,23 @@ pgdevkit/db/model.py,sha256=ntuXonq-SCGkbNw-lvdMS5VuzLjxYRT8O6xaVqiw56I,980
|
|
|
27
27
|
pgdevkit/db/mssql_crud.py,sha256=yN4izZ0fsFwAs14008JECHH4dqjNbdHUHGEG8kidyNs,11374
|
|
28
28
|
pgdevkit/db/mssql_sql.py,sha256=DO3UMsTFN9pg0tNdaPGb0wf6lWlHGcqwqzkrGVhJF2g,2292
|
|
29
29
|
pgdevkit/testdb/__init__.py,sha256=tphuORo4t0QHQp_gFi6ZHXXgd32w6qUoKlaQCab6izA,366
|
|
30
|
-
pgdevkit/testdb/_docker.py,sha256
|
|
30
|
+
pgdevkit/testdb/_docker.py,sha256=-W59YBbcSIl9H_YmySRtVbOV4ImZPHOq9hxmlO-p56s,2807
|
|
31
31
|
pgdevkit/testdb/api.py,sha256=13YgTz6hPcYWfsUlQJhJ7k20-W_4hzepedVaT8gWhxI,9709
|
|
32
32
|
pgdevkit/testdb/config.py,sha256=NyeskDeThUgwOuxiMgHVnUOiHW-xVO9s2lJQoJcQwW4,2839
|
|
33
|
-
pgdevkit/testdb/constants.py,sha256=
|
|
34
|
-
pgdevkit/testdb/container.py,sha256=
|
|
33
|
+
pgdevkit/testdb/constants.py,sha256=cvdj800WnkzpXC1FZP4tmDDwwoIgZpXo36XIJngjHR0,2194
|
|
34
|
+
pgdevkit/testdb/container.py,sha256=_BYqs5IZmf_c5CsxLCzB1yLSSM6F0NWb1K6CujkfJ44,3641
|
|
35
35
|
pgdevkit/testdb/naming.py,sha256=iHZVYdBQjHOD5sihgmZFe2qOC1djgBb6iP6R8wLUfL0,4377
|
|
36
36
|
pgdevkit/testdb/query.py,sha256=iYpy_EoYIq5USfwr6pNktmDjcGi_yQx0vHvjHZNGRr0,3854
|
|
37
37
|
pgdevkit/testdb/schema.py,sha256=XYBK3xyay98a5gzFW6SAQ336Jge-NhOQhildSQDOaf4,15101
|
|
38
38
|
pgdevkit/testdb/mssql/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
39
39
|
pgdevkit/testdb/mssql/api.py,sha256=Ah95QTsOLvtubyHxRWDywjX9NCvTVgurmANLP5RY2Ck,8959
|
|
40
|
-
pgdevkit/testdb/mssql/constants.py,sha256=
|
|
41
|
-
pgdevkit/testdb/mssql/container.py,sha256=
|
|
40
|
+
pgdevkit/testdb/mssql/constants.py,sha256=qyA1FCv-2LAQ_C8OydePEXhyG_ZBPPB7vg1686xVpVU,3453
|
|
41
|
+
pgdevkit/testdb/mssql/container.py,sha256=sqJPAuhN1by3kZZ96gLet4pRt3uJmUMO6Kkmvjydg1w,3791
|
|
42
42
|
pgdevkit/docs/database-layout.md,sha256=j9N8GuT63D2oVf9rIOEv8GTWs4yTtjZTGH-zM5Wrg5o,8163
|
|
43
43
|
pgdevkit/skills/pgdevkit/SKILL.md,sha256=ADqEaQtMJPUUAiieqokzUUmIf27bWWJNB1ZvsfgiKAE,12205
|
|
44
44
|
pgdevkit/skills/pgdevkit/references/dynamic-sql.md,sha256=aTR1sx81moiTwaMaiOecaqk-9rT8y5Zxz7W1BoC3vK0,2774
|
|
45
45
|
pgdevkit/skills/pgdevkit/references/temporal-tables.md,sha256=LwZnItvQWI7bB0oRHxIfUc0ynnq7N0V5Mnv-QHvFN3Q,1364
|
|
46
|
-
pgdevkit-0.
|
|
47
|
-
pgdevkit-0.
|
|
48
|
-
pgdevkit-0.
|
|
49
|
-
pgdevkit-0.
|
|
46
|
+
pgdevkit-0.8.0.dist-info/METADATA,sha256=vLpobYq-Amjixm5ZHz8041Syn8y6_41Wu6j3wmhbGUs,21824
|
|
47
|
+
pgdevkit-0.8.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
48
|
+
pgdevkit-0.8.0.dist-info/entry_points.txt,sha256=FK2P55lf0WaGlOZJIINOGgCt8WB7ep0OnPsgnrp80bg,42
|
|
49
|
+
pgdevkit-0.8.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|