tina4-python 3.13.45__tar.gz → 3.13.46__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 (158) hide show
  1. {tina4_python-3.13.45 → tina4_python-3.13.46}/PKG-INFO +1 -1
  2. {tina4_python-3.13.45 → tina4_python-3.13.46}/pyproject.toml +1 -1
  3. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/__init__.py +1 -1
  4. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/sqlite.py +35 -15
  5. {tina4_python-3.13.45 → tina4_python-3.13.46}/.gitignore +0 -0
  6. {tina4_python-3.13.45 → tina4_python-3.13.46}/README.md +0 -0
  7. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/CLAUDE.md +0 -0
  8. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/HtmlElement.py +0 -0
  9. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/Testing.py +0 -0
  10. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/ai/__init__.py +0 -0
  11. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/api/__init__.py +0 -0
  12. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/auth/__init__.py +0 -0
  13. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/cache/__init__.py +0 -0
  14. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/cli/__init__.py +0 -0
  15. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/container/__init__.py +0 -0
  16. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/__init__.py +0 -0
  17. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/cache.py +0 -0
  18. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/constants.py +0 -0
  19. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/events.py +0 -0
  20. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/middleware.py +0 -0
  21. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/rate_limiter.py +0 -0
  22. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/request.py +0 -0
  23. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/response.py +0 -0
  24. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/router.py +0 -0
  25. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/core/server.py +0 -0
  26. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/crud/__init__.py +0 -0
  27. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/__init__.py +0 -0
  28. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/adapter.py +0 -0
  29. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/connection.py +0 -0
  30. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/firebird.py +0 -0
  31. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/mongodb.py +0 -0
  32. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/mssql.py +0 -0
  33. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/mysql.py +0 -0
  34. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/odbc.py +0 -0
  35. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/database/postgres.py +0 -0
  36. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/debug/__init__.py +0 -0
  37. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/debug/error_overlay.py +0 -0
  38. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/dev_admin/__init__.py +0 -0
  39. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/dev_admin/metrics.py +0 -0
  40. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/dev_admin/plan.py +0 -0
  41. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/dev_admin/project_index.py +0 -0
  42. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/docs.py +0 -0
  43. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/docstore/__init__.py +0 -0
  44. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/dotenv/__init__.py +0 -0
  45. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/env.py +0 -0
  46. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/frond/FROND.md +0 -0
  47. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/frond/__init__.py +0 -0
  48. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/frond/engine.py +0 -0
  49. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/auth/meta.json +0 -0
  50. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
  51. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/database/meta.json +0 -0
  52. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
  53. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/error-overlay/meta.json +0 -0
  54. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
  55. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/orm/meta.json +0 -0
  56. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
  57. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
  58. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/queue/meta.json +0 -0
  59. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
  60. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/rest-api/meta.json +0 -0
  61. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
  62. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/templates/meta.json +0 -0
  63. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
  64. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
  65. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/graphql/__init__.py +0 -0
  66. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/i18n/__init__.py +0 -0
  67. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/mcp/__init__.py +0 -0
  68. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/mcp/protocol.py +0 -0
  69. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/mcp/tools.py +0 -0
  70. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/messenger/__init__.py +0 -0
  71. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/migration/__init__.py +0 -0
  72. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/migration/runner.py +0 -0
  73. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/orm/__init__.py +0 -0
  74. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/orm/fields.py +0 -0
  75. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/orm/model.py +0 -0
  76. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/__feedback/widget.js +0 -0
  77. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/css/tina4.css +0 -0
  78. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/css/tina4.min.css +0 -0
  79. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/favicon.ico +0 -0
  80. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/images/logo.svg +0 -0
  81. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
  82. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/js/frond.js +0 -0
  83. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/js/frond.min.js +0 -0
  84. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/js/tina4-dev-admin.js +0 -0
  85. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
  86. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/js/tina4.min.js +0 -0
  87. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/js/tina4js.min.js +0 -0
  88. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/swagger/index.html +0 -0
  89. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
  90. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/query_builder/__init__.py +0 -0
  91. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue/__init__.py +0 -0
  92. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue/job.py +0 -0
  93. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue/kafka_backend.py +0 -0
  94. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue/lite_backend.py +0 -0
  95. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue/mongo_backend.py +0 -0
  96. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue/rabbitmq_backend.py +0 -0
  97. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue_backends/__init__.py +0 -0
  98. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue_backends/kafka_backend.py +0 -0
  99. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue_backends/mongo_backend.py +0 -0
  100. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
  101. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/__init__.py +0 -0
  102. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_alerts.scss +0 -0
  103. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_badges.scss +0 -0
  104. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_buttons.scss +0 -0
  105. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_cards.scss +0 -0
  106. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_forms.scss +0 -0
  107. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_grid.scss +0 -0
  108. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_modals.scss +0 -0
  109. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_nav.scss +0 -0
  110. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_reset.scss +0 -0
  111. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_tables.scss +0 -0
  112. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_typography.scss +0 -0
  113. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_utilities.scss +0 -0
  114. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/_variables.scss +0 -0
  115. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/base.scss +0 -0
  116. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/colors.scss +0 -0
  117. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/scss/tina4css/tina4.scss +0 -0
  118. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/seeder/__init__.py +0 -0
  119. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/service/__init__.py +0 -0
  120. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/session/__init__.py +0 -0
  121. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/session_handlers/__init__.py +0 -0
  122. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/session_handlers/mongodb_handler.py +0 -0
  123. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/session_handlers/redis_handler.py +0 -0
  124. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/session_handlers/valkey_handler.py +0 -0
  125. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/swagger/__init__.py +0 -0
  126. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/components/crud.twig +0 -0
  127. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
  128. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
  129. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/docker/python/Dockerfile +0 -0
  130. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/docker/uv/Dockerfile +0 -0
  131. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/errors/302.twig +0 -0
  132. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/errors/401.twig +0 -0
  133. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/errors/403.twig +0 -0
  134. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/errors/404.twig +0 -0
  135. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/errors/500.twig +0 -0
  136. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/errors/502.twig +0 -0
  137. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/errors/503.twig +0 -0
  138. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/errors/base.twig +0 -0
  139. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/frontend/README.md +0 -0
  140. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/templates/readme.md +0 -0
  141. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/test/__init__.py +0 -0
  142. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/test_client/__init__.py +0 -0
  143. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
  144. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
  145. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  146. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
  147. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
  148. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
  149. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  150. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
  151. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
  152. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
  153. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
  154. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
  155. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/validator/__init__.py +0 -0
  156. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/websocket/__init__.py +0 -0
  157. {tina4_python-3.13.45 → tina4_python-3.13.46}/tina4_python/websocket/backplane.py +0 -0
  158. {tina4_python-3.13.45 → tina4_python-3.13.46}/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.13.45
3
+ Version: 3.13.46
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.13.45"
3
+ version = "3.13.46"
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.13.45"
11
+ __version__ = "3.13.46"
12
12
 
13
13
  # ── Route decorators ──
14
14
  from tina4_python.core.router import ( # noqa: E402, F401
@@ -93,23 +93,43 @@ class SQLiteAdapter(DatabaseAdapter):
93
93
  )
94
94
 
95
95
  def execute_many(self, sql: str, params_list: list[list] = None) -> DatabaseResult:
96
- """Optimized batch execute using SQLite's executemany."""
96
+ """Optimized batch execute using SQLite's executemany — ATOMIC (one txn).
97
+
98
+ The batch runs inside one transaction so a bad row mid-batch rolls the
99
+ WHOLE batch back (all-or-nothing) instead of leaving the rows applied
100
+ before the failure in an open, uncommitted transaction. Mirrors the base
101
+ DatabaseAdapter.execute_many owns-transaction guard and the other engines.
102
+ """
97
103
  sql = self._translate_sql(sql)
98
104
  rows = params_list or []
99
- self._conn.executemany(sql, rows)
100
-
101
- # cursor.rowcount / cursor.lastrowid are unreliable after executemany()
102
- # in sqlite3 (rowcount can come back 0 or -1, lastrowid is not set) and
103
- # were non-deterministic across pooled connections. The batch is
104
- # all-or-raise, so every supplied row was applied; the last inserted id
105
- # is read deterministically from last_insert_rowid() on this connection.
106
- affected = len(rows)
107
- last_row = self._conn.execute("SELECT last_insert_rowid()").fetchone()
108
- last_id = last_row[0] if last_row and last_row[0] else None
109
-
110
- if not self._in_transaction and self.autocommit:
111
- if self._conn.in_transaction:
112
- self._conn.execute("COMMIT")
105
+
106
+ # Own (and commit/rollback) the batch transaction only for a standalone
107
+ # write in autocommit mode never inside a caller's explicit transaction.
108
+ standalone = self.autocommit and not self._in_transaction
109
+ if standalone and not self._conn.in_transaction:
110
+ self._conn.execute("BEGIN")
111
+
112
+ try:
113
+ self._conn.executemany(sql, rows)
114
+ # cursor.rowcount / cursor.lastrowid are unreliable after executemany()
115
+ # in sqlite3 (rowcount can come back 0 or -1, lastrowid is not set).
116
+ # The batch is all-or-nothing, so every supplied row was applied; read
117
+ # the last inserted id deterministically from last_insert_rowid().
118
+ affected = len(rows)
119
+ last_row = self._conn.execute("SELECT last_insert_rowid()").fetchone()
120
+ last_id = last_row[0] if last_row and last_row[0] else None
121
+ except Exception:
122
+ # Roll the partial batch back so nothing is left half-applied, then
123
+ # FAIL LOUD (re-raise) — parity with execute() and the other engines.
124
+ if standalone and self._conn.in_transaction:
125
+ try:
126
+ self._conn.execute("ROLLBACK")
127
+ except Exception:
128
+ pass
129
+ raise
130
+
131
+ if standalone and self._conn.in_transaction:
132
+ self._conn.execute("COMMIT")
113
133
 
114
134
  return DatabaseResult(
115
135
  affected_rows=affected,
File without changes