mountaineer 0.4.2.dev3__tar.gz → 0.5.0.dev1__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.
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.gitignore +1 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/Cargo.lock +1 -1
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/Cargo.toml +1 -1
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/PKG-INFO +1 -1
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/app.py +2 -0
- mountaineer-0.5.0.dev1/ci_webapp/ci_webapp/controllers/root_layout.py +23 -0
- mountaineer-0.5.0.dev1/ci_webapp/ci_webapp/views/app/layout.tsx +25 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/editor_configs/vim/.vimrc +3 -1
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/editor_configs/vscode/.vscode/settings.json +2 -1
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/.gitignore +1 -0
- mountaineer-0.5.0.dev1/docs_website/docs/api/controller.md +7 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/deploy.md +1 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/quickstart.md +2 -2
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/views.md +77 -2
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/pyproject.toml +1 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__init__.py +1 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/actions/test_fields.py +19 -4
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/actions/test_passthrough.py +5 -3
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/actions/test_sideeffect.py +11 -7
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/client_builder/test_builder.py +49 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_app.py +26 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_cli.py +1 -1
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_controller.py +9 -2
- mountaineer-0.5.0.dev1/mountaineer/__tests__/test_controller_layout.py +42 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_paths.py +1 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_ssr.py +5 -3
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/actions/fields.py +23 -5
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/actions/passthrough.py +2 -2
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/actions/sideeffect.py +17 -5
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/app.py +66 -8
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/cli.py +4 -6
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/client_builder/builder.py +34 -6
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/controller.py +64 -12
- mountaineer-0.5.0.dev1/mountaineer/controller_layout.py +23 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/js_compiler/javascript.py +25 -3
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/paths.py +14 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/ssr.py +4 -5
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/static/api.ts +10 -5
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/watch.py +1 -1
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/watch_server.py +25 -5
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/pyproject.toml +1 -1
- mountaineer-0.4.2.dev3/docs_website/docs/api/controller.md +0 -3
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.git-blame-ignore-revs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.gitattributes +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/README_SCRIPTS.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/poetry.lock +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/pyproject.toml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/scripts/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/scripts/__tests__/test_update_version.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/scripts/check_dependencies.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/scripts/update_version.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/workflows/publish_docs.yml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/workflows/test.yml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/.github/workflows/validate.yml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/Dockerfile +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/LICENSE +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/Makefile +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/README.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/benchmarking/README.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/benchmarking/benchmarking/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/benchmarking/benchmarking/simple_render.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/benchmarking/poetry.lock +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/benchmarking/pyproject.toml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/README.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/cli.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/config.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/controllers/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/controllers/complex.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/controllers/detail.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/controllers/home.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/controllers/stream.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/main.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/app/complex/page.tsx +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/app/detail/page.tsx +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/app/home/page.tsx +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/app/main.css +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/app/stream/page.tsx +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/package-lock.json +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/package.json +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/postcss.config.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/ci_webapp/views/tailwind.config.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/poetry.lock +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/ci_webapp/pyproject.toml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/README.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/__tests__/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/__tests__/common.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/__tests__/test_builder.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/__tests__/test_cli.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/__tests__/test_generation.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/builder.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/cli.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/environments/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/environments/base.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/environments/poetry.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/environments/venv.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/external.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/generation.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/io.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/.zed/settings.json +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/editor_configs/zed/pyrightconfig.json +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/.env +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/README.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/app.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/cli.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/config.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/controllers/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/controllers/detail.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/controllers/home.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/main.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/models/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/models/detail.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/app/detail/page.tsx +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/app/home/page.tsx +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/app/main.css +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/package.json +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/postcss.config.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/[project_name]/views/tailwind.config.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/docker-compose.yml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/create_mountaineer_app/templates/project/pyproject.toml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/poetry.lock +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/create_mountaineer_app/pyproject.toml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/.zed/settings.json +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/README.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/CNAME +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/actions.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/api_exception.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/app-controller.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/build_plugins/base.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/build_plugins/javascript.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/build_plugins/postcss.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/cli.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/config.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/core_dependencies.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/database/config.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/database/dependencies.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/logging.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/render.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/ssr.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/api/watch_server.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/client_actions.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/cma.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/database.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/error_handling.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/index.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/internal/core_library.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/links.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/media/final_todo_list.png +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/media/ide_typehints.png +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/media/network_debug.png +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/media/server_side_rendering.png +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/metadata.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/postcss.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/static_analysis.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/structure.md +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/docs/stylesheets/extra.css +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/mkdocs.yml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/overrides/partials/footer.html +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/docs_website/poetry.lock +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/media/header.png +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/actions/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/client_builder/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/client_builder/test_build_actions.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/client_builder/test_build_links.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/client_builder/test_build_schemas.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/client_builder/test_typescript.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/common.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/conftest.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/database/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/database/dependencies/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/database/dependencies/conftest.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/database/dependencies/test_core.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/database/test_config.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/database/test_sqlmodel.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/dependencies/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/dependencies/test_base.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/fixtures/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/fixtures/complex_controller_ssr_with_react.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/fixtures/home_controller_source_map.js.map +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/fixtures/home_controller_ssr_with_react.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/js_compiler/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/js_compiler/test_javascript.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/js_compiler/test_postcss.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/js_compiler/test_source_maps.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_annotation_helpers.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_cache.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_config.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_cropper.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_exceptions.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_logging.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/test_watch.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/actions/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/annotation_helpers.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/cache.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/client_builder/build_actions.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/client_builder/build_links.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/client_builder/build_schemas.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/client_builder/openapi.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/client_builder/typescript.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/config.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/console.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/constants.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/controllers/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/controllers/exception_controller.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/cropper.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/database/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/database/cli.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/database/config.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/database/dependencies/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/database/dependencies/core.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/database/sqlmodel.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/database/validator.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/dependencies/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/dependencies/base.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/dependencies/core/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/dependencies/core/core.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/exceptions.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/io.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/js_compiler/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/js_compiler/base.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/js_compiler/exceptions.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/js_compiler/postcss.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/js_compiler/source_maps.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/logging.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/py.typed +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/render.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/static/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/static/live_reload.ts +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/static/ssr_polyfills.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/test_utilities.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/views/__init__.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/views/core/exception/page.tsx +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/views/core/layout.tsx +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/views/core/main.css +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/views/package-lock.json +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/views/package.json +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/views/postcss.config.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/views/tailwind.config.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/webservice.py +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/poetry.lock +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/benches/fixtures/complex_sourcemap_mapping.txt +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/benches/fixtures/home_controller_ssr_with_react.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/benches/fixtures/ssr_polyfill_archive.js +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/benches/lexers_benchmark.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/benches/source_map_benchmark.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/benches/ssr_benchmark.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/errors.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/lexers.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/lib.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/logging.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/source_map.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/ssr.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src/timeout.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src_go/Cargo.toml +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src_go/build.rs +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src_go/go/js_build.go +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src_go/go.mod +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src_go/go.sum +0 -0
- {mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/src_go/src/lib.rs +0 -0
|
@@ -5,6 +5,7 @@ from ci_webapp.config import AppConfig
|
|
|
5
5
|
from ci_webapp.controllers.complex import ComplexController
|
|
6
6
|
from ci_webapp.controllers.detail import DetailController
|
|
7
7
|
from ci_webapp.controllers.home import HomeController
|
|
8
|
+
from ci_webapp.controllers.root_layout import RootLayoutController
|
|
8
9
|
from ci_webapp.controllers.stream import StreamController
|
|
9
10
|
|
|
10
11
|
controller = AppController(
|
|
@@ -20,3 +21,4 @@ controller.register(HomeController())
|
|
|
20
21
|
controller.register(DetailController())
|
|
21
22
|
controller.register(ComplexController())
|
|
22
23
|
controller.register(StreamController())
|
|
24
|
+
controller.register(RootLayoutController())
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from mountaineer import LayoutControllerBase, RenderBase
|
|
2
|
+
from mountaineer.actions import sideeffect
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class RootLayoutRender(RenderBase):
|
|
6
|
+
layout_value: int
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RootLayoutController(LayoutControllerBase):
|
|
10
|
+
view_path = "/app/layout.tsx"
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.layout_value = 0
|
|
15
|
+
|
|
16
|
+
def render(self) -> RootLayoutRender:
|
|
17
|
+
return RootLayoutRender(
|
|
18
|
+
layout_value=self.layout_value,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
@sideeffect
|
|
22
|
+
async def increment_layout_value(self) -> None:
|
|
23
|
+
self.layout_value += 1
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
import { useServer } from "./_server";
|
|
3
|
+
|
|
4
|
+
const Layout = ({ children }: { children: ReactNode }) => {
|
|
5
|
+
const serverState = useServer();
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<div className="p-6">
|
|
9
|
+
<h1>Layout State: {serverState.layout_value}</h1>
|
|
10
|
+
<div>{children}</div>
|
|
11
|
+
<div>
|
|
12
|
+
<button
|
|
13
|
+
className="rounded-md bg-indigo-500 p-2 text-white"
|
|
14
|
+
onClick={async () => {
|
|
15
|
+
await serverState.increment_layout_value();
|
|
16
|
+
}}
|
|
17
|
+
>
|
|
18
|
+
Layout increment
|
|
19
|
+
</button>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default Layout;
|
|
@@ -294,9 +294,9 @@ export default Home;
|
|
|
294
294
|
|
|
295
295
|
Go ahead and load it in your browser. If you open up your web tools, you can create a new Todo and see POST requests sending data to the backend and receiving the current server state. The actual data updates and merging happens internally by Mountaineer.
|
|
296
296
|
|
|
297
|
-
{ height="400" }
|
|
298
298
|
|
|
299
|
-
{ height="400" }
|
|
300
300
|
|
|
301
301
|
You can use these serverState variables anywhere you'd use dynamic React state variables (useEffect, useCallback, etc). But unlike React state, these variables are automatically updated when a relevant sideeffect is triggered.
|
|
302
302
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Frontend Views
|
|
1
|
+
# Frontend Views & Layouts
|
|
2
2
|
|
|
3
3
|
Your React app should be initialized in the `/views` folder of your Mountaineer project. This is the directory where we look for package.json and tsconfig.json, and where esbuild looks for specific build-time overrides. In other words, the views folder should look just like your frontend application if you were building a Single-Page-App (SPA). It's just embedded within your larger Mountaineer project and rendered separately.
|
|
4
4
|
|
|
@@ -84,7 +84,82 @@ This allows you to chain layouts before rendering the final, most specific page:
|
|
|
84
84
|
/layout.tsx
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
When rendering `dashboard/home/page.tsx`, the view will be wrapped in the `app/dashboard/layout.tsx` layout alongside `app/layout.tsx`. These
|
|
87
|
+
When rendering `dashboard/home/page.tsx`, the view will be wrapped in the `app/dashboard/layout.tsx` layout alongside `app/layout.tsx`. These layout files will be automatically found by Mountaineer during the build process. They don't require any explicit declaration in your Python backend if you're just using them for styling.
|
|
88
|
+
|
|
89
|
+
If you need more server side power and want to define them in Python, you can add a LayoutController that backs the layout.
|
|
90
|
+
|
|
91
|
+
## Layout Controllers
|
|
92
|
+
|
|
93
|
+
Layouts support most of the same controller logic that regular pages do. They can specify their own actions, both sideeffects and passthroughs, which will re-render the layout as required.
|
|
94
|
+
|
|
95
|
+
```python title="/controllers/root_layout.py"
|
|
96
|
+
from mountaineer import LayoutControllerBase, RenderBase
|
|
97
|
+
from mountaineer.actions import sideeffect
|
|
98
|
+
|
|
99
|
+
class RootLayoutRender(RenderBase):
|
|
100
|
+
layout_value: int
|
|
101
|
+
|
|
102
|
+
class RootLayoutController(LayoutControllerBase):
|
|
103
|
+
view_path = "/app/layout.tsx"
|
|
104
|
+
|
|
105
|
+
def __init__(self):
|
|
106
|
+
super().__init__()
|
|
107
|
+
self.layout_value = 0
|
|
108
|
+
|
|
109
|
+
def render(self) -> RootLayoutRender:
|
|
110
|
+
return RootLayoutRender(
|
|
111
|
+
layout_value=self.layout_value,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
@sideeffect
|
|
115
|
+
async def increment_layout_value(self) -> None:
|
|
116
|
+
self.layout_value += 1
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
All these functions are now exposed to the frontend layout, including the link generator, state, and any actions specified.
|
|
120
|
+
|
|
121
|
+
```typescript title="/views/app/layout.tsx"
|
|
122
|
+
import React, { ReactNode } from "react";
|
|
123
|
+
import { useServer } from "./_server";
|
|
124
|
+
|
|
125
|
+
const Layout = ({ children }: { children: ReactNode }) => {
|
|
126
|
+
const serverState = useServer();
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<div className="p-6">
|
|
130
|
+
<h1>Layout State: {serverState.layout_value}</h1>
|
|
131
|
+
<div>{children}</div>
|
|
132
|
+
<div>
|
|
133
|
+
<button
|
|
134
|
+
className="rounded-md bg-indigo-500 p-2 text-white"
|
|
135
|
+
onClick={async () => {
|
|
136
|
+
await serverState.increment_layout_value();
|
|
137
|
+
}}
|
|
138
|
+
>
|
|
139
|
+
Increase Ticker
|
|
140
|
+
</button>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export default Layout;
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Once your controller is declared, you'll need to mount your layout into the AppController like you do for regular pages.
|
|
150
|
+
|
|
151
|
+
```python title="/app.py"
|
|
152
|
+
app_controller = AppController(...)
|
|
153
|
+
app_controller.register(RootLayoutController())
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
In general you can implement layout controllers just like you do for pages. But since they're shared across multiple pages there are a few important differences to keep in mind:
|
|
157
|
+
|
|
158
|
+
- Layout controllers will be rendered in an isolated scope. Sideeffects in one layout controller won't affect the others.
|
|
159
|
+
- Dependency injections are similarly isolated. They are run in an isolated, synthetic context and not with the same dependency injection parameters that the page uses.
|
|
160
|
+
- Layout controllers don't modify the page signature. Query params on layouts won't be extracted, for instance.
|
|
161
|
+
|
|
162
|
+
As long as you write your layout controllers without directly referencing the page that they might be wrapping, which is the case for most layouts, you should be good to go.
|
|
88
163
|
|
|
89
164
|
## Typescript Configuration
|
|
90
165
|
|
|
@@ -6,6 +6,7 @@ from mountaineer.actions import passthrough as passthrough, sideeffect as sideef
|
|
|
6
6
|
from mountaineer.app import AppController as AppController
|
|
7
7
|
from mountaineer.config import ConfigBase as ConfigBase
|
|
8
8
|
from mountaineer.controller import ControllerBase as ControllerBase
|
|
9
|
+
from mountaineer.controller_layout import LayoutControllerBase as LayoutControllerBase
|
|
9
10
|
from mountaineer.dependencies import CoreDependencies as CoreDependencies
|
|
10
11
|
from mountaineer.exceptions import APIException as APIException
|
|
11
12
|
from mountaineer.js_compiler.postcss import PostCSSBundler as PostCSSBundler
|
{mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/actions/test_fields.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import AsyncIterator, Iterator, Optional, Type
|
|
1
|
+
from typing import AsyncIterator, Iterator, Optional, Type, cast
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
from fastapi.responses import JSONResponse
|
|
@@ -15,6 +15,7 @@ from mountaineer.actions.fields import (
|
|
|
15
15
|
get_function_metadata,
|
|
16
16
|
)
|
|
17
17
|
from mountaineer.actions.sideeffect import sideeffect
|
|
18
|
+
from mountaineer.controller import ControllerBase
|
|
18
19
|
from mountaineer.render import Metadata, RenderBase
|
|
19
20
|
|
|
20
21
|
|
|
@@ -27,6 +28,11 @@ class ExamplePassthroughModel(BaseModel):
|
|
|
27
28
|
passthrough_value_a: str
|
|
28
29
|
|
|
29
30
|
|
|
31
|
+
class ExampleController(ControllerBase):
|
|
32
|
+
async def render(self) -> None:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
30
36
|
def basic_compare_model_fields(
|
|
31
37
|
actual: dict[str, FieldInfo],
|
|
32
38
|
expected: dict[str, FieldInfo],
|
|
@@ -113,8 +119,16 @@ def test_fuse_metadata_to_response_typehint(
|
|
|
113
119
|
expected_sideeffect_fields: dict[str, FieldInfo],
|
|
114
120
|
expected_passthrough_fields: dict[str, FieldInfo],
|
|
115
121
|
):
|
|
116
|
-
|
|
122
|
+
sample_controller = ExampleController()
|
|
123
|
+
raw_model = fuse_metadata_to_response_typehint(
|
|
124
|
+
metadata, sample_controller, render_model
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
assert "ExampleController" in raw_model.model_fields.keys()
|
|
117
128
|
|
|
129
|
+
fused_model = cast(
|
|
130
|
+
BaseModel, raw_model.model_fields["ExampleController"].annotation
|
|
131
|
+
)
|
|
118
132
|
if expected_sideeffect_fields:
|
|
119
133
|
assert "sideeffect" in fused_model.model_fields.keys()
|
|
120
134
|
assert fused_model.model_fields["sideeffect"].annotation
|
|
@@ -131,7 +145,7 @@ def test_fuse_metadata_to_response_typehint(
|
|
|
131
145
|
expected_passthrough_fields,
|
|
132
146
|
)
|
|
133
147
|
|
|
134
|
-
assert
|
|
148
|
+
assert raw_model.__name__ == expected_model_name
|
|
135
149
|
|
|
136
150
|
|
|
137
151
|
class ParentRender(RenderBase):
|
|
@@ -143,7 +157,7 @@ class ChildRender(ParentRender):
|
|
|
143
157
|
|
|
144
158
|
|
|
145
159
|
def test_fuse_metadata_to_response_typehint_inherit_render():
|
|
146
|
-
class ParentController(
|
|
160
|
+
class ParentController(ControllerBase):
|
|
147
161
|
def render(self) -> ParentRender:
|
|
148
162
|
return ParentRender(render_value_a="example")
|
|
149
163
|
|
|
@@ -157,6 +171,7 @@ def test_fuse_metadata_to_response_typehint_inherit_render():
|
|
|
157
171
|
|
|
158
172
|
model_fused = fuse_metadata_to_response_typehint(
|
|
159
173
|
get_function_metadata(ChildController.sideeffect),
|
|
174
|
+
ChildController(),
|
|
160
175
|
ChildRender,
|
|
161
176
|
)
|
|
162
177
|
assert set(
|
{mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/actions/test_passthrough.py
RENAMED
|
@@ -100,9 +100,11 @@ async def test_can_call_passthrough():
|
|
|
100
100
|
|
|
101
101
|
# The response payload should be the same both both sync and async endpoints
|
|
102
102
|
expected_response = {
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
"TestController": {
|
|
104
|
+
"passthrough": ExamplePassthroughModel(
|
|
105
|
+
status="success",
|
|
106
|
+
)
|
|
107
|
+
}
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
assert return_value_sync == expected_response
|
{mountaineer-0.4.2.dev3 → mountaineer-0.5.0.dev1}/mountaineer/__tests__/actions/test_sideeffect.py
RENAMED
|
@@ -101,11 +101,13 @@ async def call_sideeffect_common(controller: ControllerCommon):
|
|
|
101
101
|
|
|
102
102
|
# The response payload should be the same both both sync and async endpoints
|
|
103
103
|
expected_response = {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
controller.__class__.__name__: {
|
|
105
|
+
"sideeffect": ExampleRenderModel(
|
|
106
|
+
value_a="Hello",
|
|
107
|
+
value_b="World",
|
|
108
|
+
),
|
|
109
|
+
"passthrough": None,
|
|
110
|
+
}
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
assert return_value_sync == expected_response
|
|
@@ -277,8 +279,10 @@ def test_limit_codepath_experimental(
|
|
|
277
279
|
elapsed = (monotonic_ns() - start) / 1e9
|
|
278
280
|
assert response.status_code == 200
|
|
279
281
|
assert response.json() == {
|
|
280
|
-
"
|
|
281
|
-
"
|
|
282
|
+
"ExampleController": {
|
|
283
|
+
"sideeffect": {
|
|
284
|
+
"value_a": "Hello 1229",
|
|
285
|
+
}
|
|
282
286
|
}
|
|
283
287
|
}
|
|
284
288
|
|
|
@@ -8,6 +8,7 @@ import pytest
|
|
|
8
8
|
from mountaineer.app import AppController
|
|
9
9
|
from mountaineer.client_builder.builder import ClientBuilder
|
|
10
10
|
from mountaineer.controller import ControllerBase
|
|
11
|
+
from mountaineer.controller_layout import LayoutControllerBase
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class ExampleHomeController(ControllerBase):
|
|
@@ -169,3 +170,51 @@ def test_cache_is_outdated_url_change(
|
|
|
169
170
|
)
|
|
170
171
|
|
|
171
172
|
assert builder.cache_is_outdated() is True
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_validate_unique_paths_exact_definition(
|
|
176
|
+
builder: ClientBuilder,
|
|
177
|
+
):
|
|
178
|
+
"""
|
|
179
|
+
Two controllers can't manage the same view path.
|
|
180
|
+
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
class ConflictingDetailController(ControllerBase):
|
|
184
|
+
url = "/detail/other_url/"
|
|
185
|
+
view_path = "/detail/page.tsx"
|
|
186
|
+
|
|
187
|
+
def render(self) -> None:
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
builder.app.register(ConflictingDetailController())
|
|
191
|
+
|
|
192
|
+
# Raises for the same exact view path
|
|
193
|
+
with pytest.raises(
|
|
194
|
+
ValueError, match="duplicate view paths under controller management"
|
|
195
|
+
):
|
|
196
|
+
builder.validate_unique_paths()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_validate_unique_paths_conflicting_layout(
|
|
200
|
+
builder: ClientBuilder,
|
|
201
|
+
):
|
|
202
|
+
"""
|
|
203
|
+
Layouts need to be placed in their own directory. Even if the literal paths
|
|
204
|
+
under management are different we still need to throw a validation error.
|
|
205
|
+
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
class ConflictingLayoutController(LayoutControllerBase):
|
|
209
|
+
view_path = "/detail/layout.tsx"
|
|
210
|
+
|
|
211
|
+
def render(self) -> None:
|
|
212
|
+
return None
|
|
213
|
+
|
|
214
|
+
builder.app.register(ConflictingLayoutController())
|
|
215
|
+
|
|
216
|
+
# Raises for the same exact view path
|
|
217
|
+
with pytest.raises(
|
|
218
|
+
ValueError, match="duplicate view paths under controller management"
|
|
219
|
+
):
|
|
220
|
+
builder.validate_unique_paths()
|
|
@@ -12,6 +12,7 @@ from mountaineer.app import AppController
|
|
|
12
12
|
from mountaineer.client_builder.openapi import OpenAPIDefinition
|
|
13
13
|
from mountaineer.config import ConfigBase
|
|
14
14
|
from mountaineer.controller import ControllerBase
|
|
15
|
+
from mountaineer.controller_layout import LayoutControllerBase
|
|
15
16
|
from mountaineer.exceptions import APIException
|
|
16
17
|
|
|
17
18
|
|
|
@@ -43,6 +44,26 @@ def test_requires_render_return_value():
|
|
|
43
44
|
app.register(TestControllerWithRenderMarkup())
|
|
44
45
|
|
|
45
46
|
|
|
47
|
+
def test_validates_layouts_exclude_urls():
|
|
48
|
+
"""
|
|
49
|
+
The app controller should reject the registration of layouts that specify
|
|
50
|
+
a url.
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
class TestLayoutController(LayoutControllerBase):
|
|
55
|
+
# Not allowed, but might typehint correctly because the ControllerBase
|
|
56
|
+
# superclass supports it.
|
|
57
|
+
url = "/layout_url"
|
|
58
|
+
|
|
59
|
+
async def render(self) -> None:
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
app_controller = AppController(view_root=Path(""))
|
|
63
|
+
with pytest.raises(ValueError, match="are not directly mountable to the router"):
|
|
64
|
+
app_controller.register(TestLayoutController())
|
|
65
|
+
|
|
66
|
+
|
|
46
67
|
def test_generate_openapi():
|
|
47
68
|
class ExampleSubModel(BaseModel):
|
|
48
69
|
sub_value: str
|
|
@@ -72,6 +93,7 @@ def test_generate_openapi():
|
|
|
72
93
|
"TestExceptionActionResponse",
|
|
73
94
|
"ExampleException",
|
|
74
95
|
"ExampleSubModel",
|
|
96
|
+
"TestExceptionActionResponseRaw",
|
|
75
97
|
}
|
|
76
98
|
|
|
77
99
|
|
|
@@ -133,6 +155,7 @@ def test_handle_conflicting_exception_names():
|
|
|
133
155
|
|
|
134
156
|
assert openapi_definition.components.schemas.keys() == {
|
|
135
157
|
"TestExceptionActionResponse",
|
|
158
|
+
"TestExceptionActionResponseRaw",
|
|
136
159
|
"mountaineer.__tests__.test_1.ExampleException",
|
|
137
160
|
"mountaineer.__tests__.test_2.ExampleException",
|
|
138
161
|
}
|
|
@@ -199,6 +222,9 @@ def test_inherit_parent_spec():
|
|
|
199
222
|
assert parent_controller.definition
|
|
200
223
|
assert child_controller.definition
|
|
201
224
|
|
|
225
|
+
assert parent_controller.definition.render_router
|
|
226
|
+
assert child_controller.definition.render_router
|
|
227
|
+
|
|
202
228
|
parent_routes = parent_controller.definition.render_router.routes
|
|
203
229
|
child_routes = child_controller.definition.render_router.routes
|
|
204
230
|
|
|
@@ -100,7 +100,7 @@ def test_dev_thrown_exception_on_get(env_process: IsolatedEnvProcess):
|
|
|
100
100
|
response = test_client.get("/")
|
|
101
101
|
assert response.status_code == 500
|
|
102
102
|
assert (
|
|
103
|
-
'<div id="root">Passthrough: {"exception":"This is a test",'
|
|
103
|
+
'<div id="root">Passthrough: {"ExceptionController":{"exception":"This is a test",'
|
|
104
104
|
in response.text
|
|
105
105
|
)
|
|
106
106
|
|
|
@@ -2,7 +2,7 @@ from pathlib import Path
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
|
-
from mountaineer.controller import ControllerBase
|
|
5
|
+
from mountaineer.controller import BuildMetadata, ControllerBase
|
|
6
6
|
from mountaineer.render import (
|
|
7
7
|
LinkAttribute,
|
|
8
8
|
MetaAttribute,
|
|
@@ -196,6 +196,7 @@ def test_resolve_paths(tmp_path: Path):
|
|
|
196
196
|
view_base = tmp_path / "views"
|
|
197
197
|
ssr_base = view_base / "_ssr"
|
|
198
198
|
static_base = view_base / "_static"
|
|
199
|
+
metadata_base = view_base / "_metadata"
|
|
199
200
|
|
|
200
201
|
controller = StubController()
|
|
201
202
|
assert not controller.resolve_paths(view_base)
|
|
@@ -212,12 +213,18 @@ def test_resolve_paths(tmp_path: Path):
|
|
|
212
213
|
(ssr_base / "stub_controller.js.map").touch()
|
|
213
214
|
assert not controller.resolve_paths(view_base)
|
|
214
215
|
|
|
215
|
-
# Finally, create the static script file
|
|
216
216
|
# Our hash has to be exactly 32 digits to match the regex
|
|
217
217
|
static_base.mkdir()
|
|
218
218
|
random_hash = "b5ecd0c4405374100d6ef93088b86898"
|
|
219
219
|
(static_base / f"stub_controller-{random_hash}.js").touch()
|
|
220
220
|
(static_base / f"stub_controller-{random_hash}.js.map").touch()
|
|
221
|
+
assert not controller.resolve_paths(view_base)
|
|
222
|
+
|
|
223
|
+
# Finally, create the metadata file
|
|
224
|
+
metadata_base.mkdir()
|
|
225
|
+
(metadata_base / "stub_controller.json").write_text(
|
|
226
|
+
BuildMetadata(view_path=Path()).model_dump_json()
|
|
227
|
+
)
|
|
221
228
|
assert controller.resolve_paths(view_base)
|
|
222
229
|
|
|
223
230
|
# Now ensure that the paths are correctly set
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from mountaineer.app import AppController
|
|
6
|
+
from mountaineer.controller_layout import LayoutControllerBase
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ExampleLayoutController(LayoutControllerBase):
|
|
10
|
+
async def render(self) -> None:
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.mark.asyncio
|
|
15
|
+
async def test_disallows_direct_rendering():
|
|
16
|
+
"""
|
|
17
|
+
Layouts can't be rendered directly. They're intended for use
|
|
18
|
+
only as pages wrappers.
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
layout_controller = ExampleLayoutController()
|
|
22
|
+
|
|
23
|
+
with pytest.raises(NotImplementedError):
|
|
24
|
+
await layout_controller._generate_html(global_metadata={})
|
|
25
|
+
|
|
26
|
+
with pytest.raises(NotImplementedError):
|
|
27
|
+
layout_controller._generate_ssr_html({})
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_layout_registration():
|
|
31
|
+
"""
|
|
32
|
+
Layout controllers must register with the AppController for them
|
|
33
|
+
to be used by client render controllers.
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
app_controller = AppController(view_root=Path(""))
|
|
37
|
+
layout_controller = ExampleLayoutController()
|
|
38
|
+
|
|
39
|
+
app_controller.register(layout_controller)
|
|
40
|
+
assert len(app_controller.controllers) == 1
|
|
41
|
+
|
|
42
|
+
assert app_controller.controllers[0].controller == layout_controller
|
|
@@ -143,6 +143,7 @@ def test_managed_view_paths_code_directories(tmpdir):
|
|
|
143
143
|
assert root_path.get_managed_code_dir() == root_path / "_server"
|
|
144
144
|
assert root_path.get_managed_static_dir() == root_path / "_static"
|
|
145
145
|
assert root_path.get_managed_ssr_dir() == root_path / "_ssr"
|
|
146
|
+
assert root_path.get_managed_metadata_dir() == root_path / "_metadata"
|
|
146
147
|
|
|
147
148
|
# Non-root paths should only yield the server directory
|
|
148
149
|
non_root_path = root_path / "subdir"
|
|
@@ -26,7 +26,7 @@ def test_ssr_speed_baseline():
|
|
|
26
26
|
start = monotonic_ns()
|
|
27
27
|
render_ssr(
|
|
28
28
|
js_contents,
|
|
29
|
-
FakeModel(random_id=uuid4()),
|
|
29
|
+
FakeModel(random_id=uuid4()).model_dump(mode="json"),
|
|
30
30
|
hard_timeout=1,
|
|
31
31
|
)
|
|
32
32
|
all_measurements.append((monotonic_ns() - start) / 1e9)
|
|
@@ -54,7 +54,9 @@ def test_ssr_timeout():
|
|
|
54
54
|
with pytest.raises(TimeoutError):
|
|
55
55
|
render_ssr(
|
|
56
56
|
script=js_contents,
|
|
57
|
-
render_data=FakeWaitDurationModel(
|
|
57
|
+
render_data=FakeWaitDurationModel(
|
|
58
|
+
delay_loops=5, random_id=uuid4()
|
|
59
|
+
).model_dump(mode="json"),
|
|
58
60
|
hard_timeout=0.5,
|
|
59
61
|
)
|
|
60
62
|
assert ((monotonic_ns() - start) / 1e9) < 1.0
|
|
@@ -84,7 +86,7 @@ def test_ssr_exception_context():
|
|
|
84
86
|
try:
|
|
85
87
|
render_ssr(
|
|
86
88
|
script=js_contents,
|
|
87
|
-
render_data=FakeModel(random_id=uuid4()),
|
|
89
|
+
render_data=FakeModel(random_id=uuid4()).model_dump(mode="json"),
|
|
88
90
|
hard_timeout=0,
|
|
89
91
|
)
|
|
90
92
|
except V8RuntimeError as e:
|