tina4-python 3.13.60__tar.gz → 3.13.61__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.60 → tina4_python-3.13.61}/PKG-INFO +1 -1
- {tina4_python-3.13.60 → tina4_python-3.13.61}/pyproject.toml +1 -1
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/CLAUDE.md +5 -5
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/__init__.py +1 -1
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/orm/model.py +29 -1
- {tina4_python-3.13.60 → tina4_python-3.13.61}/.gitignore +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/README.md +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/env.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/js/tina4-dev-admin.js +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/realtime/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/realtime/models/Attachment.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/realtime/models/Channel.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/realtime/models/ChannelMember.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/realtime/models/Message.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/realtime/models/Workspace.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/realtime/models/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/realtime/storage.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -262,16 +262,16 @@ Queue(topic="tasks").push({"action": "send_email"})
|
|
|
262
262
|
### 11. Key tina4_python Gotchas
|
|
263
263
|
|
|
264
264
|
1. **Database import**: Use `from tina4_python.database import Database` (NOT `from tina4_python import Database`)
|
|
265
|
-
2. **noauth/secured import**: Use `from tina4_python.core.router import noauth, secured` (there is NO `tina4_python.Decorators` module). **
|
|
265
|
+
2. **noauth/secured import**: Use `from tina4_python.core.router import noauth, secured` (there is NO `tina4_python.Decorators` module). `tina4_python.swagger` does **not** export `noauth` (importing it raises `ImportError`). The real docs-only trap is **`@security()`** (from `tina4_python.swagger`): it sets OpenAPI metadata only and does NOT gate a route — use `@secured()`/`@noauth()` for actual auth.
|
|
266
266
|
2b. **Decorator ordering**: Route decorators (`@get`, `@post`, etc.) must be the **innermost** (closest to the function). Swagger/meta decorators (`@description`, `@tags`, `@noauth`, `@secured`) go above. Correct: `@noauth()` → `@description(...)` → `@post(...)` → `def handler`. Wrong: `@post(...)` → `@description(...)` → `def handler` (will crash).
|
|
267
|
-
3. **
|
|
267
|
+
3. **Frond template syntax** (Frond is Jinja2-*like*, not Jinja2 — note the differences):
|
|
268
268
|
- **Ternary operator supported**: Both `{{ x ? 'a' : 'b' }}` and `{{ 'a' if x else 'b' }}` work
|
|
269
|
-
- **elif
|
|
269
|
+
- **elif or elseif**: Frond accepts **both** `{% elif %}` and `{% elseif %}`
|
|
270
270
|
- **Unescaped output**: Both `{{ var | safe }}` and `{{ var | raw }}` work for unescaped output
|
|
271
271
|
- **format filter**: Use `{{ "%.2f" | format(value) }}` for number formatting
|
|
272
272
|
- **e() filter has NO arguments**: Use `{{ var|e }}` NOT `{{ var|e('js') }}` — Jinja2's `|e` is HTML-only with no mode parameter (that's PHP Twig syntax)
|
|
273
273
|
- **JS string escaping**: Use `{{ var|replace("'", "\\'") }}` to escape single quotes for inline JS onclick handlers
|
|
274
|
-
-
|
|
274
|
+
- **`|e`/`|escape` are HTML-only**: a mode arg like `|e('js')` is **ignored** by Frond (not an error) — for inline-JS escaping use `{{ var|replace("'", "\\'") }}`
|
|
275
275
|
- **Ternary inline**: Use `{{ 's' if count != 1 else '' }}` NOT `{{ count != 1 ? 's' : '' }}`
|
|
276
276
|
- **Default values**: Use `{{ var|default('fallback') }}` — works on undefined and None
|
|
277
277
|
- **Chaining filters**: `{{ var|default('')|replace("'", "\\'") }}` — left to right
|
|
@@ -289,7 +289,7 @@ Queue(topic="tasks").push({"action": "send_email"})
|
|
|
289
289
|
4. **fetch_one()**: Returns a plain dict (or None), NOT a DatabaseResult
|
|
290
290
|
5. **Dict access**: All query results use dict access `row["column"]` not attribute access `row.column`
|
|
291
291
|
6. **Connection strings**: v3 uses standard URL format: `driver://host:port/database` with separate `username` and `password` parameters. Example: `Database("firebird://localhost:3050//path/to/db", "SYSDBA", "masterkey")`. Environment variable: `TINA4_DATABASE_URL`.
|
|
292
|
-
7. **Running the app**: `
|
|
292
|
+
7. **Running the app**: use the `tina4` CLI — `tina4 serve`. The framework **refuses to boot via a plain `python app.py`** (it must be launched by the CLI; `TINA4_OVERRIDE_CLIENT=true` only for embedding). Port/name are CLI args.
|
|
293
293
|
8. **SCSS**: Files in `src/scss/` are auto-compiled to `src/public/css/` on startup
|
|
294
294
|
12. **Background tasks**: Use `background(fn, interval)` from `tina4_python.core.server` — never use `threading.Thread` for periodic work. The `background()` function runs tasks cooperatively in the asyncio event loop with proper shutdown handling.
|
|
295
295
|
|
|
@@ -437,7 +437,35 @@ class ORM(metaclass=ORMMeta):
|
|
|
437
437
|
# which db.execute()/insert()/update() populate, falling back to
|
|
438
438
|
# the exception text) on self.last_error so it survives, and log
|
|
439
439
|
# it with model/table context. ──
|
|
440
|
-
|
|
440
|
+
cause = db.get_error() or str(e)
|
|
441
|
+
# ── DX hint (v3.13.60): turn a bare driver error into an
|
|
442
|
+
# actionable fix for the two commonest ORM write footguns. Match
|
|
443
|
+
# the message case-insensitively (SQLite says "no such table" /
|
|
444
|
+
# "no such column: is_deleted" / "has no column named is_deleted";
|
|
445
|
+
# Postgres/MySQL say "does not exist" / "doesn't exist"). Any
|
|
446
|
+
# OTHER error keeps its raw cause untouched so we never mask an
|
|
447
|
+
# unrelated failure (e.g. a NOT NULL / duplicate-PK violation). ──
|
|
448
|
+
low = cause.lower()
|
|
449
|
+
if self.soft_delete and "is_deleted" in low and (
|
|
450
|
+
"no such column" in low or "has no column" in low
|
|
451
|
+
or "does not exist" in low or "doesn't exist" in low
|
|
452
|
+
or "unknown column" in low
|
|
453
|
+
):
|
|
454
|
+
cause += (
|
|
455
|
+
" — soft_delete=True requires an is_deleted column; declare "
|
|
456
|
+
"it (is_deleted = IntegerField(default=0)) or add a migration"
|
|
457
|
+
)
|
|
458
|
+
elif "no such table" in low or (
|
|
459
|
+
("does not exist" in low or "doesn't exist" in low)
|
|
460
|
+
# exclude a column-not-found (e.g. Postgres 'column "x" does not exist')
|
|
461
|
+
# so a genuine missing-column error never gets a spurious table hint
|
|
462
|
+
and "column" not in low
|
|
463
|
+
):
|
|
464
|
+
cause += (
|
|
465
|
+
f" — table '{table}' does not exist; call "
|
|
466
|
+
f"{type(self).__name__}.create_table() or run a migration"
|
|
467
|
+
)
|
|
468
|
+
self.last_error = cause
|
|
441
469
|
Log.error(
|
|
442
470
|
f"{type(self).__name__}.save() failed for table "
|
|
443
471
|
f"'{table}': {self.last_error}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.60 → tina4_python-3.13.61}/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.60 → tina4_python-3.13.61}/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.60 → tina4_python-3.13.61}/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.60 → tina4_python-3.13.61}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/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.60 → tina4_python-3.13.61}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.60 → tina4_python-3.13.61}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|