tina4-python 3.13.76__tar.gz → 3.13.78__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.76 → tina4_python-3.13.78}/PKG-INFO +1 -1
- {tina4_python-3.13.76 → tina4_python-3.13.78}/pyproject.toml +4 -1
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/CLAUDE.md +13 -13
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/server.py +60 -26
- {tina4_python-3.13.76 → tina4_python-3.13.78}/.gitignore +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/README.md +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/context/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/context/chunker.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/env.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/js/tina4-dev-admin.js +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/realtime/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/realtime/models/Attachment.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/realtime/models/Channel.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/realtime/models/ChannelMember.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/realtime/models/Message.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/realtime/models/Workspace.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/realtime/models/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/realtime/storage.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tina4-python"
|
|
3
|
-
version = "3.13.
|
|
3
|
+
version = "3.13.78"
|
|
4
4
|
description = "Tina4 Python v3 — Zero-dependency, lightweight web framework"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Andre van Zuydam", email = "andrevanzuydam@gmail.com"}
|
|
@@ -64,6 +64,9 @@ tina4python = "tina4_python.cli:main"
|
|
|
64
64
|
[tool.pytest.ini_options]
|
|
65
65
|
asyncio_mode = "auto"
|
|
66
66
|
testpaths = ["tests"]
|
|
67
|
+
markers = [
|
|
68
|
+
"slow: a test that needs real wall-clock time to reproduce a timing bug (deselect with -m 'not slow')",
|
|
69
|
+
]
|
|
67
70
|
|
|
68
71
|
[tool.ruff]
|
|
69
72
|
target-version = "py312"
|
|
@@ -514,23 +514,23 @@ TINA4_TOKEN_LIMIT is used to set the session time, default 60 minutes
|
|
|
514
514
|
|
|
515
515
|
Set `TINA4_SESSION_BACKEND` to choose a backend:
|
|
516
516
|
|
|
517
|
-
|
|
517
|
+
The value is the backend NAME, not a class name. An unknown value falls back to
|
|
518
|
+
the file backend without raising.
|
|
519
|
+
|
|
520
|
+
| Value | Backend | Required package |
|
|
518
521
|
|---------|---------|-----------------|
|
|
519
|
-
| `
|
|
520
|
-
| `
|
|
521
|
-
| `
|
|
522
|
-
| `
|
|
522
|
+
| `file` (default) | File system | none |
|
|
523
|
+
| `redis` | Redis | `redis` |
|
|
524
|
+
| `valkey` | Valkey | `valkey` |
|
|
525
|
+
| `mongodb` | MongoDB | `pymongo` |
|
|
526
|
+
| `database` | Your ORM DB | none |
|
|
523
527
|
|
|
524
528
|
#### MongoDB session env vars
|
|
525
529
|
|
|
526
530
|
```bash
|
|
527
|
-
TINA4_SESSION_BACKEND=
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
TINA4_SESSION_MONGO_URI= # full URI (overrides host/port)
|
|
531
|
-
TINA4_SESSION_MONGO_USERNAME= # optional
|
|
532
|
-
TINA4_SESSION_MONGO_PASSWORD= # optional
|
|
533
|
-
TINA4_SESSION_MONGO_DB=tina4_sessions # default database
|
|
531
|
+
TINA4_SESSION_BACKEND=mongodb # backend NAME, not a class name
|
|
532
|
+
TINA4_SESSION_MONGO_URI=mongodb://localhost:27017 # connection URI
|
|
533
|
+
TINA4_SESSION_MONGO_DB=tina4_sessions # default database
|
|
534
534
|
TINA4_SESSION_MONGO_COLLECTION=sessions # default collection
|
|
535
535
|
TINA4_SESSION_SAMESITE=Lax # SameSite attribute for session cookies (default: Lax)
|
|
536
536
|
```
|
|
@@ -1644,7 +1644,7 @@ TINA4_OVERRIDE_CLIENT=false # Set to true to allow running without tina4 C
|
|
|
1644
1644
|
HOST_NAME=localhost:7145
|
|
1645
1645
|
|
|
1646
1646
|
# Sessions
|
|
1647
|
-
TINA4_SESSION_BACKEND=
|
|
1647
|
+
TINA4_SESSION_BACKEND=file # file, redis, valkey, mongodb, database (unknown value falls back to file)
|
|
1648
1648
|
TINA4_SESSION_SAMESITE=Lax # SameSite attribute for session cookies (default: Lax)
|
|
1649
1649
|
|
|
1650
1650
|
# Swagger/OpenAPI
|
|
@@ -49,6 +49,58 @@ def background(callback, interval: float = 1.0):
|
|
|
49
49
|
_background_tasks.append({"callback": callback, "interval": interval})
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
async def background_tick_loop(callback, interval: float, executor, shutdown):
|
|
53
|
+
"""Run one registered background task on its interval until shutdown.
|
|
54
|
+
|
|
55
|
+
A task NEVER overlaps itself: each run is awaited to completion before the
|
|
56
|
+
interval sleep and the next tick. That is the only sound reading of an
|
|
57
|
+
interval scheduler, and it is what makes the one-worker-per-task pool sizing
|
|
58
|
+
in `_serve` safe.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
callback: The registered callable (sync or async, no arguments).
|
|
62
|
+
interval: Seconds to sleep between runs.
|
|
63
|
+
executor: ThreadPoolExecutor used for sync callbacks.
|
|
64
|
+
shutdown: asyncio.Event that ends the loop when set.
|
|
65
|
+
"""
|
|
66
|
+
timeout = max(interval * 2, 5.0)
|
|
67
|
+
loop = asyncio.get_running_loop()
|
|
68
|
+
while not shutdown.is_set():
|
|
69
|
+
try:
|
|
70
|
+
if asyncio.iscoroutinefunction(callback):
|
|
71
|
+
# A coroutine IS cancellable, so the timeout really interrupts it.
|
|
72
|
+
await asyncio.wait_for(callback(), timeout=timeout)
|
|
73
|
+
else:
|
|
74
|
+
# Run sync callback in a thread pool — never blocks the event loop.
|
|
75
|
+
#
|
|
76
|
+
# A callable already running in a ThreadPoolExecutor CANNOT be
|
|
77
|
+
# cancelled: Future.cancel() returns False once it has started and
|
|
78
|
+
# there is no way to interrupt the thread. So this must NOT use
|
|
79
|
+
# wait_for() — that abandons the wrapper future while the thread
|
|
80
|
+
# keeps running, and the next tick then starts a SECOND copy
|
|
81
|
+
# alongside the first (silent double-execution of a slow sweep,
|
|
82
|
+
# with every later tick piling on another). Wait for the run to
|
|
83
|
+
# finish and only WARN about the overrun.
|
|
84
|
+
fut = loop.run_in_executor(executor, callback)
|
|
85
|
+
done, _pending = await asyncio.wait({fut}, timeout=timeout)
|
|
86
|
+
if not done:
|
|
87
|
+
Log.warning(
|
|
88
|
+
f"Background task is still running after {timeout:.1f}s. "
|
|
89
|
+
f"The next run is deferred until it finishes (a running sync "
|
|
90
|
+
f"task cannot be interrupted). Use non-blocking calls "
|
|
91
|
+
f"(e.g. queue.pop() instead of queue.consume())."
|
|
92
|
+
)
|
|
93
|
+
await fut # never overlap; re-raises the callback's error
|
|
94
|
+
except asyncio.TimeoutError:
|
|
95
|
+
Log.warning(
|
|
96
|
+
f"Background task exceeded {timeout:.1f}s timeout and was interrupted. "
|
|
97
|
+
f"Use non-blocking calls (e.g. queue.pop() instead of queue.consume())."
|
|
98
|
+
)
|
|
99
|
+
except Exception as e:
|
|
100
|
+
Log.error(f"Background task error: {e}")
|
|
101
|
+
await asyncio.sleep(interval)
|
|
102
|
+
|
|
103
|
+
|
|
52
104
|
# module_name → source-file mtime at the last (re)import. Drives the
|
|
53
105
|
# changed-file detection in ``_auto_discover``: a file whose mtime is newer
|
|
54
106
|
# than the recorded value is re-executed in place, so editing an existing
|
|
@@ -2743,7 +2795,9 @@ def run(host: str | None = None, port: int | None = None, no_browser: bool = Fal
|
|
|
2743
2795
|
|
|
2744
2796
|
# Start registered background tasks as asyncio tasks.
|
|
2745
2797
|
# Sync callbacks run in a thread pool so they CANNOT block the event loop.
|
|
2746
|
-
#
|
|
2798
|
+
# max_workers is one per registered task — sound only because a task never
|
|
2799
|
+
# overlaps itself (see background_tick_loop), so tasks cannot starve each
|
|
2800
|
+
# other of workers.
|
|
2747
2801
|
import concurrent.futures
|
|
2748
2802
|
_executor = concurrent.futures.ThreadPoolExecutor(
|
|
2749
2803
|
max_workers=max(len(_background_tasks), 2),
|
|
@@ -2751,31 +2805,11 @@ def run(host: str | None = None, port: int | None = None, no_browser: bool = Fal
|
|
|
2751
2805
|
)
|
|
2752
2806
|
bg_tasks = []
|
|
2753
2807
|
for task_def in _background_tasks:
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
while not shutdown.is_set():
|
|
2760
|
-
try:
|
|
2761
|
-
if asyncio.iscoroutinefunction(_cb):
|
|
2762
|
-
await asyncio.wait_for(_cb(), timeout=timeout)
|
|
2763
|
-
else:
|
|
2764
|
-
# Run sync callback in thread pool — never blocks the event loop
|
|
2765
|
-
await asyncio.wait_for(
|
|
2766
|
-
loop.run_in_executor(_executor, _cb),
|
|
2767
|
-
timeout=timeout,
|
|
2768
|
-
)
|
|
2769
|
-
except asyncio.TimeoutError:
|
|
2770
|
-
Log.warning(
|
|
2771
|
-
f"Background task exceeded {timeout:.1f}s timeout and was interrupted. "
|
|
2772
|
-
f"Use non-blocking calls (e.g. queue.pop() instead of queue.consume())."
|
|
2773
|
-
)
|
|
2774
|
-
except Exception as e:
|
|
2775
|
-
Log.error(f"Background task error: {e}")
|
|
2776
|
-
await asyncio.sleep(_iv)
|
|
2777
|
-
|
|
2778
|
-
bg_tasks.append(asyncio.create_task(_tick_loop()))
|
|
2808
|
+
bg_tasks.append(asyncio.create_task(
|
|
2809
|
+
background_tick_loop(
|
|
2810
|
+
task_def["callback"], task_def["interval"], _executor, shutdown,
|
|
2811
|
+
)
|
|
2812
|
+
))
|
|
2779
2813
|
|
|
2780
2814
|
await shutdown.wait()
|
|
2781
2815
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.76 → tina4_python-3.13.78}/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.76 → tina4_python-3.13.78}/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.76 → tina4_python-3.13.78}/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
|
|
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.76 → tina4_python-3.13.78}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/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.76 → tina4_python-3.13.78}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.76 → tina4_python-3.13.78}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|