modulearn 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.
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ *.whl
8
+ .venv/
9
+ venv/
10
+ env/
11
+ runs/
12
+ .DS_Store
13
+ .idea/
14
+ .vscode/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Isaiah Broderson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: modulearn
3
+ Version: 0.1.0
4
+ Summary: A visual, Unreal-Blueprints-style node-graph editor for building and launching ML training runs.
5
+ Project-URL: Homepage, https://github.com/IsaiahKoamalu/modulearn
6
+ Project-URL: Source, https://github.com/IsaiahKoamalu/modulearn
7
+ Author: Isaiah Broderson
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: fastapi,machine-learning,node-graph,training,visual-programming
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Framework :: FastAPI
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Requires-Python: >=3.10
17
+ Requires-Dist: fastapi>=0.110
18
+ Requires-Dist: pydantic>=2.0
19
+ Requires-Dist: uvicorn>=0.29
20
+ Provides-Extra: dev
21
+ Requires-Dist: build; extra == 'dev'
22
+ Requires-Dist: pytest>=7; extra == 'dev'
23
+ Requires-Dist: twine; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # ModuLearn
27
+
28
+ A visual, [Unreal-Blueprints](https://dev.epicgames.com/documentation/en-us/unreal-engine/blueprints-visual-scripting-in-unreal-engine)-style
29
+ node-graph editor for building and launching machine-learning training runs.
30
+ Drop **Dataset → Model → Train** nodes on a canvas, wire **hyperparameters**,
31
+ **loss** and **feature transforms** into them, hit ▶ Train, and watch the learning
32
+ curve live on the graph. No forms, no drift between the UI and the code it runs.
33
+
34
+ > **ModuLearn** is a working name — you assemble training runs from modular nodes and
35
+ > learn from the live curve. Rename the package/repo freely; nothing depends on the name.
36
+
37
+ <!-- A screenshot or GIF of the editor goes well here. -->
38
+
39
+ ## Why
40
+
41
+ Most training UIs are flat forms that slowly rot out of sync with the code behind
42
+ them. ModuLearn inverts that: your Python is the single source of truth. You *declare*
43
+ what you can train once, in a `Registry`, and the entire editor — palette, typed
44
+ wiring rules, live validation, launch — is generated from it. Wire something the
45
+ backend can't accept and it simply won't connect.
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ pip install -e . # fastapi + uvicorn + pydantic
51
+ modulearn demo # serve the bundled editor at http://localhost:8000
52
+ ```
53
+
54
+ `modulearn demo` is a complete, **dependency-free** editor (its "trainer" is a toy
55
+ loss curve) so you can click around immediately. Once you've built your own app,
56
+ serve it the same way:
57
+
58
+ ```bash
59
+ modulearn run myproject.py # serves the `app` you built with create_app
60
+ modulearn run myproject.py:editor # ...or a differently-named app / factory
61
+ modulearn --help
62
+ ```
63
+
64
+ Swap `on_train` for your real training loop and nothing else changes. (The
65
+ equivalent source file lives at [`examples/quickstart.py`](examples/quickstart.py)
66
+ if you'd rather run it directly with `python`.)
67
+
68
+ ## The whole integration is two things
69
+
70
+ ```python
71
+ from modulearn import Registry, Param, create_app
72
+
73
+ reg = Registry()
74
+
75
+ reg.add_dataset("iris", title="Iris", kind="tabular",
76
+ features=[...], targets=["species"])
77
+ reg.add_model("mlp", title="MLP", requires_kind="tabular",
78
+ params=[Param("hidden", "hidden layers", "int_list", [64, 32])])
79
+ reg.add_hyperparameter("lr", label="learning rate", default=1e-3, min=1e-6, max=1)
80
+ reg.add_loss([Param("loss", "kind", "enum", "mse", choices=["mse", "cross_entropy"])])
81
+
82
+ def on_train(compiled, reporter):
83
+ # compiled.dataset, .model, .model_params, .hyperparameters, .loss_params, .transforms
84
+ reporter.state(epochs=100)
85
+ for e in range(100):
86
+ reporter.metric(epoch=e, train=..., val=...) # drives the live chart
87
+ reporter.state(epoch=e, best_val=...)
88
+ reporter.state(phase="done", test_score=...)
89
+
90
+ app = create_app(reg, on_train, title="My Project")
91
+ ```
92
+
93
+ 1. **A `Registry`** — declare datasets, models, hyperparameters, a loss, and
94
+ optional feature transforms. Each hyperparameter you add automatically grows a
95
+ matching, type-checked input on the Train sink.
96
+ 2. **`on_train(compiled, reporter)`** — your training loop. `compiled` is a
97
+ fully-validated [`CompiledGraph`](modulearn/compiler.py); `reporter` publishes
98
+ progress the editor polls (see the state contract below).
99
+
100
+ ## How it fits together
101
+
102
+ ```
103
+ registry.py ── you declare nodes ──► catalog (GET /api/nodes)
104
+ │ │
105
+ ▼ ▼
106
+ compiler.py ◄── canvas JSON ──────── static/ (custom canvas engine)
107
+ │ type-checks every wire, runs semantic checks
108
+
109
+ CompiledGraph ──► your on_train(compiled, reporter) ──► runs/<id>/{state,metrics}.json
110
+
111
+ editor polls ◄─┘ (live panel + chart)
112
+ ```
113
+
114
+ - **Typed ports.** Links carry a family (`dataset`, `model`, `loss`, `run`) or a
115
+ field-specific scalar subtype (`scalar/lr`), so a learning-rate value fits the
116
+ `lr` input and *never* `epochs` — enforced both client-side and in the compiler.
117
+ - **All-or-nothing compile.** `compile_graph` collects every structural, type and
118
+ semantic error and raises them together, so the UI flags all bad wires at once.
119
+ - **Composable transforms.** Chain `Dataset → Transform → … → Model`; the compiler
120
+ walks the chain into `compiled.transforms`. Mark a transform `live=False` to show
121
+ it in the palette but have the compiler refuse it until your backend is ready.
122
+ - **Stateless live window.** Training runs in a background thread and persists to
123
+ `runs/<id>/`. Closing the browser never stops a run; reopening shows true state.
124
+
125
+ ## The state contract
126
+
127
+ Your `on_train` reports through `reporter`, and the editor reads these keys:
128
+
129
+ | call | keys the UI understands |
130
+ |------|-------------------------|
131
+ | `reporter.state(**kw)` | `phase` (`running`/`done`/`error`), `epoch`, `epochs`, `best_val`, `test_score`, `error` |
132
+ | `reporter.metric(**row)` | `epoch`, `train`, `val` → the live learning curve |
133
+
134
+ Anything else you write is stored and returned by the API, just not charted.
135
+
136
+ ## Editor niceties
137
+
138
+ - Searchable palette with collapsible category dropdowns; `⌘K` / `/` to focus,
139
+ Enter to drop the first match.
140
+ - Wires colored by type, with flowing pulses that speed up on the edges feeding a
141
+ running Train node; ports glow while you drag a compatible connection.
142
+ - Canvas persists to `localStorage`; reload/fork any past run's blueprint.
143
+ - All motion respects `prefers-reduced-motion`.
144
+
145
+ ## Layout
146
+
147
+ ```
148
+ modulearn/
149
+ registry.py the declarative surface your app fills in
150
+ compiler.py graph JSON -> validated CompiledGraph (pure, unit-testable)
151
+ server.py create_app(): FastAPI factory + background job runner
152
+ cli.py the `modulearn` command (demo / run)
153
+ demo.py the app `modulearn demo` serves
154
+ static/ graph.html, graph.js (app), graph-engine.js (canvas engine)
155
+ examples/
156
+ quickstart.py a complete, dependency-free editor
157
+ ```
158
+
159
+ ## License
160
+
161
+ MIT (see [LICENSE](LICENSE)). The canvas node-graph engine
162
+ (`static/graph-engine.js`) is our own, built from scratch — no third-party
163
+ graph library.
@@ -0,0 +1,103 @@
1
+ # Publishing `modulearn`
2
+
3
+ The exact steps to cut a release. The package builds to the distribution name
4
+ **`modulearn`** (so `pip install modulearn`), with the CLI entry point `modulearn`.
5
+
6
+ Replace `<USER>` with the GitHub account you're publishing under.
7
+
8
+ ## 0. One-time setup
9
+
10
+ ```bash
11
+ pip install -e ".[dev]" # pytest + build + twine
12
+ ```
13
+
14
+ ## 1. Sanity checks
15
+
16
+ ```bash
17
+ python tests/test_smoke.py # or: pytest -q
18
+ python -m build # writes dist/modulearn-<ver>-*.whl and .tar.gz
19
+ twine check dist/* # validates the rendered PyPI metadata
20
+ ```
21
+
22
+ Confirm the wheel bundles the static assets (the editor is dead without them):
23
+
24
+ ```bash
25
+ python -c "import zipfile,glob; print('\n'.join(zipfile.ZipFile(sorted(glob.glob('dist/*.whl'))[-1]).namelist()))" | grep static
26
+ # expect: modulearn/static/graph.html, graph.js, graph-engine.js
27
+ ```
28
+
29
+ ## 2. Push the source to GitHub (a different account than you're logged into)
30
+
31
+ This repo isn't wired to a remote yet. Create an **empty** repo named `modulearn`
32
+ under `<USER>` on github.com (no README/license — this repo already has them), then:
33
+
34
+ ```bash
35
+ git init
36
+ git add .
37
+ git commit -m "modulearn 0.1.0"
38
+ git branch -M main
39
+ ```
40
+
41
+ Pick one auth path for the other account:
42
+
43
+ **A. gh CLI, if that account is already added to `gh`:**
44
+ ```bash
45
+ gh auth switch --user <USER> # or: gh auth login
46
+ gh repo view <USER>/modulearn >/dev/null 2>&1 || gh repo create <USER>/modulearn --public --source=. --remote=origin
47
+ git push -u origin main
48
+ ```
49
+
50
+ **B. Plain git over SSH (no gh):** add that account's SSH key to your agent, then:
51
+ ```bash
52
+ git remote add origin git@github.com:<USER>/modulearn.git
53
+ git push -u origin main
54
+ ```
55
+
56
+ **C. Plain git over HTTPS:** push and, when prompted, authenticate as `<USER>`
57
+ (use a Personal Access Token as the password, not your login password):
58
+ ```bash
59
+ git remote add origin https://github.com/<USER>/modulearn.git
60
+ git push -u origin main
61
+ ```
62
+
63
+ > The `Homepage`/`Source` URLs in `pyproject.toml` must point at
64
+ > `github.com/<USER>/modulearn` so the PyPI page's links resolve.
65
+
66
+ ## 3. TestPyPI dry run (always do this first)
67
+
68
+ A given filename can never be re-uploaded, so rehearse on TestPyPI. Get a token at
69
+ https://test.pypi.org/manage/account/token/.
70
+
71
+ ```bash
72
+ twine upload --repository testpypi dist/*
73
+ # install it fresh to prove it works end-to-end:
74
+ python -m venv /tmp/ml-test && /tmp/ml-test/bin/pip install \
75
+ --index-url https://test.pypi.org/simple/ \
76
+ --extra-index-url https://pypi.org/simple/ modulearn
77
+ /tmp/ml-test/bin/modulearn demo # open http://localhost:8000
78
+ ```
79
+
80
+ Eyeball the rendered page at https://test.pypi.org/project/modulearn/.
81
+
82
+ ## 4. Publish to PyPI
83
+
84
+ Token from https://pypi.org/manage/account/token/.
85
+
86
+ ```bash
87
+ twine upload dist/*
88
+ ```
89
+
90
+ Then verify:
91
+
92
+ ```bash
93
+ pip install modulearn
94
+ modulearn demo
95
+ ```
96
+
97
+ ## Cutting later releases
98
+
99
+ 1. Bump `version` in `pyproject.toml` **and** `__version__` in `modulearn/__init__.py`.
100
+ 2. `rm -rf dist && python -m build`
101
+ 3. `twine check dist/*`
102
+ 4. `git commit -am "modulearn <ver>" && git tag v<ver> && git push --tags`
103
+ 5. `twine upload dist/*`
@@ -0,0 +1,138 @@
1
+ # ModuLearn
2
+
3
+ A visual, [Unreal-Blueprints](https://dev.epicgames.com/documentation/en-us/unreal-engine/blueprints-visual-scripting-in-unreal-engine)-style
4
+ node-graph editor for building and launching machine-learning training runs.
5
+ Drop **Dataset → Model → Train** nodes on a canvas, wire **hyperparameters**,
6
+ **loss** and **feature transforms** into them, hit ▶ Train, and watch the learning
7
+ curve live on the graph. No forms, no drift between the UI and the code it runs.
8
+
9
+ > **ModuLearn** is a working name — you assemble training runs from modular nodes and
10
+ > learn from the live curve. Rename the package/repo freely; nothing depends on the name.
11
+
12
+ <!-- A screenshot or GIF of the editor goes well here. -->
13
+
14
+ ## Why
15
+
16
+ Most training UIs are flat forms that slowly rot out of sync with the code behind
17
+ them. ModuLearn inverts that: your Python is the single source of truth. You *declare*
18
+ what you can train once, in a `Registry`, and the entire editor — palette, typed
19
+ wiring rules, live validation, launch — is generated from it. Wire something the
20
+ backend can't accept and it simply won't connect.
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ pip install -e . # fastapi + uvicorn + pydantic
26
+ modulearn demo # serve the bundled editor at http://localhost:8000
27
+ ```
28
+
29
+ `modulearn demo` is a complete, **dependency-free** editor (its "trainer" is a toy
30
+ loss curve) so you can click around immediately. Once you've built your own app,
31
+ serve it the same way:
32
+
33
+ ```bash
34
+ modulearn run myproject.py # serves the `app` you built with create_app
35
+ modulearn run myproject.py:editor # ...or a differently-named app / factory
36
+ modulearn --help
37
+ ```
38
+
39
+ Swap `on_train` for your real training loop and nothing else changes. (The
40
+ equivalent source file lives at [`examples/quickstart.py`](examples/quickstart.py)
41
+ if you'd rather run it directly with `python`.)
42
+
43
+ ## The whole integration is two things
44
+
45
+ ```python
46
+ from modulearn import Registry, Param, create_app
47
+
48
+ reg = Registry()
49
+
50
+ reg.add_dataset("iris", title="Iris", kind="tabular",
51
+ features=[...], targets=["species"])
52
+ reg.add_model("mlp", title="MLP", requires_kind="tabular",
53
+ params=[Param("hidden", "hidden layers", "int_list", [64, 32])])
54
+ reg.add_hyperparameter("lr", label="learning rate", default=1e-3, min=1e-6, max=1)
55
+ reg.add_loss([Param("loss", "kind", "enum", "mse", choices=["mse", "cross_entropy"])])
56
+
57
+ def on_train(compiled, reporter):
58
+ # compiled.dataset, .model, .model_params, .hyperparameters, .loss_params, .transforms
59
+ reporter.state(epochs=100)
60
+ for e in range(100):
61
+ reporter.metric(epoch=e, train=..., val=...) # drives the live chart
62
+ reporter.state(epoch=e, best_val=...)
63
+ reporter.state(phase="done", test_score=...)
64
+
65
+ app = create_app(reg, on_train, title="My Project")
66
+ ```
67
+
68
+ 1. **A `Registry`** — declare datasets, models, hyperparameters, a loss, and
69
+ optional feature transforms. Each hyperparameter you add automatically grows a
70
+ matching, type-checked input on the Train sink.
71
+ 2. **`on_train(compiled, reporter)`** — your training loop. `compiled` is a
72
+ fully-validated [`CompiledGraph`](modulearn/compiler.py); `reporter` publishes
73
+ progress the editor polls (see the state contract below).
74
+
75
+ ## How it fits together
76
+
77
+ ```
78
+ registry.py ── you declare nodes ──► catalog (GET /api/nodes)
79
+ │ │
80
+ ▼ ▼
81
+ compiler.py ◄── canvas JSON ──────── static/ (custom canvas engine)
82
+ │ type-checks every wire, runs semantic checks
83
+
84
+ CompiledGraph ──► your on_train(compiled, reporter) ──► runs/<id>/{state,metrics}.json
85
+
86
+ editor polls ◄─┘ (live panel + chart)
87
+ ```
88
+
89
+ - **Typed ports.** Links carry a family (`dataset`, `model`, `loss`, `run`) or a
90
+ field-specific scalar subtype (`scalar/lr`), so a learning-rate value fits the
91
+ `lr` input and *never* `epochs` — enforced both client-side and in the compiler.
92
+ - **All-or-nothing compile.** `compile_graph` collects every structural, type and
93
+ semantic error and raises them together, so the UI flags all bad wires at once.
94
+ - **Composable transforms.** Chain `Dataset → Transform → … → Model`; the compiler
95
+ walks the chain into `compiled.transforms`. Mark a transform `live=False` to show
96
+ it in the palette but have the compiler refuse it until your backend is ready.
97
+ - **Stateless live window.** Training runs in a background thread and persists to
98
+ `runs/<id>/`. Closing the browser never stops a run; reopening shows true state.
99
+
100
+ ## The state contract
101
+
102
+ Your `on_train` reports through `reporter`, and the editor reads these keys:
103
+
104
+ | call | keys the UI understands |
105
+ |------|-------------------------|
106
+ | `reporter.state(**kw)` | `phase` (`running`/`done`/`error`), `epoch`, `epochs`, `best_val`, `test_score`, `error` |
107
+ | `reporter.metric(**row)` | `epoch`, `train`, `val` → the live learning curve |
108
+
109
+ Anything else you write is stored and returned by the API, just not charted.
110
+
111
+ ## Editor niceties
112
+
113
+ - Searchable palette with collapsible category dropdowns; `⌘K` / `/` to focus,
114
+ Enter to drop the first match.
115
+ - Wires colored by type, with flowing pulses that speed up on the edges feeding a
116
+ running Train node; ports glow while you drag a compatible connection.
117
+ - Canvas persists to `localStorage`; reload/fork any past run's blueprint.
118
+ - All motion respects `prefers-reduced-motion`.
119
+
120
+ ## Layout
121
+
122
+ ```
123
+ modulearn/
124
+ registry.py the declarative surface your app fills in
125
+ compiler.py graph JSON -> validated CompiledGraph (pure, unit-testable)
126
+ server.py create_app(): FastAPI factory + background job runner
127
+ cli.py the `modulearn` command (demo / run)
128
+ demo.py the app `modulearn demo` serves
129
+ static/ graph.html, graph.js (app), graph-engine.js (canvas engine)
130
+ examples/
131
+ quickstart.py a complete, dependency-free editor
132
+ ```
133
+
134
+ ## License
135
+
136
+ MIT (see [LICENSE](LICENSE)). The canvas node-graph engine
137
+ (`static/graph-engine.js`) is our own, built from scratch — no third-party
138
+ graph library.