hemonc-alchemy 0.1.0__tar.gz
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.
- hemonc_alchemy-0.1.0/.devcontainer/Dockerfile +30 -0
- hemonc_alchemy-0.1.0/.devcontainer/bootstrap.py +45 -0
- hemonc_alchemy-0.1.0/.devcontainer/compose.yaml +62 -0
- hemonc_alchemy-0.1.0/.devcontainer/config.toml +80 -0
- hemonc_alchemy-0.1.0/.devcontainer/devcontainer.json +28 -0
- hemonc_alchemy-0.1.0/.devcontainer/initdb/01-enable-pgvector.sql +1 -0
- hemonc_alchemy-0.1.0/.devcontainer/pgpass +1 -0
- hemonc_alchemy-0.1.0/.devcontainer/post-create.sh +24 -0
- hemonc_alchemy-0.1.0/.devcontainer/register-kernel.sh +20 -0
- hemonc_alchemy-0.1.0/.devcontainer/servers.json +16 -0
- hemonc_alchemy-0.1.0/.env_sample +13 -0
- hemonc_alchemy-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +63 -0
- hemonc_alchemy-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- hemonc_alchemy-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +32 -0
- hemonc_alchemy-0.1.0/.github/ISSUE_TEMPLATE/not_working.yml +55 -0
- hemonc_alchemy-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +10 -0
- hemonc_alchemy-0.1.0/.github/release-drafter.yml +31 -0
- hemonc_alchemy-0.1.0/.github/workflows/ci.yml +47 -0
- hemonc_alchemy-0.1.0/.github/workflows/docs.yml +13 -0
- hemonc_alchemy-0.1.0/.github/workflows/manual-release.yml +24 -0
- hemonc_alchemy-0.1.0/.github/workflows/merge.yml +16 -0
- hemonc_alchemy-0.1.0/.github/workflows/publish.yml +25 -0
- hemonc_alchemy-0.1.0/.gitignore +139 -0
- hemonc_alchemy-0.1.0/.importlinter +27 -0
- hemonc_alchemy-0.1.0/CONTRIBUTING.md +31 -0
- hemonc_alchemy-0.1.0/PKG-INFO +125 -0
- hemonc_alchemy-0.1.0/README.md +70 -0
- hemonc_alchemy-0.1.0/docs/getting-started/configuration.md +83 -0
- hemonc_alchemy-0.1.0/docs/getting-started/index.md +13 -0
- hemonc_alchemy-0.1.0/docs/getting-started/installation.md +51 -0
- hemonc_alchemy-0.1.0/docs/getting-started/local-development.md +58 -0
- hemonc_alchemy-0.1.0/docs/getting-started/quickstart.md +60 -0
- hemonc_alchemy-0.1.0/docs/index.md +56 -0
- hemonc_alchemy-0.1.0/docs/integrations/omop.md +84 -0
- hemonc_alchemy-0.1.0/docs/js/mermaid-init.js +10 -0
- hemonc_alchemy-0.1.0/docs/maintainers/regeneration.md +28 -0
- hemonc_alchemy-0.1.0/docs/maintainers/release-process.md +55 -0
- hemonc_alchemy-0.1.0/docs/model/entities.md +55 -0
- hemonc_alchemy-0.1.0/docs/model/index.md +44 -0
- hemonc_alchemy-0.1.0/docs/model/loading.md +30 -0
- hemonc_alchemy-0.1.0/docs/model/relationships.md +43 -0
- hemonc_alchemy-0.1.0/docs/toolkit/core.md +71 -0
- hemonc_alchemy-0.1.0/docs/toolkit/index.md +42 -0
- hemonc_alchemy-0.1.0/docs/toolkit/scheduling.md +36 -0
- hemonc_alchemy-0.1.0/docs/toolkit/treatment.md +70 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/__init__.py +62 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/cli.py +234 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/__init__.py +10 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/audit.py +464 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/diff.py +141 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/generate.py +170 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/infer.py +243 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/load_helpers.py +34 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/schema_model.py +1115 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/spec_adapter.py +135 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/validate.py +145 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/config.py +69 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/errors.py +6 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/__init__.py +13 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/__init__.py +59 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/binding.py +82 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/diagnostics.py +245 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/mapping.py +238 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/queries.py +279 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/model/__init__.py +20 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/model/base.py +115 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/model/entities.py +1959 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/model/enums.py +704 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/model/relationships.py +110 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/naming.py +139 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/schema/registry.json +5215 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/__init__.py +11 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/__init__.py +1 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/__init__.py +51 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/bundles.py +50 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/classification.py +65 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/filters.py +82 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/__init__.py +33 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/handling.py +174 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/properties.py +246 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/routes.py +61 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/tokens.py +65 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/selection/__init__.py +21 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/selection/components.py +152 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/selection/specs.py +108 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/selection/variants.py +127 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/__init__.py +58 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/coercion.py +30 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/components.py +150 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/conditions.py +64 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/links.py +138 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/sigs.py +202 -0
- hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/loading.py +438 -0
- hemonc_alchemy-0.1.0/mkdocs.yml +102 -0
- hemonc_alchemy-0.1.0/pyproject.toml +104 -0
- hemonc_alchemy-0.1.0/tests/conftest.py +65 -0
- hemonc_alchemy-0.1.0/tests/docker-compose.yaml +18 -0
- hemonc_alchemy-0.1.0/tests/fixtures/README.md +5 -0
- hemonc_alchemy-0.1.0/tests/test_audit.py +76 -0
- hemonc_alchemy-0.1.0/tests/test_casting.py +154 -0
- hemonc_alchemy-0.1.0/tests/test_diff.py +113 -0
- hemonc_alchemy-0.1.0/tests/test_enum_casting.py +168 -0
- hemonc_alchemy-0.1.0/tests/test_generated_model.py +45 -0
- hemonc_alchemy-0.1.0/tests/test_infer.py +224 -0
- hemonc_alchemy-0.1.0/tests/test_loading.py +316 -0
- hemonc_alchemy-0.1.0/tests/test_notebook_taxonomy.py +127 -0
- hemonc_alchemy-0.1.0/tests/test_omop_integration.py +105 -0
- hemonc_alchemy-0.1.0/tests/test_schedule.py +93 -0
- hemonc_alchemy-0.1.0/tests/test_schedule_properties.py +268 -0
- hemonc_alchemy-0.1.0/tests/test_schema_model.py +473 -0
- hemonc_alchemy-0.1.0/tests/test_spec_adapter.py +115 -0
- hemonc_alchemy-0.1.0/tests/test_toolkit.py +179 -0
- hemonc_alchemy-0.1.0/tests/test_toolkit_postgres.py +129 -0
- hemonc_alchemy-0.1.0/tests/test_toolkit_queries.py +185 -0
- hemonc_alchemy-0.1.0/tests/test_validate.py +125 -0
- hemonc_alchemy-0.1.0/uv.lock +3588 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
FROM python:3.12-slim-bookworm
|
|
2
|
+
|
|
3
|
+
# Copy uv from the official image while keeping the application image Python slim.
|
|
4
|
+
COPY --from=ghcr.io/astral-sh/uv:0.8.17 /uv /uvx /bin/
|
|
5
|
+
|
|
6
|
+
ARG USERNAME=vscode
|
|
7
|
+
ARG USER_UID=1000
|
|
8
|
+
ARG USER_GID=1000
|
|
9
|
+
|
|
10
|
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
11
|
+
PYTHONUNBUFFERED=1 \
|
|
12
|
+
UV_LINK_MODE=copy \
|
|
13
|
+
UV_PROJECT_ENVIRONMENT=/opt/venv \
|
|
14
|
+
PATH="/opt/venv/bin:/home/${USERNAME}/.local/bin:${PATH}"
|
|
15
|
+
|
|
16
|
+
RUN groupadd --gid "${USER_GID}" "${USERNAME}" \
|
|
17
|
+
&& useradd --uid "${USER_UID}" --gid "${USER_GID}" -m -s /bin/bash "${USERNAME}"
|
|
18
|
+
|
|
19
|
+
WORKDIR /workspace/hemonc-alchemy
|
|
20
|
+
|
|
21
|
+
# The source is mounted by Compose. The project and its extras are installed by
|
|
22
|
+
# the Compose command/post-create hook when the mounted Git checkout is
|
|
23
|
+
# available to hatch-vcs; installing here would omit the mounted source tree.
|
|
24
|
+
RUN apt-get update \
|
|
25
|
+
&& apt-get install --yes --no-install-recommends git \
|
|
26
|
+
&& rm -rf /var/lib/apt/lists/* \
|
|
27
|
+
&& mkdir --parents /opt/venv \
|
|
28
|
+
&& chown -R "${USERNAME}:${USERNAME}" /opt/venv
|
|
29
|
+
|
|
30
|
+
USER ${USERNAME}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
import sqlalchemy.orm as so
|
|
6
|
+
|
|
7
|
+
from hemonc_alchemy.model import entities
|
|
8
|
+
from hemonc_alchemy.model.base import Base, concrete_entities, register_enum_casts
|
|
9
|
+
from hemonc_alchemy.toolkit.loading import load_all
|
|
10
|
+
|
|
11
|
+
data_dir = Path("/workspace/hemonc-alchemy/data/Tables")
|
|
12
|
+
engine = sa.create_engine(os.environ["DATABASE_URL"])
|
|
13
|
+
|
|
14
|
+
# This script is a full rebuild for the disposable development database. The
|
|
15
|
+
# denormalised child tables are loaded with INSERTs, so dropping first also
|
|
16
|
+
# makes reruns after a partial import deterministic.
|
|
17
|
+
with engine.begin() as connection:
|
|
18
|
+
inspector = sa.inspect(connection)
|
|
19
|
+
for table_name in inspector.get_table_names():
|
|
20
|
+
if table_name.startswith("_staging_"):
|
|
21
|
+
quoted_name = connection.dialect.identifier_preparer.quote(table_name)
|
|
22
|
+
connection.exec_driver_sql(f"DROP TABLE IF EXISTS {quoted_name} CASCADE")
|
|
23
|
+
|
|
24
|
+
Base.metadata.drop_all(engine)
|
|
25
|
+
Base.metadata.create_all(engine)
|
|
26
|
+
register_enum_casts()
|
|
27
|
+
|
|
28
|
+
source_entities = sorted(
|
|
29
|
+
(
|
|
30
|
+
cls for cls in concrete_entities(entities)
|
|
31
|
+
if getattr(cls, "filename", None)
|
|
32
|
+
),
|
|
33
|
+
key=lambda cls: cls.__tablename__,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
with so.Session(engine) as session:
|
|
37
|
+
for entity_cls in source_entities:
|
|
38
|
+
counts = load_all(
|
|
39
|
+
session,
|
|
40
|
+
entity_cls,
|
|
41
|
+
data_dir,
|
|
42
|
+
chunksize=100_000,
|
|
43
|
+
)
|
|
44
|
+
session.commit()
|
|
45
|
+
print(entity_cls.__tablename__, counts)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
services:
|
|
2
|
+
python-hemonc-alchemy:
|
|
3
|
+
build:
|
|
4
|
+
context: ..
|
|
5
|
+
dockerfile: .devcontainer/Dockerfile
|
|
6
|
+
command: ["/bin/sh", "-c", "uv sync --frozen --extra dev --extra author --extra exploration --extra postgres --extra omop && sleep infinity"]
|
|
7
|
+
environment:
|
|
8
|
+
DATABASE_URL: postgresql+psycopg://hemonc:hemonc@postgres:5432/hemonc_alchemy
|
|
9
|
+
OA_CONFIG_PATH: /home/vscode/.config/omop/config.toml
|
|
10
|
+
PGHOST: postgres
|
|
11
|
+
PGPORT: "5432"
|
|
12
|
+
PGDATABASE: hemonc_alchemy
|
|
13
|
+
PGUSER: hemonc
|
|
14
|
+
PGPASSWORD: hemonc
|
|
15
|
+
depends_on:
|
|
16
|
+
postgres:
|
|
17
|
+
condition: service_healthy
|
|
18
|
+
volumes:
|
|
19
|
+
- ..:/workspace/hemonc-alchemy:cached
|
|
20
|
+
|
|
21
|
+
postgres:
|
|
22
|
+
image: pgvector/pgvector:0.8.6-pg18-bookworm
|
|
23
|
+
environment:
|
|
24
|
+
POSTGRES_DB: hemonc_alchemy
|
|
25
|
+
POSTGRES_USER: hemonc
|
|
26
|
+
POSTGRES_PASSWORD: hemonc
|
|
27
|
+
healthcheck:
|
|
28
|
+
test: ["CMD-SHELL", "pg_isready -U hemonc -d hemonc_alchemy"]
|
|
29
|
+
interval: 5s
|
|
30
|
+
timeout: 5s
|
|
31
|
+
retries: 10
|
|
32
|
+
ports:
|
|
33
|
+
- "5432:5432"
|
|
34
|
+
volumes:
|
|
35
|
+
# PostgreSQL 18 stores data under a major-version-specific subdirectory.
|
|
36
|
+
- postgres-data:/var/lib/postgresql
|
|
37
|
+
- ./initdb:/docker-entrypoint-initdb.d:ro
|
|
38
|
+
|
|
39
|
+
pgadmin:
|
|
40
|
+
image: dpage/pgadmin4:latest
|
|
41
|
+
environment:
|
|
42
|
+
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-admin@example.com}
|
|
43
|
+
# Development-only default; override this in .env for a shared machine.
|
|
44
|
+
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-hemonc-admin}
|
|
45
|
+
# Load the checked-in server definition whenever the container starts.
|
|
46
|
+
PGADMIN_SERVER_JSON_FILE: /pgadmin4/servers.json
|
|
47
|
+
PGADMIN_REPLACE_SERVERS_ON_STARTUP: ${PGADMIN_REPLACE_SERVERS_ON_STARTUP:-True}
|
|
48
|
+
# The password cannot be stored in servers.json; pgAdmin reads it from pgpass.
|
|
49
|
+
PGPASS_FILE: /pgadmin4/pgpass
|
|
50
|
+
depends_on:
|
|
51
|
+
postgres:
|
|
52
|
+
condition: service_healthy
|
|
53
|
+
ports:
|
|
54
|
+
- "${PGADMIN_PORT:-5050}:80"
|
|
55
|
+
volumes:
|
|
56
|
+
- pgadmin-data:/var/lib/pgadmin
|
|
57
|
+
- ./servers.json:/pgadmin4/servers.json:ro
|
|
58
|
+
- ./pgpass:/pgadmin4/pgpass:ro
|
|
59
|
+
|
|
60
|
+
volumes:
|
|
61
|
+
postgres-data:
|
|
62
|
+
pgadmin-data:
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# oa-configurator stack config for the HemOnc Alchemy devcontainer.
|
|
2
|
+
#
|
|
3
|
+
# Copied to ~/.config/omop/config.toml (mode 600) by post-create.sh the first
|
|
4
|
+
# time the container is created, so `omop-config configure hemonc_alchemy` can
|
|
5
|
+
# edit it afterwards without touching this checked-in seed. Delete that copy
|
|
6
|
+
# and rebuild the container to start again from this file.
|
|
7
|
+
#
|
|
8
|
+
# The credentials below are the throwaway ones the compose stack creates; they
|
|
9
|
+
# only reach the `postgres` service on the devcontainer network. Real passwords
|
|
10
|
+
# belong in your own ~/.config/omop/config.toml, never here.
|
|
11
|
+
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
# Connections: the compose `postgres` service, addressed by service name.
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
[connections.devcontainer_postgres]
|
|
17
|
+
dialect = "postgresql+psycopg"
|
|
18
|
+
host = "postgres"
|
|
19
|
+
port = 5432
|
|
20
|
+
user = "hemonc"
|
|
21
|
+
password = "hemonc"
|
|
22
|
+
database_name = "hemonc_alchemy"
|
|
23
|
+
|
|
24
|
+
# Same server, separate database, so `pytest -m postgres` never writes to the
|
|
25
|
+
# database you loaded with bootstrap.py. Created on first use by the
|
|
26
|
+
# oa-configurator pytest plugin; `test_only` is the safety check that lets it.
|
|
27
|
+
[connections.devcontainer_postgres_test]
|
|
28
|
+
dialect = "postgresql+psycopg"
|
|
29
|
+
host = "postgres"
|
|
30
|
+
port = 5432
|
|
31
|
+
user = "hemonc"
|
|
32
|
+
password = "hemonc"
|
|
33
|
+
database_name = "hemonc_alchemy_test"
|
|
34
|
+
test_only = true
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Databases: the logical targets used by HemOnc and OMOP Alchemy.
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
[databases.hemonc_db]
|
|
41
|
+
kind = "generic"
|
|
42
|
+
connection = "devcontainer_postgres"
|
|
43
|
+
schema_name = "public"
|
|
44
|
+
|
|
45
|
+
[databases.test_hemonc_db]
|
|
46
|
+
kind = "generic"
|
|
47
|
+
connection = "devcontainer_postgres_test"
|
|
48
|
+
schema_name = "public"
|
|
49
|
+
|
|
50
|
+
# OMOP-alchemy's CDM target shares the compose PostgreSQL service and the
|
|
51
|
+
# HemOnc schema for now. This is a configuration choice for the disposable
|
|
52
|
+
# development database; oa-configurator will own schema resolution when its
|
|
53
|
+
# cross-package support is available.
|
|
54
|
+
[databases.cdm_db]
|
|
55
|
+
kind = "cdm"
|
|
56
|
+
connection = "devcontainer_postgres"
|
|
57
|
+
schema_name = "public"
|
|
58
|
+
|
|
59
|
+
[databases.test_cdm_db]
|
|
60
|
+
kind = "cdm"
|
|
61
|
+
connection = "devcontainer_postgres_test"
|
|
62
|
+
schema_name = "public"
|
|
63
|
+
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
# Tools: package-specific [tools.<tool_name>] sections.
|
|
66
|
+
# ---------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
[tools.hemonc_alchemy]
|
|
69
|
+
hemonc_db = "hemonc_db"
|
|
70
|
+
test_hemonc_db = "test_hemonc_db"
|
|
71
|
+
|
|
72
|
+
[tools.omop_alchemy]
|
|
73
|
+
cdm_db = "cdm_db"
|
|
74
|
+
test_cdm_db = "test_cdm_db"
|
|
75
|
+
|
|
76
|
+
[logging]
|
|
77
|
+
level = "INFO"
|
|
78
|
+
|
|
79
|
+
[logging.loggers]
|
|
80
|
+
"sqlalchemy.engine" = "WARNING"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "HemOnc Alchemy",
|
|
3
|
+
"dockerComposeFile": "compose.yaml",
|
|
4
|
+
"service": "python-hemonc-alchemy",
|
|
5
|
+
"workspaceFolder": "/workspace/hemonc-alchemy",
|
|
6
|
+
"remoteUser": "vscode",
|
|
7
|
+
"updateRemoteUserUID": true,
|
|
8
|
+
"postCreateCommand": "bash .devcontainer/post-create.sh",
|
|
9
|
+
// also on start, so containers created before the kernel fix get it
|
|
10
|
+
"postStartCommand": "bash .devcontainer/register-kernel.sh",
|
|
11
|
+
"customizations": {
|
|
12
|
+
"vscode": {
|
|
13
|
+
"extensions": [
|
|
14
|
+
"ms-python.python",
|
|
15
|
+
"ms-python.vscode-pylance",
|
|
16
|
+
"ms-toolsai.jupyter",
|
|
17
|
+
"charliermarsh.ruff"
|
|
18
|
+
],
|
|
19
|
+
"settings": {
|
|
20
|
+
"python.defaultInterpreterPath": "/opt/venv/bin/python",
|
|
21
|
+
"python.analysis.extraPaths": [
|
|
22
|
+
"/workspace/hemonc-alchemy"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"shutdownAction": "none"
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
postgres:5432:hemonc_alchemy:hemonc:hemonc
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Devcontainer create-time setup: install the project, then seed the
|
|
3
|
+
# oa-configurator stack config pointing at the compose `postgres` service.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
cd "$(dirname "$0")/.."
|
|
7
|
+
|
|
8
|
+
uv sync --frozen --extra dev --extra author --extra exploration --extra postgres --extra omop
|
|
9
|
+
|
|
10
|
+
bash "$(dirname "$0")/register-kernel.sh"
|
|
11
|
+
|
|
12
|
+
config_path="${OA_CONFIG_PATH:-${HOME}/.config/omop/config.toml}"
|
|
13
|
+
mkdir -p "$(dirname "${config_path}")"
|
|
14
|
+
|
|
15
|
+
if [ -e "${config_path}" ]; then
|
|
16
|
+
echo "Keeping the existing stack config at ${config_path}"
|
|
17
|
+
else
|
|
18
|
+
# Mode 600 because the file holds database passwords; oa-configurator warns
|
|
19
|
+
# about anything more permissive. Copied rather than mounted so that
|
|
20
|
+
# `omop-config configure hemonc_alchemy` can rewrite it in place, without
|
|
21
|
+
# the edit landing back in the checked-in seed.
|
|
22
|
+
install -m 600 .devcontainer/config.toml "${config_path}"
|
|
23
|
+
echo "Installed the devcontainer stack config at ${config_path}"
|
|
24
|
+
fi
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Register the project environment as the `python3` Jupyter kernel.
|
|
3
|
+
#
|
|
4
|
+
# The VS Code Jupyter extension supplies its own kernel when it attaches, but
|
|
5
|
+
# `jupyter execute`, nbclient and papermill all resolve `python3` from the
|
|
6
|
+
# kernel spec directory. Without this, running the notebooks from the CLI
|
|
7
|
+
# fails with NoSuchKernel even though every dependency is installed.
|
|
8
|
+
#
|
|
9
|
+
# Run from postStartCommand, not just postCreateCommand: a container created
|
|
10
|
+
# before this script existed would otherwise never get the kernel.
|
|
11
|
+
# `ipykernel install` is idempotent, so re-running on every start is safe.
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
if ! python -c "import ipykernel" 2>/dev/null; then
|
|
15
|
+
echo "ipykernel not installed; skipping kernel registration (needs the exploration extra)"
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
python -m ipykernel install --user --name python3 --display-name "hemonc-alchemy" >/dev/null
|
|
20
|
+
echo "Registered the python3 Jupyter kernel"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Servers": {
|
|
3
|
+
"1": {
|
|
4
|
+
"Name": "HemOnc Alchemy PostgreSQL",
|
|
5
|
+
"Group": "HemOnc Alchemy",
|
|
6
|
+
"Host": "postgres",
|
|
7
|
+
"Port": 5432,
|
|
8
|
+
"MaintenanceDB": "hemonc_alchemy",
|
|
9
|
+
"Username": "hemonc",
|
|
10
|
+
"ConnectionParameters": {
|
|
11
|
+
"sslmode": "prefer",
|
|
12
|
+
"connect_timeout": 10
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# The devcontainer seeds its own oa-configurator stack config from
|
|
2
|
+
# .devcontainer/config.toml into ~/.config/omop/config.toml inside the
|
|
3
|
+
# container
|
|
4
|
+
|
|
5
|
+
# Set OA_CONFIG_PATH only to point oa-configurator at a different file.
|
|
6
|
+
# OA_CONFIG_PATH=/home/vscode/.config/omop/config.toml
|
|
7
|
+
|
|
8
|
+
# pgAdmin (available at http://localhost:5050 by default)
|
|
9
|
+
PGADMIN_PORT=5050
|
|
10
|
+
PGADMIN_DEFAULT_EMAIL=admin@example.com
|
|
11
|
+
PGADMIN_DEFAULT_PASSWORD=change-me
|
|
12
|
+
# Set to False if you want to preserve servers added manually in pgAdmin.
|
|
13
|
+
PGADMIN_REPLACE_SERVERS_ON_STARTUP=True
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: "🐞 Bug Report"
|
|
2
|
+
description: Report a reproducible bug.
|
|
3
|
+
type: "Bug"
|
|
4
|
+
body:
|
|
5
|
+
- type: checkboxes
|
|
6
|
+
attributes:
|
|
7
|
+
label: Pre-flight
|
|
8
|
+
options:
|
|
9
|
+
- label: I searched existing issues and this is not a duplicate.
|
|
10
|
+
required: true
|
|
11
|
+
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: summary
|
|
14
|
+
attributes:
|
|
15
|
+
label: Summary
|
|
16
|
+
description: One or two sentences describing the bug.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: reproduction
|
|
22
|
+
attributes:
|
|
23
|
+
label: Reproduction
|
|
24
|
+
description: Steps and/or a minimal code example that reproduces the issue. Wrap code in triple backticks.
|
|
25
|
+
placeholder: |
|
|
26
|
+
1. Import X and call Y with Z
|
|
27
|
+
2. Observe error
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
# minimal example
|
|
31
|
+
```
|
|
32
|
+
validations:
|
|
33
|
+
required: true
|
|
34
|
+
|
|
35
|
+
- type: textarea
|
|
36
|
+
id: actual
|
|
37
|
+
attributes:
|
|
38
|
+
label: Actual behaviour
|
|
39
|
+
validations:
|
|
40
|
+
required: true
|
|
41
|
+
|
|
42
|
+
- type: textarea
|
|
43
|
+
id: expected
|
|
44
|
+
attributes:
|
|
45
|
+
label: Expected behaviour
|
|
46
|
+
validations:
|
|
47
|
+
required: true
|
|
48
|
+
|
|
49
|
+
- type: textarea
|
|
50
|
+
id: logs
|
|
51
|
+
attributes:
|
|
52
|
+
label: Error output
|
|
53
|
+
description: Full traceback if applicable. Formatted automatically.
|
|
54
|
+
render: python-traceback
|
|
55
|
+
|
|
56
|
+
- type: textarea
|
|
57
|
+
id: system
|
|
58
|
+
attributes:
|
|
59
|
+
label: System info
|
|
60
|
+
description: |
|
|
61
|
+
Run the following command and paste its output:
|
|
62
|
+
python <(curl -s https://raw.githubusercontent.com/AustralianCancerDataNetwork/cava-devops/main/scripts/cava_system_info.py)
|
|
63
|
+
render: shell
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: "🚀 Feature Request"
|
|
2
|
+
description: Propose a new feature or enhancement.
|
|
3
|
+
type: "Feature"
|
|
4
|
+
body:
|
|
5
|
+
- type: checkboxes
|
|
6
|
+
attributes:
|
|
7
|
+
label: Pre-flight
|
|
8
|
+
options:
|
|
9
|
+
- label: I searched existing issues and this has not been requested before.
|
|
10
|
+
required: true
|
|
11
|
+
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: problem
|
|
14
|
+
attributes:
|
|
15
|
+
label: Problem or motivation
|
|
16
|
+
description: What are you trying to do that you currently cannot?
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: proposal
|
|
22
|
+
attributes:
|
|
23
|
+
label: Proposed solution
|
|
24
|
+
description: How would you like this to work?
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
|
|
28
|
+
- type: textarea
|
|
29
|
+
id: alternatives
|
|
30
|
+
attributes:
|
|
31
|
+
label: Alternatives considered
|
|
32
|
+
description: Other approaches you considered and why you ruled them out.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: "❗ Something is not working"
|
|
2
|
+
description: Something behaves unexpectedly but you are not sure if it is a bug.
|
|
3
|
+
body:
|
|
4
|
+
- type: checkboxes
|
|
5
|
+
attributes:
|
|
6
|
+
label: Pre-flight
|
|
7
|
+
options:
|
|
8
|
+
- label: I searched existing issues for this problem.
|
|
9
|
+
required: true
|
|
10
|
+
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: summary
|
|
13
|
+
attributes:
|
|
14
|
+
label: Problem summary
|
|
15
|
+
description: One or two sentences describing what is not working.
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: reproduction
|
|
21
|
+
attributes:
|
|
22
|
+
label: Reproduction
|
|
23
|
+
description: Steps and/or a minimal code example. Wrap code in triple backticks.
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: actual
|
|
29
|
+
attributes:
|
|
30
|
+
label: Actual outcome
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
|
|
34
|
+
- type: textarea
|
|
35
|
+
id: expected
|
|
36
|
+
attributes:
|
|
37
|
+
label: Expected outcome
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
|
|
41
|
+
- type: textarea
|
|
42
|
+
id: logs
|
|
43
|
+
attributes:
|
|
44
|
+
label: Error messages
|
|
45
|
+
description: Full traceback if applicable. Formatted automatically.
|
|
46
|
+
render: python-traceback
|
|
47
|
+
|
|
48
|
+
- type: textarea
|
|
49
|
+
id: system
|
|
50
|
+
attributes:
|
|
51
|
+
label: System info
|
|
52
|
+
description: |
|
|
53
|
+
Run the following command and paste its output:
|
|
54
|
+
python <(curl -s https://raw.githubusercontent.com/AustralianCancerDataNetwork/cava-devops/main/scripts/cava_system_info.py)
|
|
55
|
+
render: shell
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- Keep the PR title concise and factual: it becomes the release-note entry. Use this section for reviewer context, trade-offs, and validation details. -->
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] Applied exactly one label (`breaking`, `feature`, `fix`, `dependencies`, or `chore`)
|
|
8
|
+
- [ ] Tests pass locally (`uv run pytest -q`)
|
|
9
|
+
- [ ] Lint passes (`uv run ruff check .`)
|
|
10
|
+
- [ ] Generated model changes were regenerated and reviewed, if applicable
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name-template: 'v$RESOLVED_VERSION'
|
|
2
|
+
tag-template: 'v$RESOLVED_VERSION'
|
|
3
|
+
commitish: main
|
|
4
|
+
|
|
5
|
+
categories:
|
|
6
|
+
- title: Breaking Changes
|
|
7
|
+
labels: ['breaking']
|
|
8
|
+
- title: Features
|
|
9
|
+
labels: ['feature']
|
|
10
|
+
- title: Fixes
|
|
11
|
+
labels: ['fix']
|
|
12
|
+
- title: Dependencies
|
|
13
|
+
labels: ['dependencies']
|
|
14
|
+
|
|
15
|
+
template: |
|
|
16
|
+
$CHANGES
|
|
17
|
+
|
|
18
|
+
change-template: '- **$TITLE** (#$NUMBER) @$AUTHOR'
|
|
19
|
+
|
|
20
|
+
version-resolver:
|
|
21
|
+
major:
|
|
22
|
+
labels: ['breaking']
|
|
23
|
+
minor:
|
|
24
|
+
labels: ['feature']
|
|
25
|
+
patch:
|
|
26
|
+
labels: ['fix', 'dependencies']
|
|
27
|
+
default: patch
|
|
28
|
+
|
|
29
|
+
exclude-labels: ['chore']
|
|
30
|
+
|
|
31
|
+
autolabeler: []
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
types: [opened, synchronize, reopened, labeled, unlabeled]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pull-requests: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
label-gate:
|
|
14
|
+
uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/label-gate.yml@main
|
|
15
|
+
|
|
16
|
+
build-test:
|
|
17
|
+
uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/build-test-postgres.yml@main
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
postgres-db: test
|
|
21
|
+
postgres-user: test
|
|
22
|
+
postgres-password: test
|
|
23
|
+
# The generated model and loader use dynamic SQLAlchemy/pandas types
|
|
24
|
+
# that are not yet clean under ty. Keep the shared check focused on the
|
|
25
|
+
# typed public/configuration boundary until those surfaces are annotated.
|
|
26
|
+
ty-src: hemonc_alchemy/cli.py hemonc_alchemy/config.py hemonc_alchemy/integrations
|
|
27
|
+
setup-commands: |
|
|
28
|
+
mkdir -p "$HOME/.config/omop"
|
|
29
|
+
cat > "$HOME/.config/omop/config.toml" <<'EOF'
|
|
30
|
+
[connections.ci_postgres]
|
|
31
|
+
dialect = "postgresql+psycopg"
|
|
32
|
+
host = "localhost"
|
|
33
|
+
port = 5432
|
|
34
|
+
user = "test"
|
|
35
|
+
password = "test"
|
|
36
|
+
database_name = "test"
|
|
37
|
+
test_only = true
|
|
38
|
+
|
|
39
|
+
[databases.ci_hemonc_db]
|
|
40
|
+
kind = "generic"
|
|
41
|
+
connection = "ci_postgres"
|
|
42
|
+
schema_name = "public"
|
|
43
|
+
|
|
44
|
+
[tools.hemonc_alchemy]
|
|
45
|
+
hemonc_db = "ci_hemonc_db"
|
|
46
|
+
test_hemonc_db = "ci_hemonc_db"
|
|
47
|
+
EOF
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Manual Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
description: Version to release (for example, 1.2.3; no leading v)
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
prerelease:
|
|
11
|
+
description: Mark the release as a pre-release
|
|
12
|
+
required: false
|
|
13
|
+
default: false
|
|
14
|
+
type: boolean
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: write
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
release:
|
|
21
|
+
uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/manual-release.yml@main
|
|
22
|
+
with:
|
|
23
|
+
version: ${{ inputs.version }}
|
|
24
|
+
prerelease: ${{ inputs.prerelease }}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: Release Update
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
types: [closed]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
pull-requests: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
draft:
|
|
14
|
+
if: github.event.pull_request.merged == true
|
|
15
|
+
uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/release-drafter.yml@main
|
|
16
|
+
secrets: inherit
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/publish.yml@main
|
|
10
|
+
|
|
11
|
+
publish:
|
|
12
|
+
needs: build
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
id-token: write
|
|
16
|
+
environment:
|
|
17
|
+
name: pypi
|
|
18
|
+
url: https://pypi.org/p/hemonc-alchemy
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/download-artifact@v4
|
|
21
|
+
with:
|
|
22
|
+
name: dist
|
|
23
|
+
path: dist/
|
|
24
|
+
|
|
25
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|