Add framework infrastructure for modules-as-published-packages - #19
Merged
Conversation
Makes each module a separately-published PyPI package that a host — scaffolded by a CLI — installs and assembles at boot. Closes ten gaps identified in the modular-distribution plan. Framework additions: - Framework API version contract: FRAMEWORK_API_VERSION + ModuleMeta. requires_framework; host refuses to boot on mismatch. - Selective module loading via Settings.modules_enabled allowlist. - ModuleBase.template_dirs() and static_mounts() hooks; host aggregates template dirs into the Jinja loader and mounts module statics. - simple_module_db.build_module_metadata() and make_include_object() consolidate the Alembic discovery logic; host env.py drops to ~20 lines. - get_module_package_name() helper consumed by migrations + scaffolding. - app_builder exposes wire_module_routes() so test harnesses stay in sync. Frontend pipeline: - scaffolding.write_module_pages_manifest() emits modules.manifest.json and modules.generated.ts so Vite can import pages from pip-installed module wheels. Content-hash guard avoids spurious HMR cascades. - host/client_app/pages.ts consumes moduleGlobs; vite.config.ts extends server.fs.allow from the manifest. simple-module-testing (new package): - FakeEventBus records publish/publish_nowait for assertions while still firing subscribed handlers. - build_test_app() wraps one module in a minimal FastAPI app. - pytest11 entry_point auto-registers fixtures — no conftest.py needed. CLI (sm command, added to simple-module-hosting): - sm create-host <name> [--with=...] scaffolds a full-stack host (backend + client_app + templates + migrations + Makefile). - sm create-module <name> scaffolds a publishable module with pyproject entry_point, pages/ dir, force-include for static/dist, GitHub Actions workflows (CI + PyPI trusted publishing), and fixture-using tests. - sm gen-pages regenerates the frontend manifest. Docs: - docs/module-authoring.md covers the full author workflow (API versioning, migrations, settings conventions, testing, publishing). Verification: - 313 pytest tests pass (was 271); ruff + ty clean. - sm create-host produces 19 files; sm create-module produces 12 files.
# Conflicts: # framework/core/simple_module_core/__init__.py # framework/core/simple_module_core/discovery.py # framework/core/tests/test_core.py # framework/hosting/simple_module_hosting/app_builder.py # framework/hosting/simple_module_hosting/settings.py # host/client_app/pages.ts
host/client_app/pages.ts imports from ./modules.generated, which is emitted by `sm gen-pages` from the installed Python modules and is gitignored. The js-typecheck CI job only set up Node, so tsc could not find the file and failed with TS2307. Add uv setup + `make install-py` + `make gen-pages` to the job so the manifest exists before tsc runs. Matches the developer flow where `make dev` calls gen-pages before starting the Vite server.
antosubash
added a commit
that referenced
this pull request
Apr 14, 2026
Pulls in PR #19 (modules-as-published-packages framework) and resolves four conflicts: * Makefile — combined main's new `gen-pages` target with my `ci-check-file-size` target and updated the .PHONY list. * framework/hosting/simple_module_hosting/app_builder.py — reconciled main's new boot-path features with my extracted helpers: - Added wire_module_routes() helper (from main). - discover_modules() now takes settings.modules_enabled (from main). - Phase 2 emits the frontend module-pages manifest in dev (from main). - Phase 9 uses wire_module_routes() and iterates mod.static_mounts(). - setup_inertia() signature grew to (app, settings, modules, root) so it can aggregate template_dirs() contributed by each module. - Kept check_migrations / error handlers / setup_inertia extracted to sibling _*.py modules (my earlier refactor). * framework/core/tests/test_core.py — main added three new test classes to what my branch had already split. Routed them to the matching split files: - TestFrameworkVersion -> new test_versioning.py - TestSelectiveModuleLoading -> appended to test_discovery.py - TestModuleAssetHooks -> appended to test_module_base.py * framework/db/tests/test_db.py — main added TestMigrationsHelper; split into a new test_migrations.py. Additionally, the auto-merged test_app.py ended up at 498 lines (over the 300-line cap) because main added three large new classes to it. Extracted TestModulePagesManifest + TestCreateHost into test_scaffolding_host.py (157 lines) and TestCreateModule into test_scaffolding_module.py (179 lines); test_app.py itself is back to 154 lines. Added the missing `pytest` import that came with the new tests. Verified: 339 tests pass across the configured testpaths; ruff, ty, and the file-size check are all green.
antosubash
added a commit
that referenced
this pull request
Apr 14, 2026
Pulls in PR #19 (modules-as-published-packages framework) and resolves four conflicts: * Makefile — combined main's new `gen-pages` target with my `ci-check-file-size` target and updated the .PHONY list. * framework/hosting/simple_module_hosting/app_builder.py — reconciled main's new boot-path features with my extracted helpers: - Added wire_module_routes() helper (from main). - discover_modules() now takes settings.modules_enabled (from main). - Phase 2 emits the frontend module-pages manifest in dev (from main). - Phase 9 uses wire_module_routes() and iterates mod.static_mounts(). - setup_inertia() signature grew to (app, settings, modules, root) so it can aggregate template_dirs() contributed by each module. - Kept check_migrations / error handlers / setup_inertia extracted to sibling _*.py modules (my earlier refactor). * framework/core/tests/test_core.py — main added three new test classes to what my branch had already split. Routed them to the matching split files: - TestFrameworkVersion -> new test_versioning.py - TestSelectiveModuleLoading -> appended to test_discovery.py - TestModuleAssetHooks -> appended to test_module_base.py * framework/db/tests/test_db.py — main added TestMigrationsHelper; split into a new test_migrations.py. Additionally, the auto-merged test_app.py ended up at 498 lines (over the 300-line cap) because main added three large new classes to it. Extracted TestModulePagesManifest + TestCreateHost into test_scaffolding_host.py and TestCreateModule into test_scaffolding_module.py. Added the missing `pytest` import that came with the new tests. Verified: 339 tests pass across the configured testpaths; ruff, ty, and the file-size check are all green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR introduces comprehensive framework infrastructure to support publishing modules as independent packages, enabling a distributed architecture for the simple-module system.
Key Changes
Core Framework (
framework/core)module.pywith additional module lifecycle managementDatabase Framework (
framework/db)Hosting Framework (
framework/hosting)Testing Framework (
framework/testing)Documentation
Configuration Updates
Impact
Enables developers to create, package, and publish modules independently while maintaining integration with the host application, supporting a plugin-like architecture.