tina4-python 3.13.134__tar.gz → 3.13.136__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.134 → tina4_python-3.13.136}/PKG-INFO +1 -1
- {tina4_python-3.13.134 → tina4_python-3.13.136}/pyproject.toml +1 -1
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/__init__.py +1 -1
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/connection.py +58 -40
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/dev_admin/__init__.py +36 -7
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/swagger/index.html +1 -1
- {tina4_python-3.13.134 → tina4_python-3.13.136}/.gitignore +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/README.md +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/.tina4-metrics.json +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/_import_helper.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/ai/client.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/context/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/context/chunker.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/port_takeover.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/database_url.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/sql_translator.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/env.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/frond/compiler.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/frond/parser.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/graph/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/graph/adapter.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/graph/adapters/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/graph/adapters/arango.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/graph/adapters/bolt.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/graph/adapters/ultipa.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/graph/graph_url.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/mqtt/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/mqtt/message.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/orm/collection.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/orm/point.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/push/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue/amqp_url.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/models/Attachment.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/models/Channel.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/models/ChannelMember.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/models/Message.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/models/Workspace.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/models/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/storage.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/memcached_handler.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/sso.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -10,6 +10,7 @@ Connection pooling:
|
|
|
10
10
|
db = Database("sqlite:///data/app.db", pool=4) # 4 connections, round-robin
|
|
11
11
|
"""
|
|
12
12
|
import hashlib
|
|
13
|
+
import importlib
|
|
13
14
|
import os
|
|
14
15
|
import threading
|
|
15
16
|
import time
|
|
@@ -129,43 +130,56 @@ def register_driver(scheme: str, adapter_class: type):
|
|
|
129
130
|
_DRIVERS[scheme] = adapter_class
|
|
130
131
|
|
|
131
132
|
|
|
132
|
-
# Register built-in SQLite
|
|
133
|
+
# Register built-in SQLite eagerly. It is stdlib, so importing it drags in no
|
|
134
|
+
# third-party package -- the zero-dependency default carries no import cost.
|
|
133
135
|
from tina4_python.database.sqlite import SQLiteAdapter
|
|
134
136
|
register_driver("sqlite", SQLiteAdapter)
|
|
135
137
|
|
|
136
|
-
#
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
#
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
138
|
+
# Every OTHER adapter is registered LAZILY: its module -- and the third-party
|
|
139
|
+
# driver that module imports -- is loaded only when a URL for that scheme is
|
|
140
|
+
# actually connected. Importing tina4_python.database (which happens on the first
|
|
141
|
+
# Database(url), regardless of engine) therefore never drags psycopg2,
|
|
142
|
+
# firebird-driver (+ protobuf + dateutil), pymssql or pymongo into an app that
|
|
143
|
+
# does not use them. Connecting to Postgres loads only psycopg2; a SQLite app
|
|
144
|
+
# loads no third-party driver at all. This mirrors PHP/Ruby autoload and Node's
|
|
145
|
+
# optionalDependencies + dynamic import. Aliases share the same target so the
|
|
146
|
+
# canonical engine and every alias resolve to one adapter class.
|
|
147
|
+
_LAZY_DRIVERS: dict[str, tuple[str, str]] = {
|
|
148
|
+
"postgres": ("tina4_python.database.postgres", "PostgreSQLAdapter"),
|
|
149
|
+
"postgresql": ("tina4_python.database.postgres", "PostgreSQLAdapter"),
|
|
150
|
+
"pgsql": ("tina4_python.database.postgres", "PostgreSQLAdapter"), # PDO / Laravel / Doctrine (issue #58)
|
|
151
|
+
"mysql": ("tina4_python.database.mysql", "MySQLAdapter"),
|
|
152
|
+
"mssql": ("tina4_python.database.mssql", "MSSQLAdapter"),
|
|
153
|
+
"sqlserver": ("tina4_python.database.mssql", "MSSQLAdapter"),
|
|
154
|
+
"firebird": ("tina4_python.database.firebird", "FirebirdAdapter"),
|
|
155
|
+
"odbc": ("tina4_python.database.odbc", "ODBCAdapter"),
|
|
156
|
+
"mongodb": ("tina4_python.database.mongodb", "MongoDBAdapter"),
|
|
157
|
+
"pymongo": ("tina4_python.database.mongodb", "MongoDBAdapter"),
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def known_drivers() -> set[str]:
|
|
162
|
+
"""Every URL scheme the framework can resolve: eagerly-registered (sqlite,
|
|
163
|
+
plus anything an app registered by hand via register_driver) and the
|
|
164
|
+
lazily-registered built-ins that import their driver on first use."""
|
|
165
|
+
return set(_DRIVERS) | set(_LAZY_DRIVERS)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _resolve_lazy_driver(scheme: str) -> None:
|
|
169
|
+
"""Import a lazily-declared adapter and register it, on first use.
|
|
170
|
+
|
|
171
|
+
Raises a clear ValueError if the adapter's driver package is not installed,
|
|
172
|
+
rather than an opaque ImportError from deep in the driver.
|
|
173
|
+
"""
|
|
174
|
+
module_path, class_name = _LAZY_DRIVERS[scheme]
|
|
175
|
+
try:
|
|
176
|
+
module = importlib.import_module(module_path)
|
|
177
|
+
except ImportError as exc:
|
|
178
|
+
raise ValueError(
|
|
179
|
+
f"Database driver '{scheme}' is unavailable: {exc}. "
|
|
180
|
+
f"Install the driver package and it will register automatically."
|
|
181
|
+
) from exc
|
|
182
|
+
register_driver(scheme, getattr(module, class_name))
|
|
169
183
|
|
|
170
184
|
|
|
171
185
|
class Database:
|
|
@@ -339,12 +353,16 @@ class Database:
|
|
|
339
353
|
scheme = (urlparse(self.url).scheme or "").lower()
|
|
340
354
|
|
|
341
355
|
if scheme not in _DRIVERS:
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
356
|
+
if scheme in _LAZY_DRIVERS:
|
|
357
|
+
# First connection to this engine: import + register its adapter.
|
|
358
|
+
_resolve_lazy_driver(scheme)
|
|
359
|
+
else:
|
|
360
|
+
available = ", ".join(sorted(known_drivers()))
|
|
361
|
+
raise ValueError(
|
|
362
|
+
f"Unknown database driver '{scheme}'. "
|
|
363
|
+
f"Available: {available}. "
|
|
364
|
+
f"Install the driver package and it will register automatically."
|
|
365
|
+
)
|
|
348
366
|
|
|
349
367
|
return _DRIVERS[scheme]()
|
|
350
368
|
|
|
@@ -1933,20 +1933,41 @@ def _route_count() -> int:
|
|
|
1933
1933
|
|
|
1934
1934
|
|
|
1935
1935
|
async def _api_version_check(request, response):
|
|
1936
|
-
"""Proxy version check to PyPI
|
|
1936
|
+
"""Proxy the version check to PyPI so the browser dodges a CORS error.
|
|
1937
|
+
|
|
1938
|
+
A check that did not happen says so. This used to fall back to
|
|
1939
|
+
latest = current on any failure, and the toolbar renders that as a green
|
|
1940
|
+
"You are up to date!" -- so a developer several releases behind, on a
|
|
1941
|
+
machine with no route out, was told the opposite of the truth, and the
|
|
1942
|
+
toolbar's own "Could not check for updates" branch could never fire because
|
|
1943
|
+
the failure arrived as a success. latest is None when the check could not be
|
|
1944
|
+
made, and error says why.
|
|
1945
|
+
|
|
1946
|
+
The registry URL is TINA4_VERSION_CHECK_URL when set (a mirror, or a test's
|
|
1947
|
+
own server), else PyPI.
|
|
1948
|
+
"""
|
|
1937
1949
|
import urllib.request
|
|
1938
1950
|
current = __version__
|
|
1939
|
-
|
|
1951
|
+
url = os.environ.get(
|
|
1952
|
+
"TINA4_VERSION_CHECK_URL", "https://pypi.org/pypi/tina4-python/json"
|
|
1953
|
+
)
|
|
1954
|
+
|
|
1955
|
+
def failed(why):
|
|
1956
|
+
return response({"current": current, "latest": None, "error": why})
|
|
1957
|
+
|
|
1940
1958
|
try:
|
|
1941
1959
|
req = urllib.request.Request(
|
|
1942
|
-
"
|
|
1943
|
-
headers={"User-Agent": "tina4-python/" + current},
|
|
1960
|
+
url, headers={"User-Agent": "tina4-python/" + current}
|
|
1944
1961
|
)
|
|
1945
1962
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
1946
1963
|
data = json.loads(resp.read().decode())
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1964
|
+
except Exception as exc: # offline, timeout, DNS, unreadable body
|
|
1965
|
+
return failed(str(exc) or exc.__class__.__name__)
|
|
1966
|
+
# Reaching PyPI is not the same as learning the version: an answer we
|
|
1967
|
+
# cannot read a version out of is the same lie by another route.
|
|
1968
|
+
latest = (data.get("info") or {}).get("version")
|
|
1969
|
+
if not latest:
|
|
1970
|
+
return failed("PyPI did not report a version")
|
|
1950
1971
|
return response({"current": current, "latest": latest})
|
|
1951
1972
|
|
|
1952
1973
|
|
|
@@ -2139,6 +2160,13 @@ def toolbar_js() -> str:
|
|
|
2139
2160
|
el.className = 't4-ok';
|
|
2140
2161
|
el.innerHTML = 'Latest: <strong class="t4-ok">v' + latest + '</strong> — You are up to date!';
|
|
2141
2162
|
}
|
|
2163
|
+
// A check that did not happen is not a clean bill of health. The server
|
|
2164
|
+
// sends latest: null when it could not reach the registry, and saying so is
|
|
2165
|
+
// the whole point -- "up to date" here would be a guess dressed as a fact.
|
|
2166
|
+
function couldNotCheck(el, why) {
|
|
2167
|
+
el.className = 't4-err';
|
|
2168
|
+
el.textContent = 'Could not check for updates' + (why ? ' (' + why + ')' : '');
|
|
2169
|
+
}
|
|
2142
2170
|
function checkVersion() {
|
|
2143
2171
|
if (modal.style.display === 'block') { modal.style.display = 'none'; return; }
|
|
2144
2172
|
modal.style.display = 'block';
|
|
@@ -2147,6 +2175,7 @@ def toolbar_js() -> str:
|
|
|
2147
2175
|
el.textContent = 'Checking for updates...';
|
|
2148
2176
|
fetch('/__dev/api/version-check').then(function (r) { return r.json(); }).then(function (d) {
|
|
2149
2177
|
var latest = d.latest, current = d.current;
|
|
2178
|
+
if (!latest) { couldNotCheck(el, d.error); return; }
|
|
2150
2179
|
if (latest === current) { upToDate(el, latest); return; }
|
|
2151
2180
|
var cP = current.split('.').map(Number), lP = latest.split('.').map(Number);
|
|
2152
2181
|
var isNewer = false, i, c, l;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.134 → tina4_python-3.13.136}/tina4_python/gallery/error-overlay/meta.json
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
|
|
File without changes
|
|
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.134 → tina4_python-3.13.136}/tina4_python/public/images/tina4-logo-icon.webp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/public/js/tina4-dev-admin.min.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/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.134 → tina4_python-3.13.136}/tina4_python/queue_backends/kafka_backend.py
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue_backends/mongo_backend.py
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/queue_backends/rabbitmq_backend.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/realtime/models/ChannelMember.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
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/memcached_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/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.134 → tina4_python-3.13.136}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.134 → tina4_python-3.13.136}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|