learningfoundry 0.79.2__tar.gz → 0.79.3__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.
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/.gitignore +19 -6
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/CHANGELOG.md +15 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/PKG-INFO +1 -1
- learningfoundry-0.79.3/docs/specs/nbfoundry/README.md +176 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/docs/specs/pyve/README.md +123 -215
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/pyproject.toml +1 -1
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/__init__.py +1 -1
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/pipeline.py +7 -3
- learningfoundry-0.79.2/docs/specs/nbfoundry/README.md +0 -100
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/LICENSE +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/README.md +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/docs/specs/quizazz/README.md +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/__main__.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/asset_resolver.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/cli.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/config.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/directives.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/exceptions.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/generator.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/integrations/__init__.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/integrations/d3foundry_stub.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/integrations/nbfoundry_stub.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/integrations/protocols.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/integrations/quizazz.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/logging_config.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/parser.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/py.typed +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/resolver.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/schema_extensions.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/schema_v1.py +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/README.md +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/finish.spec.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/fixtures/curriculum.json +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/global-teardown.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/lifecycle.spec.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/navigation.spec.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/progress.spec.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/reset.spec.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/text-block-bottom.spec.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/e2e/video.spec.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/package.json +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/playwright.config.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/pnpm-lock.yaml +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/pnpm-workspace.yaml +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/app.css +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/app.html +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/AssessmentBlock.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/AssessmentBlock.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ContentBlock.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ExerciseBlock.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/LessonList.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/LessonList.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/LessonView.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/LessonView.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/LockedLessonPlaceholder.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ModuleList.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ModuleList.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/Navigation.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/PlaceholderBlock.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ProgressBar.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ProgressDashboard.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ProgressDashboard.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/RecordingPausedBanner.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/RecordingPausedBanner.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ResetCourseButton.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/ResetCourseButton.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/TextBlock.observer.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/TextBlock.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/TextBlock.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/VideoBlock.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/VideoBlock.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/VisualizationBlock.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/lesson-view.helpers.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/module-list.helpers.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/module-list.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/mount.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/navigation.helpers.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/navigation.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/components/progress-dashboard.helpers.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/db/database.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/db/database.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/db/index.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/db/progress.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/db/progress.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/db/user-id.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/db/user-id.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/stores/curriculum.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/stores/curriculum.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/stores/db-init.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/stores/db-init.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/stores/progress.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/stores/progress.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/types/index.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/assessment-passed.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/assessment-passed.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/duration.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/duration.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/locking.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/locking.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/markdown-directives.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/markdown.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/markdown.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/progress.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/progress.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/lib/utils/viewport-completion.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/+layout.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/+layout.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/+page.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/[module]/[lesson]/+page.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/[module]/[lesson]/page.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/[module]/assessment/[id]/+page.svelte +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/[module]/assessment/[id]/page.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/layout.helpers.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/layout.scroll.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/layout.scroll.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/src/routes/layout.test.ts +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/static/.gitkeep +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/svelte.config.js +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/test-results/.last-run.json +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/tsconfig.json +0 -0
- {learningfoundry-0.79.2 → learningfoundry-0.79.3}/src/learningfoundry/sveltekit_template/vite.config.ts +0 -0
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# >>> pyve:managed:gitignore >>>
|
|
2
|
+
# pyve-managed .gitignore — do not edit between the markers;
|
|
3
|
+
# add your own ignores above or below the managed section.
|
|
4
|
+
# macOS
|
|
2
5
|
.DS_Store
|
|
3
6
|
|
|
7
|
+
# Pyve-managed
|
|
8
|
+
.pyve/
|
|
9
|
+
.envrc
|
|
10
|
+
.env
|
|
11
|
+
.vscode/settings.json
|
|
12
|
+
.venv
|
|
13
|
+
|
|
4
14
|
# Python build and test artifacts
|
|
5
15
|
__pycache__
|
|
6
16
|
*.pyc
|
|
@@ -19,12 +29,15 @@ build/
|
|
|
19
29
|
.ipynb_checkpoints/
|
|
20
30
|
*.ipynb_checkpoints
|
|
21
31
|
|
|
32
|
+
# <<< pyve:managed:gitignore <<<
|
|
33
|
+
# macOS only
|
|
34
|
+
|
|
35
|
+
# Python build and test artifacts
|
|
36
|
+
|
|
37
|
+
# Jupyter notebooks
|
|
38
|
+
|
|
22
39
|
# Pyve virtual environment
|
|
23
|
-
.pyve
|
|
24
|
-
.pyve/testenv
|
|
25
|
-
.envrc
|
|
26
|
-
.env
|
|
27
|
-
.vscode/settings.json
|
|
40
|
+
.pyve
|
|
28
41
|
|
|
29
42
|
# Node / SvelteKit
|
|
30
43
|
node_modules/
|
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.79.3] - 2026-06-15
|
|
11
|
+
|
|
12
|
+
Fix `learningfoundry preview` appearing to hang silently during the `pnpm install` step and then reporting an empty failure on Ctrl-C. The install step captured pnpm's output (with no timeout) while leaving stdin attached, so progress and any interactive prompt were hidden — a prompting or slow install looked like a silent hang — and a non-zero exit produced `` `pnpm install` failed in `dist`: `` with nothing after the colon. Fixed via Story K.a.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **`pipeline.py` — `pnpm install` now streams to the terminal.** The install `subprocess.run(...)` dropped `capture_output=True, text=True`, so pnpm inherits the terminal exactly like the sibling `pnpm run dev` call. Download progress and any interactive prompt (pnpm 10 build-script approval, store/lock waits, registry auth) are now visible instead of being piped away into a silent hang.
|
|
17
|
+
- **`pipeline.py` — actionable install-failure message.** The `returncode != 0` branch no longer interpolates the (often empty) captured `result.stderr`. It now reads `` `pnpm install` failed in `<dir>` (exit code N); see the pnpm output above. `` — so a real failure or a Ctrl-C no longer dead-ends at a bare colon.
|
|
18
|
+
|
|
19
|
+
### Verified
|
|
20
|
+
|
|
21
|
+
- `pyve test` → 413 passed (was 411; +2 new regression tests in `TestRunPreviewInstallVisibility`, which fail pre-fix and pass post-fix).
|
|
22
|
+
- Prevention scan: `grep -rn 'subprocess.run\|capture_output' src/learningfoundry/` returns only the two pipeline calls (install now streams; `pnpm run dev` already streamed). No other instance of the anti-pattern in learningfoundry code.
|
|
23
|
+
|
|
10
24
|
## [0.79.2] - 2026-06-02
|
|
11
25
|
|
|
12
26
|
Fix sql.js browser-ESM init failure in the SvelteKit template's dev-server preview path. Module and lesson routes were returning 500 in `learningfoundry preview` because `(await import('sql.js')).default` was `undefined` in the browser. Diagnosed in `docs/specs/bug-sql-js-browser-esm-spec.md`; fixed via Story J.y.
|
|
@@ -21,6 +35,7 @@ Fix sql.js browser-ESM init failure in the SvelteKit template's dev-server previ
|
|
|
21
35
|
- `pnpm exec vitest run` → 278 passed (was 277; +1 new contract test for the CJS/ESM interop guard).
|
|
22
36
|
- `pnpm exec svelte-check` → 0 errors, 0 warnings.
|
|
23
37
|
- `pnpm exec vite build` → succeeds (confirms the gated `optimizeDeps.exclude` doesn't break prod build; the J.w comment's "covers both prod build" framing was incorrect).
|
|
38
|
+
- `pyve test` → 411 passed (Python pipeline regression check; bootstrapped the testenv editable install first since the testenv had been recently reinitialized).
|
|
24
39
|
- Manual: dev-server `/{moduleId}/{lessonId}` route renders without 500 in the d802-deep-learning consumer (verification scheduled with the consumer team — captured as a `[ ]` follow-up).
|
|
25
40
|
|
|
26
41
|
## [0.79.1] - 2026-05-22
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learningfoundry
|
|
3
|
-
Version: 0.79.
|
|
3
|
+
Version: 0.79.3
|
|
4
4
|
Summary: A curriculum engine that turns a YAML curriculum definition into a deployable SvelteKit learning application.
|
|
5
5
|
Project-URL: Homepage, https://github.com/pointmatic/learningfoundry
|
|
6
6
|
Project-URL: Repository, https://github.com/pointmatic/learningfoundry
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# nbfoundry
|
|
2
|
+
|
|
3
|
+
[](https://github.com/pointmatic/nbfoundry/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/gh/pointmatic/nbfoundry)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Marimo-based notebook framework for ML/DS work. One notebook source compiles into two
|
|
8
|
+
artifacts: a standalone runnable application and an `ExerciseBlock`-compatible artifact
|
|
9
|
+
that drops into a learningfoundry curriculum.
|
|
10
|
+
|
|
11
|
+
For the why, see [`docs/specs/concept.md`](docs/specs/concept.md). For the what, see
|
|
12
|
+
[`docs/specs/features.md`](docs/specs/features.md). For the how, see
|
|
13
|
+
[`docs/specs/tech-spec.md`](docs/specs/tech-spec.md).
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
`nbfoundry` targets Python 3.12.13 with **Pyve + venv** (exclusively — no conda or
|
|
18
|
+
micromamba). The Metal ML stack is fully pip-installable on Apple Silicon, so each
|
|
19
|
+
scaffolded project ships per-stage pip requirements instead of a conda env file:
|
|
20
|
+
|
|
21
|
+
- [`requirements-base.txt`](src/nbfoundry/templates/requirements-base.txt) — framework-agnostic core (the `data_*` stages).
|
|
22
|
+
- [`requirements-torch.txt`](src/nbfoundry/templates/requirements-torch.txt) — torch-family stack (the `model_*` stages); `-r`-includes the base.
|
|
23
|
+
- [`requirements-tf.txt`](src/nbfoundry/templates/requirements-tf.txt) — TensorFlow-family option; `-r`-includes the base.
|
|
24
|
+
|
|
25
|
+
These ship as package data: `nbfoundry init` copies the **stage-appropriate** file into
|
|
26
|
+
every scaffolded project, and the standalone artifact emitter falls back to
|
|
27
|
+
`requirements-base.txt` when the source carries none.
|
|
28
|
+
|
|
29
|
+
### Apple Silicon quickstart
|
|
30
|
+
|
|
31
|
+
The stack defaults to Apple Silicon with Metal/MPS acceleration: PyTorch via the bare
|
|
32
|
+
`torch` MPS wheel, TensorFlow via `tensorflow-macos` + `tensorflow-metal`, and the
|
|
33
|
+
bundled Keras 3 namespace from TF 2.16+. The torch stack also ships the wider
|
|
34
|
+
cross-project set (HuggingFace `transformers` / `datasets` / `peft`, Optuna, the
|
|
35
|
+
plotly/seaborn/pyarrow utility set, and the Pointmatic-internal `ml-datarefinery`).
|
|
36
|
+
|
|
37
|
+
Scaffold a project and build its venv with plain pip — no micromamba:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
nbfoundry init demo --template model_experimentation
|
|
41
|
+
cd demo
|
|
42
|
+
pyve init # creates the project venv
|
|
43
|
+
pip install -r requirements-torch.txt # torch + HuggingFace + Optuna on MPS
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
A `data_*` scaffold instead emits `requirements-base.txt` (no ML framework). Because
|
|
47
|
+
`torch` and `tensorflow` are never co-installed in one venv, a learner cannot hit the
|
|
48
|
+
PyTorch-MPS / TensorFlow-Metal co-residence crash.
|
|
49
|
+
|
|
50
|
+
> **Framework Metal verification** is done dev-side via the lazy named smoke envs
|
|
51
|
+
> (`pyve test --env smoke-torch …` / `--env smoke-tensorflow …`); see
|
|
52
|
+
> [`docs/specs/env-dependencies.md`](docs/specs/env-dependencies.md).
|
|
53
|
+
|
|
54
|
+
#### Cross-platform users (CUDA / CPU-only)
|
|
55
|
+
|
|
56
|
+
The requirements files ship comment-delimited swap guidance:
|
|
57
|
+
|
|
58
|
+
- **PyTorch CUDA:** install torch from the PyTorch index instead of the bare line, e.g.
|
|
59
|
+
`pip install torch --index-url https://download.pytorch.org/whl/cu128` (`cpu` / `cu126`
|
|
60
|
+
/ `cu128`).
|
|
61
|
+
- **TensorFlow CPU-only or Linux+CUDA:** in `requirements-tf.txt`, replace the
|
|
62
|
+
`tensorflow-macos` / `tensorflow-metal` lines with `tensorflow>=2.16` (CPU-only) or
|
|
63
|
+
`tensorflow[and-cuda]>=2.16` (Linux + CUDA).
|
|
64
|
+
|
|
65
|
+
Both notes are documented inline at the top of the relevant requirements file.
|
|
66
|
+
|
|
67
|
+
### Development setup (Pyve two-env)
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pyve init
|
|
71
|
+
pyve run pip install -e .
|
|
72
|
+
pyve env init
|
|
73
|
+
pyve env run pip install -e .
|
|
74
|
+
pyve env install -r requirements-dev.txt
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Run the suite with `pyve test` (lint: `pyve env run ruff check .`; types:
|
|
78
|
+
`pyve env run mypy`). Hardware smokes are opt-in: `pyve test --env smoke-torch …`
|
|
79
|
+
/ `--env smoke-tensorflow … -m hardware`.
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
`nbfoundry` exposes four commands. Compile and validate are **offline,
|
|
84
|
+
deterministic, and side-effect-free** — they read only the files you point them at
|
|
85
|
+
and never touch the network.
|
|
86
|
+
|
|
87
|
+
### 1. Scaffold a notebook — `init`
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
nbfoundry init demo --template data_exploration
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`--template` is one of the five lifecycle stages: `data_exploration`,
|
|
94
|
+
`data_preparation`, `model_experimentation`, `model_optimization`,
|
|
95
|
+
`model_evaluation` (defaults to `data_exploration`). The scaffold contains a
|
|
96
|
+
reactive Marimo `notebook.py` plus the stage-appropriate `requirements-*.txt`.
|
|
97
|
+
|
|
98
|
+
### 2. Run it as a standalone app — `compile`
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
nbfoundry compile demo --out dist
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Produces a self-contained artifact directory (the compiled notebook(s), the
|
|
105
|
+
`requirements-*.txt`, and a `launch.py` entry point) that runs locally with no
|
|
106
|
+
server or cloud dependency.
|
|
107
|
+
|
|
108
|
+
### 3. Compile to a learningfoundry exercise — `compile-exercise`
|
|
109
|
+
|
|
110
|
+
Author an exercise YAML whose sections carry (or reference, via `code_file`) the
|
|
111
|
+
notebook code, plus instructional metadata:
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
# exercise.yaml
|
|
115
|
+
title: Explore a dataset
|
|
116
|
+
description: Load, describe, and visualize the data.
|
|
117
|
+
sections:
|
|
118
|
+
- title: Load
|
|
119
|
+
description: Read the CSV into a DataFrame.
|
|
120
|
+
code: |
|
|
121
|
+
import pandas as pd
|
|
122
|
+
df = pd.read_csv("data.csv")
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
nbfoundry compile-exercise exercise.yaml --out exercise.json # or omit --out for stdout
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The output is an `ExerciseBlock`-compatible dict (the BR-1 wire shape) that drops
|
|
130
|
+
into a learningfoundry curriculum. The full schema — instructions, hints,
|
|
131
|
+
expected outputs, and the BR-4 `submission` block with client-side grading — is
|
|
132
|
+
defined in [`docs/specs/learningfoundry/dependency-spec.md`](docs/specs/learningfoundry/dependency-spec.md).
|
|
133
|
+
|
|
134
|
+
### 4. Validate without compiling — `validate`
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
nbfoundry validate exercise.yaml # exit 0 when clean; exit 1 with all errors on stdout
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Two surfaces from one source (AC-3)
|
|
141
|
+
|
|
142
|
+
The same notebook source feeds **both** outputs: `compile` turns it into a
|
|
143
|
+
runnable standalone app, while `compile-exercise` (whose sections reference that
|
|
144
|
+
same notebook via `code_file`) turns it into an embeddable curriculum exercise —
|
|
145
|
+
no rewrite when the purpose shifts. That dual-surface compile is the core of
|
|
146
|
+
nbfoundry's value (see [`docs/specs/concept.md`](docs/specs/concept.md)).
|
|
147
|
+
|
|
148
|
+
## Further reading
|
|
149
|
+
|
|
150
|
+
- [`docs/specs/concept.md`](docs/specs/concept.md) — why nbfoundry exists (problem/solution space).
|
|
151
|
+
- [`docs/specs/features.md`](docs/specs/features.md) — what it does (requirements, behavior, acceptance criteria).
|
|
152
|
+
- [`docs/specs/tech-spec.md`](docs/specs/tech-spec.md) — how it is built (architecture, dependencies, testing strategy).
|
|
153
|
+
- [`docs/specs/learningfoundry/dependency-spec.md`](docs/specs/learningfoundry/dependency-spec.md) — the `ExerciseBlock` contract the compiled exercise targets.
|
|
154
|
+
- [`docs/specs/env-dependencies.md`](docs/specs/env-dependencies.md) — the dev/test environment topology.
|
|
155
|
+
|
|
156
|
+
## Releasing to PyPI
|
|
157
|
+
|
|
158
|
+
Releases ship through [`.github/workflows/publish.yml`](.github/workflows/publish.yml),
|
|
159
|
+
which is triggered by pushing a `v*` tag. The workflow builds an sdist + wheel with
|
|
160
|
+
`hatch build` and publishes via PyPI [trusted publishing](https://docs.pypi.org/trusted-publishers/)
|
|
161
|
+
(OIDC, no long-lived API tokens).
|
|
162
|
+
|
|
163
|
+
One-time PyPI setup: register `nbfoundry` on PyPI and add a pending trusted publisher
|
|
164
|
+
under the project's *Publishing* settings — owner `pointmatic`, repository `nbfoundry`,
|
|
165
|
+
workflow `publish.yml`, environment `pypi`.
|
|
166
|
+
|
|
167
|
+
Per-release procedure:
|
|
168
|
+
|
|
169
|
+
1. Land the version-bump story on `main` (package version in `src/nbfoundry/_version.py`
|
|
170
|
+
and a matching `CHANGELOG.md` entry).
|
|
171
|
+
2. Tag the commit with the matching `v<version>` (e.g. `git tag v0.29.0 && git push origin v0.29.0`).
|
|
172
|
+
3. The workflow verifies the tag matches `hatch version`, builds the distributions, and
|
|
173
|
+
publishes to PyPI under the `pypi` GitHub environment.
|
|
174
|
+
|
|
175
|
+
The workflow refuses to publish if the tag and `hatch version` disagree, so the only way
|
|
176
|
+
to ship a release is to tag the same commit that owns the version bump.
|