[WIP] Add tethys run — zero-config single-file app runner (express mode POC) - #1287
Draft
gagelarsen wants to merge 3 commits into
Draft
[WIP] Add tethys run — zero-config single-file app runner (express mode POC)#1287gagelarsen wants to merge 3 commits into
tethys run — zero-config single-file app runner (express mode POC)#1287gagelarsen wants to merge 3 commits into
Conversation
Proof-of-concept, Shiny-inspired runner: "tethys run app.py" serves a single-file component app with no portal configuration, no database setup, no pip install, and no login. It generates an isolated TETHYS_HOME (~/.tethys/express/<pkg>_<hash>/) containing a portal config (single-app mode + open portal) and a throwaway SQLite database, grafts the app file into the tethysapp namespace via sys.modules, and launches the standard development server. - tethys_cli/run_commands.py: new "run" subcommand (-p/--port, --host, --no-browser, --no-reload, --clean) - tethys_apps/base/express.py: express loader + metadata synthesis (package/name/root_url/index derived from the file when omitted) - tethys_apps/harvester.py: include the express app during harvest - tethys_apps/base/component_base.py: __init_subclass__ hook for express metadata; fix auto nav links in single-app mode (/apps/<url>/ 404s when MULTIPLE_APP_MODE=False) - tethys_apps/utilities.py: catch sqlite OperationalError in get_configured_standalone_app (fresh single-app portals crashed during migrate when reactpy_django imports the URLconf) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- docs/tethys_cli/run.rst: full reference page (quick start, how it works, auto-generated arguments via sphinx-argparse, examples) - docs/tethys_cli.rst: add run to the CLI toctree - docs/whats_new.rst: release note entry for express mode - docs/tethys_sdk/components.rst: tip cross-referencing tethys run from the component app.py docs Docs build verified locally with sphinx (no warnings from these files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
|
Added documentation in 35617c4:
Sphinx build verified locally — no warnings from the changed files. 🤖 Generated with Claude Code |
6 tasks
There was a problem hiding this comment.
Pull request overview
This PR adds an “express mode” workflow for running a single-file Tethys Component App via tethys run, by bootstrapping an isolated ephemeral portal config + DB and loading the app file under the tethysapp.<package> namespace so the existing portal/harvester machinery can run it unmodified.
Changes:
- Adds
tethys runCLI command that generates an isolatedTETHYS_HOME, migrates SQLite, and startsrunserver. - Implements express app loading/metadata synthesis (
tethys_apps.base.express) and hooks it into harvesting and ComponentBase initialization. - Documents the new command and adds unit tests for CLI + express loader behavior; includes a small standalone-app-mode DB error-handling fix.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tethys_cli/run_commands.py | New tethys run command: validates app file, generates express TETHYS_HOME, migrates DB, runs dev server. |
| tethys_cli/init.py | Wires the new run parser into the CLI entrypoint. |
| tethys_apps/utilities.py | Broadens standalone-app lookup exception handling to include SQLite OperationalError. |
| tethys_apps/harvester.py | Hooks express app harvesting into the existing app harvesting flow. |
| tethys_apps/base/express.py | New express-mode module loader and metadata synthesis utilities. |
| tethys_apps/base/component_base.py | Adds express metadata synthesis hook and fixes auto-nav links in single-app mode. |
| tests/unit_tests/test_tethys_cli/test_run_commands.py | Unit tests for tethys run CLI behavior and generated portal config. |
| tests/unit_tests/test_tethys_apps/test_base/test_express.py | Unit tests for express loader helpers and harvesting behavior. |
| docs/whats_new.rst | Release notes entry describing tethys run / express mode. |
| docs/tethys_sdk/components.rst | Adds a tip pointing component users to tethys run for quick prototyping. |
| docs/tethys_cli/run.rst | New CLI documentation page for tethys run. |
| docs/tethys_cli.rst | Adds the new tethys_cli/run page to the CLI docs toctree. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+77
to
+80
| package = re.sub(r"\W", "_", _source_stem(app_file)).lower() | ||
| if package[0].isdigit(): | ||
| package = f"app_{package}" | ||
| return package |
| ) | ||
| exit(1) | ||
|
|
||
| package = get_express_package_name(app_file) |
Comment on lines
+141
to
+145
| url = f"http://{args.host}:{args.port}/" | ||
| write_success(f'Running "{app_file.name}" at {url} (CTRL+C to quit)') | ||
|
|
||
| if not args.no_browser: | ||
| threading.Timer(2, webbrowser.open, args=[url]).start() |
Comment on lines
+8
to
+11
| .. important:: | ||
|
|
||
| This command only supports :ref:`Component Apps <tethys_components>`. Classic template-based apps are not supported. | ||
|
|
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.
This is an AI-generated proof of concept. The design and implementation were produced with an AI assistant (Claude) working interactively with @gagelarsen, then verified end-to-end locally. It is a draft for discussion with the Tethys team — not a request to merge as-is. All suggestions, redesigns, and pushback are welcome.
Implements #1286.
What this does
Runs a bare, single-file component app — never pip-installed, no
pyproject.toml, no portal config, no database setup, no login — with the ergonomics ofshiny run/streamlit run:First run takes ~4s (silent SQLite migration); subsequent runs ~3s. Hot reload is on by default (Django's stock autoreloader — the app file is an imported module).
tethys runwith no argument looks forapp.pyin the cwd.How it works (design)
"Portal-in-a-box": the existing portal runtime runs unmodified, configured down via an ephemeral generated environment — chosen over (a) a purpose-built minimal runtime (dual-runtime drift risk) and (b) materializing the file into a generated package (codegen indirection). Because everything downstream is stock machinery, an express app is guaranteed to behave identically when later installed in a real portal — the same file drops verbatim into a scaffolded component app's
app.py(a futuretethys scaffold --from app.pycould automate graduation).tethys_cli/run_commands.py(new): validates the file (AST check for aComponentBasesubclass), creates~/.tethys/express/<pkg>_<hash-of-abs-path>/as an isolatedTETHYS_HOME, writes aportal_config.ymlinto it (MULTIPLE_APP_MODE: False,STANDALONE_APP: <pkg>,ENABLE_OPEN_PORTAL: True, persistedSECRET_KEY), runsmanage.py migrate --no-input(idempotent, every start), then execsmanage.py runserver. Configuration flows through env vars (TETHYS_HOME,TETHYS_EXPRESS_APP) so it survives autoreloader restarts. No changes tosettings.pywere needed.tethys_apps/base/express.py(new): whenTETHYS_EXPRESS_APPis set, loads the file astethysapp.<pkg>.appand pre-registers it (plus a synthetic parent package) insys.modules, so the untouched harvester/register_controllersmachinery — including itsimportlib.reload()— resolves it like an installed app. Missing metadata is synthesized:package/root_urlfrom the filename (parent dir for genericapp.py),nametitle-cased,index= first@App.pagefunction.tethys_apps/harvester.py(~10 lines): include the express app in the harvest dict.tethys_apps/base/component_base.py:__init_subclass__hook calls the metadata synthesis at class-definition time — required because@App.pagereadsapp.packageat decoration time (ComponentLibrary keying).Drive-by bug fixes (pre-existing, single-app mode)
Both were hit during testing and affect non-express portals too — happy to split them into a separate PR:
tethys_apps/utilities.py:get_configured_standalone_app()caught Postgres'sProgrammingErrorbut not SQLite'sOperationalError, so a fresh single-app portal withreactpy_djangoinstalled crashed duringmigrate(reactpy's app-ready hook imports the URLconf, which queriesTethysAppbefore tables exist).tethys_apps/base/component_base.py: auto nav links hard-coded/apps/<root_url>/, which 404s whenMULTIPLE_APP_MODE=False(apps are served at root). Now settings-aware.Verification performed
test_express.py,test_run_commands.py) — all passing; regression run of touched-module test files shows failure sets identical tomain(3 pre-existing, unrelated).flake8andblack --checkclean.Known limitations / open questions
ENABLE_OPEN_PORTAL); no auth flag yet.controllers.pyetc. are importable via the synthetic package path) but are untested/undocumented.~/.tethys/express/(per-app, keyed by file path;--cleanwipes one app's state). No global GC.requests/network access to esm.sh (React CDN) is required at page load, as with all component apps.tethys runvstethys express), the state-dir lifecycle, and whether portal-in-a-box is the right long-term architecture are all up for debate in Feature proposal:tethys run app.py— zero-config single-file app runner ("Tethys Express") #1286.🤖 Generated with Claude Code