Skip to content

Commit e3564ee

Browse files
authored
Merge pull request #229 from datakind/feat/local_inst_testing
feat: Optional local institution seed from `config/local_inst_data.json`
2 parents 55c2009 + bea4abf commit e3564ee

5 files changed

Lines changed: 131 additions & 11 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ ENV/
9797
env.bak/
9898
venv.bak/
9999

100+
# Local config / dev data
101+
config/local_inst_data.json
102+
100103
# mkdocs documentation
101104
/site
102105

README.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,3 @@ This repo contains:
1313

1414

1515
NOTE: this repo was forked from the https://github.com/datakind/student-success-tool repo, which means some of the static files (e.g. CONTRIBUTING.md) may be outdated or may include irrelevant information from that repo. Please update those as you see fit. For information about the specific items listed above, defer to the specific readmes in the relevant directory.
16-
17-
## Local edvise development override
18-
19-
Production uses a pinned Git reference for `edvise`. For local development, use an
20-
editable install after syncing the environment.
21-
22-
1. Clone `edvise` alongside `edvise-api` (so `../edvise` exists).
23-
2. Run `uv sync`.
24-
3. Override locally: `uv pip install -e ../edvise`
25-
26-
To revert back to the pinned Git dependency, run `uv sync --reinstall-package edvise`.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
[
2+
{
3+
"inst_id": "inst-uuid-here",
4+
"name": "Example institution",
5+
"state": "XX",
6+
"retention_days": null,
7+
"pdp_id": "",
8+
"edvise_id": null,
9+
"batches": [
10+
{
11+
"batch_id": "batch-uuid-here",
12+
"inst_id": "inst-uuid-here",
13+
"file_names_to_ids": {
14+
"example_course.csv": "file-id-course",
15+
"example_student.csv": "file-id-student"
16+
},
17+
"name": "example_batch_1",
18+
"created_by": "uploader-uuid-here",
19+
"deleted": false,
20+
"completed": true,
21+
"deletion_request_time": null,
22+
"created_at": "2025-01-15T12:00:00",
23+
"updated_at": "2025-01-15T12:00:00",
24+
"updated_by": ""
25+
}
26+
],
27+
"files": [
28+
{
29+
"name": "example_course.csv",
30+
"data_id": "file-id-course",
31+
"batch_ids": ["batch-uuid-here"],
32+
"inst_id": "inst-uuid-here",
33+
"uploader": "uploader-uuid-here",
34+
"source": "MANUAL_UPLOAD",
35+
"schemas": ["COURSE"],
36+
"deleted": false,
37+
"deletion_request_time": null,
38+
"retention_days": null,
39+
"sst_generated": false,
40+
"valid": true,
41+
"uploaded_date": "2025-01-15T11:58:00"
42+
},
43+
{
44+
"name": "example_student.csv",
45+
"data_id": "file-id-student",
46+
"batch_ids": ["batch-uuid-here"],
47+
"inst_id": "inst-uuid-here",
48+
"uploader": "uploader-uuid-here",
49+
"source": "MANUAL_UPLOAD",
50+
"schemas": ["STUDENT"],
51+
"deleted": false,
52+
"deletion_request_time": null,
53+
"retention_days": null,
54+
"sst_generated": false,
55+
"valid": true,
56+
"uploaded_date": "2025-01-15T11:57:00"
57+
}
58+
]
59+
}
60+
]

src/webapp/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,25 @@ The process to upload a file involves three API calls:
168168
## Local VSCode Debugging
169169

170170
From the Run & Debug panel (⇧⌘D on 🍎) you can run the [debug launch config](../../.vscode/launch.json) for the webapp or worker modules. This will allow you to set breakpoints within the source code while the applications are running.
171+
172+
## Local edvise development override
173+
174+
Production uses a pinned Git reference for `edvise`. For local development, use an
175+
editable install after syncing the environment.
176+
177+
1. Clone `edvise` alongside `edvise-api` (so `../edvise` exists).
178+
2. Run `uv sync`.
179+
3. Override locally: `uv pip install -e ../edvise`
180+
181+
To revert back to the pinned Git dependency, run `uv sync --reinstall-package edvise`.
182+
183+
## Local institutions (optional)
184+
185+
You can seed the local database with institution, batch, and file metadata that matches dev or staging (names, UUIDs, batch membership) without checking secrets into Git.
186+
187+
1. Copy `config/local_inst_data.example.json` to `config/local_inst_data.json`. The latter is gitignored.
188+
2. Edit `local_inst_data.json` to match your needs. Use the example file as the schema: one array element per institution, with `inst_id`, `name`, and optionally `state`, `pdp_id`, `batches`, and `files`.
189+
190+
If the file is missing, startup skips this step and the default local seed in code still applies.
191+
192+
**Limitation:** Endpoints that read uploaded CSV (for example EDA) load blobs from GCS under the bucket name `dev_<institution_uuid_hex>`, not from this JSON. To exercise those flows locally you still need GCP credentials and the corresponding objects in that bucket, or you rely on tests/mocks instead.

src/webapp/database.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""Database configuration."""
22

3+
import json
34
import uuid
45
import datetime
6+
from pathlib import Path
57
from typing import Set, List, Any
68
from contextvars import ContextVar
79
import enum
@@ -61,6 +63,49 @@ class Base(DeclarativeBase):
6163
DATETIME_TESTING = datetime.datetime(2024, 12, 26, 19, 37, 59, 753357)
6264

6365

66+
def _setup_test_institutions(session: Session) -> None:
67+
"""Load optional local institution display data from config/local_inst_data.json (gitignored)."""
68+
file = Path("config/local_inst_data.json")
69+
if file.exists():
70+
with open(file) as f:
71+
for inst in json.load(f):
72+
session.merge(
73+
InstTable(
74+
id=uuid.UUID(inst["inst_id"]),
75+
name=inst["name"],
76+
state=inst.get("state"),
77+
pdp_id=inst.get("pdp_id"),
78+
created_at=DATETIME_TESTING,
79+
updated_at=DATETIME_TESTING,
80+
created_by=LOCAL_USER_UUID,
81+
)
82+
)
83+
schemas_by_file_id = {
84+
f["data_id"]: f.get("schemas", []) for f in inst.get("files", [])
85+
}
86+
for batch in inst.get("batches", []):
87+
batch_table = BatchTable(
88+
id=uuid.UUID(batch["batch_id"]),
89+
inst_id=uuid.UUID(inst["inst_id"]),
90+
name=batch["name"],
91+
created_at=DATETIME_TESTING,
92+
updated_at=DATETIME_TESTING,
93+
created_by=LOCAL_USER_UUID,
94+
)
95+
for file_name, file_id in batch["file_names_to_ids"].items():
96+
batch_table.files.add(
97+
session.merge(
98+
FileTable(
99+
id=uuid.UUID(file_id),
100+
inst_id=uuid.UUID(inst["inst_id"]),
101+
name=file_name,
102+
schemas=schemas_by_file_id.get(file_id, []),
103+
)
104+
) # type: ignore
105+
)
106+
session.merge(batch_table)
107+
108+
64109
@event.listens_for(Mapper, "before_insert")
65110
@event.listens_for(Mapper, "before_update")
66111
def validate_string_lengths(mapper, connection, target):
@@ -121,6 +166,7 @@ def init_db(env: str) -> None:
121166
)
122167
# Create test files and batches for LOCAL environment
123168
if env == "LOCAL":
169+
_setup_test_institutions(session)
124170
# Create test files
125171
test_file_1 = FileTable(
126172
id=uuid.UUID("f0bb3a20-6d92-4254-afed-6a72f43c562a"),

0 commit comments

Comments
 (0)