tina4-python 3.10.50__tar.gz → 3.10.54__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.50 → tina4_python-3.10.54}/PKG-INFO +1 -1
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/__init__.py +1 -1
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/cli/__init__.py +5 -2
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/server.py +48 -9
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/firebird.py +1 -1
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/dev_admin/__init__.py +4 -2
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/orm/model.py +11 -1
- {tina4_python-3.10.50 → tina4_python-3.10.54}/.gitignore +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/README.md +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/pyproject.toml +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/Testing.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/events.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/request.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/response.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/core/router.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/dev_reload.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -156,7 +156,7 @@ Usage: tina4python <command> [options]
|
|
|
156
156
|
|
|
157
157
|
Commands:
|
|
158
158
|
init [dir] Scaffold a new project
|
|
159
|
-
serve [--port P] [--no-browser] Start dev server (default: 0.0.0.0:7146)
|
|
159
|
+
serve [--port P] [--no-browser] [--no-reload] Start dev server (default: 0.0.0.0:7146)
|
|
160
160
|
migrate Run pending database migrations
|
|
161
161
|
migrate:create <desc> Create a new migration file
|
|
162
162
|
migrate:rollback Rollback last migration batch
|
|
@@ -327,12 +327,15 @@ def _serve(args):
|
|
|
327
327
|
if os.environ.get("TINA4_OPEN_BROWSER", "").lower() in ("false", "0", "no"):
|
|
328
328
|
no_browser = True
|
|
329
329
|
|
|
330
|
+
# --no-reload flag
|
|
331
|
+
no_reload = "no-reload" in flags
|
|
332
|
+
|
|
330
333
|
# Kill existing process on port
|
|
331
334
|
port = cli_port or int(os.environ.get("PORT", os.environ.get("TINA4_PORT", "7146")))
|
|
332
335
|
_kill_process_on_port(port)
|
|
333
336
|
|
|
334
337
|
from tina4_python.core import run
|
|
335
|
-
run(host=cli_host, port=cli_port, no_browser=no_browser)
|
|
338
|
+
run(host=cli_host, port=cli_port, no_browser=no_browser, no_reload=no_reload)
|
|
336
339
|
|
|
337
340
|
|
|
338
341
|
# ── Migrate ───────────────────────────────────────────────────────────
|
|
@@ -9,6 +9,7 @@ import os
|
|
|
9
9
|
import sys
|
|
10
10
|
import signal
|
|
11
11
|
import asyncio
|
|
12
|
+
import contextvars
|
|
12
13
|
import importlib
|
|
13
14
|
import uuid
|
|
14
15
|
from pathlib import Path
|
|
@@ -25,6 +26,9 @@ _cors = CorsMiddleware()
|
|
|
25
26
|
_rate_limiter = RateLimiter()
|
|
26
27
|
|
|
27
28
|
|
|
29
|
+
# ContextVar to signal that the current request is being served on the AI dev port
|
|
30
|
+
_ai_port_ctx: contextvars.ContextVar[bool] = contextvars.ContextVar("_ai_port_ctx", default=False)
|
|
31
|
+
|
|
28
32
|
# Track startup time
|
|
29
33
|
_start_time: float = 0
|
|
30
34
|
|
|
@@ -1222,7 +1226,7 @@ def resolve_config(cli_host: str | None = None, cli_port: int | None = None) ->
|
|
|
1222
1226
|
return host, port
|
|
1223
1227
|
|
|
1224
1228
|
|
|
1225
|
-
def _print_banner(host: str, port: int, server_name: str = "asyncio"):
|
|
1229
|
+
def _print_banner(host: str, port: int, server_name: str = "asyncio", ai_port: int | None = None):
|
|
1226
1230
|
"""Print the Tina4 Slant ASCII banner to stdout (not through the logger)."""
|
|
1227
1231
|
from tina4_python.dotenv import is_truthy
|
|
1228
1232
|
|
|
@@ -1234,6 +1238,8 @@ def _print_banner(host: str, port: int, server_name: str = "asyncio"):
|
|
|
1234
1238
|
color = "\033[34m" if sys.stdout.isatty() else ""
|
|
1235
1239
|
reset = "\033[0m" if sys.stdout.isatty() else ""
|
|
1236
1240
|
|
|
1241
|
+
ai_port_line = f"\n AI Port: http://{display}:{ai_port} (no-reload)" if ai_port else ""
|
|
1242
|
+
|
|
1237
1243
|
banner = f"""{color}
|
|
1238
1244
|
______ _ __ __
|
|
1239
1245
|
/_ __/(_)___ ____ _/ // /
|
|
@@ -1246,12 +1252,12 @@ def _print_banner(host: str, port: int, server_name: str = "asyncio"):
|
|
|
1246
1252
|
Server: http://{display}:{port} ({server_name})
|
|
1247
1253
|
Swagger: http://localhost:{port}/swagger
|
|
1248
1254
|
Dashboard: http://localhost:{port}/__dev
|
|
1249
|
-
Debug: {"ON" if is_debug else "OFF"} (Log level: {log_level})
|
|
1255
|
+
Debug: {"ON" if is_debug else "OFF"} (Log level: {log_level}){ai_port_line}
|
|
1250
1256
|
"""
|
|
1251
1257
|
print(banner)
|
|
1252
1258
|
|
|
1253
1259
|
|
|
1254
|
-
def run(host: str | None = None, port: int | None = None, no_browser: bool = False):
|
|
1260
|
+
def run(host: str | None = None, port: int | None = None, no_browser: bool = False, no_reload: bool = False):
|
|
1255
1261
|
"""Start the Tina4 dev server.
|
|
1256
1262
|
|
|
1257
1263
|
Discovers routes from src/, starts ASGI server, handles shutdown.
|
|
@@ -1260,11 +1266,15 @@ def run(host: str | None = None, port: int | None = None, no_browser: bool = Fal
|
|
|
1260
1266
|
host: Bind address. Falls back to HOST env var, then 0.0.0.0.
|
|
1261
1267
|
port: Bind port. Falls back to PORT env var, then 7146.
|
|
1262
1268
|
no_browser: If True, do not open browser on startup.
|
|
1269
|
+
no_reload: If True, disable the file watcher / live-reload.
|
|
1263
1270
|
"""
|
|
1264
1271
|
import time
|
|
1265
1272
|
global _start_time
|
|
1266
1273
|
_start_time = time.time()
|
|
1267
1274
|
|
|
1275
|
+
if no_reload:
|
|
1276
|
+
os.environ["TINA4_NO_RELOAD"] = "true"
|
|
1277
|
+
|
|
1268
1278
|
# Ensure CWD is on sys.path so auto-discovered modules can be imported
|
|
1269
1279
|
cwd = os.getcwd()
|
|
1270
1280
|
if cwd not in sys.path:
|
|
@@ -1302,11 +1312,13 @@ def run(host: str | None = None, port: int | None = None, no_browser: bool = Fal
|
|
|
1302
1312
|
|
|
1303
1313
|
# Start DevReload file watcher in debug mode
|
|
1304
1314
|
if is_debug:
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1315
|
+
no_reload = os.environ.get("TINA4_NO_RELOAD", "").lower() in ("true", "1", "yes")
|
|
1316
|
+
if not no_reload:
|
|
1317
|
+
try:
|
|
1318
|
+
from tina4_python.dev_reload import start as _start_dev_reload
|
|
1319
|
+
_start_dev_reload(["src", "public"])
|
|
1320
|
+
except Exception as e:
|
|
1321
|
+
Log.error(f"DevReload: failed to start: {e}")
|
|
1310
1322
|
|
|
1311
1323
|
prod = None
|
|
1312
1324
|
if not is_debug:
|
|
@@ -1314,11 +1326,17 @@ def run(host: str | None = None, port: int | None = None, no_browser: bool = Fal
|
|
|
1314
1326
|
|
|
1315
1327
|
server_name = prod[0] if prod else "asyncio"
|
|
1316
1328
|
|
|
1329
|
+
# Determine AI dev port (port+1) when debug is on and not suppressed
|
|
1330
|
+
_no_ai_port = os.environ.get("TINA4_NO_AI_PORT", "").lower() in ("true", "1", "yes")
|
|
1331
|
+
_ai_port = (port + 1) if (is_debug and not _no_ai_port) else None
|
|
1332
|
+
|
|
1317
1333
|
# Banner — printed directly to stdout, not through the logger
|
|
1318
|
-
_print_banner(host, port, server_name)
|
|
1334
|
+
_print_banner(host, port, server_name, ai_port=_ai_port)
|
|
1319
1335
|
|
|
1320
1336
|
display = "localhost" if host in ("0.0.0.0", "::") else host
|
|
1321
1337
|
Log.info(f"Server started http://{display}:{port} ({server_name})")
|
|
1338
|
+
if _ai_port:
|
|
1339
|
+
Log.info(f"AI dev port: http://{display}:{_ai_port} (no-reload)")
|
|
1322
1340
|
|
|
1323
1341
|
# Open browser after a short delay (unless --no-browser)
|
|
1324
1342
|
_skip_browser = no_browser or os.environ.get("TINA4_NO_BROWSER", "").lower() in ("true", "1", "yes")
|
|
@@ -1387,6 +1405,11 @@ def run(host: str | None = None, port: int | None = None, no_browser: bool = Fal
|
|
|
1387
1405
|
# Check for WebSocket upgrade before reading body
|
|
1388
1406
|
_header_dict = {k.decode(): v.decode() for k, v in headers}
|
|
1389
1407
|
if _header_dict.get("upgrade", "").lower() == "websocket":
|
|
1408
|
+
if hasattr(writer, "_tina4_ai_port") and path == "/__dev_reload":
|
|
1409
|
+
writer.write(b"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n")
|
|
1410
|
+
await writer.drain()
|
|
1411
|
+
writer.close()
|
|
1412
|
+
return
|
|
1390
1413
|
await _handle_dev_websocket(reader, writer, _header_dict, path)
|
|
1391
1414
|
return
|
|
1392
1415
|
|
|
@@ -1441,6 +1464,19 @@ def run(host: str | None = None, port: int | None = None, no_browser: bool = Fal
|
|
|
1441
1464
|
|
|
1442
1465
|
server = await start_server(_handle_connection, host, port)
|
|
1443
1466
|
|
|
1467
|
+
# AI dev port (port + 1) — no-reload, no live-reload WebSocket
|
|
1468
|
+
ai_server = None
|
|
1469
|
+
if _ai_port:
|
|
1470
|
+
try:
|
|
1471
|
+
async def _handle_ai_connection(reader, writer):
|
|
1472
|
+
_ai_port_ctx.set(True)
|
|
1473
|
+
writer._tina4_ai_port = True
|
|
1474
|
+
await _handle_connection(reader, writer)
|
|
1475
|
+
|
|
1476
|
+
ai_server = await start_server(_handle_ai_connection, host, _ai_port)
|
|
1477
|
+
except OSError:
|
|
1478
|
+
Log.warning(f"AI port {_ai_port} in use — skipping")
|
|
1479
|
+
|
|
1444
1480
|
loop = asyncio.get_running_loop()
|
|
1445
1481
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
|
1446
1482
|
try:
|
|
@@ -1449,6 +1485,9 @@ def run(host: str | None = None, port: int | None = None, no_browser: bool = Fal
|
|
|
1449
1485
|
pass # Windows
|
|
1450
1486
|
|
|
1451
1487
|
await shutdown.wait()
|
|
1488
|
+
if ai_server:
|
|
1489
|
+
ai_server.close()
|
|
1490
|
+
await ai_server.wait_closed()
|
|
1452
1491
|
server.close()
|
|
1453
1492
|
await server.wait_closed()
|
|
1454
1493
|
Log.info("Server stopped.")
|
|
@@ -49,7 +49,7 @@ class FirebirdAdapter(DatabaseAdapter):
|
|
|
49
49
|
host = parsed.hostname or "localhost"
|
|
50
50
|
port = parsed.port or 3050
|
|
51
51
|
# Firebird database path — decode URL-encoded characters
|
|
52
|
-
db_path = unquote(parsed.path.
|
|
52
|
+
db_path = unquote(parsed.path[1:]) if parsed.path.startswith("/") else unquote(parsed.path)
|
|
53
53
|
user = parsed.username or username or "SYSDBA"
|
|
54
54
|
password = parsed.password or password or "masterkey"
|
|
55
55
|
charset = kwargs.pop("charset", "UTF8")
|
|
@@ -2447,8 +2447,10 @@ def render_dev_toolbar(method: str, path: str, matched_pattern: str,
|
|
|
2447
2447
|
and a close button.
|
|
2448
2448
|
"""
|
|
2449
2449
|
import sys
|
|
2450
|
+
from tina4_python.core.server import _ai_port_ctx
|
|
2450
2451
|
python_version = sys.version.split()[0]
|
|
2451
2452
|
poll_interval_ms = int(os.environ.get("TINA4_DEV_POLL_INTERVAL", "3000"))
|
|
2453
|
+
no_reload = os.environ.get("TINA4_NO_RELOAD", "").lower() in ("true", "1", "yes") or _ai_port_ctx.get()
|
|
2452
2454
|
|
|
2453
2455
|
return f"""<div id="tina4-dev-toolbar" style="position:fixed;bottom:0;left:0;right:0;background:#333;color:#fff;font-family:monospace;font-size:12px;padding:6px 16px;z-index:99999;display:flex;align-items:center;gap:16px;">
|
|
2454
2456
|
<span id="tina4-ver-btn" style="color:#3572A5;font-weight:bold;cursor:pointer;text-decoration:underline dotted;" onclick="tina4VersionModal()" title="Click to check for updates">Tina4 v{__version__}</span>
|
|
@@ -2472,7 +2474,7 @@ def render_dev_toolbar(method: str, path: str, matched_pattern: str,
|
|
|
2472
2474
|
<span onclick="this.parentElement.style.display='none'" style="cursor:pointer;color:#888;margin-left:8px;">✕</span>
|
|
2473
2475
|
</div>
|
|
2474
2476
|
<script>
|
|
2475
|
-
(function(){{
|
|
2477
|
+
{'(function(){})();' if no_reload else f"""(function(){{
|
|
2476
2478
|
var _t4_mtime=0,_t4_css_exts=['.css','.scss'],_t4_debounce=null;
|
|
2477
2479
|
var _t4_interval=parseInt('{poll_interval_ms}')||3000;
|
|
2478
2480
|
function _t4_apply(d){{
|
|
@@ -2499,7 +2501,7 @@ def render_dev_toolbar(method: str, path: str, matched_pattern: str,
|
|
|
2499
2501
|
}}).catch(function(){{}});
|
|
2500
2502
|
}}
|
|
2501
2503
|
setInterval(_t4_poll,_t4_interval);
|
|
2502
|
-
}})();
|
|
2504
|
+
}})();"""}
|
|
2503
2505
|
function tina4VersionModal(){{
|
|
2504
2506
|
var m=document.getElementById('tina4-ver-modal');
|
|
2505
2507
|
if(m.style.display==='block'){{m.style.display='none';return;}}
|
|
@@ -204,8 +204,18 @@ class ORM(metaclass=ORMMeta):
|
|
|
204
204
|
return cls._db # Direct Database instance
|
|
205
205
|
|
|
206
206
|
if _database is None:
|
|
207
|
+
# Try auto-discovery from DATABASE_URL
|
|
208
|
+
import os
|
|
209
|
+
url = os.environ.get("DATABASE_URL")
|
|
210
|
+
if url:
|
|
211
|
+
from tina4_python.database import Database
|
|
212
|
+
username = os.environ.get("DATABASE_USERNAME", "")
|
|
213
|
+
password = os.environ.get("DATABASE_PASSWORD", "")
|
|
214
|
+
global _database
|
|
215
|
+
_database = Database(url, username, password)
|
|
216
|
+
return _database
|
|
207
217
|
raise RuntimeError(
|
|
208
|
-
"No database bound. Call orm_bind(db)
|
|
218
|
+
"No database bound. Call orm_bind(db) or set DATABASE_URL in .env"
|
|
209
219
|
)
|
|
210
220
|
return _database
|
|
211
221
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.50 → tina4_python-3.10.54}/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.50 → tina4_python-3.10.54}/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.50 → tina4_python-3.10.54}/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.50 → tina4_python-3.10.54}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/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.50 → tina4_python-3.10.54}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.50 → tina4_python-3.10.54}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|