tina4-python 3.6.0__tar.gz → 3.7.1__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.6.0 → tina4_python-3.7.1}/PKG-INFO +1 -1
- {tina4_python-3.6.0 → tina4_python-3.7.1}/pyproject.toml +1 -1
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/server.py +56 -17
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/migration/runner.py +68 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/queue/__init__.py +2 -2
- {tina4_python-3.6.0 → tina4_python-3.7.1}/.gitignore +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/README.md +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/Testing.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/events.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/request.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/response.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/core/router.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/dev_reload.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -136,13 +136,45 @@ def _render_error_page(status_code: int, path: str, request_id: str, error_messa
|
|
|
136
136
|
return None
|
|
137
137
|
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
_template_cache: dict[str, str] | None = None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _resolve_template(path: str) -> str | None:
|
|
143
|
+
"""Resolve a URL path to a template file in src/templates/.
|
|
144
|
+
Dev mode: checks filesystem every time for live changes.
|
|
145
|
+
Production: uses a cached lookup built once at startup.
|
|
146
|
+
"""
|
|
147
|
+
clean_path = path.strip("/") or "index"
|
|
148
|
+
is_dev = os.environ.get("TINA4_DEBUG", "false").lower() in ("true", "1", "yes")
|
|
149
|
+
|
|
150
|
+
if is_dev:
|
|
151
|
+
template_dir = Path("src/templates")
|
|
152
|
+
for ext in (".twig", ".html"):
|
|
153
|
+
candidate = clean_path + ext
|
|
154
|
+
if (template_dir / candidate).is_file():
|
|
155
|
+
return candidate
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
global _template_cache
|
|
159
|
+
if _template_cache is None:
|
|
160
|
+
_build_template_cache()
|
|
161
|
+
return _template_cache.get(clean_path)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _build_template_cache() -> None:
|
|
165
|
+
"""Scan src/templates/ once and build url_path -> template_file lookup."""
|
|
166
|
+
global _template_cache
|
|
167
|
+
_template_cache = {}
|
|
141
168
|
template_dir = Path("src/templates")
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
169
|
+
if not template_dir.is_dir():
|
|
170
|
+
return
|
|
171
|
+
for f in template_dir.rglob("*"):
|
|
172
|
+
if not f.is_file() or f.suffix not in (".twig", ".html"):
|
|
173
|
+
continue
|
|
174
|
+
rel = str(f.relative_to(template_dir)).replace("\\", "/")
|
|
175
|
+
url_path = rel.rsplit(".", 1)[0]
|
|
176
|
+
if url_path not in _template_cache:
|
|
177
|
+
_template_cache[url_path] = rel
|
|
146
178
|
|
|
147
179
|
|
|
148
180
|
def _is_gallery_deployed(name: str) -> bool:
|
|
@@ -779,19 +811,26 @@ async def app(scope: dict, receive, send):
|
|
|
779
811
|
static = _try_static(request.path)
|
|
780
812
|
if static:
|
|
781
813
|
response = static
|
|
782
|
-
elif request.path == "/" and not _has_index_template():
|
|
783
|
-
# No "/" route registered and no index template — show default landing page
|
|
784
|
-
response.html(_render_landing_page())
|
|
785
814
|
else:
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
815
|
+
# Try serving a template file (e.g. /hello -> src/templates/hello.twig or hello.html)
|
|
816
|
+
tpl_file = _resolve_template(request.path)
|
|
817
|
+
if tpl_file:
|
|
818
|
+
from tina4_python.frond import Frond
|
|
819
|
+
frond = Frond()
|
|
820
|
+
html = frond.render(tpl_file, {})
|
|
821
|
+
response.html(html)
|
|
822
|
+
elif request.path == "/":
|
|
823
|
+
response.html(_render_landing_page())
|
|
789
824
|
else:
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
825
|
+
html = _render_error_page(404, request.path, request_id)
|
|
826
|
+
if html:
|
|
827
|
+
response.status(404).html(html)
|
|
828
|
+
else:
|
|
829
|
+
response.status(404).json({
|
|
830
|
+
"error": "Not Found",
|
|
831
|
+
"path": request.path,
|
|
832
|
+
"status": 404,
|
|
833
|
+
})
|
|
795
834
|
|
|
796
835
|
# Apply CORS headers to all responses
|
|
797
836
|
_cors.apply(request, response)
|
|
@@ -8,11 +8,14 @@ Both naming patterns are supported. New migrations use timestamp format by defau
|
|
|
8
8
|
Each file is executed once. State tracked in tina4_migration table.
|
|
9
9
|
Rollback uses matching .down.sql files.
|
|
10
10
|
"""
|
|
11
|
+
import logging
|
|
11
12
|
import os
|
|
12
13
|
import re
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
from datetime import datetime, timezone
|
|
15
16
|
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
def _ensure_tracking_table(db):
|
|
18
21
|
"""Create the migration tracking table if it doesn't exist."""
|
|
@@ -94,6 +97,64 @@ def _split_statements(sql: str, delimiter: str = ";") -> list[str]:
|
|
|
94
97
|
return statements
|
|
95
98
|
|
|
96
99
|
|
|
100
|
+
def _is_firebird(db) -> bool:
|
|
101
|
+
"""Check if the database connection is Firebird."""
|
|
102
|
+
try:
|
|
103
|
+
return db.get_database_type() == "firebird"
|
|
104
|
+
except (AttributeError, Exception):
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# Regex to match ALTER TABLE <table> ADD <column> ...
|
|
109
|
+
# Captures the table name and column name from the SQL statement.
|
|
110
|
+
_ALTER_ADD_RE = re.compile(
|
|
111
|
+
r"^\s*ALTER\s+TABLE\s+"
|
|
112
|
+
r"(?:\"([^\"]+)\"|(\S+))" # table name (quoted or unquoted)
|
|
113
|
+
r"\s+ADD\s+"
|
|
114
|
+
r"(?:\"([^\"]+)\"|(\S+))", # column name (quoted or unquoted)
|
|
115
|
+
re.IGNORECASE,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _firebird_column_exists(db, table: str, column: str) -> bool:
|
|
120
|
+
"""Check if a column already exists in a Firebird table via RDB$RELATION_FIELDS.
|
|
121
|
+
|
|
122
|
+
Firebird does not support IF NOT EXISTS for ALTER TABLE ADD, so we query
|
|
123
|
+
the system catalogue directly. Column and table names are compared in
|
|
124
|
+
upper-case because Firebird stores unquoted identifiers that way.
|
|
125
|
+
"""
|
|
126
|
+
row = db.fetch_one(
|
|
127
|
+
"SELECT 1 FROM RDB$RELATION_FIELDS "
|
|
128
|
+
"WHERE RDB$RELATION_NAME = ? AND TRIM(RDB$FIELD_NAME) = ?",
|
|
129
|
+
[table.upper(), column.upper()],
|
|
130
|
+
)
|
|
131
|
+
return row is not None
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _should_skip_for_firebird(db, stmt: str) -> str | None:
|
|
135
|
+
"""If stmt is an ALTER TABLE ... ADD on Firebird and the column already exists, return a skip reason.
|
|
136
|
+
|
|
137
|
+
Returns None if the statement should be executed normally.
|
|
138
|
+
This makes ALTER TABLE ADD idempotent on Firebird, which lacks IF NOT EXISTS
|
|
139
|
+
for column additions. Only genuine duplicates are skipped — other errors
|
|
140
|
+
(bad syntax, wrong data type, etc.) will still raise normally on execute().
|
|
141
|
+
"""
|
|
142
|
+
if not _is_firebird(db):
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
m = _ALTER_ADD_RE.match(stmt)
|
|
146
|
+
if not m:
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
table = m.group(1) or m.group(2)
|
|
150
|
+
column = m.group(3) or m.group(4)
|
|
151
|
+
|
|
152
|
+
if _firebird_column_exists(db, table, column):
|
|
153
|
+
return f"Column {column} already exists in {table}, skipping"
|
|
154
|
+
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
|
|
97
158
|
def migrate(db, migration_folder: str = "migrations", delimiter: str = ";") -> list[str]:
|
|
98
159
|
"""Run all pending migrations.
|
|
99
160
|
|
|
@@ -127,6 +188,13 @@ def migrate(db, migration_folder: str = "migrations", delimiter: str = ";") -> l
|
|
|
127
188
|
try:
|
|
128
189
|
db.start_transaction()
|
|
129
190
|
for stmt in statements:
|
|
191
|
+
# Firebird lacks IF NOT EXISTS for ALTER TABLE ADD.
|
|
192
|
+
# Pre-check the system catalogue so duplicate columns are
|
|
193
|
+
# silently skipped instead of raising an error.
|
|
194
|
+
skip_reason = _should_skip_for_firebird(db, stmt)
|
|
195
|
+
if skip_reason:
|
|
196
|
+
logger.info(f"Migration {sql_file.name}: {skip_reason}")
|
|
197
|
+
continue
|
|
130
198
|
db.execute(stmt)
|
|
131
199
|
|
|
132
200
|
# Record as passed
|
|
@@ -483,7 +483,7 @@ class Queue:
|
|
|
483
483
|
|
|
484
484
|
if job_id is not None:
|
|
485
485
|
# Consume a specific job by ID
|
|
486
|
-
job = self.
|
|
486
|
+
job = self.pop_by_id(topic, job_id)
|
|
487
487
|
if job is not None:
|
|
488
488
|
yield job
|
|
489
489
|
return
|
|
@@ -495,7 +495,7 @@ class Queue:
|
|
|
495
495
|
break
|
|
496
496
|
yield job
|
|
497
497
|
|
|
498
|
-
def
|
|
498
|
+
def pop_by_id(self, topic: str, job_id: str) -> Job | None:
|
|
499
499
|
"""Pop a specific job by ID from the queue."""
|
|
500
500
|
if hasattr(self._backend, '_db'):
|
|
501
501
|
# SQLite backend — query by ID
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.6.0 → tina4_python-3.7.1}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py
RENAMED
|
File without changes
|
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/database/src/routes/api/gallery_db.py
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.6.0 → tina4_python-3.7.1}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/gallery/templates/src/routes/gallery_page.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.6.0 → tina4_python-3.7.1}/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
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.6.0 → tina4_python-3.7.1}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|