tina4-python 3.10.21__tar.gz → 3.10.24__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.
Files changed (139) hide show
  1. {tina4_python-3.10.21 → tina4_python-3.10.24}/PKG-INFO +1 -1
  2. {tina4_python-3.10.21 → tina4_python-3.10.24}/pyproject.toml +1 -1
  3. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/__init__.py +1 -1
  4. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/frond/engine.py +39 -19
  5. {tina4_python-3.10.21 → tina4_python-3.10.24}/.gitignore +0 -0
  6. {tina4_python-3.10.21 → tina4_python-3.10.24}/README.md +0 -0
  7. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/CLAUDE.md +0 -0
  8. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/HtmlElement.py +0 -0
  9. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/Testing.py +0 -0
  10. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/ai/__init__.py +0 -0
  11. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/api/__init__.py +0 -0
  12. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/auth/__init__.py +0 -0
  13. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/cache/__init__.py +0 -0
  14. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/cli/__init__.py +0 -0
  15. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/container/__init__.py +0 -0
  16. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/__init__.py +0 -0
  17. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/cache.py +0 -0
  18. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/constants.py +0 -0
  19. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/events.py +0 -0
  20. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/middleware.py +0 -0
  21. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/request.py +0 -0
  22. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/response.py +0 -0
  23. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/router.py +0 -0
  24. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/core/server.py +0 -0
  25. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/crud/__init__.py +0 -0
  26. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/__init__.py +0 -0
  27. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/adapter.py +0 -0
  28. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/connection.py +0 -0
  29. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/firebird.py +0 -0
  30. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/mssql.py +0 -0
  31. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/mysql.py +0 -0
  32. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/odbc.py +0 -0
  33. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/postgres.py +0 -0
  34. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/database/sqlite.py +0 -0
  35. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/debug/__init__.py +0 -0
  36. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/debug/error_overlay.py +0 -0
  37. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/dev_admin/__init__.py +0 -0
  38. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/dev_reload.py +0 -0
  39. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/dotenv/__init__.py +0 -0
  40. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/frond/FROND.md +0 -0
  41. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/frond/__init__.py +0 -0
  42. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/auth/meta.json +0 -0
  43. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
  44. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/database/meta.json +0 -0
  45. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
  46. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/error-overlay/meta.json +0 -0
  47. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
  48. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/orm/meta.json +0 -0
  49. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
  50. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
  51. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/queue/meta.json +0 -0
  52. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
  53. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/rest-api/meta.json +0 -0
  54. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
  55. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/templates/meta.json +0 -0
  56. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
  57. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
  58. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/graphql/__init__.py +0 -0
  59. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/i18n/__init__.py +0 -0
  60. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/messenger/__init__.py +0 -0
  61. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/migration/__init__.py +0 -0
  62. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/migration/runner.py +0 -0
  63. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/orm/__init__.py +0 -0
  64. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/orm/fields.py +0 -0
  65. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/orm/model.py +0 -0
  66. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/css/tina4.css +0 -0
  67. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/css/tina4.min.css +0 -0
  68. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/favicon.ico +0 -0
  69. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/images/logo.svg +0 -0
  70. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
  71. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/js/frond.min.js +0 -0
  72. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
  73. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/js/tina4.min.js +0 -0
  74. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/js/tina4js.min.js +0 -0
  75. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/swagger/index.html +0 -0
  76. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
  77. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/query_builder/__init__.py +0 -0
  78. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/queue/__init__.py +0 -0
  79. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/queue_backends/__init__.py +0 -0
  80. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/queue_backends/kafka_backend.py +0 -0
  81. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/queue_backends/mongo_backend.py +0 -0
  82. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
  83. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/__init__.py +0 -0
  84. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_alerts.scss +0 -0
  85. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_badges.scss +0 -0
  86. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_buttons.scss +0 -0
  87. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_cards.scss +0 -0
  88. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_forms.scss +0 -0
  89. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_grid.scss +0 -0
  90. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_modals.scss +0 -0
  91. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_nav.scss +0 -0
  92. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_reset.scss +0 -0
  93. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_tables.scss +0 -0
  94. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_typography.scss +0 -0
  95. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_utilities.scss +0 -0
  96. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/_variables.scss +0 -0
  97. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/base.scss +0 -0
  98. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/colors.scss +0 -0
  99. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/scss/tina4css/tina4.scss +0 -0
  100. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/seeder/__init__.py +0 -0
  101. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/service/__init__.py +0 -0
  102. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/session/__init__.py +0 -0
  103. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/session_handlers/__init__.py +0 -0
  104. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/session_handlers/mongodb_handler.py +0 -0
  105. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/session_handlers/redis_handler.py +0 -0
  106. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/session_handlers/valkey_handler.py +0 -0
  107. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/swagger/__init__.py +0 -0
  108. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/components/crud.twig +0 -0
  109. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
  110. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
  111. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/docker/python/Dockerfile +0 -0
  112. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/docker/uv/Dockerfile +0 -0
  113. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/errors/302.twig +0 -0
  114. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/errors/401.twig +0 -0
  115. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/errors/403.twig +0 -0
  116. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/errors/404.twig +0 -0
  117. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/errors/500.twig +0 -0
  118. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/errors/502.twig +0 -0
  119. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/errors/503.twig +0 -0
  120. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/errors/base.twig +0 -0
  121. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/frontend/README.md +0 -0
  122. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/templates/readme.md +0 -0
  123. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/test_client/__init__.py +0 -0
  124. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
  125. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
  126. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  127. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
  128. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
  129. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
  130. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  131. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
  132. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
  133. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
  134. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
  135. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
  136. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/validator/__init__.py +0 -0
  137. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/websocket/__init__.py +0 -0
  138. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/websocket/backplane.py +0 -0
  139. {tina4_python-3.10.21 → tina4_python-3.10.24}/tina4_python/wsdl/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tina4-python
3
- Version: 3.10.21
3
+ Version: 3.10.24
4
4
  Summary: Tina4 Python v3 — Zero-dependency, lightweight web framework
5
5
  Author-email: Andre van Zuydam <andrevanzuydam@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tina4-python"
3
- version = "3.10.21"
3
+ version = "3.10.24"
4
4
  description = "Tina4 Python v3 — Zero-dependency, lightweight web framework"
5
5
  authors = [
6
6
  {name = "Andre van Zuydam", email = "andrevanzuydam@gmail.com"}
@@ -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.21"
11
+ __version__ = "3.10.24"
12
12
 
13
13
  # ── HTTP Constants ──
14
14
  from tina4_python.core.constants import ( # noqa: E402, F401
@@ -9,6 +9,7 @@ import re
9
9
  import html
10
10
  import hashlib
11
11
  import json
12
+ import secrets
12
13
  from functools import lru_cache
13
14
  from pathlib import Path
14
15
  from datetime import datetime
@@ -940,8 +941,8 @@ def _wordwrap(text: str, width: int) -> str:
940
941
  # ── Form Token ─────────────────────────────────────────────────
941
942
 
942
943
 
943
- def _form_token(descriptor: str = "", session_id: str = "") -> str:
944
- """Generate a JWT form token and return a hidden input element.
944
+ def _generate_form_jwt(descriptor: str = "", session_id: str = "") -> str:
945
+ """Generate a JWT form token string.
945
946
 
946
947
  Args:
947
948
  descriptor: Optional string to enrich the token payload.
@@ -949,13 +950,11 @@ def _form_token(descriptor: str = "", session_id: str = "") -> str:
949
950
  - ``"admin_panel"``: payload is ``{"type": "form", "context": "admin_panel"}``
950
951
  - ``"checkout|order_123"``: payload is ``{"type": "form", "context": "checkout", "ref": "order_123"}``
951
952
  session_id: Optional session ID to bind the token to a specific session.
952
- When provided, the CSRF middleware will verify the token belongs to
953
- the same session. If empty, checks ``_form_token_session_id`` global.
954
953
 
955
954
  Returns:
956
- ``<input type="hidden" name="formToken" value="TOKEN">``
955
+ The raw JWT string.
957
956
  """
958
- payload = {"type": "form"}
957
+ payload = {"type": "form", "nonce": secrets.token_hex(8)}
959
958
  if descriptor:
960
959
  descriptor = str(descriptor)
961
960
  if "|" in descriptor:
@@ -973,10 +972,32 @@ def _form_token(descriptor: str = "", session_id: str = "") -> str:
973
972
  secret = os.environ.get("SECRET", "tina4-default-secret")
974
973
  ttl = int(os.environ.get("TINA4_TOKEN_EXPIRES_IN", "60"))
975
974
  auth = _FrondAuth(secret=secret, expires_in=ttl)
976
- token = auth.get_token(payload)
975
+ return auth.get_token(payload)
976
+
977
+
978
+ def _form_token(descriptor: str = "", session_id: str = "") -> str:
979
+ """Generate a JWT form token and return a hidden input element.
980
+
981
+ Usage in templates: ``{{ form_token() }}`` or ``{{ "context" | form_token }}``
982
+
983
+ Returns:
984
+ ``<input type="hidden" name="formToken" value="TOKEN">``
985
+ """
986
+ token = _generate_form_jwt(descriptor, session_id)
977
987
  return SafeString(f'<input type="hidden" name="formToken" value="{token}">')
978
988
 
979
989
 
990
+ def _form_token_value(descriptor: str = "", session_id: str = "") -> str:
991
+ """Generate a JWT form token and return just the raw token string.
992
+
993
+ Usage in templates: ``{{ formTokenValue("Sleek") }}``
994
+
995
+ Returns:
996
+ The raw JWT string (no HTML wrapper).
997
+ """
998
+ return SafeString(_generate_form_jwt(descriptor, session_id))
999
+
1000
+
980
1001
  # Module-level session ID holder — set by the server before rendering templates
981
1002
  # so that form_token() can bind tokens to the current session.
982
1003
  _form_token_session_id: str = ""
@@ -1015,6 +1036,8 @@ class Frond:
1015
1036
 
1016
1037
  # Built-in global functions
1017
1038
  self._globals["form_token"] = _form_token
1039
+ self._globals["formTokenValue"] = _form_token_value
1040
+ self._globals["form_token_value"] = _form_token_value
1018
1041
 
1019
1042
  def sandbox(self, allowed_filters: list[str] = None,
1020
1043
  allowed_tags: list[str] = None,
@@ -1069,23 +1092,20 @@ class Frond:
1069
1092
  raise FileNotFoundError(f"Template not found: {path}")
1070
1093
 
1071
1094
  debug_mode = os.environ.get("TINA4_DEBUG", "").lower() == "true"
1072
- cached = self._compiled.get(template)
1073
1095
 
1074
- if cached is not None:
1075
- if debug_mode:
1076
- # Dev mode: check if file changed
1077
- mtime = path.stat().st_mtime
1078
- if cached[1] == mtime:
1079
- return self._execute_cached(cached[0], context, template)
1080
- else:
1081
- # Production: skip mtime check, cache is permanent
1096
+ if not debug_mode:
1097
+ # Production: permanent cache, no filesystem checks
1098
+ cached = self._compiled.get(template)
1099
+ if cached is not None:
1082
1100
  return self._execute_cached(cached[0], context, template)
1083
1101
 
1084
- # Cache missload, tokenize, cache
1102
+ # Dev mode: skip cache entirely always re-read and re-tokenize.
1103
+ # mtime-based invalidation doesn't catch changes to included/extended
1104
+ # templates (parent or partial changes don't update the caller's mtime).
1085
1105
  source = path.read_text(encoding="utf-8")
1086
- mtime = path.stat().st_mtime
1087
1106
  tokens = _tokenize(source)
1088
- self._compiled[template] = (tokens, mtime)
1107
+ if not debug_mode:
1108
+ self._compiled[template] = (tokens, 0)
1089
1109
  return self._execute_with_source(source, tokens, context, template)
1090
1110
 
1091
1111
  def render_string(self, source: str, data: dict = None) -> str:
File without changes