tina4-python 3.13.87__tar.gz → 3.13.88__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.87 → tina4_python-3.13.88}/PKG-INFO +1 -1
- {tina4_python-3.13.87 → tina4_python-3.13.88}/pyproject.toml +1 -1
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/frond/engine.py +81 -3
- {tina4_python-3.13.87 → tina4_python-3.13.88}/.gitignore +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/README.md +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/context/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/context/chunker.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/env.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/frond/compiler.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/frond/parser.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/mqtt/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/mqtt/message.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/realtime/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/realtime/models/Attachment.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/realtime/models/Channel.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/realtime/models/ChannelMember.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/realtime/models/Message.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/realtime/models/Workspace.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/realtime/models/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/realtime/storage.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_pagination.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -14,6 +14,7 @@ import re
|
|
|
14
14
|
import html
|
|
15
15
|
import hashlib
|
|
16
16
|
import json
|
|
17
|
+
import math
|
|
17
18
|
import secrets
|
|
18
19
|
import time
|
|
19
20
|
from functools import lru_cache
|
|
@@ -1187,6 +1188,83 @@ def _dict_replace(s: str, mapping: dict) -> str:
|
|
|
1187
1188
|
|
|
1188
1189
|
|
|
1189
1190
|
# Built-in filters
|
|
1191
|
+
def _json_safe(value) -> "SafeString":
|
|
1192
|
+
"""Serialize to JSON that is valid JSON, valid JavaScript, and safe in HTML.
|
|
1193
|
+
|
|
1194
|
+
THE cross-framework contract for ``json_encode`` / ``to_json`` / ``tojson``.
|
|
1195
|
+
Keep the four implementations byte-identical; ``frond_expression_corpus.txt``
|
|
1196
|
+
locks it.
|
|
1197
|
+
|
|
1198
|
+
Three things this must never do, each of which was a real bug:
|
|
1199
|
+
|
|
1200
|
+
1. **Never emit a non-finite literal.** ``json.dumps`` writes bare
|
|
1201
|
+
``Infinity``/``NaN`` by default. Neither is JSON -- ``JSON.parse`` throws
|
|
1202
|
+
-- so the payload only survives when inlined straight into a ``<script>``.
|
|
1203
|
+
The JSON spec has no infinity, so a non-finite number serializes as
|
|
1204
|
+
``null``, which is what ``JSON.stringify`` has always done. Reported as
|
|
1205
|
+
tina4-php#184 by justin-k-bruce, who found it in production: two ``INF``
|
|
1206
|
+
sort keys in a 657-row grid blanked the whole screen.
|
|
1207
|
+
2. **Never emit nothing.** A serializer that fails must not collapse to an
|
|
1208
|
+
empty string (or, worse, to something that still parses and means
|
|
1209
|
+
something else). ``var ROWS = ;`` is at least a loud SyntaxError;
|
|
1210
|
+
``var ROWS = false;`` is valid JS carrying wrong data. Same fail-loud
|
|
1211
|
+
contract the DB layer got: no swallow-to-empty.
|
|
1212
|
+
3. **Never HTML-escape it.** Entity-encoding JSON produces
|
|
1213
|
+
``{"a":1}``, which is a SyntaxError inside ``<script>`` -- it
|
|
1214
|
+
breaks the filter's primary use. Instead escape only the characters that
|
|
1215
|
+
are dangerous in HTML, as JSON ``\\uXXXX`` escapes, which keeps the output
|
|
1216
|
+
valid JSON AND valid JS: ``</script>`` cannot terminate the block, and the
|
|
1217
|
+
result is safe inside a single-quoted attribute. This is exactly what
|
|
1218
|
+
Jinja2's ``tojson`` does, and it is why the result is marked SafeString.
|
|
1219
|
+
|
|
1220
|
+
U+2028 and U+2029 join that escape set. Both are legal inside a JSON string
|
|
1221
|
+
and both were illegal inside a JavaScript string literal before ES2019, so an
|
|
1222
|
+
unescaped one turns a valid payload into a SyntaxError on an older engine.
|
|
1223
|
+
|
|
1224
|
+
``ensure_ascii=False`` keeps non-ASCII text as itself. PHP, Ruby and Node all
|
|
1225
|
+
emit raw UTF-8; Python was the only one escaping to ``\\uXXXX``, so the four
|
|
1226
|
+
disagreed byte-for-byte on any accented character. Raw wins on ADR-0004 -- it
|
|
1227
|
+
is shorter, readable, and still valid JSON.
|
|
1228
|
+
|
|
1229
|
+
The sanitising walk runs ONLY on the failure path, so a well-formed payload
|
|
1230
|
+
pays nothing beyond the escape pass.
|
|
1231
|
+
"""
|
|
1232
|
+
try:
|
|
1233
|
+
# allow_nan=False turns a non-finite into a raised ValueError instead of
|
|
1234
|
+
# a bare Infinity token, so the happy path stays a single dumps() call.
|
|
1235
|
+
text = json.dumps(
|
|
1236
|
+
value, separators=(",", ":"), allow_nan=False, ensure_ascii=False, default=str
|
|
1237
|
+
)
|
|
1238
|
+
except (ValueError, TypeError):
|
|
1239
|
+
text = json.dumps(
|
|
1240
|
+
_json_sanitize(value), separators=(",", ":"), ensure_ascii=False, default=str
|
|
1241
|
+
)
|
|
1242
|
+
return SafeString(
|
|
1243
|
+
text.replace("<", "\\u003c")
|
|
1244
|
+
.replace(">", "\\u003e")
|
|
1245
|
+
.replace("&", "\\u0026")
|
|
1246
|
+
.replace("'", "\\u0027")
|
|
1247
|
+
.replace("\u2028", "\\u2028")
|
|
1248
|
+
.replace("\u2029", "\\u2029")
|
|
1249
|
+
)
|
|
1250
|
+
|
|
1251
|
+
|
|
1252
|
+
def _json_sanitize(value):
|
|
1253
|
+
"""Replace anything json.dumps refuses with a JSON-representable stand-in.
|
|
1254
|
+
|
|
1255
|
+
Only reached when the happy path raised. Non-finite floats become ``None``
|
|
1256
|
+
(the JSON spec has no Infinity/NaN); anything else unencodable is left for
|
|
1257
|
+
``default=str`` to stringify.
|
|
1258
|
+
"""
|
|
1259
|
+
if isinstance(value, float):
|
|
1260
|
+
return value if math.isfinite(value) else None
|
|
1261
|
+
if isinstance(value, dict):
|
|
1262
|
+
return {k: _json_sanitize(v) for k, v in value.items()}
|
|
1263
|
+
if isinstance(value, (list, tuple)):
|
|
1264
|
+
return [_json_sanitize(v) for v in value]
|
|
1265
|
+
return value
|
|
1266
|
+
|
|
1267
|
+
|
|
1190
1268
|
_BUILTIN_FILTERS = {
|
|
1191
1269
|
"upper": lambda v, *a: str(v).upper(),
|
|
1192
1270
|
"lower": lambda v, *a: str(v).lower(),
|
|
@@ -1220,9 +1298,9 @@ _BUILTIN_FILTERS = {
|
|
|
1220
1298
|
"int": lambda v, *a: int(v) if v else 0,
|
|
1221
1299
|
"float": lambda v, *a: float(v) if v else 0.0,
|
|
1222
1300
|
"string": lambda v, *a: str(v),
|
|
1223
|
-
"json_encode": lambda v, *a:
|
|
1224
|
-
"to_json": lambda v, *a:
|
|
1225
|
-
"tojson": lambda v, *a:
|
|
1301
|
+
"json_encode": lambda v, *a: _json_safe(v),
|
|
1302
|
+
"to_json": lambda v, *a: _json_safe(v),
|
|
1303
|
+
"tojson": lambda v, *a: _json_safe(v),
|
|
1226
1304
|
"js_escape": lambda v, *a: SafeString(str(v).replace("\\", "\\\\").replace("'", "\\'").replace('"', '\\"').replace("\n", "\\n").replace("\r", "\\r")),
|
|
1227
1305
|
"json_decode": lambda v, *a: json.loads(v) if isinstance(v, str) else v,
|
|
1228
1306
|
"keys": lambda v, *a: list(v.keys()) if isinstance(v, dict) else [],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.87 → tina4_python-3.13.88}/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
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/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.87 → tina4_python-3.13.88}/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
|
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/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.87 → tina4_python-3.13.88}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.87 → tina4_python-3.13.88}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|