tina4-python 3.13.2__tar.gz → 3.13.3__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.2 → tina4_python-3.13.3}/PKG-INFO +1 -1
- {tina4_python-3.13.2 → tina4_python-3.13.3}/pyproject.toml +1 -1
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/__init__.py +4 -1
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/debug/__init__.py +51 -0
- tina4_python-3.13.3/tina4_python/env.py +111 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/.gitignore +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/README.md +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/js/tina4-dev-admin.js +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -8,7 +8,7 @@ Tina4 Python v3.0 — Zero-dependency, lightweight web framework.
|
|
|
8
8
|
|
|
9
9
|
One import, everything works.
|
|
10
10
|
"""
|
|
11
|
-
__version__ = "3.13.
|
|
11
|
+
__version__ = "3.13.3"
|
|
12
12
|
|
|
13
13
|
# ── Route decorators ──
|
|
14
14
|
from tina4_python.core.router import ( # noqa: E402, F401
|
|
@@ -42,6 +42,9 @@ from tina4_python.orm import ( # noqa: E402, F401
|
|
|
42
42
|
has_many, has_one, belongs_to, # relationship descriptors
|
|
43
43
|
)
|
|
44
44
|
|
|
45
|
+
# ── Env (typed env-var helpers) ──
|
|
46
|
+
from tina4_python.env import Env # noqa: E402, F401
|
|
47
|
+
|
|
45
48
|
# ── Auth ──
|
|
46
49
|
from tina4_python.auth import Auth # noqa: E402, F401
|
|
47
50
|
|
|
@@ -320,10 +320,57 @@ class Log:
|
|
|
320
320
|
now = datetime.now(timezone.utc)
|
|
321
321
|
return now.strftime("%Y-%m-%dT%H:%M:%S.") + f"{now.microsecond // 1000:03d}Z"
|
|
322
322
|
|
|
323
|
+
# Frame names that belong to Log itself — walk past them when looking
|
|
324
|
+
# for the real caller. Kept as a class attribute so subclasses can
|
|
325
|
+
# extend if they layer extra wrappers (and so tests can introspect).
|
|
326
|
+
_OWN_FRAMES = frozenset({
|
|
327
|
+
"_caller_name", "_format_line", "_format", "_log",
|
|
328
|
+
"debug", "info", "warning", "error", "critical",
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
@classmethod
|
|
332
|
+
def _caller_name(cls) -> str | None:
|
|
333
|
+
"""Return the function name that called Log.{debug,info,warning,error}.
|
|
334
|
+
|
|
335
|
+
Active only when ``TINA4_LOG_FUNC=true`` — the lookup uses
|
|
336
|
+
``inspect.currentframe()`` which is ~5% overhead per log call.
|
|
337
|
+
Walks past Log's own frames (``_OWN_FRAMES``) to land on the
|
|
338
|
+
real caller, so the count is robust whether the test calls
|
|
339
|
+
``_format_line`` directly or goes through ``Log.info`` →
|
|
340
|
+
``_log`` → ``_format_line``. Returns ``None`` if the stack is
|
|
341
|
+
too shallow (e.g. log called from module import) or if anything
|
|
342
|
+
goes wrong — never raises. Parity feature #41 across all four
|
|
343
|
+
Tina4 frameworks.
|
|
344
|
+
"""
|
|
345
|
+
import os
|
|
346
|
+
if os.environ.get("TINA4_LOG_FUNC", "").strip().lower() not in (
|
|
347
|
+
"1", "true", "on", "yes", "y", "t"
|
|
348
|
+
):
|
|
349
|
+
return None
|
|
350
|
+
try:
|
|
351
|
+
import inspect
|
|
352
|
+
frame = inspect.currentframe()
|
|
353
|
+
# Walk past Log's own frames. Cap the walk at 16 to defend
|
|
354
|
+
# against any pathological recursion / wrapper stack.
|
|
355
|
+
for _ in range(16):
|
|
356
|
+
if frame is None:
|
|
357
|
+
return None
|
|
358
|
+
name = frame.f_code.co_name
|
|
359
|
+
if name not in cls._OWN_FRAMES:
|
|
360
|
+
# Filter out anonymous / module-level callers — they're noise.
|
|
361
|
+
if name in ("<module>", "<lambda>", "<genexpr>", "<listcomp>", "<setcomp>", "<dictcomp>"):
|
|
362
|
+
return None
|
|
363
|
+
return name
|
|
364
|
+
frame = frame.f_back
|
|
365
|
+
return None
|
|
366
|
+
except Exception:
|
|
367
|
+
return None
|
|
368
|
+
|
|
323
369
|
@classmethod
|
|
324
370
|
def _format_line(cls, level: str, message: str, **kwargs) -> str:
|
|
325
371
|
timestamp = cls._timestamp()
|
|
326
372
|
request_id = get_request_id()
|
|
373
|
+
caller = cls._caller_name()
|
|
327
374
|
|
|
328
375
|
# JSON format wins whenever the explicit env opt-in is set,
|
|
329
376
|
# regardless of production flag (so dev devs can ship JSON to
|
|
@@ -336,6 +383,8 @@ class Log:
|
|
|
336
383
|
}
|
|
337
384
|
if request_id:
|
|
338
385
|
entry["request_id"] = request_id
|
|
386
|
+
if caller:
|
|
387
|
+
entry["function"] = caller
|
|
339
388
|
if kwargs:
|
|
340
389
|
entry["context"] = {k: v for k, v in kwargs.items()}
|
|
341
390
|
return json.dumps(entry, default=str)
|
|
@@ -345,6 +394,8 @@ class Log:
|
|
|
345
394
|
parts = [timestamp, f"[{level_str}]"]
|
|
346
395
|
if request_id:
|
|
347
396
|
parts.append(f"[{request_id}]")
|
|
397
|
+
if caller:
|
|
398
|
+
parts.append(f"[{caller}]")
|
|
348
399
|
parts.append(message)
|
|
349
400
|
if kwargs:
|
|
350
401
|
parts.append(json.dumps(kwargs, default=str))
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Tina4 Env — Typed environment-variable helpers.
|
|
2
|
+
# Copyright 2007 - present Tina4
|
|
3
|
+
# License: MIT
|
|
4
|
+
"""Typed environment-variable helpers — zero-deps.
|
|
5
|
+
|
|
6
|
+
Reading env vars by hand gets old fast: every boolean flag becomes a
|
|
7
|
+
``os.getenv("TINA4_DEBUG", "false").lower() in ("1", "true", "on", "yes")``
|
|
8
|
+
incantation. Every numeric tuning knob needs a try/except around int().
|
|
9
|
+
Env centralises that. Same API across all four Tina4 frameworks
|
|
10
|
+
(``Tina4\\Env`` in PHP, ``Tina4::Env`` in Ruby, ``Env`` in Node.js).
|
|
11
|
+
|
|
12
|
+
from tina4_python import Env
|
|
13
|
+
|
|
14
|
+
debug = Env.bool("TINA4_DEBUG", default=False)
|
|
15
|
+
workers = Env.int("WORKERS", default=4)
|
|
16
|
+
rate = Env.float("RATE_LIMIT", default=10.0)
|
|
17
|
+
region = Env.str("AWS_REGION", default="us-east-1")
|
|
18
|
+
|
|
19
|
+
Values are accepted case-insensitively after ``strip()``. Truthy:
|
|
20
|
+
``1 / true / on / yes / y / t``. Falsy: ``0 / false / off / no / n / f``.
|
|
21
|
+
Any other value triggers the ``default``. Unparseable ints and floats
|
|
22
|
+
log a warning via ``Log`` and fall back to ``default`` — never raise.
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import os
|
|
27
|
+
|
|
28
|
+
# Lazy import so ``import tina4_python.env`` doesn't drag the whole Log
|
|
29
|
+
# chain in for callers who don't want it (CLI scaffolding, etc).
|
|
30
|
+
_TRUTHY = frozenset({"1", "true", "on", "yes", "y", "t"})
|
|
31
|
+
_FALSY = frozenset({"0", "false", "off", "no", "n", "f", ""})
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _log_warning(message: str) -> None:
|
|
35
|
+
"""Emit a warning via Log without creating a circular import at module load."""
|
|
36
|
+
try:
|
|
37
|
+
from tina4_python.debug import Log
|
|
38
|
+
Log.warning(message)
|
|
39
|
+
except Exception:
|
|
40
|
+
# Log not yet wired (e.g. very early bootstrap) — silently skip.
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Env:
|
|
45
|
+
"""Typed environment-variable helpers.
|
|
46
|
+
|
|
47
|
+
All methods are classmethods so callers can write ``Env.bool(...)``
|
|
48
|
+
without instantiating anything — matching the PHP/Ruby/Node ports.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def bool(cls, name: str, default: bool = False) -> bool:
|
|
53
|
+
"""Read ``name`` and coerce to bool.
|
|
54
|
+
|
|
55
|
+
Truthy values (case-insensitive after strip): ``1``, ``true``,
|
|
56
|
+
``on``, ``yes``, ``y``, ``t``. Falsy: ``0``, ``false``, ``off``,
|
|
57
|
+
``no``, ``n``, ``f``, empty string. Anything else returns the
|
|
58
|
+
``default`` — never raises.
|
|
59
|
+
"""
|
|
60
|
+
raw = os.environ.get(name)
|
|
61
|
+
if raw is None:
|
|
62
|
+
return default
|
|
63
|
+
token = raw.strip().lower()
|
|
64
|
+
if token in _TRUTHY:
|
|
65
|
+
return True
|
|
66
|
+
if token in _FALSY:
|
|
67
|
+
return False
|
|
68
|
+
return default
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def int(cls, name: str, default: int = 0) -> int:
|
|
72
|
+
"""Read ``name`` and coerce to int. Returns ``default`` on parse failure."""
|
|
73
|
+
raw = os.environ.get(name)
|
|
74
|
+
if raw is None:
|
|
75
|
+
return default
|
|
76
|
+
try:
|
|
77
|
+
return int(raw.strip())
|
|
78
|
+
except (ValueError, TypeError):
|
|
79
|
+
_log_warning(
|
|
80
|
+
f"Env.int({name!r}): could not parse {raw!r} as int — "
|
|
81
|
+
f"using default {default!r}"
|
|
82
|
+
)
|
|
83
|
+
return default
|
|
84
|
+
|
|
85
|
+
@classmethod
|
|
86
|
+
def float(cls, name: str, default: float = 0.0) -> float:
|
|
87
|
+
"""Read ``name`` and coerce to float. Returns ``default`` on parse failure."""
|
|
88
|
+
raw = os.environ.get(name)
|
|
89
|
+
if raw is None:
|
|
90
|
+
return default
|
|
91
|
+
try:
|
|
92
|
+
return float(raw.strip())
|
|
93
|
+
except (ValueError, TypeError):
|
|
94
|
+
_log_warning(
|
|
95
|
+
f"Env.float({name!r}): could not parse {raw!r} as float — "
|
|
96
|
+
f"using default {default!r}"
|
|
97
|
+
)
|
|
98
|
+
return default
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def str(cls, name: str, default: str = "") -> str:
|
|
102
|
+
"""Read ``name`` as a string. Returns ``default`` if unset.
|
|
103
|
+
|
|
104
|
+
Whitespace is preserved — this is a pass-through for the raw env
|
|
105
|
+
value. ``Env.str("PATH")`` is exactly ``os.environ.get("PATH", "")``
|
|
106
|
+
with a more discoverable name.
|
|
107
|
+
"""
|
|
108
|
+
raw = os.environ.get(name)
|
|
109
|
+
if raw is None:
|
|
110
|
+
return default
|
|
111
|
+
return raw
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.2 → tina4_python-3.13.3}/tina4_python/gallery/auth/src/routes/api/gallery_auth.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
|
|
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.2 → tina4_python-3.13.3}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.2 → tina4_python-3.13.3}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/templates/docker/distroless/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
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.2 → tina4_python-3.13.3}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|