tina4-python 3.13.41__tar.gz → 3.13.42__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.
- {tina4_python-3.13.41 → tina4_python-3.13.42}/PKG-INFO +1 -1
- {tina4_python-3.13.41 → tina4_python-3.13.42}/pyproject.toml +1 -1
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/CLAUDE.md +31 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/__init__.py +1 -1
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/swagger/__init__.py +260 -12
- {tina4_python-3.13.41 → tina4_python-3.13.42}/.gitignore +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/README.md +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/env.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/js/tina4-dev-admin.js +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -1657,6 +1657,37 @@ TINA4_SWAGGER_LICENSE= # SPDX license name (e.g. MIT) for info.licens
|
|
|
1657
1657
|
TINA4_SWAGGER_SERVERS= # comma-separated server URLs for the OpenAPI servers[] block; falls back to SWAGGER_DEV_URL
|
|
1658
1658
|
TINA4_SWAGGER_UI_CDN= # base URL for the Swagger UI assets (default jsdelivr); point at a self-hosted mirror for air-gapped use
|
|
1659
1659
|
SWAGGER_DEV_URL=http://localhost:7145 # single dev-server URL (used when TINA4_SWAGGER_SERVERS is unset)
|
|
1660
|
+
TINA4_SWAGGER_OPENAPI=3.0.3 # OpenAPI version: 3.0.3 (default) or 3.1 (-> emits 3.1.0)
|
|
1661
|
+
TINA4_SWAGGER_BEARER_FORMAT=JWT # bearerFormat on the built-in bearerAuth scheme (e.g. opaque for sk_live_ keys)
|
|
1662
|
+
TINA4_SWAGGER_API_KEY_NAME= # if set, emit an apiKeyAuth scheme with this header/query name (e.g. X-Api-Key)
|
|
1663
|
+
TINA4_SWAGGER_API_KEY_IN=header # where the apiKey lives: header (default) | query | cookie
|
|
1664
|
+
TINA4_SWAGGER_DEFAULT_SCHEME=bearerAuth # scheme secured routes use when no @security is set
|
|
1665
|
+
TINA4_SWAGGER_INCLUDE= # comma-separated path prefixes to include (allow-list; only these documented)
|
|
1666
|
+
TINA4_SWAGGER_EXCLUDE= # comma-separated path prefixes to drop (/swagger + /__dev are always excluded)
|
|
1667
|
+
```
|
|
1668
|
+
|
|
1669
|
+
**Per-route security + reusable schemas (v3.13.42).** Configure named security
|
|
1670
|
+
schemes (configurable `bearerFormat`, an optional `apiKey` scheme, or register
|
|
1671
|
+
arbitrary schemes incl. `oauth2` with scopes via `Swagger.add_security_scheme(name, def)`),
|
|
1672
|
+
then declare them per route with `@security`:
|
|
1673
|
+
|
|
1674
|
+
```python
|
|
1675
|
+
from tina4_python.swagger import security, request_schema, response_schema, Swagger
|
|
1676
|
+
|
|
1677
|
+
@security("oauth2", scopes=["read:users"]) # scopes kept only for oauth2/openIdConnect
|
|
1678
|
+
@get("/api/v1/users")
|
|
1679
|
+
async def list_users(request, response): ...
|
|
1680
|
+
|
|
1681
|
+
@security("public") # explicitly public (overrides write-secure-by-default)
|
|
1682
|
+
@post("/api/v1/webhook")
|
|
1683
|
+
async def webhook(request, response): ...
|
|
1684
|
+
|
|
1685
|
+
# Reusable component schemas referenced by $ref (beyond ORM-model auto-schemas):
|
|
1686
|
+
Swagger.add_schema("CreateUser", {"type": "object", "properties": {"email": {"type": "string"}}})
|
|
1687
|
+
@request_schema("CreateUser")
|
|
1688
|
+
@response_schema("User", status=200)
|
|
1689
|
+
@post("/api/v1/users")
|
|
1690
|
+
async def create_user(request, response): ...
|
|
1660
1691
|
```
|
|
1661
1692
|
|
|
1662
1693
|
The spec is OpenAPI 3.0.3. ORM models registered via AutoCrud become reusable
|
|
@@ -23,6 +23,18 @@ v3.13.40 — the generator now:
|
|
|
23
23
|
request bodies (@example(..., content_type="multipart/form-data")),
|
|
24
24
|
- converts wildcard/splat routes to spec-valid {wildcard} templating,
|
|
25
25
|
- de-duplicates operationIds.
|
|
26
|
+
|
|
27
|
+
v3.13.42 — configurability for external/public APIs:
|
|
28
|
+
- per-route security + scopes via @security("oauth2", scopes=[...]) (overrides
|
|
29
|
+
the default scheme; scopes kept valid — only oauth2/openIdConnect carry them),
|
|
30
|
+
- configurable security schemes: TINA4_SWAGGER_BEARER_FORMAT (non-JWT bearers),
|
|
31
|
+
an apiKey scheme via TINA4_SWAGGER_API_KEY_NAME/_IN, TINA4_SWAGGER_DEFAULT_SCHEME,
|
|
32
|
+
and Swagger.add_security_scheme(name, def) for arbitrary schemes (oauth2 + scopes),
|
|
33
|
+
- path filtering: TINA4_SWAGGER_INCLUDE / _EXCLUDE prefixes (framework
|
|
34
|
+
internals /swagger + /__dev always excluded),
|
|
35
|
+
- OpenAPI 3.1 opt-in: TINA4_SWAGGER_OPENAPI=3.1 (default 3.0.3),
|
|
36
|
+
- reusable custom schemas: Swagger.add_schema(name, schema) + @request_schema /
|
|
37
|
+
@response_schema referencing them by $ref.
|
|
26
38
|
"""
|
|
27
39
|
import json
|
|
28
40
|
import os
|
|
@@ -40,9 +52,19 @@ _SWAGGER_ATTRS = (
|
|
|
40
52
|
"_swagger_summary", "_swagger_tags", "_swagger_example", "_swagger_example_content_type",
|
|
41
53
|
"_swagger_example_response", "_swagger_example_responses", "_swagger_deprecated",
|
|
42
54
|
"_swagger_model", "_swagger_model_list",
|
|
55
|
+
"_swagger_security", "_swagger_request_schema", "_swagger_response_schemas",
|
|
43
56
|
)
|
|
44
57
|
|
|
45
58
|
|
|
59
|
+
# ── Configuration registry ─────────────────────────────────────
|
|
60
|
+
# Process-wide registries for security schemes and reusable component schemas
|
|
61
|
+
# declared programmatically (Swagger.add_security_scheme / Swagger.add_schema).
|
|
62
|
+
# Kept module-level so app bootstrap can register before any generate() call;
|
|
63
|
+
# reset_registry() clears them (tests).
|
|
64
|
+
_REGISTERED_SCHEMES: dict[str, dict] = {}
|
|
65
|
+
_REGISTERED_SCHEMAS: dict[str, dict] = {}
|
|
66
|
+
|
|
67
|
+
|
|
46
68
|
def _carry(fn, wrapper):
|
|
47
69
|
"""Copy any already-set swagger attrs from fn onto wrapper (idempotent)."""
|
|
48
70
|
for attr in _SWAGGER_ATTRS:
|
|
@@ -199,12 +221,114 @@ def deprecated():
|
|
|
199
221
|
return decorator
|
|
200
222
|
|
|
201
223
|
|
|
224
|
+
def _normalize_security(scheme_or_reqs, scopes):
|
|
225
|
+
"""Normalize @security args to an OpenAPI security-requirement list.
|
|
226
|
+
|
|
227
|
+
Accepts:
|
|
228
|
+
@security("oauth2", scopes=["read"]) -> [{"oauth2": ["read"]}]
|
|
229
|
+
@security({"bearerAuth": []}) -> [{"bearerAuth": []}] (AND within one dict)
|
|
230
|
+
@security([{"oauth2": ["read"]}, {"apiKeyAuth": []}]) -> verbatim (OR across dicts)
|
|
231
|
+
@security("public") / @security([]) -> [] (explicitly no auth)
|
|
232
|
+
"""
|
|
233
|
+
if scheme_or_reqs in ("public", "none", None) and not scopes:
|
|
234
|
+
return []
|
|
235
|
+
if isinstance(scheme_or_reqs, str):
|
|
236
|
+
return [{scheme_or_reqs: list(scopes or [])}]
|
|
237
|
+
if isinstance(scheme_or_reqs, dict):
|
|
238
|
+
return [{k: list(v or []) for k, v in scheme_or_reqs.items()}]
|
|
239
|
+
if isinstance(scheme_or_reqs, list):
|
|
240
|
+
return [{k: list(v or []) for k, v in req.items()} for req in scheme_or_reqs]
|
|
241
|
+
return []
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def security(scheme_or_reqs="bearerAuth", scopes=None):
|
|
245
|
+
"""Declare the security requirement(s) for a route (overrides the default).
|
|
246
|
+
|
|
247
|
+
@security("bearerAuth") # default bearer, no scopes
|
|
248
|
+
@security("oauth2", scopes=["read:users"]) # oauth2 scheme + scopes
|
|
249
|
+
@security({"apiKeyAuth": []}) # a registered API-key scheme
|
|
250
|
+
@security([{"oauth2": ["read"]}, {"apiKeyAuth": []}]) # either (OR)
|
|
251
|
+
@security("public") # explicitly public (no security)
|
|
252
|
+
|
|
253
|
+
Scopes are meaningful only for ``oauth2``/``openIdConnect`` schemes; for
|
|
254
|
+
``http``/``apiKey`` schemes OpenAPI requires an empty scope array, so the
|
|
255
|
+
generator drops any scopes you pass on those (keeping the spec valid).
|
|
256
|
+
"""
|
|
257
|
+
reqs = _normalize_security(scheme_or_reqs, scopes)
|
|
258
|
+
def decorator(fn):
|
|
259
|
+
fn._swagger_security = reqs
|
|
260
|
+
@functools.wraps(fn)
|
|
261
|
+
def wrapper(*args, **kwargs):
|
|
262
|
+
return fn(*args, **kwargs)
|
|
263
|
+
wrapper._swagger_security = reqs
|
|
264
|
+
_carry(fn, wrapper)
|
|
265
|
+
return wrapper
|
|
266
|
+
return decorator
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def request_schema(name: str, content_type: str = "application/json"):
|
|
270
|
+
"""Reference a registered component schema as the request body.
|
|
271
|
+
|
|
272
|
+
Swagger.add_schema("CreateUser", {...})
|
|
273
|
+
@request_schema("CreateUser")
|
|
274
|
+
"""
|
|
275
|
+
def decorator(fn):
|
|
276
|
+
fn._swagger_request_schema = (name, content_type)
|
|
277
|
+
@functools.wraps(fn)
|
|
278
|
+
def wrapper(*args, **kwargs):
|
|
279
|
+
return fn(*args, **kwargs)
|
|
280
|
+
wrapper._swagger_request_schema = (name, content_type)
|
|
281
|
+
_carry(fn, wrapper)
|
|
282
|
+
return wrapper
|
|
283
|
+
return decorator
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def response_schema(name: str, status: int = 200, is_list: bool = False):
|
|
287
|
+
"""Reference a registered component schema as a response body (per status).
|
|
288
|
+
|
|
289
|
+
@response_schema("User", status=200)
|
|
290
|
+
@response_schema("Error", status=404)
|
|
291
|
+
@response_schema("User", status=200, is_list=True) # array of User
|
|
292
|
+
"""
|
|
293
|
+
def decorator(fn):
|
|
294
|
+
existing = dict(getattr(fn, "_swagger_response_schemas", {}) or {})
|
|
295
|
+
existing[int(status)] = (name, bool(is_list))
|
|
296
|
+
fn._swagger_response_schemas = existing
|
|
297
|
+
@functools.wraps(fn)
|
|
298
|
+
def wrapper(*args, **kwargs):
|
|
299
|
+
return fn(*args, **kwargs)
|
|
300
|
+
wrapper._swagger_response_schemas = existing
|
|
301
|
+
_carry(fn, wrapper)
|
|
302
|
+
return wrapper
|
|
303
|
+
return decorator
|
|
304
|
+
|
|
305
|
+
|
|
202
306
|
# ── Swagger Generator ──────────────────────────────────────────
|
|
203
307
|
|
|
204
308
|
def _swagger_truthy(val) -> bool:
|
|
205
309
|
return str(val or "").strip().lower() in ("true", "1", "yes", "on")
|
|
206
310
|
|
|
207
311
|
|
|
312
|
+
def _csv(val) -> list[str]:
|
|
313
|
+
"""Split a comma-separated env value into a clean list."""
|
|
314
|
+
return [p.strip() for p in str(val or "").split(",") if p.strip()]
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _resolve_openapi_version(val) -> str:
|
|
318
|
+
"""Resolve TINA4_SWAGGER_OPENAPI to a concrete version string.
|
|
319
|
+
|
|
320
|
+
Default 3.0.3 (broad tool support). '3.1' / '3.1.0' -> '3.1.0'.
|
|
321
|
+
"""
|
|
322
|
+
v = str(val or "").strip()
|
|
323
|
+
if not v:
|
|
324
|
+
return "3.0.3"
|
|
325
|
+
if v in ("3.1", "3.1.0"):
|
|
326
|
+
return "3.1.0"
|
|
327
|
+
if v in ("3.0", "3.0.3"):
|
|
328
|
+
return "3.0.3"
|
|
329
|
+
return v # honour an explicit full version verbatim
|
|
330
|
+
|
|
331
|
+
|
|
208
332
|
def is_enabled() -> bool:
|
|
209
333
|
"""Whether Swagger UI should be served.
|
|
210
334
|
|
|
@@ -279,6 +403,99 @@ class Swagger:
|
|
|
279
403
|
if license_name is not None
|
|
280
404
|
else os.environ.get("TINA4_SWAGGER_LICENSE", "")
|
|
281
405
|
)
|
|
406
|
+
# OpenAPI version — default 3.0.3 for broad tool compatibility; opt in to
|
|
407
|
+
# 3.1.0 via TINA4_SWAGGER_OPENAPI=3.1 (the schemas this generator emits
|
|
408
|
+
# are valid in both dialects).
|
|
409
|
+
self.openapi_version = _resolve_openapi_version(
|
|
410
|
+
os.environ.get("TINA4_SWAGGER_OPENAPI")
|
|
411
|
+
)
|
|
412
|
+
# Default bearer format (the built-in bearerAuth scheme). JWT unless an
|
|
413
|
+
# API uses opaque tokens / API keys as the bearer (e.g. sk_live_...).
|
|
414
|
+
self.bearer_format = os.environ.get("TINA4_SWAGGER_BEARER_FORMAT", "JWT")
|
|
415
|
+
# Optional apiKey scheme — emitted as "apiKeyAuth" when a header/query
|
|
416
|
+
# name is configured (e.g. X-Api-Key).
|
|
417
|
+
self.api_key_name = os.environ.get("TINA4_SWAGGER_API_KEY_NAME", "")
|
|
418
|
+
self.api_key_in = os.environ.get("TINA4_SWAGGER_API_KEY_IN", "header")
|
|
419
|
+
# Which scheme secured routes use by default when no @security is set.
|
|
420
|
+
self.default_scheme = os.environ.get("TINA4_SWAGGER_DEFAULT_SCHEME", "bearerAuth")
|
|
421
|
+
# Path filters (comma-separated prefixes on the raw route path).
|
|
422
|
+
self.include_prefixes = _csv(os.environ.get("TINA4_SWAGGER_INCLUDE", ""))
|
|
423
|
+
self.exclude_prefixes = _csv(os.environ.get("TINA4_SWAGGER_EXCLUDE", ""))
|
|
424
|
+
|
|
425
|
+
# ── Programmatic registries ────────────────────────────────────
|
|
426
|
+
|
|
427
|
+
@staticmethod
|
|
428
|
+
def add_security_scheme(name: str, definition: dict) -> None:
|
|
429
|
+
"""Register a named OpenAPI security scheme (e.g. an oauth2 scheme with
|
|
430
|
+
scopes, or a custom apiKey). Call at app bootstrap, before generate().
|
|
431
|
+
|
|
432
|
+
Swagger.add_security_scheme("oauth2", {
|
|
433
|
+
"type": "oauth2",
|
|
434
|
+
"flows": {"clientCredentials": {
|
|
435
|
+
"tokenUrl": "https://api.example.com/oauth/token",
|
|
436
|
+
"scopes": {"read:users": "Read users", "write:users": "Write users"},
|
|
437
|
+
}},
|
|
438
|
+
})
|
|
439
|
+
"""
|
|
440
|
+
_REGISTERED_SCHEMES[name] = definition
|
|
441
|
+
|
|
442
|
+
@staticmethod
|
|
443
|
+
def add_schema(name: str, schema: dict) -> None:
|
|
444
|
+
"""Register a reusable component schema, referenceable via
|
|
445
|
+
@request_schema(name) / @response_schema(name) or a raw $ref."""
|
|
446
|
+
_REGISTERED_SCHEMAS[name] = schema
|
|
447
|
+
|
|
448
|
+
@staticmethod
|
|
449
|
+
def reset_registry() -> None:
|
|
450
|
+
"""Clear the security-scheme and schema registries (test helper)."""
|
|
451
|
+
_REGISTERED_SCHEMES.clear()
|
|
452
|
+
_REGISTERED_SCHEMAS.clear()
|
|
453
|
+
|
|
454
|
+
def _security_schemes(self) -> dict:
|
|
455
|
+
"""Resolve components.securitySchemes from defaults + env + registry."""
|
|
456
|
+
schemes: dict[str, dict] = {
|
|
457
|
+
"bearerAuth": {
|
|
458
|
+
"type": "http",
|
|
459
|
+
"scheme": "bearer",
|
|
460
|
+
"bearerFormat": self.bearer_format,
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if self.api_key_name:
|
|
464
|
+
schemes["apiKeyAuth"] = {
|
|
465
|
+
"type": "apiKey",
|
|
466
|
+
"name": self.api_key_name,
|
|
467
|
+
"in": self.api_key_in if self.api_key_in in ("header", "query", "cookie") else "header",
|
|
468
|
+
}
|
|
469
|
+
# Registered schemes win (let an app override bearerAuth or add oauth2).
|
|
470
|
+
schemes.update(_REGISTERED_SCHEMES)
|
|
471
|
+
return schemes
|
|
472
|
+
|
|
473
|
+
def _sanitize_security(self, reqs: list, schemes: dict) -> list:
|
|
474
|
+
"""Keep a security-requirement list spec-valid: scopes are allowed only
|
|
475
|
+
on oauth2/openIdConnect schemes; everything else gets an empty array."""
|
|
476
|
+
scope_ok = {"oauth2", "openIdConnect"}
|
|
477
|
+
out = []
|
|
478
|
+
for req in reqs:
|
|
479
|
+
clean = {}
|
|
480
|
+
for name, scopes in req.items():
|
|
481
|
+
stype = (schemes.get(name) or {}).get("type")
|
|
482
|
+
clean[name] = list(scopes) if stype in scope_ok else []
|
|
483
|
+
out.append(clean)
|
|
484
|
+
return out
|
|
485
|
+
|
|
486
|
+
def _included(self, raw_path: str) -> bool:
|
|
487
|
+
"""Path-filter a raw route path. Framework internals are always
|
|
488
|
+
excluded; then TINA4_SWAGGER_INCLUDE (allow-list) / _EXCLUDE apply."""
|
|
489
|
+
for internal in ("/swagger", "/__dev"):
|
|
490
|
+
if raw_path == internal or raw_path.startswith(internal + "/"):
|
|
491
|
+
return False
|
|
492
|
+
if self.include_prefixes and not any(
|
|
493
|
+
raw_path == p or raw_path.startswith(p) for p in self.include_prefixes
|
|
494
|
+
):
|
|
495
|
+
return False
|
|
496
|
+
if any(raw_path == p or raw_path.startswith(p) for p in self.exclude_prefixes):
|
|
497
|
+
return False
|
|
498
|
+
return True
|
|
282
499
|
|
|
283
500
|
def _servers(self) -> list[dict]:
|
|
284
501
|
"""Resolve the servers[] block.
|
|
@@ -315,27 +532,25 @@ class Swagger:
|
|
|
315
532
|
if self.license_name:
|
|
316
533
|
info["license"] = {"name": self.license_name}
|
|
317
534
|
|
|
535
|
+
schemes = self._security_schemes()
|
|
318
536
|
spec = {
|
|
319
|
-
"openapi":
|
|
537
|
+
"openapi": self.openapi_version,
|
|
320
538
|
"info": info,
|
|
321
539
|
"servers": self._servers(),
|
|
322
540
|
"paths": {},
|
|
323
541
|
"components": {
|
|
324
|
-
"securitySchemes":
|
|
325
|
-
"bearerAuth": {
|
|
326
|
-
"type": "http",
|
|
327
|
-
"scheme": "bearer",
|
|
328
|
-
"bearerFormat": "JWT",
|
|
329
|
-
}
|
|
330
|
-
}
|
|
542
|
+
"securitySchemes": schemes,
|
|
331
543
|
},
|
|
332
544
|
}
|
|
333
545
|
|
|
334
546
|
models: dict[str, type] = {} # name -> ORM model class, for components.schemas
|
|
547
|
+
ref_schemas: set[str] = set() # registered schema names referenced by routes
|
|
335
548
|
used_tags: list[str] = [] # insertion-ordered unique tags
|
|
336
549
|
seen_ids: set[str] = set() # operationId de-dup
|
|
337
550
|
|
|
338
551
|
for route in routes:
|
|
552
|
+
if not self._included(route.get("path", "")):
|
|
553
|
+
continue
|
|
339
554
|
path = self._openapi_path(route["path"])
|
|
340
555
|
method = route["method"].lower()
|
|
341
556
|
handler = route.get("handler")
|
|
@@ -378,10 +593,16 @@ class Swagger:
|
|
|
378
593
|
# an inferred schema from @example. application/json unless the
|
|
379
594
|
# example declares multipart/form-data.
|
|
380
595
|
if method in ("post", "put", "patch"):
|
|
596
|
+
req_schema = getattr(handler, "_swagger_request_schema", None)
|
|
381
597
|
ct = getattr(handler, "_swagger_example_content_type", "application/json")
|
|
382
598
|
ex = getattr(handler, "_swagger_example", None)
|
|
383
599
|
media: dict = {}
|
|
384
|
-
if
|
|
600
|
+
if req_schema is not None:
|
|
601
|
+
sname, sct = req_schema
|
|
602
|
+
ct = sct or ct
|
|
603
|
+
ref_schemas.add(sname)
|
|
604
|
+
media["schema"] = {"$ref": f"#/components/schemas/{sname}"}
|
|
605
|
+
elif ref is not None:
|
|
385
606
|
media["schema"] = {"$ref": ref}
|
|
386
607
|
elif ex is not None:
|
|
387
608
|
media["schema"] = self._infer_schema(ex)
|
|
@@ -425,6 +646,19 @@ class Swagger:
|
|
|
425
646
|
},
|
|
426
647
|
}
|
|
427
648
|
|
|
649
|
+
# Registered response schemas ($ref) — explicit and authoritative.
|
|
650
|
+
resp_schemas = getattr(handler, "_swagger_response_schemas", None)
|
|
651
|
+
if resp_schemas:
|
|
652
|
+
for status_code, (sname, is_list) in resp_schemas.items():
|
|
653
|
+
ref_schemas.add(sname)
|
|
654
|
+
sref = f"#/components/schemas/{sname}"
|
|
655
|
+
schema = ({"type": "array", "items": {"$ref": sref}} if is_list
|
|
656
|
+
else {"$ref": sref})
|
|
657
|
+
operation["responses"][str(status_code)] = {
|
|
658
|
+
"description": "Successful response" if str(status_code).startswith("2") else "Response",
|
|
659
|
+
"content": {"application/json": {"schema": schema}},
|
|
660
|
+
}
|
|
661
|
+
|
|
428
662
|
# Parameters: path params (+ types) then query params from @description(query=)
|
|
429
663
|
params = self._extract_path_params(route["path"])
|
|
430
664
|
if handler:
|
|
@@ -444,9 +678,15 @@ class Swagger:
|
|
|
444
678
|
if params:
|
|
445
679
|
operation["parameters"] = params
|
|
446
680
|
|
|
447
|
-
# Auth
|
|
448
|
-
|
|
449
|
-
|
|
681
|
+
# Auth — explicit @security wins (an empty list = explicitly public);
|
|
682
|
+
# otherwise a secured route gets the default scheme.
|
|
683
|
+
sec = getattr(handler, "_swagger_security", None) if handler else None
|
|
684
|
+
if sec is not None:
|
|
685
|
+
operation["security"] = self._sanitize_security(sec, schemes) if sec else []
|
|
686
|
+
elif route.get("auth_required", False):
|
|
687
|
+
operation["security"] = self._sanitize_security(
|
|
688
|
+
[{self.default_scheme: []}], schemes
|
|
689
|
+
)
|
|
450
690
|
|
|
451
691
|
spec["paths"][path][method] = operation
|
|
452
692
|
|
|
@@ -456,6 +696,13 @@ class Swagger:
|
|
|
456
696
|
for name, model_class in models.items():
|
|
457
697
|
schemas[name] = self._model_schema(model_class)
|
|
458
698
|
|
|
699
|
+
# Registered component schemas referenced via @request_schema/@response_schema.
|
|
700
|
+
if ref_schemas:
|
|
701
|
+
schemas = spec["components"].setdefault("schemas", {})
|
|
702
|
+
for name in ref_schemas:
|
|
703
|
+
if name in _REGISTERED_SCHEMAS and name not in schemas:
|
|
704
|
+
schemas[name] = _REGISTERED_SCHEMAS[name]
|
|
705
|
+
|
|
459
706
|
# top-level tags[] (name-only is valid OpenAPI; descriptions optional)
|
|
460
707
|
if used_tags:
|
|
461
708
|
spec["tags"] = [{"name": t} for t in used_tags]
|
|
@@ -609,4 +856,5 @@ __all__ = [
|
|
|
609
856
|
"Swagger", "is_enabled",
|
|
610
857
|
"description", "summary", "tags",
|
|
611
858
|
"example", "example_response", "deprecated",
|
|
859
|
+
"security", "request_schema", "response_schema",
|
|
612
860
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/images/tina4-logo-icon.webp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/public/swagger/oauth2-redirect.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/queue_backends/rabbitmq_backend.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/templates/docker/python/Dockerfile
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.41 → tina4_python-3.13.42}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|