tina4-python 3.13.135__tar.gz → 3.13.136__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 (173) hide show
  1. {tina4_python-3.13.135 → tina4_python-3.13.136}/PKG-INFO +1 -1
  2. {tina4_python-3.13.135 → tina4_python-3.13.136}/pyproject.toml +1 -1
  3. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/__init__.py +1 -1
  4. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/connection.py +58 -40
  5. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/swagger/index.html +1 -1
  6. {tina4_python-3.13.135 → tina4_python-3.13.136}/.gitignore +0 -0
  7. {tina4_python-3.13.135 → tina4_python-3.13.136}/README.md +0 -0
  8. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/.tina4-metrics.json +0 -0
  9. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/CLAUDE.md +0 -0
  10. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/HtmlElement.py +0 -0
  11. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/Testing.py +0 -0
  12. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/_import_helper.py +0 -0
  13. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/ai/__init__.py +0 -0
  14. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/ai/client.py +0 -0
  15. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/api/__init__.py +0 -0
  16. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/auth/__init__.py +0 -0
  17. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/cache/__init__.py +0 -0
  18. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/cli/__init__.py +0 -0
  19. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/container/__init__.py +0 -0
  20. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/context/__init__.py +0 -0
  21. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/context/chunker.py +0 -0
  22. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/__init__.py +0 -0
  23. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/cache.py +0 -0
  24. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/constants.py +0 -0
  25. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/events.py +0 -0
  26. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/middleware.py +0 -0
  27. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/port_takeover.py +0 -0
  28. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/rate_limiter.py +0 -0
  29. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/request.py +0 -0
  30. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/response.py +0 -0
  31. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/router.py +0 -0
  32. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/core/server.py +0 -0
  33. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/crud/__init__.py +0 -0
  34. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/__init__.py +0 -0
  35. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/adapter.py +0 -0
  36. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/database_url.py +0 -0
  37. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/firebird.py +0 -0
  38. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/mongodb.py +0 -0
  39. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/mssql.py +0 -0
  40. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/mysql.py +0 -0
  41. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/odbc.py +0 -0
  42. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/postgres.py +0 -0
  43. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/sql_translator.py +0 -0
  44. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/database/sqlite.py +0 -0
  45. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/debug/__init__.py +0 -0
  46. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/debug/error_overlay.py +0 -0
  47. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/dev_admin/__init__.py +0 -0
  48. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/dev_admin/metrics.py +0 -0
  49. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/dev_admin/plan.py +0 -0
  50. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/dev_admin/project_index.py +0 -0
  51. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/docs.py +0 -0
  52. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/docstore/__init__.py +0 -0
  53. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/dotenv/__init__.py +0 -0
  54. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/env.py +0 -0
  55. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/frond/FROND.md +0 -0
  56. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/frond/__init__.py +0 -0
  57. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/frond/compiler.py +0 -0
  58. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/frond/engine.py +0 -0
  59. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/frond/parser.py +0 -0
  60. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/auth/meta.json +0 -0
  61. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
  62. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/database/meta.json +0 -0
  63. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
  64. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/error-overlay/meta.json +0 -0
  65. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
  66. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/orm/meta.json +0 -0
  67. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
  68. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
  69. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/queue/meta.json +0 -0
  70. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
  71. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/rest-api/meta.json +0 -0
  72. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
  73. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/templates/meta.json +0 -0
  74. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
  75. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
  76. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/graph/__init__.py +0 -0
  77. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/graph/adapter.py +0 -0
  78. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/graph/adapters/__init__.py +0 -0
  79. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/graph/adapters/arango.py +0 -0
  80. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/graph/adapters/bolt.py +0 -0
  81. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/graph/adapters/ultipa.py +0 -0
  82. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/graph/graph_url.py +0 -0
  83. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/graphql/__init__.py +0 -0
  84. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/i18n/__init__.py +0 -0
  85. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/mcp/__init__.py +0 -0
  86. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/mcp/protocol.py +0 -0
  87. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/mcp/tools.py +0 -0
  88. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/messenger/__init__.py +0 -0
  89. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/migration/__init__.py +0 -0
  90. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/migration/runner.py +0 -0
  91. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/mqtt/__init__.py +0 -0
  92. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/mqtt/message.py +0 -0
  93. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/orm/__init__.py +0 -0
  94. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/orm/collection.py +0 -0
  95. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/orm/fields.py +0 -0
  96. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/orm/model.py +0 -0
  97. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/orm/point.py +0 -0
  98. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/__feedback/widget.js +0 -0
  99. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/css/tina4.css +0 -0
  100. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/css/tina4.min.css +0 -0
  101. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/favicon.ico +0 -0
  102. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/images/logo.svg +0 -0
  103. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
  104. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/js/frond.js +0 -0
  105. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/js/frond.min.js +0 -0
  106. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
  107. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/js/tina4.min.js +0 -0
  108. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/js/tina4js.min.js +0 -0
  109. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
  110. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/push/__init__.py +0 -0
  111. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/query_builder/__init__.py +0 -0
  112. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue/__init__.py +0 -0
  113. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue/amqp_url.py +0 -0
  114. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue/job.py +0 -0
  115. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue/kafka_backend.py +0 -0
  116. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue/lite_backend.py +0 -0
  117. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue/mongo_backend.py +0 -0
  118. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue/rabbitmq_backend.py +0 -0
  119. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue_backends/__init__.py +0 -0
  120. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue_backends/kafka_backend.py +0 -0
  121. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue_backends/mongo_backend.py +0 -0
  122. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
  123. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/realtime/__init__.py +0 -0
  124. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/realtime/models/Attachment.py +0 -0
  125. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/realtime/models/Channel.py +0 -0
  126. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/realtime/models/ChannelMember.py +0 -0
  127. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/realtime/models/Message.py +0 -0
  128. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/realtime/models/Workspace.py +0 -0
  129. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/realtime/models/__init__.py +0 -0
  130. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/realtime/storage.py +0 -0
  131. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/seeder/__init__.py +0 -0
  132. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/service/__init__.py +0 -0
  133. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/session/__init__.py +0 -0
  134. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/session_handlers/__init__.py +0 -0
  135. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/session_handlers/memcached_handler.py +0 -0
  136. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/session_handlers/mongodb_handler.py +0 -0
  137. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/session_handlers/redis_handler.py +0 -0
  138. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/session_handlers/valkey_handler.py +0 -0
  139. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/sso.py +0 -0
  140. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/swagger/__init__.py +0 -0
  141. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/components/crud.twig +0 -0
  142. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
  143. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
  144. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/docker/python/Dockerfile +0 -0
  145. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/docker/uv/Dockerfile +0 -0
  146. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/errors/302.twig +0 -0
  147. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/errors/401.twig +0 -0
  148. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/errors/403.twig +0 -0
  149. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/errors/404.twig +0 -0
  150. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/errors/500.twig +0 -0
  151. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/errors/502.twig +0 -0
  152. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/errors/503.twig +0 -0
  153. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/errors/base.twig +0 -0
  154. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/frontend/README.md +0 -0
  155. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/templates/readme.md +0 -0
  156. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/test/__init__.py +0 -0
  157. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/test_client/__init__.py +0 -0
  158. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
  159. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
  160. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  161. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
  162. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
  163. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
  164. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  165. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
  166. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
  167. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
  168. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
  169. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
  170. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/validator/__init__.py +0 -0
  171. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/websocket/__init__.py +0 -0
  172. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/websocket/backplane.py +0 -0
  173. {tina4_python-3.13.135 → tina4_python-3.13.136}/tina4_python/wsdl/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tina4-python
3
- Version: 3.13.135
3
+ Version: 3.13.136
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.135"
3
+ version = "3.13.136"
4
4
  description = "Tina4 Python v3 — Zero-dependency, lightweight web framework"
5
5
  authors = [
6
6
  {name = "Andre van Zuydam", email = "andrevanzuydam@gmail.com"}
@@ -51,7 +51,7 @@ def _resolve_version() -> str:
51
51
  #
52
52
  # test_version_constant.py now asserts this literal equals the pyproject
53
53
  # version, so the release bump cannot leave it behind again.
54
- return "3.13.135"
54
+ return "3.13.136"
55
55
 
56
56
 
57
57
  __version__ = _resolve_version()
@@ -10,6 +10,7 @@ Connection pooling:
10
10
  db = Database("sqlite:///data/app.db", pool=4) # 4 connections, round-robin
11
11
  """
12
12
  import hashlib
13
+ import importlib
13
14
  import os
14
15
  import threading
15
16
  import time
@@ -129,43 +130,56 @@ def register_driver(scheme: str, adapter_class: type):
129
130
  _DRIVERS[scheme] = adapter_class
130
131
 
131
132
 
132
- # Register built-in SQLite
133
+ # Register built-in SQLite eagerly. It is stdlib, so importing it drags in no
134
+ # third-party package -- the zero-dependency default carries no import cost.
133
135
  from tina4_python.database.sqlite import SQLiteAdapter
134
136
  register_driver("sqlite", SQLiteAdapter)
135
137
 
136
- # Register ODBC (lazy only fails if you actually use it without pyodbc)
137
- try:
138
- from tina4_python.database.odbc import ODBCAdapter
139
- register_driver("odbc", ODBCAdapter)
140
- except ImportError:
141
- pass # pyodbc not installed that's fine
142
-
143
- # Register PostgreSQL (psycopg2 optional)
144
- from tina4_python.database.postgres import PostgreSQLAdapter
145
- register_driver("postgresql", PostgreSQLAdapter)
146
- register_driver("postgres", PostgreSQLAdapter)
147
- register_driver("pgsql", PostgreSQLAdapter) # PDO / Laravel / Doctrine scheme name (issue #58)
148
-
149
- # Register MySQL (mysql-connector-python — optional)
150
- from tina4_python.database.mysql import MySQLAdapter
151
- register_driver("mysql", MySQLAdapter)
152
-
153
- # Register MSSQL (pymssql — optional)
154
- from tina4_python.database.mssql import MSSQLAdapter
155
- register_driver("mssql", MSSQLAdapter)
156
- register_driver("sqlserver", MSSQLAdapter)
157
-
158
- # Register Firebird (fdb — optional)
159
- from tina4_python.database.firebird import FirebirdAdapter
160
- register_driver("firebird", FirebirdAdapter)
161
-
162
- # Register MongoDB (pymongo optional)
163
- try:
164
- from tina4_python.database.mongodb import MongoDBAdapter
165
- register_driver("mongodb", MongoDBAdapter)
166
- register_driver("pymongo", MongoDBAdapter)
167
- except ImportError:
168
- pass
138
+ # Every OTHER adapter is registered LAZILY: its module -- and the third-party
139
+ # driver that module imports -- is loaded only when a URL for that scheme is
140
+ # actually connected. Importing tina4_python.database (which happens on the first
141
+ # Database(url), regardless of engine) therefore never drags psycopg2,
142
+ # firebird-driver (+ protobuf + dateutil), pymssql or pymongo into an app that
143
+ # does not use them. Connecting to Postgres loads only psycopg2; a SQLite app
144
+ # loads no third-party driver at all. This mirrors PHP/Ruby autoload and Node's
145
+ # optionalDependencies + dynamic import. Aliases share the same target so the
146
+ # canonical engine and every alias resolve to one adapter class.
147
+ _LAZY_DRIVERS: dict[str, tuple[str, str]] = {
148
+ "postgres": ("tina4_python.database.postgres", "PostgreSQLAdapter"),
149
+ "postgresql": ("tina4_python.database.postgres", "PostgreSQLAdapter"),
150
+ "pgsql": ("tina4_python.database.postgres", "PostgreSQLAdapter"), # PDO / Laravel / Doctrine (issue #58)
151
+ "mysql": ("tina4_python.database.mysql", "MySQLAdapter"),
152
+ "mssql": ("tina4_python.database.mssql", "MSSQLAdapter"),
153
+ "sqlserver": ("tina4_python.database.mssql", "MSSQLAdapter"),
154
+ "firebird": ("tina4_python.database.firebird", "FirebirdAdapter"),
155
+ "odbc": ("tina4_python.database.odbc", "ODBCAdapter"),
156
+ "mongodb": ("tina4_python.database.mongodb", "MongoDBAdapter"),
157
+ "pymongo": ("tina4_python.database.mongodb", "MongoDBAdapter"),
158
+ }
159
+
160
+
161
+ def known_drivers() -> set[str]:
162
+ """Every URL scheme the framework can resolve: eagerly-registered (sqlite,
163
+ plus anything an app registered by hand via register_driver) and the
164
+ lazily-registered built-ins that import their driver on first use."""
165
+ return set(_DRIVERS) | set(_LAZY_DRIVERS)
166
+
167
+
168
+ def _resolve_lazy_driver(scheme: str) -> None:
169
+ """Import a lazily-declared adapter and register it, on first use.
170
+
171
+ Raises a clear ValueError if the adapter's driver package is not installed,
172
+ rather than an opaque ImportError from deep in the driver.
173
+ """
174
+ module_path, class_name = _LAZY_DRIVERS[scheme]
175
+ try:
176
+ module = importlib.import_module(module_path)
177
+ except ImportError as exc:
178
+ raise ValueError(
179
+ f"Database driver '{scheme}' is unavailable: {exc}. "
180
+ f"Install the driver package and it will register automatically."
181
+ ) from exc
182
+ register_driver(scheme, getattr(module, class_name))
169
183
 
170
184
 
171
185
  class Database:
@@ -339,12 +353,16 @@ class Database:
339
353
  scheme = (urlparse(self.url).scheme or "").lower()
340
354
 
341
355
  if scheme not in _DRIVERS:
342
- available = ", ".join(_DRIVERS.keys())
343
- raise ValueError(
344
- f"Unknown database driver '{scheme}'. "
345
- f"Available: {available}. "
346
- f"Install the driver package and it will register automatically."
347
- )
356
+ if scheme in _LAZY_DRIVERS:
357
+ # First connection to this engine: import + register its adapter.
358
+ _resolve_lazy_driver(scheme)
359
+ else:
360
+ available = ", ".join(sorted(known_drivers()))
361
+ raise ValueError(
362
+ f"Unknown database driver '{scheme}'. "
363
+ f"Available: {available}. "
364
+ f"Install the driver package and it will register automatically."
365
+ )
348
366
 
349
367
  return _DRIVERS[scheme]()
350
368
 
@@ -71,7 +71,7 @@
71
71
 
72
72
  // Build a system
73
73
  const ui = SwaggerUIBundle({
74
- url: "{SWAGGER_ROUTE}/swagger.json",
74
+ url: "/swagger/openapi.json",
75
75
  dom_id: '#swagger-ui',
76
76
  deepLinking: true,
77
77
  presets: [