tina4-python 3.13.116__tar.gz → 3.13.117__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.116 → tina4_python-3.13.117}/PKG-INFO +1 -1
- {tina4_python-3.13.116 → tina4_python-3.13.117}/pyproject.toml +1 -1
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/__init__.py +10 -1
- tina4_python-3.13.117/tina4_python/_import_helper.py +113 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/cli/__init__.py +274 -3
- {tina4_python-3.13.116 → tina4_python-3.13.117}/.gitignore +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/README.md +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/ai/client.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/context/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/context/chunker.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/port_takeover.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/database_url.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/sql_translator.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/env.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/frond/compiler.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/frond/parser.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/graph/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/graph/adapter.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/graph/adapters/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/graph/adapters/arango.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/graph/adapters/bolt.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/graph/adapters/ultipa.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/graph/graph_url.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/mqtt/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/mqtt/message.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/orm/point.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue/amqp_url.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/realtime/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/realtime/models/Attachment.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/realtime/models/Channel.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/realtime/models/ChannelMember.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/realtime/models/Message.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/realtime/models/Workspace.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/realtime/models/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/realtime/storage.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session_handlers/memcached_handler.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/sso.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -51,7 +51,7 @@ def _resolve_version() -> str:
|
|
|
51
51
|
#
|
|
52
52
|
# test_version_constant.py now asserts this literal equals the pyproject
|
|
53
53
|
# version, so the release bump cannot leave it behind again.
|
|
54
|
-
return "3.13.
|
|
54
|
+
return "3.13.117"
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
__version__ = _resolve_version()
|
|
@@ -221,3 +221,12 @@ def _preload_from_manifest() -> None:
|
|
|
221
221
|
|
|
222
222
|
|
|
223
223
|
_preload_from_manifest()
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
# ── Import-hint fallback (ADR-0062, agent-experience contract) ──
|
|
227
|
+
# Registered LAST so Python's normal resolution runs first — this finder is
|
|
228
|
+
# only consulted for `tina4_python.<X>` names that every other finder already
|
|
229
|
+
# failed on, which is what keeps it from ever masking a legitimate ImportError
|
|
230
|
+
# raised inside a module that DOES exist. See tina4_python/_import_helper.py.
|
|
231
|
+
from tina4_python._import_helper import install as _install_import_helper # noqa: E402
|
|
232
|
+
_install_import_helper()
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tina4_python._import_helper — turn a wrong `tina4_python.<X>` import into a
|
|
3
|
+
helpful ModuleNotFoundError that names the closest real module in the tree.
|
|
4
|
+
|
|
5
|
+
The finder registers LAST on sys.meta_path, so Python's normal resolution runs
|
|
6
|
+
first. We're only consulted for names that all other finders already gave up
|
|
7
|
+
on — which means we never mask a legitimate ImportError raised deeper inside
|
|
8
|
+
a module that DOES exist. If we're being asked, the module truly does not
|
|
9
|
+
exist under this name.
|
|
10
|
+
|
|
11
|
+
The suggestion is derived from the REAL installed tree (pkgutil.walk_packages),
|
|
12
|
+
so a rename in the framework updates the hint automatically. There is no
|
|
13
|
+
hand-maintained wrong-guess list.
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import importlib
|
|
18
|
+
import pkgutil
|
|
19
|
+
import sys
|
|
20
|
+
from difflib import get_close_matches
|
|
21
|
+
from importlib.abc import MetaPathFinder
|
|
22
|
+
from typing import Sequence
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_PREFIX = "tina4_python."
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _Tina4ModuleFinder(MetaPathFinder):
|
|
29
|
+
"""Last-resort finder that turns tina4_python.X misses into hints."""
|
|
30
|
+
|
|
31
|
+
def __init__(self) -> None:
|
|
32
|
+
# Snapshot the tree once at install time. If a plugin registers a new
|
|
33
|
+
# submodule after install, that plugin's own module load succeeds via
|
|
34
|
+
# the normal finders BEFORE we're consulted, so the snapshot only
|
|
35
|
+
# matters for the "did-you-mean" list. A missing plugin module still
|
|
36
|
+
# produces a helpful hint, just without the plugin's name in it.
|
|
37
|
+
self._known: tuple[str, ...] = tuple(self._walk())
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def _walk() -> Sequence[str]:
|
|
41
|
+
try:
|
|
42
|
+
pkg = importlib.import_module("tina4_python")
|
|
43
|
+
return sorted(
|
|
44
|
+
name for _, name, _ in pkgutil.walk_packages(pkg.__path__, prefix=_PREFIX)
|
|
45
|
+
)
|
|
46
|
+
except Exception: # noqa: BLE001 — never let the helper break import
|
|
47
|
+
return ()
|
|
48
|
+
|
|
49
|
+
def find_spec(self, fullname, path, target=None): # noqa: D401
|
|
50
|
+
# Only intervene for tina4_python.<X> — everything else defers to
|
|
51
|
+
# whatever finder comes next, but since we appended ourselves last
|
|
52
|
+
# and this call reached us, no next finder exists.
|
|
53
|
+
if not fullname.startswith(_PREFIX):
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
# Compute the hint. Any failure here degrades to a plain
|
|
57
|
+
# ModuleNotFoundError rather than raising the helper's own bug.
|
|
58
|
+
try:
|
|
59
|
+
hint = self._hint(fullname)
|
|
60
|
+
except Exception: # noqa: BLE001
|
|
61
|
+
hint = ""
|
|
62
|
+
|
|
63
|
+
message = f"No module named {fullname!r}"
|
|
64
|
+
if hint:
|
|
65
|
+
message = f"{message}. {hint}"
|
|
66
|
+
raise ModuleNotFoundError(message, name=fullname)
|
|
67
|
+
|
|
68
|
+
def _hint(self, fullname: str) -> str:
|
|
69
|
+
tail = fullname[len(_PREFIX):]
|
|
70
|
+
last = tail.rsplit(".", 1)[-1]
|
|
71
|
+
|
|
72
|
+
# 1) Exact-suffix match — e.g. miss "route" surfaces every real
|
|
73
|
+
# module whose last component contains "route" ("core.router",
|
|
74
|
+
# "routing_x", "route_helper"). Cheap and reads well.
|
|
75
|
+
suffix_matches = [
|
|
76
|
+
m for m in self._known
|
|
77
|
+
if m != fullname and last in m.rsplit(".", 1)[-1]
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
# 2) Fuzzy fallback — Levenshtein-style close matches on the
|
|
81
|
+
# FULL dotted name, so "tina4_python.route" surfaces
|
|
82
|
+
# "tina4_python.core.router" even though "route" is not a
|
|
83
|
+
# substring of "router".
|
|
84
|
+
fuzzy = get_close_matches(fullname, list(self._known), n=5, cutoff=0.55)
|
|
85
|
+
|
|
86
|
+
# Merge preserving order, cap at 5.
|
|
87
|
+
seen: set[str] = set()
|
|
88
|
+
merged: list[str] = []
|
|
89
|
+
for name in (*suffix_matches, *fuzzy):
|
|
90
|
+
if name in seen:
|
|
91
|
+
continue
|
|
92
|
+
seen.add(name)
|
|
93
|
+
merged.append(name)
|
|
94
|
+
if len(merged) >= 5:
|
|
95
|
+
break
|
|
96
|
+
|
|
97
|
+
if not merged:
|
|
98
|
+
return ""
|
|
99
|
+
if len(merged) == 1:
|
|
100
|
+
return f"Did you mean {merged[0]!r}?"
|
|
101
|
+
return "Did you mean one of: " + ", ".join(repr(m) for m in merged) + "?"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
_installed: bool = False
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def install() -> None:
|
|
108
|
+
"""Idempotent: append the finder to sys.meta_path exactly once."""
|
|
109
|
+
global _installed
|
|
110
|
+
if _installed:
|
|
111
|
+
return
|
|
112
|
+
sys.meta_path.append(_Tina4ModuleFinder())
|
|
113
|
+
_installed = True
|
|
@@ -129,7 +129,7 @@ def _parse_flags(args: list[str]) -> tuple[dict, list[str]]:
|
|
|
129
129
|
"""Parse --key value and --flag from args. Returns (flags, positional)."""
|
|
130
130
|
# Boolean-only flags that never take a value argument
|
|
131
131
|
boolean_flags = {"no-browser", "no-reload", "no-kill", "production", "managed", "all", "clear",
|
|
132
|
-
"json", "public", "no-migration", "once"}
|
|
132
|
+
"json", "public", "no-migration", "once", "dry-run", "quote"}
|
|
133
133
|
|
|
134
134
|
flags = {}
|
|
135
135
|
positional = []
|
|
@@ -965,6 +965,254 @@ def _ai(args):
|
|
|
965
965
|
install_selected(".", selection)
|
|
966
966
|
|
|
967
967
|
|
|
968
|
+
# ── Generate resolution envelope (ADR-0062, agent-experience contract) ─────
|
|
969
|
+
#
|
|
970
|
+
# Every `generate model/route/migration/middleware` call ALSO exposes the
|
|
971
|
+
# mapping the framework decided to build — the class name, the (maybe
|
|
972
|
+
# pluralized) table name, every file it will write, and every transformation
|
|
973
|
+
# it applied. An agent (or a human) sees WHAT was chosen without having to
|
|
974
|
+
# reverse-engineer it from the generated files. Emitted as a JSON envelope
|
|
975
|
+
# on `--json`, as a human block on stderr for bare invocations, and skipping
|
|
976
|
+
# every write on `--dry-run` (composable with `--json`).
|
|
977
|
+
#
|
|
978
|
+
# The envelope shape is the SAME across all four language backends and is
|
|
979
|
+
# advertised as `resolution_contract` on the `commands --json` manifest so a
|
|
980
|
+
# caller can programmatically discover the schema version.
|
|
981
|
+
|
|
982
|
+
# The four generators wired for the envelope. Others (crud, service, queue,
|
|
983
|
+
# validator, seeder, websocket, listener, auth, test, form, view) keep their
|
|
984
|
+
# existing behaviour — this is the minimum surface the plan calls out.
|
|
985
|
+
_RESOLUTION_TARGETS = {"model", "route", "migration", "middleware"}
|
|
986
|
+
|
|
987
|
+
# Envelope schema version. Bump when the SHAPE changes; adding an optional
|
|
988
|
+
# key on the resolution object is not a break.
|
|
989
|
+
_RESOLUTION_ENVELOPE_VERSION = "1"
|
|
990
|
+
|
|
991
|
+
|
|
992
|
+
def _input_fields(flags: dict):
|
|
993
|
+
"""Normalise `--fields` back into the envelope's `input.fields` field.
|
|
994
|
+
|
|
995
|
+
A missing / bare / boolean `--fields` maps to null so an agent can rely on
|
|
996
|
+
the shape; a real "name:string,price:float" value is preserved as-is (the
|
|
997
|
+
raw text the caller actually supplied).
|
|
998
|
+
"""
|
|
999
|
+
value = flags.get("fields")
|
|
1000
|
+
if not isinstance(value, str) or not value:
|
|
1001
|
+
return None
|
|
1002
|
+
return value
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
def _resolve_generation(target: str, name: str, flags: dict,
|
|
1006
|
+
timestamp: str | None = None) -> dict:
|
|
1007
|
+
"""Compute the resolution mapping for a generate call. Pure — no writes.
|
|
1008
|
+
|
|
1009
|
+
Called BEFORE the generator runs, so the same envelope drives both --json
|
|
1010
|
+
(emit + write) and --dry-run (emit + skip) without a second walk of the
|
|
1011
|
+
tree. Timestamps for migration filenames are locked at the call site and
|
|
1012
|
+
threaded through the underlying generator via the private `_timestamp`
|
|
1013
|
+
flag, so the envelope path always equals the on-disk filename.
|
|
1014
|
+
"""
|
|
1015
|
+
ts = timestamp or datetime.now().strftime("%Y%m%d%H%M%S")
|
|
1016
|
+
|
|
1017
|
+
if target == "model":
|
|
1018
|
+
raw_table = _to_snake(name)
|
|
1019
|
+
table = _to_table(name)
|
|
1020
|
+
transformations = []
|
|
1021
|
+
if raw_table in SQL_RESERVED_TABLE_NAMES and raw_table != table:
|
|
1022
|
+
transformations.append({
|
|
1023
|
+
"kind": "reserved_word_pluralize",
|
|
1024
|
+
"from": raw_table,
|
|
1025
|
+
"to": table,
|
|
1026
|
+
"reason": f"SQL reserved word '{raw_table}' would break CREATE TABLE",
|
|
1027
|
+
"override": (
|
|
1028
|
+
f"--table {raw_table} --quote (requires quoted-identifier "
|
|
1029
|
+
"mode, not yet implemented)"
|
|
1030
|
+
),
|
|
1031
|
+
})
|
|
1032
|
+
migration_filename = f"{ts}_create_{table}.sql"
|
|
1033
|
+
return {
|
|
1034
|
+
"class_name": name,
|
|
1035
|
+
"table_name": table,
|
|
1036
|
+
"file_path": f"src/orm/{name}.py",
|
|
1037
|
+
"migration_path": f"migrations/{migration_filename}",
|
|
1038
|
+
"transformations": transformations,
|
|
1039
|
+
"routes": [],
|
|
1040
|
+
"test_paths": [f"tests/test_{table}_model.py"],
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
if target == "route":
|
|
1044
|
+
route_path = name.lstrip("/")
|
|
1045
|
+
return {
|
|
1046
|
+
"class_name": None,
|
|
1047
|
+
"table_name": None,
|
|
1048
|
+
"file_path": f"src/routes/{route_path}.py",
|
|
1049
|
+
"migration_path": None,
|
|
1050
|
+
"transformations": [],
|
|
1051
|
+
"routes": [
|
|
1052
|
+
f"/api/{route_path}",
|
|
1053
|
+
f"/api/{route_path}/{{id:int}}",
|
|
1054
|
+
],
|
|
1055
|
+
"test_paths": [f"tests/test_{route_path}.py"],
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
if target == "migration":
|
|
1059
|
+
table = name.removeprefix("create_").removeprefix("add_").removeprefix("drop_")
|
|
1060
|
+
table = _to_snake(table)
|
|
1061
|
+
filename = f"{ts}_{name}.sql"
|
|
1062
|
+
is_create = name.startswith("create_")
|
|
1063
|
+
return {
|
|
1064
|
+
"class_name": None,
|
|
1065
|
+
"table_name": table,
|
|
1066
|
+
"file_path": f"migrations/{filename}",
|
|
1067
|
+
"migration_path": f"migrations/{filename}",
|
|
1068
|
+
"transformations": [],
|
|
1069
|
+
"routes": [],
|
|
1070
|
+
"test_paths": [f"tests/test_{table}_migration.py"] if is_create else [],
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
if target == "middleware":
|
|
1074
|
+
snake = _to_snake(name)
|
|
1075
|
+
return {
|
|
1076
|
+
"class_name": name,
|
|
1077
|
+
"table_name": None,
|
|
1078
|
+
"file_path": f"src/middleware/{snake}.py",
|
|
1079
|
+
"migration_path": None,
|
|
1080
|
+
"transformations": [],
|
|
1081
|
+
"routes": [],
|
|
1082
|
+
"test_paths": [f"tests/test_{snake}.py"],
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
return {} # never reached; guarded by _RESOLUTION_TARGETS
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
def _actions_from_resolution(target: str, resolution: dict) -> list[str]:
|
|
1089
|
+
"""Flat "wrote X" list mirroring what the generators actually write.
|
|
1090
|
+
|
|
1091
|
+
The generators print ` ✓ Created <path>` per file; this reconstructs the
|
|
1092
|
+
same list from the resolution so the envelope's `actions_taken` matches
|
|
1093
|
+
the on-disk effect without having to shadow the generator's own I/O.
|
|
1094
|
+
"""
|
|
1095
|
+
actions: list[str] = []
|
|
1096
|
+
file_path = resolution.get("file_path")
|
|
1097
|
+
if file_path:
|
|
1098
|
+
actions.append(f"wrote {file_path}")
|
|
1099
|
+
|
|
1100
|
+
# Migration + its matching .down.sql — _gen_migration writes both.
|
|
1101
|
+
if target == "model" and resolution.get("migration_path"):
|
|
1102
|
+
migration = resolution["migration_path"]
|
|
1103
|
+
actions.append(f"wrote {migration}")
|
|
1104
|
+
actions.append(f"wrote {migration[:-len('.sql')]}.down.sql")
|
|
1105
|
+
if target == "migration" and file_path and file_path.endswith(".sql"):
|
|
1106
|
+
actions.append(f"wrote {file_path[:-len('.sql')]}.down.sql")
|
|
1107
|
+
|
|
1108
|
+
for test_path in resolution.get("test_paths", []):
|
|
1109
|
+
actions.append(f"wrote {test_path}")
|
|
1110
|
+
|
|
1111
|
+
return actions
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
def _format_resolution_block(name: str, target: str, resolution: dict,
|
|
1115
|
+
dry_run: bool = False) -> str:
|
|
1116
|
+
"""Render the human-readable resolution block for stderr on bare calls.
|
|
1117
|
+
|
|
1118
|
+
Same shape as the plan / ADR-0062 example. A generator with no route/table
|
|
1119
|
+
footprint (middleware, route without a matching table) simply omits the
|
|
1120
|
+
lines that don't apply — the block is honest about what was chosen.
|
|
1121
|
+
"""
|
|
1122
|
+
suffix = " (dry-run — nothing written)" if dry_run else ""
|
|
1123
|
+
lines = [f"Generated {target} {name}{suffix}"]
|
|
1124
|
+
|
|
1125
|
+
class_name = resolution.get("class_name")
|
|
1126
|
+
file_path = resolution.get("file_path")
|
|
1127
|
+
if class_name and file_path:
|
|
1128
|
+
lines.append(f" class {class_name} (in {file_path})")
|
|
1129
|
+
elif file_path:
|
|
1130
|
+
lines.append(f" file {file_path}")
|
|
1131
|
+
|
|
1132
|
+
pluralize = next(
|
|
1133
|
+
(t for t in resolution.get("transformations", [])
|
|
1134
|
+
if t.get("kind") == "reserved_word_pluralize"),
|
|
1135
|
+
None,
|
|
1136
|
+
)
|
|
1137
|
+
if resolution.get("table_name"):
|
|
1138
|
+
note = ""
|
|
1139
|
+
if pluralize:
|
|
1140
|
+
note = f" (auto-pluralized: '{pluralize['from']}' is a SQL reserved word)"
|
|
1141
|
+
lines.append(f" table {resolution['table_name']}{note}")
|
|
1142
|
+
|
|
1143
|
+
if resolution.get("routes"):
|
|
1144
|
+
lines.append(f" routes {', '.join(resolution['routes'])}")
|
|
1145
|
+
if target != "migration" and resolution.get("migration_path"):
|
|
1146
|
+
lines.append(f" migration {resolution['migration_path']}")
|
|
1147
|
+
|
|
1148
|
+
if pluralize:
|
|
1149
|
+
lines.append("")
|
|
1150
|
+
lines.append(f" To keep the raw name '{pluralize['from']}' as the table:")
|
|
1151
|
+
lines.append(
|
|
1152
|
+
f" tina4 generate {target} {name} "
|
|
1153
|
+
f"--table {pluralize['from']} --quote "
|
|
1154
|
+
"(opt-in, ADR-0062 forthcoming)"
|
|
1155
|
+
)
|
|
1156
|
+
|
|
1157
|
+
return "\n".join(lines) + "\n"
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
def _emit_resolution(target: str, name: str, flags: dict) -> None:
|
|
1161
|
+
"""Handle the --json / --dry-run / bare paths for the 4 wired generators.
|
|
1162
|
+
|
|
1163
|
+
Contract shared by every language (ADR-0062):
|
|
1164
|
+
- --json → envelope on stdout; nothing else on stdout.
|
|
1165
|
+
- --dry-run → skip every write; envelope with dry_run=true.
|
|
1166
|
+
- --json + --dry-run → both compose (envelope with actions_taken=[]).
|
|
1167
|
+
- bare → normal write, then human resolution block on stderr.
|
|
1168
|
+
"""
|
|
1169
|
+
import contextlib
|
|
1170
|
+
import io
|
|
1171
|
+
import json as _json
|
|
1172
|
+
|
|
1173
|
+
dry_run = bool(flags.get("dry-run"))
|
|
1174
|
+
want_json = bool(flags.get("json"))
|
|
1175
|
+
|
|
1176
|
+
# Lock the timestamp so the envelope's migration_path and the on-disk
|
|
1177
|
+
# filename agree byte-for-byte (threaded through via `_timestamp` flag).
|
|
1178
|
+
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
1179
|
+
resolution = _resolve_generation(target, name, flags, timestamp=timestamp)
|
|
1180
|
+
|
|
1181
|
+
actions_taken: list[str] = []
|
|
1182
|
+
if not dry_run:
|
|
1183
|
+
# Thread the locked-in timestamp through the underlying generator,
|
|
1184
|
+
# then run it. When --json we swallow the generator's stdout so the
|
|
1185
|
+
# JSON envelope is the SOLE thing on stdout; otherwise we let its
|
|
1186
|
+
# "Created X" lines through as before.
|
|
1187
|
+
generator_flags = dict(flags)
|
|
1188
|
+
generator_flags["_timestamp"] = timestamp
|
|
1189
|
+
handler = GENERATORS[target]["handler"]
|
|
1190
|
+
|
|
1191
|
+
stdout_sink = io.StringIO() if want_json else sys.stdout
|
|
1192
|
+
with contextlib.redirect_stdout(stdout_sink):
|
|
1193
|
+
handler(name, generator_flags)
|
|
1194
|
+
|
|
1195
|
+
actions_taken = _actions_from_resolution(target, resolution)
|
|
1196
|
+
|
|
1197
|
+
envelope = {
|
|
1198
|
+
"command": "generate",
|
|
1199
|
+
"target": target,
|
|
1200
|
+
"input": {"name": name, "fields": _input_fields(flags)},
|
|
1201
|
+
"resolution": resolution,
|
|
1202
|
+
"actions_taken": actions_taken,
|
|
1203
|
+
"dry_run": dry_run,
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
if want_json:
|
|
1207
|
+
print(_json.dumps(envelope, indent=2))
|
|
1208
|
+
else:
|
|
1209
|
+
# Human resolution block always lands on STDERR (per plan): stdout
|
|
1210
|
+
# keeps whatever the generator printed on the bare path, and the
|
|
1211
|
+
# block never contends with a caller parsing stdout.
|
|
1212
|
+
sys.stderr.write(_format_resolution_block(name, target, resolution,
|
|
1213
|
+
dry_run=dry_run))
|
|
1214
|
+
|
|
1215
|
+
|
|
968
1216
|
# ── Generate (rich scaffolding) ───────────────────────────────────────
|
|
969
1217
|
|
|
970
1218
|
def _generate(args):
|
|
@@ -1004,6 +1252,15 @@ def _generate(args):
|
|
|
1004
1252
|
name = args[1] if len(args) > 1 else ""
|
|
1005
1253
|
flags, _ = _parse_flags(args[2:] if len(args) > 2 else [])
|
|
1006
1254
|
|
|
1255
|
+
# ADR-0062: the four wired generators expose a JSON envelope and a
|
|
1256
|
+
# stderr resolution block on every call, so an agent can see WHAT the
|
|
1257
|
+
# framework decided to build with its input. --json emits the envelope;
|
|
1258
|
+
# --dry-run computes it without writing; bare calls print the human
|
|
1259
|
+
# block to stderr AFTER the normal writes complete.
|
|
1260
|
+
if what in _RESOLUTION_TARGETS:
|
|
1261
|
+
_emit_resolution(what, name, flags)
|
|
1262
|
+
return
|
|
1263
|
+
|
|
1007
1264
|
# Dispatch from the module-level GENERATORS registry (single source of truth
|
|
1008
1265
|
# for the generate subcommands; also feeds `_help` and the manifest).
|
|
1009
1266
|
gen_spec = GENERATORS.get(what)
|
|
@@ -1385,7 +1642,10 @@ def _gen_migration(name: str, flags: dict = None, *,
|
|
|
1385
1642
|
"""
|
|
1386
1643
|
flags = flags or {}
|
|
1387
1644
|
now = datetime.now()
|
|
1388
|
-
|
|
1645
|
+
# ADR-0062: the resolution envelope pre-computes the migration path from a
|
|
1646
|
+
# snapshotted timestamp; if it was supplied via the private `_timestamp`
|
|
1647
|
+
# flag, honour it so envelope and disk agree byte-for-byte.
|
|
1648
|
+
timestamp = flags.get("_timestamp") or now.strftime("%Y%m%d%H%M%S")
|
|
1389
1649
|
target = Path("migrations")
|
|
1390
1650
|
target.mkdir(parents=True, exist_ok=True)
|
|
1391
1651
|
|
|
@@ -3111,7 +3371,18 @@ def _commands_manifest() -> dict:
|
|
|
3111
3371
|
if spec.get("args"):
|
|
3112
3372
|
entry["args"] = list(spec["args"])
|
|
3113
3373
|
commands.append(entry)
|
|
3114
|
-
return {
|
|
3374
|
+
return {
|
|
3375
|
+
"framework": "python",
|
|
3376
|
+
"version": __version__,
|
|
3377
|
+
"commands": commands,
|
|
3378
|
+
# ADR-0062: agents discover the generate resolution envelope shape
|
|
3379
|
+
# programmatically. A version bump here is a break; adding an
|
|
3380
|
+
# optional envelope key is not.
|
|
3381
|
+
"resolution_contract": {
|
|
3382
|
+
"version": _RESOLUTION_ENVELOPE_VERSION,
|
|
3383
|
+
"envelope": "generate_v1",
|
|
3384
|
+
},
|
|
3385
|
+
}
|
|
3115
3386
|
|
|
3116
3387
|
|
|
3117
3388
|
def _commands(args=None):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.116 → tina4_python-3.13.117}/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
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/images/tina4-logo-icon.webp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/public/js/tina4-dev-admin.min.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/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
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue_backends/kafka_backend.py
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue_backends/mongo_backend.py
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/queue_backends/rabbitmq_backend.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/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.116 → tina4_python-3.13.117}/tina4_python/session_handlers/memcached_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/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.116 → tina4_python-3.13.117}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.116 → tina4_python-3.13.117}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|