tina4-python 3.13.29__tar.gz → 3.13.30__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.29 → tina4_python-3.13.30}/PKG-INFO +1 -1
- {tina4_python-3.13.29 → tina4_python-3.13.30}/pyproject.toml +1 -1
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/CLAUDE.md +1 -1
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/__init__.py +1 -1
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/router.py +48 -7
- {tina4_python-3.13.29 → tina4_python-3.13.30}/.gitignore +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/README.md +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/env.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/js/tina4-dev-admin.js +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -529,7 +529,7 @@ TINA4_SESSION_SAMESITE=Lax # SameSite attribute for session cookie
|
|
|
529
529
|
|
|
530
530
|
### Authentication & Security
|
|
531
531
|
- Use `Auth.hash_password()` from `tina4_python.auth` to hash passwords — never use hashlib directly.
|
|
532
|
-
- Use `Auth.check_password(
|
|
532
|
+
- Use `Auth.check_password(password, hash)` from `tina4_python.auth` to verify passwords.
|
|
533
533
|
|
|
534
534
|
## Templates (Twig)
|
|
535
535
|
|
|
@@ -171,11 +171,12 @@ class Router:
|
|
|
171
171
|
- ``event`` is ``"open"``, ``"message"``, or ``"close"``
|
|
172
172
|
- ``data`` is the message payload (str for message, None for open/close)
|
|
173
173
|
"""
|
|
174
|
-
pattern, param_names = _compile_pattern(path)
|
|
174
|
+
pattern, param_names, param_types = _compile_pattern(path)
|
|
175
175
|
route = {
|
|
176
176
|
"path": path,
|
|
177
177
|
"pattern": pattern,
|
|
178
178
|
"param_names": param_names,
|
|
179
|
+
"param_types": param_types,
|
|
179
180
|
"handler": handler,
|
|
180
181
|
}
|
|
181
182
|
_ws_routes.append(route)
|
|
@@ -188,8 +189,9 @@ class Router:
|
|
|
188
189
|
m = route["pattern"].match(path)
|
|
189
190
|
if m:
|
|
190
191
|
params = {}
|
|
192
|
+
_types = route.get("param_types", {})
|
|
191
193
|
for i, name in enumerate(route["param_names"]):
|
|
192
|
-
params[name] = m.group(i + 1)
|
|
194
|
+
params[name] = _cast_param(m.group(i + 1), _types.get(name))
|
|
193
195
|
return route, params
|
|
194
196
|
return None, {}
|
|
195
197
|
|
|
@@ -303,7 +305,7 @@ class Router:
|
|
|
303
305
|
combined_mw = list(cls._group_middleware) + list(handler_mw) + route_mw
|
|
304
306
|
effective_middleware = combined_mw or []
|
|
305
307
|
|
|
306
|
-
pattern, param_names = _compile_pattern(path)
|
|
308
|
+
pattern, param_names, param_types = _compile_pattern(path)
|
|
307
309
|
|
|
308
310
|
# Auth default: GET=public, writes=secured (unless custom middleware handles auth)
|
|
309
311
|
m = method.upper()
|
|
@@ -329,6 +331,7 @@ class Router:
|
|
|
329
331
|
"path": path,
|
|
330
332
|
"pattern": pattern,
|
|
331
333
|
"param_names": param_names,
|
|
334
|
+
"param_types": param_types,
|
|
332
335
|
"handler": handler,
|
|
333
336
|
"middleware": effective_middleware,
|
|
334
337
|
"auth_required": auth_required,
|
|
@@ -359,8 +362,9 @@ class Router:
|
|
|
359
362
|
m = route["pattern"].match(path)
|
|
360
363
|
if m:
|
|
361
364
|
params = {}
|
|
365
|
+
_types = route.get("param_types", {})
|
|
362
366
|
for i, name in enumerate(route["param_names"]):
|
|
363
|
-
params[name] = m.group(i + 1)
|
|
367
|
+
params[name] = _cast_param(m.group(i + 1), _types.get(name))
|
|
364
368
|
return route, params
|
|
365
369
|
|
|
366
370
|
# Second pass: HEAD auto-fallback to GET when no HEAD route registered
|
|
@@ -371,8 +375,9 @@ class Router:
|
|
|
371
375
|
m = route["pattern"].match(path)
|
|
372
376
|
if m:
|
|
373
377
|
params = {}
|
|
378
|
+
_types = route.get("param_types", {})
|
|
374
379
|
for i, name in enumerate(route["param_names"]):
|
|
375
|
-
params[name] = m.group(i + 1)
|
|
380
|
+
params[name] = _cast_param(m.group(i + 1), _types.get(name))
|
|
376
381
|
return route, params
|
|
377
382
|
|
|
378
383
|
return None, {}
|
|
@@ -454,8 +459,36 @@ _TYPE_PATTERNS = {
|
|
|
454
459
|
".*": ".+",
|
|
455
460
|
}
|
|
456
461
|
|
|
462
|
+
# Type names whose captured value is coerced from str to a Python scalar before
|
|
463
|
+
# it reaches the handler. Mirrors Ruby's ``cast_param`` (lib/tina4/router.rb):
|
|
464
|
+
# ``int``/``integer`` → ``int``, ``float``/``number`` → ``float``. Every other
|
|
465
|
+
# type (string, alpha, alnum, slug, uuid, path) and untyped params stay ``str``.
|
|
466
|
+
_TYPE_CASTS = {
|
|
467
|
+
"int": int,
|
|
468
|
+
"integer": int,
|
|
469
|
+
"float": float,
|
|
470
|
+
"number": float,
|
|
471
|
+
}
|
|
472
|
+
|
|
457
473
|
|
|
458
|
-
def
|
|
474
|
+
def _cast_param(value: str, type_hint: str | None):
|
|
475
|
+
"""Coerce a captured route param to its declared Python type.
|
|
476
|
+
|
|
477
|
+
The URL regex already guarantees the segment matches the type's pattern
|
|
478
|
+
(e.g. ``{id:int}`` only matches digits), so the cast normally can't fail.
|
|
479
|
+
We still guard it: a coercion failure must never crash routing — fall back
|
|
480
|
+
to the raw string, exactly as Ruby leaves unknown types untouched.
|
|
481
|
+
"""
|
|
482
|
+
caster = _TYPE_CASTS.get(type_hint)
|
|
483
|
+
if caster is None:
|
|
484
|
+
return value
|
|
485
|
+
try:
|
|
486
|
+
return caster(value)
|
|
487
|
+
except (TypeError, ValueError):
|
|
488
|
+
return value
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def _compile_pattern(path: str) -> tuple[re.Pattern, list[str], dict[str, str]]:
|
|
459
492
|
"""Convert a route path to a regex pattern.
|
|
460
493
|
|
|
461
494
|
Supports:
|
|
@@ -468,9 +501,16 @@ def _compile_pattern(path: str) -> tuple[re.Pattern, list[str]]:
|
|
|
468
501
|
/api/files/{p:path} → greedy (matches remaining path)
|
|
469
502
|
/api/docs/* → bare-wildcard catch-all (key "*")
|
|
470
503
|
|
|
504
|
+
Returns ``(pattern, param_names, param_types)`` where ``param_types`` maps
|
|
505
|
+
each declared name to its type hint (``"int"``, ``"float"``, …). Untyped
|
|
506
|
+
params and the ``*`` wildcard are absent from the map. The map drives
|
|
507
|
+
coercion in :meth:`Router.match` so typed params arrive at the handler as
|
|
508
|
+
Python scalars (mirrors Ruby's ``cast_param``).
|
|
509
|
+
|
|
471
510
|
Unknown type names raise ``ValueError`` at route registration time.
|
|
472
511
|
"""
|
|
473
512
|
param_names = []
|
|
513
|
+
param_types: dict[str, str] = {}
|
|
474
514
|
regex_parts = []
|
|
475
515
|
|
|
476
516
|
segments = path.strip("/").split("/")
|
|
@@ -490,6 +530,7 @@ def _compile_pattern(path: str) -> tuple[re.Pattern, list[str]]:
|
|
|
490
530
|
f"Valid types: {', '.join(sorted(k for k in _TYPE_PATTERNS if k != '.*'))}."
|
|
491
531
|
)
|
|
492
532
|
regex_parts.append("(" + _TYPE_PATTERNS[type_hint] + ")")
|
|
533
|
+
param_types[name] = type_hint
|
|
493
534
|
else:
|
|
494
535
|
name = inner
|
|
495
536
|
regex_parts.append("([^/]+)")
|
|
@@ -498,7 +539,7 @@ def _compile_pattern(path: str) -> tuple[re.Pattern, list[str]]:
|
|
|
498
539
|
regex_parts.append(re.escape(segment))
|
|
499
540
|
|
|
500
541
|
pattern_str = "^/" + "/".join(regex_parts) + "/?$"
|
|
501
|
-
return re.compile(pattern_str), param_names
|
|
542
|
+
return re.compile(pattern_str), param_names, param_types
|
|
502
543
|
|
|
503
544
|
|
|
504
545
|
# Decorator functions — the public API
|
|
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.29 → tina4_python-3.13.30}/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.29 → tina4_python-3.13.30}/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.29 → tina4_python-3.13.30}/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.29 → tina4_python-3.13.30}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/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.29 → tina4_python-3.13.30}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.29 → tina4_python-3.13.30}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|