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.
Files changed (116) hide show
  1. hemonc_alchemy-0.1.0/.devcontainer/Dockerfile +30 -0
  2. hemonc_alchemy-0.1.0/.devcontainer/bootstrap.py +45 -0
  3. hemonc_alchemy-0.1.0/.devcontainer/compose.yaml +62 -0
  4. hemonc_alchemy-0.1.0/.devcontainer/config.toml +80 -0
  5. hemonc_alchemy-0.1.0/.devcontainer/devcontainer.json +28 -0
  6. hemonc_alchemy-0.1.0/.devcontainer/initdb/01-enable-pgvector.sql +1 -0
  7. hemonc_alchemy-0.1.0/.devcontainer/pgpass +1 -0
  8. hemonc_alchemy-0.1.0/.devcontainer/post-create.sh +24 -0
  9. hemonc_alchemy-0.1.0/.devcontainer/register-kernel.sh +20 -0
  10. hemonc_alchemy-0.1.0/.devcontainer/servers.json +16 -0
  11. hemonc_alchemy-0.1.0/.env_sample +13 -0
  12. hemonc_alchemy-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +63 -0
  13. hemonc_alchemy-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  14. hemonc_alchemy-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +32 -0
  15. hemonc_alchemy-0.1.0/.github/ISSUE_TEMPLATE/not_working.yml +55 -0
  16. hemonc_alchemy-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +10 -0
  17. hemonc_alchemy-0.1.0/.github/release-drafter.yml +31 -0
  18. hemonc_alchemy-0.1.0/.github/workflows/ci.yml +47 -0
  19. hemonc_alchemy-0.1.0/.github/workflows/docs.yml +13 -0
  20. hemonc_alchemy-0.1.0/.github/workflows/manual-release.yml +24 -0
  21. hemonc_alchemy-0.1.0/.github/workflows/merge.yml +16 -0
  22. hemonc_alchemy-0.1.0/.github/workflows/publish.yml +25 -0
  23. hemonc_alchemy-0.1.0/.gitignore +139 -0
  24. hemonc_alchemy-0.1.0/.importlinter +27 -0
  25. hemonc_alchemy-0.1.0/CONTRIBUTING.md +31 -0
  26. hemonc_alchemy-0.1.0/PKG-INFO +125 -0
  27. hemonc_alchemy-0.1.0/README.md +70 -0
  28. hemonc_alchemy-0.1.0/docs/getting-started/configuration.md +83 -0
  29. hemonc_alchemy-0.1.0/docs/getting-started/index.md +13 -0
  30. hemonc_alchemy-0.1.0/docs/getting-started/installation.md +51 -0
  31. hemonc_alchemy-0.1.0/docs/getting-started/local-development.md +58 -0
  32. hemonc_alchemy-0.1.0/docs/getting-started/quickstart.md +60 -0
  33. hemonc_alchemy-0.1.0/docs/index.md +56 -0
  34. hemonc_alchemy-0.1.0/docs/integrations/omop.md +84 -0
  35. hemonc_alchemy-0.1.0/docs/js/mermaid-init.js +10 -0
  36. hemonc_alchemy-0.1.0/docs/maintainers/regeneration.md +28 -0
  37. hemonc_alchemy-0.1.0/docs/maintainers/release-process.md +55 -0
  38. hemonc_alchemy-0.1.0/docs/model/entities.md +55 -0
  39. hemonc_alchemy-0.1.0/docs/model/index.md +44 -0
  40. hemonc_alchemy-0.1.0/docs/model/loading.md +30 -0
  41. hemonc_alchemy-0.1.0/docs/model/relationships.md +43 -0
  42. hemonc_alchemy-0.1.0/docs/toolkit/core.md +71 -0
  43. hemonc_alchemy-0.1.0/docs/toolkit/index.md +42 -0
  44. hemonc_alchemy-0.1.0/docs/toolkit/scheduling.md +36 -0
  45. hemonc_alchemy-0.1.0/docs/toolkit/treatment.md +70 -0
  46. hemonc_alchemy-0.1.0/hemonc_alchemy/__init__.py +62 -0
  47. hemonc_alchemy-0.1.0/hemonc_alchemy/cli.py +234 -0
  48. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/__init__.py +10 -0
  49. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/audit.py +464 -0
  50. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/diff.py +141 -0
  51. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/generate.py +170 -0
  52. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/infer.py +243 -0
  53. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/load_helpers.py +34 -0
  54. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/schema_model.py +1115 -0
  55. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/spec_adapter.py +135 -0
  56. hemonc_alchemy-0.1.0/hemonc_alchemy/compiler/validate.py +145 -0
  57. hemonc_alchemy-0.1.0/hemonc_alchemy/config.py +69 -0
  58. hemonc_alchemy-0.1.0/hemonc_alchemy/errors.py +6 -0
  59. hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/__init__.py +13 -0
  60. hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/__init__.py +59 -0
  61. hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/binding.py +82 -0
  62. hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/diagnostics.py +245 -0
  63. hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/mapping.py +238 -0
  64. hemonc_alchemy-0.1.0/hemonc_alchemy/integrations/omop/queries.py +279 -0
  65. hemonc_alchemy-0.1.0/hemonc_alchemy/model/__init__.py +20 -0
  66. hemonc_alchemy-0.1.0/hemonc_alchemy/model/base.py +115 -0
  67. hemonc_alchemy-0.1.0/hemonc_alchemy/model/entities.py +1959 -0
  68. hemonc_alchemy-0.1.0/hemonc_alchemy/model/enums.py +704 -0
  69. hemonc_alchemy-0.1.0/hemonc_alchemy/model/relationships.py +110 -0
  70. hemonc_alchemy-0.1.0/hemonc_alchemy/naming.py +139 -0
  71. hemonc_alchemy-0.1.0/hemonc_alchemy/schema/registry.json +5215 -0
  72. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/__init__.py +11 -0
  73. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/__init__.py +1 -0
  74. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/__init__.py +51 -0
  75. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/bundles.py +50 -0
  76. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/classification.py +65 -0
  77. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/filters.py +82 -0
  78. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/__init__.py +33 -0
  79. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/handling.py +174 -0
  80. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/properties.py +246 -0
  81. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/routes.py +61 -0
  82. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/scheduling/tokens.py +65 -0
  83. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/selection/__init__.py +21 -0
  84. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/selection/components.py +152 -0
  85. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/selection/specs.py +108 -0
  86. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/analytics/treatment/selection/variants.py +127 -0
  87. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/__init__.py +58 -0
  88. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/coercion.py +30 -0
  89. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/components.py +150 -0
  90. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/conditions.py +64 -0
  91. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/links.py +138 -0
  92. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/core/sigs.py +202 -0
  93. hemonc_alchemy-0.1.0/hemonc_alchemy/toolkit/loading.py +438 -0
  94. hemonc_alchemy-0.1.0/mkdocs.yml +102 -0
  95. hemonc_alchemy-0.1.0/pyproject.toml +104 -0
  96. hemonc_alchemy-0.1.0/tests/conftest.py +65 -0
  97. hemonc_alchemy-0.1.0/tests/docker-compose.yaml +18 -0
  98. hemonc_alchemy-0.1.0/tests/fixtures/README.md +5 -0
  99. hemonc_alchemy-0.1.0/tests/test_audit.py +76 -0
  100. hemonc_alchemy-0.1.0/tests/test_casting.py +154 -0
  101. hemonc_alchemy-0.1.0/tests/test_diff.py +113 -0
  102. hemonc_alchemy-0.1.0/tests/test_enum_casting.py +168 -0
  103. hemonc_alchemy-0.1.0/tests/test_generated_model.py +45 -0
  104. hemonc_alchemy-0.1.0/tests/test_infer.py +224 -0
  105. hemonc_alchemy-0.1.0/tests/test_loading.py +316 -0
  106. hemonc_alchemy-0.1.0/tests/test_notebook_taxonomy.py +127 -0
  107. hemonc_alchemy-0.1.0/tests/test_omop_integration.py +105 -0
  108. hemonc_alchemy-0.1.0/tests/test_schedule.py +93 -0
  109. hemonc_alchemy-0.1.0/tests/test_schedule_properties.py +268 -0
  110. hemonc_alchemy-0.1.0/tests/test_schema_model.py +473 -0
  111. hemonc_alchemy-0.1.0/tests/test_spec_adapter.py +115 -0
  112. hemonc_alchemy-0.1.0/tests/test_toolkit.py +179 -0
  113. hemonc_alchemy-0.1.0/tests/test_toolkit_postgres.py +129 -0
  114. hemonc_alchemy-0.1.0/tests/test_toolkit_queries.py +185 -0
  115. hemonc_alchemy-0.1.0/tests/test_validate.py +125 -0
  116. 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,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Existing issues
4
+ url: https://github.com/AustralianCancerDataNetwork/hemonc-alchemy/issues
5
+ about: Search existing issues before opening a new report.
@@ -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,13 @@
1
+ name: Deploy Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ deploy:
13
+ uses: AustralianCancerDataNetwork/cava-devops/.github/workflows/deploy-docs.yml@main
@@ -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