tina4-python 3.13.30__tar.gz → 3.13.32__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.30 → tina4_python-3.13.32}/PKG-INFO +1 -1
- {tina4_python-3.13.30 → tina4_python-3.13.32}/pyproject.toml +1 -1
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/CLAUDE.md +3 -5
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/__init__.py +1 -1
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/cache/__init__.py +34 -1
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/connection.py +31 -18
- {tina4_python-3.13.30 → tina4_python-3.13.32}/.gitignore +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/README.md +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/env.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/js/tina4-dev-admin.js +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -492,10 +492,9 @@ return response.stream(generator) # SSE/streaming response (text/event-
|
|
|
492
492
|
|
|
493
493
|
`response()` auto-serializes a domain object — an ORM model, a list of models, or a `DatabaseResult` — to JSON with no manual `to_dict()` / `to_json()`. A single model becomes a JSON object; a list of models or a `DatabaseResult` becomes a JSON array. Dicts, lists and strings behave exactly as before (purely additive).
|
|
494
494
|
|
|
495
|
-
Add custom headers
|
|
495
|
+
Add custom headers by calling `add_header` on the `response` object in your handler:
|
|
496
496
|
```python
|
|
497
|
-
|
|
498
|
-
Response.add_header("X-Custom", "value")
|
|
497
|
+
response.add_header("X-Custom", "value")
|
|
499
498
|
```
|
|
500
499
|
|
|
501
500
|
## Sessions
|
|
@@ -1042,8 +1041,7 @@ class AuthMiddleware:
|
|
|
1042
1041
|
@staticmethod
|
|
1043
1042
|
def after_headers(request, response):
|
|
1044
1043
|
"""Add custom headers to every response."""
|
|
1045
|
-
|
|
1046
|
-
Response.add_header("X-Powered-By", "Tina4")
|
|
1044
|
+
response.add_header("X-Powered-By", "Tina4")
|
|
1047
1045
|
return request, response
|
|
1048
1046
|
|
|
1049
1047
|
@middleware(AuthMiddleware)
|
|
@@ -880,7 +880,10 @@ class ResponseCache:
|
|
|
880
880
|
self._hits += 1
|
|
881
881
|
# Move to end (most recently used)
|
|
882
882
|
self._store.move_to_end(cache_key)
|
|
883
|
-
|
|
883
|
+
remaining = max(0, int(round(entry.expires_at - time.monotonic())))
|
|
884
|
+
hit_response = response(entry.body, entry.status_code)
|
|
885
|
+
self._set_cache_headers(hit_response, "HIT", remaining)
|
|
886
|
+
return request, hit_response
|
|
884
887
|
|
|
885
888
|
self._misses += 1
|
|
886
889
|
|
|
@@ -930,6 +933,11 @@ class ResponseCache:
|
|
|
930
933
|
self._store[cache_key] = entry
|
|
931
934
|
self._store.move_to_end(cache_key)
|
|
932
935
|
|
|
936
|
+
# The handler ran for this request → MISS. Advertise the TTL the
|
|
937
|
+
# entry was just stored with so clients can see how long the next
|
|
938
|
+
# HIT will live.
|
|
939
|
+
self._set_cache_headers(response, "MISS", cache_ttl)
|
|
940
|
+
|
|
933
941
|
return request, response
|
|
934
942
|
|
|
935
943
|
# ── Public API ───────────────────────────────────────────────
|
|
@@ -965,6 +973,31 @@ class ResponseCache:
|
|
|
965
973
|
|
|
966
974
|
# ── Internal helpers ─────────────────────────────────────────
|
|
967
975
|
|
|
976
|
+
@staticmethod
|
|
977
|
+
def _set_cache_headers(response, status: str, ttl: int) -> None:
|
|
978
|
+
"""Set ``X-Cache`` / ``X-Cache-TTL`` on the outgoing response.
|
|
979
|
+
|
|
980
|
+
``status`` is ``"HIT"`` (served from cache) or ``"MISS"`` (handler
|
|
981
|
+
ran). ``ttl`` is the entry's remaining seconds on a HIT, or the
|
|
982
|
+
configured TTL on a MISS. We deliberately do NOT emit
|
|
983
|
+
``Cache-Control`` — browser-cache directives are the app's call.
|
|
984
|
+
|
|
985
|
+
Works with the framework ``Response`` (``add_header``) and with any
|
|
986
|
+
object exposing a ``headers`` dict, so middleware stubs and other
|
|
987
|
+
response shapes keep working.
|
|
988
|
+
"""
|
|
989
|
+
if response is None:
|
|
990
|
+
return
|
|
991
|
+
headers = {"X-Cache": status, "X-Cache-TTL": str(int(ttl))}
|
|
992
|
+
setter = getattr(response, "add_header", None) or getattr(response, "header", None)
|
|
993
|
+
if callable(setter):
|
|
994
|
+
for name, value in headers.items():
|
|
995
|
+
setter(name, value)
|
|
996
|
+
return
|
|
997
|
+
existing = getattr(response, "headers", None)
|
|
998
|
+
if isinstance(existing, dict):
|
|
999
|
+
existing.update(headers)
|
|
1000
|
+
|
|
968
1001
|
@staticmethod
|
|
969
1002
|
def _get_route_ttl(request) -> int | None:
|
|
970
1003
|
"""Check for a per-route cache TTL set via the @cached decorator."""
|
|
@@ -519,7 +519,7 @@ class Database:
|
|
|
519
519
|
return adapter.execute_many(sql, params_list)
|
|
520
520
|
|
|
521
521
|
def fetch(self, sql: str, params: list = None,
|
|
522
|
-
limit: int = 100, offset: int = 0) -> DatabaseResult:
|
|
522
|
+
limit: int = 100, offset: int = 0, no_cache: bool = False) -> DatabaseResult:
|
|
523
523
|
"""Fetch rows with pagination.
|
|
524
524
|
|
|
525
525
|
v3.13.11 (issue #49 Gap 3): mirror :meth:`execute` and capture
|
|
@@ -527,25 +527,32 @@ class Database:
|
|
|
527
527
|
``db.get_error()`` returning ``None`` even though the adapter
|
|
528
528
|
had stored the failure on its own ``last_error``. Callers had
|
|
529
529
|
no way to read the cause via the public API.
|
|
530
|
+
|
|
531
|
+
``no_cache=True`` bypasses the query cache for this one call — no
|
|
532
|
+
lookup and no store — and runs the query straight against the DB.
|
|
533
|
+
Works in either cache mode (request-scoped auto-cache or persistent
|
|
534
|
+
DB cache). The default (``False``) preserves today's behaviour.
|
|
530
535
|
"""
|
|
531
|
-
if self._cache_enabled:
|
|
536
|
+
if self._cache_enabled and not no_cache:
|
|
532
537
|
key = self._cache_key(sql + f":L{limit}:S{offset}", params)
|
|
533
538
|
cached = self._cache_get(key)
|
|
534
539
|
if cached is not None:
|
|
535
540
|
with self._cache_lock:
|
|
536
541
|
self._cache_hits += 1
|
|
537
542
|
return cached
|
|
538
|
-
|
|
539
|
-
try:
|
|
540
|
-
result = adapter.fetch(sql, params, limit, offset)
|
|
541
|
-
self.last_error = None
|
|
542
|
-
except Exception:
|
|
543
|
-
self.last_error = getattr(adapter, "last_error", None) or self.last_error
|
|
544
|
-
raise
|
|
543
|
+
result = self._fetch_direct(sql, params, limit, offset)
|
|
545
544
|
self._cache_set(key, result)
|
|
546
545
|
with self._cache_lock:
|
|
547
546
|
self._cache_misses += 1
|
|
548
547
|
return result
|
|
548
|
+
return self._fetch_direct(sql, params, limit, offset)
|
|
549
|
+
|
|
550
|
+
def _fetch_direct(self, sql: str, params: list, limit: int, offset: int) -> DatabaseResult:
|
|
551
|
+
"""Run a fetch straight against the adapter — no cache lookup or store.
|
|
552
|
+
|
|
553
|
+
Shared by the cached and ``no_cache`` paths so error capture stays
|
|
554
|
+
identical regardless of caching.
|
|
555
|
+
"""
|
|
549
556
|
adapter = self._get_adapter()
|
|
550
557
|
try:
|
|
551
558
|
result = adapter.fetch(sql, params, limit, offset)
|
|
@@ -556,7 +563,7 @@ class Database:
|
|
|
556
563
|
raise
|
|
557
564
|
|
|
558
565
|
def fetch_all(self, sql: str, params: list = None,
|
|
559
|
-
limit: int = 0, offset: int = 0) -> list[dict]:
|
|
566
|
+
limit: int = 0, offset: int = 0, no_cache: bool = False) -> list[dict]:
|
|
560
567
|
"""Fetch ALL rows and return the records list directly.
|
|
561
568
|
|
|
562
569
|
Symmetric with ``fetch_one``. For the common case where you just
|
|
@@ -572,26 +579,32 @@ class Database:
|
|
|
572
579
|
name says ``fetch_all``, so it returns all matching rows. Pre-v3.13.12
|
|
573
580
|
silently truncated to 100. Pass an explicit ``limit=N`` to cap.
|
|
574
581
|
|
|
575
|
-
|
|
582
|
+
``no_cache=True`` bypasses the query cache for this one call (see
|
|
583
|
+
:meth:`fetch`). Returns ``[]`` (not ``None``) when no rows match.
|
|
576
584
|
"""
|
|
577
|
-
return self.fetch(sql, params, limit, offset).records
|
|
585
|
+
return self.fetch(sql, params, limit, offset, no_cache=no_cache).records
|
|
578
586
|
|
|
579
|
-
def fetch_one(self, sql: str, params: list = None) -> dict | None:
|
|
580
|
-
|
|
587
|
+
def fetch_one(self, sql: str, params: list = None, no_cache: bool = False) -> dict | None:
|
|
588
|
+
"""Fetch a single row as a dict, or ``None`` when no row matches.
|
|
589
|
+
|
|
590
|
+
``no_cache=True`` bypasses the query cache for this one call — no
|
|
591
|
+
lookup and no store — and runs the query straight against the DB
|
|
592
|
+
(see :meth:`fetch`). The default (``False``) preserves today's
|
|
593
|
+
behaviour.
|
|
594
|
+
"""
|
|
595
|
+
if self._cache_enabled and not no_cache:
|
|
581
596
|
key = self._cache_key(sql + ":ONE", params)
|
|
582
597
|
cached = self._cache_get(key)
|
|
583
598
|
if cached is not None:
|
|
584
599
|
with self._cache_lock:
|
|
585
600
|
self._cache_hits += 1
|
|
586
601
|
return cached
|
|
587
|
-
|
|
588
|
-
result = adapter.fetch_one(sql, params)
|
|
602
|
+
result = self._get_adapter().fetch_one(sql, params)
|
|
589
603
|
self._cache_set(key, result)
|
|
590
604
|
with self._cache_lock:
|
|
591
605
|
self._cache_misses += 1
|
|
592
606
|
return result
|
|
593
|
-
|
|
594
|
-
return adapter.fetch_one(sql, params)
|
|
607
|
+
return self._get_adapter().fetch_one(sql, params)
|
|
595
608
|
|
|
596
609
|
def insert(self, table: str, data: dict | list) -> DatabaseResult:
|
|
597
610
|
if self._cache_enabled:
|
|
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.30 → tina4_python-3.13.32}/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.30 → tina4_python-3.13.32}/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.30 → tina4_python-3.13.32}/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.30 → tina4_python-3.13.32}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/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.30 → tina4_python-3.13.32}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.30 → tina4_python-3.13.32}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|