Skip to content

Add framework infrastructure for modules-as-published-packages - #19

Merged
antosubash merged 3 commits into
mainfrom
feature/goofy-burnell
Apr 14, 2026
Merged

Add framework infrastructure for modules-as-published-packages#19
antosubash merged 3 commits into
mainfrom
feature/goofy-burnell

Conversation

@antosubash

Copy link
Copy Markdown
Owner

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)

  • Enhanced module discovery and initialization system
  • Added versioning support for modules
  • New exception handling for module-related errors
  • Extended module.py with additional module lifecycle management
  • Comprehensive test coverage for core functionality

Database Framework (framework/db)

  • Added database migration system with Alembic support
  • Migration utilities for module schema management
  • Database testing infrastructure

Hosting Framework (framework/hosting)

  • CLI System: New command-line interface for project scaffolding and management
  • App Builder: Enhanced to support dynamic module loading and registration
  • Project Scaffolding: Template-based generation for both host and module projects
  • Settings Management: Configuration system for hosting environments
  • Templates: Complete project templates including:
    • Host application (Python/FastAPI + React/TypeScript)
    • Module packages (with CI/CD workflows)
    • Build configuration (Makefile, pyproject.toml)
    • Database migrations setup

Testing Framework (framework/testing)

  • New testing utilities and fixtures
  • App factory for test environments
  • Fake event generation for testing
  • Pytest plugin support
  • Comprehensive test suites

Documentation

  • Module authoring guide with best practices

Configuration Updates

  • Updated Makefile and biome.json for improved developer experience
  • Enhanced pyproject.toml files across frameworks

Impact

Enables developers to create, package, and publish modules independently while maintaining integration with the host application, supporting a plugin-like architecture.

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
antosubash merged commit 892c408 into main Apr 14, 2026
6 checks passed
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant