Skip to content

Commit 3b5ee02

Browse files
Merge pull request #130 from datajoint/pre/v2.1
2 parents 8212125 + b0b3ed7 commit 3b5ee02

35 files changed

+6601
-6295
lines changed

docker-compose.yaml

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
#
33
# MODE="LIVE" docker compose up --build # Live dev server at http://localhost:8000/
44
# MODE="BUILD" docker compose up --build # Build static site
5-
# docker compose run docs jupyter nbconvert --execute ... # Execute notebooks
5+
# MODE="EXECUTE" docker compose up --build # Execute notebooks against MySQL
6+
# MODE="EXECUTE_PG" docker compose up --build # Execute notebooks against PostgreSQL
67
#
78
services:
89
mysql:
@@ -19,6 +20,22 @@ services:
1920
timeout: 5s
2021
retries: 10
2122

23+
postgres:
24+
image: postgres:15
25+
environment:
26+
POSTGRES_USER: postgres
27+
POSTGRES_PASSWORD: tutorial
28+
POSTGRES_DB: datajoint
29+
ports:
30+
- "5432:5432"
31+
volumes:
32+
- postgres_data:/var/lib/postgresql/data
33+
healthcheck:
34+
test: ["CMD-SHELL", "pg_isready -U postgres"]
35+
interval: 5s
36+
timeout: 5s
37+
retries: 10
38+
2239
minio:
2340
image: minio/minio:latest
2441
environment:
@@ -42,9 +59,10 @@ services:
4259
dockerfile: Dockerfile
4360
environment:
4461
- MODE
45-
- DJ_HOST=mysql
46-
- DJ_USER=root
47-
- DJ_PASS=tutorial
62+
- DJ_HOST=${DJ_HOST:-mysql}
63+
- DJ_USER=${DJ_USER:-root}
64+
- DJ_PASS=${DJ_PASS:-tutorial}
65+
- DJ_BACKEND=${DJ_BACKEND:-mysql}
4866
volumes:
4967
- .:/main
5068
- ${DJ_PYTHON_PATH:-../datajoint-python}:/datajoint-python
@@ -53,6 +71,8 @@ services:
5371
depends_on:
5472
mysql:
5573
condition: service_healthy
74+
postgres:
75+
condition: service_healthy
5676
command:
5777
- sh
5878
- -c
@@ -70,14 +90,28 @@ services:
7090
# Generate llms-full.txt with current git info
7191
python scripts/gen_llms_full.py
7292
mkdocs build --config-file ./mkdocs.yaml
93+
elif echo "$${MODE}" | grep -i execute_pg &>/dev/null; then
94+
# EXECUTE_PG mode: execute notebooks against PostgreSQL
95+
pip install -e "/datajoint-python[postgres]"
96+
pip install scikit-image pooch nbconvert
97+
echo "Executing notebooks against PostgreSQL..."
98+
python scripts/execute_notebooks.py --backend postgresql
99+
elif echo "$${MODE}" | grep -i execute &>/dev/null; then
100+
# EXECUTE mode: execute notebooks against MySQL (default)
101+
pip install -e /datajoint-python
102+
pip install scikit-image pooch nbconvert
103+
echo "Executing notebooks against MySQL..."
104+
python scripts/execute_notebooks.py --backend mysql
73105
else
74-
echo "Unexpected mode..."
106+
echo "Unexpected mode. Use: LIVE, BUILD, EXECUTE, or EXECUTE_PG"
75107
exit 1
76108
fi
77109
78110
volumes:
79111
mysql_data:
80112
# Persistent storage for tutorial databases
81113
# Use `docker compose down -v` to reset
114+
postgres_data:
115+
# Persistent storage for PostgreSQL databases
82116
minio_data:
83117
# Persistent storage for external objects

mkdocs.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ nav:
8787
- reference/index.md
8888
- Specifications:
8989
- reference/specs/index.md
90+
- Database Backends: reference/specs/database-backends.md
9091
- Schema Definition:
9192
- Table Declaration: reference/specs/table-declaration.md
9293
- Master-Part: reference/specs/master-part.md
@@ -213,7 +214,7 @@ markdown_extensions:
213214
generic: true
214215
extra:
215216
generator: false # Disable watermark
216-
datajoint_version: "2.0" # DataJoint Python version this documentation covers
217+
datajoint_version: "2.1" # DataJoint Python version this documentation covers
217218
social:
218219
- icon: main/company-logo
219220
link: https://www.datajoint.com

scripts/drop_tutorial_schemas.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Drop all tutorial schemas from the database.
4+
5+
Usage:
6+
python drop_tutorial_schemas.py --backend mysql
7+
python drop_tutorial_schemas.py --backend postgresql
8+
9+
This script drops all schemas matching the 'tutorial_%' pattern,
10+
preparing for a fresh notebook execution run.
11+
"""
12+
13+
import argparse
14+
import os
15+
import sys
16+
17+
18+
def get_connection(backend: str):
19+
"""
20+
Create a database connection for the specified backend.
21+
22+
Parameters
23+
----------
24+
backend : str
25+
Either 'mysql' or 'postgresql'
26+
27+
Returns
28+
-------
29+
connection
30+
Database connection object
31+
"""
32+
if backend == "postgresql":
33+
import psycopg2
34+
35+
return psycopg2.connect(
36+
host=os.environ.get("DJ_HOST", "127.0.0.1"),
37+
port=int(os.environ.get("DJ_PORT", "5432")),
38+
user=os.environ.get("DJ_USER", "postgres"),
39+
password=os.environ.get("DJ_PASS", "tutorial"),
40+
dbname="postgres",
41+
)
42+
else: # mysql
43+
import pymysql
44+
45+
return pymysql.connect(
46+
host=os.environ.get("DJ_HOST", "127.0.0.1"),
47+
port=int(os.environ.get("DJ_PORT", "3306")),
48+
user=os.environ.get("DJ_USER", "root"),
49+
password=os.environ.get("DJ_PASS", "tutorial"),
50+
)
51+
52+
53+
def drop_tutorial_schemas(backend: str, dry_run: bool = False) -> list[str]:
54+
"""
55+
Drop all tutorial schemas from the database.
56+
57+
Parameters
58+
----------
59+
backend : str
60+
Either 'mysql' or 'postgresql'
61+
dry_run : bool
62+
If True, only list schemas without dropping
63+
64+
Returns
65+
-------
66+
list[str]
67+
List of dropped schema names
68+
"""
69+
conn = get_connection(backend)
70+
cursor = conn.cursor()
71+
72+
# Find tutorial schemas
73+
if backend == "postgresql":
74+
cursor.execute(
75+
"""
76+
SELECT schema_name FROM information_schema.schemata
77+
WHERE schema_name LIKE 'tutorial_%'
78+
ORDER BY schema_name
79+
"""
80+
)
81+
else: # mysql
82+
cursor.execute(
83+
"""
84+
SELECT schema_name FROM information_schema.schemata
85+
WHERE schema_name LIKE 'tutorial_%'
86+
ORDER BY schema_name
87+
"""
88+
)
89+
90+
schemas = [row[0] for row in cursor.fetchall()]
91+
92+
if not schemas:
93+
print("No tutorial schemas found.")
94+
return []
95+
96+
print(f"Found {len(schemas)} tutorial schema(s):")
97+
for schema in schemas:
98+
print(f" - {schema}")
99+
100+
if dry_run:
101+
print("\nDry run - no schemas dropped.")
102+
return schemas
103+
104+
print("\nDropping schemas...")
105+
106+
for schema in schemas:
107+
if backend == "postgresql":
108+
# PostgreSQL uses double quotes for identifiers
109+
cursor.execute(f'DROP SCHEMA IF EXISTS "{schema}" CASCADE')
110+
else: # mysql
111+
# MySQL uses backticks for identifiers
112+
cursor.execute(f"DROP DATABASE IF EXISTS `{schema}`")
113+
print(f" Dropped: {schema}")
114+
115+
conn.commit()
116+
cursor.close()
117+
conn.close()
118+
119+
print(f"\nDropped {len(schemas)} schema(s).")
120+
return schemas
121+
122+
123+
def main():
124+
parser = argparse.ArgumentParser(
125+
description="Drop all tutorial schemas from the database"
126+
)
127+
parser.add_argument(
128+
"--backend",
129+
choices=["mysql", "postgresql"],
130+
default="mysql",
131+
help="Database backend (default: mysql)",
132+
)
133+
parser.add_argument(
134+
"--dry-run",
135+
action="store_true",
136+
help="List schemas without dropping them",
137+
)
138+
139+
args = parser.parse_args()
140+
141+
print(f"{'=' * 60}")
142+
print(f"Drop Tutorial Schemas ({args.backend.upper()})")
143+
print(f"{'=' * 60}\n")
144+
145+
try:
146+
drop_tutorial_schemas(args.backend, args.dry_run)
147+
except Exception as e:
148+
print(f"Error: {e}", file=sys.stderr)
149+
sys.exit(1)
150+
151+
152+
if __name__ == "__main__":
153+
main()

0 commit comments

Comments
 (0)