tina4-python 3.10.59__tar.gz → 3.10.65__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.59 → tina4_python-3.10.65}/PKG-INFO +1 -1
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/HtmlElement.py +1 -1
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/Testing.py +1 -1
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/__init__.py +2 -2
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/cli/__init__.py +52 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/router.py +6 -6
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/server.py +2 -2
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/dev_admin/metrics.py +63 -10
- {tina4_python-3.10.59 → tina4_python-3.10.65}/.gitignore +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/README.md +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/pyproject.toml +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/events.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/request.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/core/response.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/dev_reload.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Tina4 Python v3.0 —
|
|
1
|
+
# Tina4 Python v3.0 — The Intelligent Native Application 4ramework.
|
|
2
2
|
# Copyright 2007 - present Tina4
|
|
3
3
|
# License: MIT https://opensource.org/licenses/MIT
|
|
4
4
|
"""
|
|
@@ -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.10.
|
|
11
|
+
__version__ = "3.10.65"
|
|
12
12
|
|
|
13
13
|
# ── Route decorators ──
|
|
14
14
|
from tina4_python.core.router import ( # noqa: E402, F401
|
|
@@ -137,6 +137,7 @@ def main():
|
|
|
137
137
|
"build": _build,
|
|
138
138
|
"ai": _ai,
|
|
139
139
|
"generate": _generate,
|
|
140
|
+
"console": _console,
|
|
140
141
|
"help": _help,
|
|
141
142
|
}
|
|
142
143
|
|
|
@@ -166,6 +167,7 @@ Commands:
|
|
|
166
167
|
test Run test suite
|
|
167
168
|
build Build distributable package
|
|
168
169
|
ai [--all] Install AI coding assistant context
|
|
170
|
+
console Start interactive REPL with framework loaded
|
|
169
171
|
|
|
170
172
|
Generators:
|
|
171
173
|
generate model <Name> [--fields "name:string,price:float"]
|
|
@@ -185,6 +187,56 @@ https://tina4.com
|
|
|
185
187
|
""")
|
|
186
188
|
|
|
187
189
|
|
|
190
|
+
# ── Console ───────────────────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
def _console(args=None):
|
|
193
|
+
"""Start an interactive REPL with the framework loaded."""
|
|
194
|
+
import code
|
|
195
|
+
import os
|
|
196
|
+
|
|
197
|
+
# Load environment
|
|
198
|
+
from tina4_python.dotenv import load_env
|
|
199
|
+
load_env()
|
|
200
|
+
|
|
201
|
+
# Import everything the user needs
|
|
202
|
+
from tina4_python import get, post, put, patch, delete, Router, Database, ORM, Auth, Queue, Frond
|
|
203
|
+
from tina4_python.debug import Log
|
|
204
|
+
from tina4_python.api import Api
|
|
205
|
+
from tina4_python.core.events import on, emit
|
|
206
|
+
|
|
207
|
+
# Try to connect database from DATABASE_URL
|
|
208
|
+
db = None
|
|
209
|
+
db_url = os.environ.get("DATABASE_URL")
|
|
210
|
+
if db_url:
|
|
211
|
+
try:
|
|
212
|
+
db = Database(db_url)
|
|
213
|
+
print(f" Database: {db_url}")
|
|
214
|
+
except Exception as e:
|
|
215
|
+
print(f" Database: failed ({e})")
|
|
216
|
+
|
|
217
|
+
# Auto-discover routes
|
|
218
|
+
from tina4_python.core.server import _auto_discover
|
|
219
|
+
_auto_discover("src")
|
|
220
|
+
route_count = len(Router.get_routes())
|
|
221
|
+
print(f" Routes: {route_count} discovered")
|
|
222
|
+
|
|
223
|
+
banner = (
|
|
224
|
+
"\n Tina4 Python Console\n"
|
|
225
|
+
" Type Python code. Framework is loaded.\n"
|
|
226
|
+
" Available: db, Router, ORM, Database, Auth, Api, Log, Queue\n"
|
|
227
|
+
" Exit: Ctrl+D or exit()\n"
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
local_vars = {
|
|
231
|
+
"db": db, "Database": Database, "ORM": ORM, "Router": Router,
|
|
232
|
+
"Auth": Auth, "Api": Api, "Log": Log, "Queue": Queue,
|
|
233
|
+
"Frond": Frond, "get": get, "post": post, "put": put,
|
|
234
|
+
"patch": patch, "delete": delete, "on": on, "emit": emit,
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
code.interact(banner=banner, local=local_vars)
|
|
238
|
+
|
|
239
|
+
|
|
188
240
|
# ── Init ──────────────────────────────────────────────────────────────
|
|
189
241
|
|
|
190
242
|
def _init(args):
|
|
@@ -79,22 +79,22 @@ class RouteGroup:
|
|
|
79
79
|
self._middleware = middleware or []
|
|
80
80
|
|
|
81
81
|
def get(self, path: str, handler, **options) -> RouteRef:
|
|
82
|
-
return self._router.add("GET",
|
|
82
|
+
return self._router.add("GET", path, handler, middleware=self._middleware, **options)
|
|
83
83
|
|
|
84
84
|
def post(self, path: str, handler, **options) -> RouteRef:
|
|
85
|
-
return self._router.add("POST",
|
|
85
|
+
return self._router.add("POST", path, handler, middleware=self._middleware, **options)
|
|
86
86
|
|
|
87
87
|
def put(self, path: str, handler, **options) -> RouteRef:
|
|
88
|
-
return self._router.add("PUT",
|
|
88
|
+
return self._router.add("PUT", path, handler, middleware=self._middleware, **options)
|
|
89
89
|
|
|
90
90
|
def patch(self, path: str, handler, **options) -> RouteRef:
|
|
91
|
-
return self._router.add("PATCH",
|
|
91
|
+
return self._router.add("PATCH", path, handler, middleware=self._middleware, **options)
|
|
92
92
|
|
|
93
93
|
def delete(self, path: str, handler, **options) -> RouteRef:
|
|
94
|
-
return self._router.add("DELETE",
|
|
94
|
+
return self._router.add("DELETE", path, handler, middleware=self._middleware, **options)
|
|
95
95
|
|
|
96
96
|
def any(self, path: str, handler, **options) -> RouteRef:
|
|
97
|
-
return self._router.add("ANY",
|
|
97
|
+
return self._router.add("ANY", path, handler, middleware=self._middleware, **options)
|
|
98
98
|
|
|
99
99
|
def group(self, prefix: str, callback, middleware=None):
|
|
100
100
|
merged = list(self._middleware) + (middleware or [])
|
|
@@ -254,7 +254,7 @@ h1{{font-size:3rem;font-weight:700;margin-bottom:0.25rem;letter-spacing:-1px}}
|
|
|
254
254
|
<div class="hero">
|
|
255
255
|
<img src="/images/tina4-logo-icon.webp" class="logo" alt="Tina4">
|
|
256
256
|
<h1>Tina4Python</h1>
|
|
257
|
-
<p class="tagline">
|
|
257
|
+
<p class="tagline">The Intelligent Native Application 4ramework</p>
|
|
258
258
|
<div class="actions">
|
|
259
259
|
<a href="https://tina4.com/python" class="btn" target="_blank">Website</a>
|
|
260
260
|
<a href="/__dev" class="btn">Dev Admin</a>
|
|
@@ -1312,7 +1312,7 @@ def _print_banner(host: str, port: int, server_name: str = "asyncio", ai_port: i
|
|
|
1312
1312
|
/ / / / / / / /_/ /__ __/
|
|
1313
1313
|
/_/ /_/_/ /_/\\__,_/ /_/
|
|
1314
1314
|
{reset}
|
|
1315
|
-
Tina4 Python v{__version__} —
|
|
1315
|
+
Tina4 Python v{__version__} — The Intelligent Native Application 4ramework
|
|
1316
1316
|
|
|
1317
1317
|
Server: http://{display}:{port} ({server_name})
|
|
1318
1318
|
Swagger: http://localhost:{port}/swagger
|
|
@@ -105,7 +105,7 @@ def quick_metrics(root: str = "src") -> dict:
|
|
|
105
105
|
total_functions += functions
|
|
106
106
|
|
|
107
107
|
file_details.append({
|
|
108
|
-
"path": str(f.relative_to(
|
|
108
|
+
"path": str(f.relative_to(root_path)),
|
|
109
109
|
"loc": loc,
|
|
110
110
|
"blank": blank,
|
|
111
111
|
"comment": comment,
|
|
@@ -211,7 +211,10 @@ def full_analysis(root: str = "src") -> dict:
|
|
|
211
211
|
except (SyntaxError, OSError):
|
|
212
212
|
continue
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
try:
|
|
215
|
+
rel_path = str(f.relative_to(root_path))
|
|
216
|
+
except ValueError:
|
|
217
|
+
rel_path = str(f.relative_to(root_path.parent)) if root_path.parent != f else f.name
|
|
215
218
|
lines = source.splitlines()
|
|
216
219
|
loc = sum(1 for l in lines if l.strip() and not l.strip().startswith("#"))
|
|
217
220
|
|
|
@@ -495,19 +498,69 @@ def _count_halstead(node: ast.AST, stats: dict):
|
|
|
495
498
|
def _has_matching_test(rel_path: str) -> bool:
|
|
496
499
|
"""Check if a source file has a matching test file.
|
|
497
500
|
|
|
498
|
-
|
|
501
|
+
Three-stage detection:
|
|
502
|
+
1. Filename matching — test_module.py, module_test.py, module_spec.py
|
|
503
|
+
2. Path matching — any test file referencing the full import path
|
|
504
|
+
3. Content matching — any test file mentioning the module or class name
|
|
499
505
|
"""
|
|
506
|
+
import re
|
|
507
|
+
|
|
500
508
|
p = Path(rel_path)
|
|
501
|
-
module = p.stem # e.g. "
|
|
509
|
+
module = p.stem # e.g. "sqlite" from "tina4_python/database/sqlite.py"
|
|
502
510
|
if module == "__init__":
|
|
503
511
|
module = p.parent.name # use parent dir name
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
512
|
+
|
|
513
|
+
# Build the full dotted import path for deeper matching
|
|
514
|
+
# e.g. "tina4_python/database/sqlite.py" → "tina4_python.database.sqlite"
|
|
515
|
+
parts = list(p.with_suffix("").parts)
|
|
516
|
+
dotted_path = ".".join(parts) # "tina4_python.database.sqlite"
|
|
517
|
+
|
|
518
|
+
# Also track the parent package name for broader matching
|
|
519
|
+
# e.g. "database" from "tina4_python/database/sqlite.py"
|
|
520
|
+
parent_module = p.parent.name if len(p.parts) > 1 else ""
|
|
521
|
+
|
|
522
|
+
# Stage 1: Filename patterns
|
|
523
|
+
test_dirs = [Path("tests"), Path("test"), Path("spec")]
|
|
524
|
+
for td in test_dirs:
|
|
525
|
+
patterns = [
|
|
526
|
+
td / f"test_{module}.py",
|
|
527
|
+
td / f"test_{module}s.py",
|
|
528
|
+
td / f"{module}_test.py",
|
|
529
|
+
td / f"{module}_spec.py",
|
|
530
|
+
]
|
|
531
|
+
# Also check parent-named tests (test_database.py covers database/sqlite.py)
|
|
532
|
+
if parent_module and parent_module != module:
|
|
533
|
+
patterns.extend([
|
|
534
|
+
td / f"test_{parent_module}.py",
|
|
535
|
+
td / f"test_{parent_module}s.py",
|
|
536
|
+
td / f"{parent_module}_test.py",
|
|
537
|
+
])
|
|
538
|
+
if any(tp.exists() for tp in patterns):
|
|
539
|
+
return True
|
|
540
|
+
|
|
541
|
+
# Stage 2+3: Content scan — check if ANY test file references this module
|
|
542
|
+
search_terms = [
|
|
543
|
+
re.compile(rf'\b{re.escape(module)}\b', re.IGNORECASE),
|
|
509
544
|
]
|
|
510
|
-
|
|
545
|
+
# Add dotted path patterns for import matching
|
|
546
|
+
if dotted_path:
|
|
547
|
+
search_terms.append(re.compile(rf'{re.escape(dotted_path)}'))
|
|
548
|
+
# Add class name guesses (CamelCase from snake_case module name)
|
|
549
|
+
class_name = "".join(w.capitalize() for w in module.split("_"))
|
|
550
|
+
if class_name != module:
|
|
551
|
+
search_terms.append(re.compile(rf'\b{re.escape(class_name)}\b'))
|
|
552
|
+
|
|
553
|
+
for td in test_dirs:
|
|
554
|
+
if not td.is_dir():
|
|
555
|
+
continue
|
|
556
|
+
for test_file in td.rglob("*.py"):
|
|
557
|
+
try:
|
|
558
|
+
content = test_file.read_text(encoding="utf-8", errors="ignore")
|
|
559
|
+
if any(pat.search(content) for pat in search_terms):
|
|
560
|
+
return True
|
|
561
|
+
except OSError:
|
|
562
|
+
pass
|
|
563
|
+
return False
|
|
511
564
|
|
|
512
565
|
|
|
513
566
|
def _maintainability_index(halstead_volume: float, avg_cc: float, loc: int) -> float:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.59 → tina4_python-3.10.65}/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.59 → tina4_python-3.10.65}/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.59 → tina4_python-3.10.65}/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.59 → tina4_python-3.10.65}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/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.59 → tina4_python-3.10.65}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.10.59 → tina4_python-3.10.65}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|