tina4-python 3.10.38__tar.gz → 3.10.39__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.10.38 → tina4_python-3.10.39}/PKG-INFO +1 -1
- {tina4_python-3.10.38 → tina4_python-3.10.39}/pyproject.toml +1 -1
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/auth/__init__.py +47 -6
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/cli/__init__.py +1 -1
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/router.py +7 -2
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/server.py +3 -3
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/dev_admin/__init__.py +2 -2
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/orm/model.py +12 -2
- {tina4_python-3.10.38 → tina4_python-3.10.39}/.gitignore +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/README.md +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/Testing.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/events.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/request.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/core/response.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/dev_reload.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -14,7 +14,7 @@ No PyJWT, no cryptography package.
|
|
|
14
14
|
payload = auth.valid_token(token)
|
|
15
15
|
|
|
16
16
|
hashed = Auth.hash_password("secret123")
|
|
17
|
-
Auth.check_password(
|
|
17
|
+
Auth.check_password("secret123", hashed) # True
|
|
18
18
|
"""
|
|
19
19
|
import os
|
|
20
20
|
import hmac
|
|
@@ -152,6 +152,25 @@ class Auth:
|
|
|
152
152
|
auth = cls(secret=secret, expires_in=expires_in)
|
|
153
153
|
return auth.refresh_token(token)
|
|
154
154
|
|
|
155
|
+
@classmethod
|
|
156
|
+
def authenticate_request_static(cls, headers: dict) -> dict | None:
|
|
157
|
+
"""Extract and validate auth from request headers without instantiating Auth.
|
|
158
|
+
|
|
159
|
+
Reads SECRET from env. Checks: Bearer JWT, Bearer API key, Basic auth.
|
|
160
|
+
Returns payload dict on success, None on failure.
|
|
161
|
+
"""
|
|
162
|
+
secret = os.environ.get("SECRET", "tina4-default-secret")
|
|
163
|
+
auth = cls(secret=secret)
|
|
164
|
+
return auth.authenticate_request(headers)
|
|
165
|
+
|
|
166
|
+
@staticmethod
|
|
167
|
+
def validate_api_key_static(provided: str, expected: str = None) -> bool:
|
|
168
|
+
"""Validate an API key without instantiating Auth.
|
|
169
|
+
|
|
170
|
+
Alias for validate_api_key (already a staticmethod).
|
|
171
|
+
"""
|
|
172
|
+
return Auth.validate_api_key(provided, expected)
|
|
173
|
+
|
|
155
174
|
# ── Password Hashing ──────────────────────────────────────────
|
|
156
175
|
|
|
157
176
|
@staticmethod
|
|
@@ -164,7 +183,7 @@ class Auth:
|
|
|
164
183
|
return f"pbkdf2_sha256${iterations}${salt}${dk.hex()}"
|
|
165
184
|
|
|
166
185
|
@staticmethod
|
|
167
|
-
def check_password(
|
|
186
|
+
def check_password(password: str, hashed: str) -> bool:
|
|
168
187
|
"""Verify a password against its PBKDF2 hash."""
|
|
169
188
|
try:
|
|
170
189
|
parts = hashed.split("$")
|
|
@@ -183,9 +202,18 @@ class Auth:
|
|
|
183
202
|
# ── API Key Auth ──────────────────────────────────────────────
|
|
184
203
|
|
|
185
204
|
@staticmethod
|
|
186
|
-
def validate_api_key(provided: str) -> bool:
|
|
187
|
-
"""Check
|
|
188
|
-
|
|
205
|
+
def validate_api_key(provided: str, expected: str = None) -> bool:
|
|
206
|
+
"""Check an API key against an expected value.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
provided: The API key provided in the request.
|
|
210
|
+
expected: The expected API key. If None, reads from
|
|
211
|
+
TINA4_API_KEY env var (falls back to API_KEY).
|
|
212
|
+
|
|
213
|
+
Returns: True if the provided key matches.
|
|
214
|
+
"""
|
|
215
|
+
if expected is None:
|
|
216
|
+
expected = os.environ.get("TINA4_API_KEY", os.environ.get("API_KEY", ""))
|
|
189
217
|
if not expected:
|
|
190
218
|
return False
|
|
191
219
|
return hmac.compare_digest(provided, expected)
|
|
@@ -255,4 +283,17 @@ def refresh_token(token: str, expires_in: int = 60) -> str | None:
|
|
|
255
283
|
return Auth.refresh_token_static(token, expires_in=expires_in)
|
|
256
284
|
|
|
257
285
|
|
|
258
|
-
|
|
286
|
+
def authenticate_request(headers: dict) -> dict | None:
|
|
287
|
+
"""Validate auth from request headers — reads SECRET from env."""
|
|
288
|
+
return Auth.authenticate_request_static(headers)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def validate_api_key(provided: str, expected: str = None) -> bool:
|
|
292
|
+
"""Validate an API key. Shortcut for Auth.validate_api_key()."""
|
|
293
|
+
return Auth.validate_api_key(provided, expected)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
__all__ = [
|
|
297
|
+
"Auth", "get_token", "valid_token", "get_payload", "refresh_token",
|
|
298
|
+
"authenticate_request", "validate_api_key",
|
|
299
|
+
]
|
|
@@ -231,8 +231,13 @@ class Router:
|
|
|
231
231
|
return None, {}
|
|
232
232
|
|
|
233
233
|
@staticmethod
|
|
234
|
-
def
|
|
235
|
-
"""Return all registered routes
|
|
234
|
+
def get_routes() -> list[dict]:
|
|
235
|
+
"""Return all registered routes."""
|
|
236
|
+
return _routes
|
|
237
|
+
|
|
238
|
+
@staticmethod
|
|
239
|
+
def list_routes() -> list[dict]:
|
|
240
|
+
"""Return all registered routes (debug-friendly)."""
|
|
236
241
|
return _routes
|
|
237
242
|
|
|
238
243
|
@staticmethod
|
|
@@ -757,7 +757,7 @@ async def app(scope: dict, receive, send):
|
|
|
757
757
|
# Serve OpenAPI spec JSON from all registered routes
|
|
758
758
|
from tina4_python.swagger import Swagger as _SwaggerGen
|
|
759
759
|
_swagger = _SwaggerGen()
|
|
760
|
-
_spec = _swagger.generate(Router.
|
|
760
|
+
_spec = _swagger.generate(Router.get_routes())
|
|
761
761
|
response.json(_spec)
|
|
762
762
|
_cors.apply(request, response)
|
|
763
763
|
headers = response.build_headers("")
|
|
@@ -929,7 +929,7 @@ async def app(scope: dict, receive, send):
|
|
|
929
929
|
matched_pattern = route["path"] if route else "-"
|
|
930
930
|
toolbar = render_dev_toolbar(
|
|
931
931
|
request.method, request.path, matched_pattern,
|
|
932
|
-
request_id, len(Router.
|
|
932
|
+
request_id, len(Router.get_routes()),
|
|
933
933
|
).encode()
|
|
934
934
|
content = response.content
|
|
935
935
|
# Inject before </body> if present, else append
|
|
@@ -1216,7 +1216,7 @@ def run(host: str | None = None, port: int | None = None):
|
|
|
1216
1216
|
|
|
1217
1217
|
# Auto-discover routes
|
|
1218
1218
|
_auto_discover("src")
|
|
1219
|
-
route_count = len(Router.
|
|
1219
|
+
route_count = len(Router.get_routes())
|
|
1220
1220
|
Log.info(f"Discovered {route_count} routes")
|
|
1221
1221
|
|
|
1222
1222
|
# Resolve host/port (CLI arg > ENV > default)
|
|
@@ -309,7 +309,7 @@ async def _api_routes(request, response):
|
|
|
309
309
|
try:
|
|
310
310
|
from tina4_python.core.router import Router
|
|
311
311
|
internal_prefixes = ("/__dev", "/health", "/swagger")
|
|
312
|
-
routes = Router.
|
|
312
|
+
routes = Router.get_routes()
|
|
313
313
|
result = []
|
|
314
314
|
for r in routes:
|
|
315
315
|
path = r.get("path", "")
|
|
@@ -926,7 +926,7 @@ async def _api_tool(request, response):
|
|
|
926
926
|
"test": [sys.executable, "-m", "pytest", "tests/", "-q", "--tb=short"],
|
|
927
927
|
"routes": [sys.executable, "-c",
|
|
928
928
|
"from tina4_python.core.router import Router; "
|
|
929
|
-
"[print(f\"{r['method']:7} {r['path']}\") for r in Router.
|
|
929
|
+
"[print(f\"{r['method']:7} {r['path']}\") for r in Router.get_routes()]"],
|
|
930
930
|
"migrate": [sys.executable, "-c",
|
|
931
931
|
"from tina4_python.cli import _migrate; _migrate([])"],
|
|
932
932
|
"seed": [sys.executable, "-c",
|
|
@@ -318,7 +318,7 @@ class ORM(metaclass=ORMMeta):
|
|
|
318
318
|
# ── Finders ─────────────────────────────────────────────────
|
|
319
319
|
|
|
320
320
|
@classmethod
|
|
321
|
-
def
|
|
321
|
+
def find_by_id(cls, pk_value, include: list[str] = None):
|
|
322
322
|
"""Find a single record by primary key. Returns instance or None.
|
|
323
323
|
|
|
324
324
|
Args:
|
|
@@ -342,10 +342,20 @@ class ORM(metaclass=ORMMeta):
|
|
|
342
342
|
cls._eager_load([instance], include)
|
|
343
343
|
return instance
|
|
344
344
|
|
|
345
|
+
@classmethod
|
|
346
|
+
def find(cls, pk_value, include: list[str] = None):
|
|
347
|
+
"""Alias for find_by_id()."""
|
|
348
|
+
return cls.find_by_id(pk_value, include)
|
|
349
|
+
|
|
350
|
+
@classmethod
|
|
351
|
+
def load(cls, pk_value, include: list[str] = None):
|
|
352
|
+
"""Alias for find_by_id()."""
|
|
353
|
+
return cls.find_by_id(pk_value, include)
|
|
354
|
+
|
|
345
355
|
@classmethod
|
|
346
356
|
def find_or_fail(cls, pk_value):
|
|
347
357
|
"""Find by primary key or raise ValueError."""
|
|
348
|
-
result = cls.
|
|
358
|
+
result = cls.find_by_id(pk_value)
|
|
349
359
|
if result is None:
|
|
350
360
|
raise ValueError(f"{cls.__name__} with {cls._get_pk()}={pk_value} not found")
|
|
351
361
|
return result
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.10.38 → tina4_python-3.10.39}/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
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/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
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/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
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/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
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.38 → tina4_python-3.10.39}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|