tina4-python 3.10.12__tar.gz → 3.10.14__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.12 → tina4_python-3.10.14}/PKG-INFO +1 -1
  2. {tina4_python-3.10.12 → tina4_python-3.10.14}/pyproject.toml +1 -1
  3. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/connection.py +49 -0
  4. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/orm/model.py +9 -0
  5. {tina4_python-3.10.12 → tina4_python-3.10.14}/.gitignore +0 -0
  6. {tina4_python-3.10.12 → tina4_python-3.10.14}/README.md +0 -0
  7. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/CLAUDE.md +0 -0
  8. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/HtmlElement.py +0 -0
  9. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/Testing.py +0 -0
  10. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/__init__.py +0 -0
  11. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/ai/__init__.py +0 -0
  12. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/api/__init__.py +0 -0
  13. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/auth/__init__.py +0 -0
  14. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/cache/__init__.py +0 -0
  15. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/cli/__init__.py +0 -0
  16. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/container/__init__.py +0 -0
  17. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/__init__.py +0 -0
  18. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/cache.py +0 -0
  19. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/constants.py +0 -0
  20. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/events.py +0 -0
  21. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/middleware.py +0 -0
  22. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/request.py +0 -0
  23. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/response.py +0 -0
  24. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/router.py +0 -0
  25. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/core/server.py +0 -0
  26. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/crud/__init__.py +0 -0
  27. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/__init__.py +0 -0
  28. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/adapter.py +0 -0
  29. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/firebird.py +0 -0
  30. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/mssql.py +0 -0
  31. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/mysql.py +0 -0
  32. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/odbc.py +0 -0
  33. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/postgres.py +0 -0
  34. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/database/sqlite.py +0 -0
  35. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/debug/__init__.py +0 -0
  36. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/debug/error_overlay.py +0 -0
  37. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/dev_admin/__init__.py +0 -0
  38. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/dev_reload.py +0 -0
  39. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/dotenv/__init__.py +0 -0
  40. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/frond/FROND.md +0 -0
  41. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/frond/__init__.py +0 -0
  42. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/frond/engine.py +0 -0
  43. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/auth/meta.json +0 -0
  44. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
  45. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/database/meta.json +0 -0
  46. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
  47. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/error-overlay/meta.json +0 -0
  48. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
  49. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/orm/meta.json +0 -0
  50. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
  51. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
  52. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/queue/meta.json +0 -0
  53. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
  54. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/rest-api/meta.json +0 -0
  55. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
  56. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/templates/meta.json +0 -0
  57. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
  58. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
  59. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/graphql/__init__.py +0 -0
  60. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/i18n/__init__.py +0 -0
  61. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/messenger/__init__.py +0 -0
  62. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/migration/__init__.py +0 -0
  63. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/migration/runner.py +0 -0
  64. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/orm/__init__.py +0 -0
  65. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/orm/fields.py +0 -0
  66. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/css/tina4.css +0 -0
  67. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/css/tina4.min.css +0 -0
  68. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/favicon.ico +0 -0
  69. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/images/logo.svg +0 -0
  70. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
  71. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/js/frond.min.js +0 -0
  72. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
  73. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/js/tina4.min.js +0 -0
  74. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/js/tina4js.min.js +0 -0
  75. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/swagger/index.html +0 -0
  76. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
  77. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/query_builder/__init__.py +0 -0
  78. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/queue/__init__.py +0 -0
  79. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/queue_backends/__init__.py +0 -0
  80. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/queue_backends/kafka_backend.py +0 -0
  81. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/queue_backends/mongo_backend.py +0 -0
  82. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
  83. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/__init__.py +0 -0
  84. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_alerts.scss +0 -0
  85. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_badges.scss +0 -0
  86. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_buttons.scss +0 -0
  87. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_cards.scss +0 -0
  88. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_forms.scss +0 -0
  89. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_grid.scss +0 -0
  90. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_modals.scss +0 -0
  91. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_nav.scss +0 -0
  92. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_reset.scss +0 -0
  93. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_tables.scss +0 -0
  94. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_typography.scss +0 -0
  95. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_utilities.scss +0 -0
  96. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/_variables.scss +0 -0
  97. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/base.scss +0 -0
  98. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/colors.scss +0 -0
  99. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/scss/tina4css/tina4.scss +0 -0
  100. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/seeder/__init__.py +0 -0
  101. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/service/__init__.py +0 -0
  102. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/session/__init__.py +0 -0
  103. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/session_handlers/__init__.py +0 -0
  104. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/session_handlers/mongodb_handler.py +0 -0
  105. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/session_handlers/redis_handler.py +0 -0
  106. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/session_handlers/valkey_handler.py +0 -0
  107. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/swagger/__init__.py +0 -0
  108. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/components/crud.twig +0 -0
  109. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
  110. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
  111. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/docker/python/Dockerfile +0 -0
  112. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/docker/uv/Dockerfile +0 -0
  113. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/errors/302.twig +0 -0
  114. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/errors/401.twig +0 -0
  115. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/errors/403.twig +0 -0
  116. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/errors/404.twig +0 -0
  117. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/errors/500.twig +0 -0
  118. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/errors/502.twig +0 -0
  119. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/errors/503.twig +0 -0
  120. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/errors/base.twig +0 -0
  121. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/frontend/README.md +0 -0
  122. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/templates/readme.md +0 -0
  123. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/test_client/__init__.py +0 -0
  124. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
  125. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
  126. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  127. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
  128. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
  129. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
  130. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  131. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
  132. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
  133. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
  134. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
  135. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
  136. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/validator/__init__.py +0 -0
  137. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/websocket/__init__.py +0 -0
  138. {tina4_python-3.10.12 → tina4_python-3.10.14}/tina4_python/websocket/backplane.py +0 -0
  139. {tina4_python-3.10.12 → tina4_python-3.10.14}/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.12
3
+ Version: 3.10.14
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.12"
3
+ version = "3.10.14"
4
4
  description = "Tina4 Python v3 — Zero-dependency, lightweight web framework"
5
5
  authors = [
6
6
  {name = "Andre van Zuydam", email = "andrevanzuydam@gmail.com"}
@@ -383,6 +383,55 @@ class Database:
383
383
  elif self._adapter is not None:
384
384
  self._adapter.autocommit = value
385
385
 
386
+ def get_next_id(self, table: str, pk_column: str = "id", generator_name: str = None) -> int:
387
+ """Get the next available ID for a table.
388
+
389
+ Engine-specific strategies:
390
+ - Firebird: uses GEN_ID(generator, 1) to increment and return
391
+ - PostgreSQL: uses nextval(sequence) if sequence exists
392
+ - SQLite/MySQL/MSSQL: SELECT MAX(pk) + 1 (fallback)
393
+
394
+ Args:
395
+ table: Table name.
396
+ pk_column: Primary key column name (default: "id").
397
+ generator_name: Firebird generator or PostgreSQL sequence name.
398
+ Auto-detected if not provided.
399
+
400
+ Returns:
401
+ The next integer ID.
402
+ """
403
+ engine = self.get_database_type()
404
+
405
+ if engine == "firebird":
406
+ gen_name = generator_name or f"GEN_{table.upper()}_ID"
407
+ # Create generator if it doesn't exist
408
+ try:
409
+ self.execute(f"CREATE GENERATOR {gen_name}")
410
+ self.commit()
411
+ except Exception:
412
+ pass # Already exists
413
+ row = self.fetch_one(
414
+ f"SELECT GEN_ID({gen_name}, 1) AS next_id FROM RDB$DATABASE"
415
+ )
416
+ return row["next_id"] if row else 1
417
+
418
+ elif engine == "postgresql":
419
+ seq_name = generator_name or f"{table}_{pk_column}_seq"
420
+ try:
421
+ row = self.fetch_one(f"SELECT nextval('{seq_name}') AS next_id")
422
+ return row["next_id"] if row else 1
423
+ except Exception:
424
+ pass # Sequence doesn't exist, fall through to MAX
425
+
426
+ # Fallback: MAX(pk) + 1
427
+ try:
428
+ row = self.fetch_one(
429
+ f"SELECT MAX({pk_column}) AS max_id FROM {table}"
430
+ )
431
+ return (row["max_id"] or 0) + 1 if row else 1
432
+ except Exception:
433
+ return 1
434
+
386
435
  def register_function(self, name: str, num_params: int, func: callable, deterministic: bool = True):
387
436
  """Register a custom SQL function (SQLite only).
388
437
 
@@ -240,6 +240,9 @@ class ORM(metaclass=ORMMeta):
240
240
  if result.last_id and pk in self._fields:
241
241
  setattr(self, pk, result.last_id)
242
242
 
243
+ # ORM save is a discrete unit of work — always commit
244
+ db.commit()
245
+
243
246
  # Invalidate cached queries and relationship cache
244
247
  self.clear_cache()
245
248
  self._rel_cache = {}
@@ -264,6 +267,9 @@ class ORM(metaclass=ORMMeta):
264
267
  else:
265
268
  db.delete(table, f"{pk_db_col} = ?", [pk_value])
266
269
 
270
+ # ORM delete is a discrete unit of work — always commit
271
+ db.commit()
272
+
267
273
  def force_delete(self):
268
274
  """Hard delete, even if soft delete is enabled."""
269
275
  db = self._get_db()
@@ -276,6 +282,7 @@ class ORM(metaclass=ORMMeta):
276
282
  raise ValueError("Cannot delete: no primary key value")
277
283
 
278
284
  db.delete(table, f"{pk_db_col} = ?", [pk_value])
285
+ db.commit()
279
286
 
280
287
  def restore(self):
281
288
  """Restore a soft-deleted record."""
@@ -290,6 +297,7 @@ class ORM(metaclass=ORMMeta):
290
297
 
291
298
  db.update(table, {"deleted_at": None}, f"{pk_db_col} = ?", [pk_value])
292
299
  self.deleted_at = None
300
+ db.commit()
293
301
 
294
302
  # ── Finders ─────────────────────────────────────────────────
295
303
 
@@ -497,6 +505,7 @@ class ORM(metaclass=ORMMeta):
497
505
  sql = SQLTranslator.auto_increment_syntax(sql, engine)
498
506
 
499
507
  db.execute(sql)
508
+ db.commit()
500
509
  return True
501
510
 
502
511
  # ── Cached Queries ────────────────────────────────────────
File without changes