tina4-python 3.12.1__tar.gz → 3.12.2__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 (154) hide show
  1. {tina4_python-3.12.1 → tina4_python-3.12.2}/PKG-INFO +1 -1
  2. {tina4_python-3.12.1 → tina4_python-3.12.2}/pyproject.toml +1 -1
  3. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/__init__.py +1 -1
  4. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/firebird.py +73 -2
  5. {tina4_python-3.12.1 → tina4_python-3.12.2}/.gitignore +0 -0
  6. {tina4_python-3.12.1 → tina4_python-3.12.2}/README.md +0 -0
  7. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/CLAUDE.md +0 -0
  8. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/HtmlElement.py +0 -0
  9. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/Testing.py +0 -0
  10. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/ai/__init__.py +0 -0
  11. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/api/__init__.py +0 -0
  12. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/auth/__init__.py +0 -0
  13. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/cache/__init__.py +0 -0
  14. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/cli/__init__.py +0 -0
  15. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/container/__init__.py +0 -0
  16. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/__init__.py +0 -0
  17. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/cache.py +0 -0
  18. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/constants.py +0 -0
  19. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/events.py +0 -0
  20. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/middleware.py +0 -0
  21. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/rate_limiter.py +0 -0
  22. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/request.py +0 -0
  23. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/response.py +0 -0
  24. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/router.py +0 -0
  25. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/core/server.py +0 -0
  26. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/crud/__init__.py +0 -0
  27. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/__init__.py +0 -0
  28. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/adapter.py +0 -0
  29. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/connection.py +0 -0
  30. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/mongodb.py +0 -0
  31. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/mssql.py +0 -0
  32. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/mysql.py +0 -0
  33. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/odbc.py +0 -0
  34. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/postgres.py +0 -0
  35. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/database/sqlite.py +0 -0
  36. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/debug/__init__.py +0 -0
  37. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/debug/error_overlay.py +0 -0
  38. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/dev_admin/__init__.py +0 -0
  39. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/dev_admin/metrics.py +0 -0
  40. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/dev_admin/plan.py +0 -0
  41. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/dev_admin/project_index.py +0 -0
  42. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/docs.py +0 -0
  43. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/dotenv/__init__.py +0 -0
  44. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/frond/FROND.md +0 -0
  45. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/frond/__init__.py +0 -0
  46. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/frond/engine.py +0 -0
  47. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/auth/meta.json +0 -0
  48. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
  49. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/database/meta.json +0 -0
  50. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
  51. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/error-overlay/meta.json +0 -0
  52. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
  53. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/orm/meta.json +0 -0
  54. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
  55. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
  56. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/queue/meta.json +0 -0
  57. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
  58. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/rest-api/meta.json +0 -0
  59. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
  60. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/templates/meta.json +0 -0
  61. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
  62. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
  63. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/graphql/__init__.py +0 -0
  64. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/i18n/__init__.py +0 -0
  65. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/mcp/__init__.py +0 -0
  66. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/mcp/protocol.py +0 -0
  67. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/mcp/tools.py +0 -0
  68. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/messenger/__init__.py +0 -0
  69. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/migration/__init__.py +0 -0
  70. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/migration/runner.py +0 -0
  71. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/orm/__init__.py +0 -0
  72. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/orm/fields.py +0 -0
  73. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/orm/model.py +0 -0
  74. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/css/tina4.css +0 -0
  75. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/css/tina4.min.css +0 -0
  76. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/favicon.ico +0 -0
  77. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/images/logo.svg +0 -0
  78. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
  79. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/js/frond.js +0 -0
  80. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/js/frond.min.js +0 -0
  81. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/js/tina4-dev-admin.js +0 -0
  82. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
  83. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/js/tina4.min.js +0 -0
  84. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/js/tina4js.min.js +0 -0
  85. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/swagger/index.html +0 -0
  86. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
  87. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/query_builder/__init__.py +0 -0
  88. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue/__init__.py +0 -0
  89. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue/job.py +0 -0
  90. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue/kafka_backend.py +0 -0
  91. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue/lite_backend.py +0 -0
  92. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue/mongo_backend.py +0 -0
  93. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue/rabbitmq_backend.py +0 -0
  94. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue_backends/__init__.py +0 -0
  95. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue_backends/kafka_backend.py +0 -0
  96. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue_backends/mongo_backend.py +0 -0
  97. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
  98. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/__init__.py +0 -0
  99. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_alerts.scss +0 -0
  100. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_badges.scss +0 -0
  101. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_buttons.scss +0 -0
  102. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_cards.scss +0 -0
  103. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_forms.scss +0 -0
  104. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_grid.scss +0 -0
  105. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_modals.scss +0 -0
  106. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_nav.scss +0 -0
  107. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_reset.scss +0 -0
  108. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_tables.scss +0 -0
  109. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_typography.scss +0 -0
  110. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_utilities.scss +0 -0
  111. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/_variables.scss +0 -0
  112. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/base.scss +0 -0
  113. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/colors.scss +0 -0
  114. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/scss/tina4css/tina4.scss +0 -0
  115. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/seeder/__init__.py +0 -0
  116. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/service/__init__.py +0 -0
  117. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/session/__init__.py +0 -0
  118. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/session_handlers/__init__.py +0 -0
  119. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/session_handlers/mongodb_handler.py +0 -0
  120. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/session_handlers/redis_handler.py +0 -0
  121. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/session_handlers/valkey_handler.py +0 -0
  122. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/swagger/__init__.py +0 -0
  123. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/components/crud.twig +0 -0
  124. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
  125. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
  126. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/docker/python/Dockerfile +0 -0
  127. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/docker/uv/Dockerfile +0 -0
  128. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/errors/302.twig +0 -0
  129. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/errors/401.twig +0 -0
  130. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/errors/403.twig +0 -0
  131. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/errors/404.twig +0 -0
  132. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/errors/500.twig +0 -0
  133. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/errors/502.twig +0 -0
  134. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/errors/503.twig +0 -0
  135. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/errors/base.twig +0 -0
  136. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/frontend/README.md +0 -0
  137. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/templates/readme.md +0 -0
  138. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/test_client/__init__.py +0 -0
  139. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
  140. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
  141. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  142. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
  143. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
  144. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
  145. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  146. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
  147. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
  148. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
  149. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
  150. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
  151. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/validator/__init__.py +0 -0
  152. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/websocket/__init__.py +0 -0
  153. {tina4_python-3.12.1 → tina4_python-3.12.2}/tina4_python/websocket/backplane.py +0 -0
  154. {tina4_python-3.12.1 → tina4_python-3.12.2}/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.12.1
3
+ Version: 3.12.2
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.12.1"
3
+ version = "3.12.2"
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.12.1"
11
+ __version__ = "3.12.2"
12
12
 
13
13
  # ── Route decorators ──
14
14
  from tina4_python.core.router import ( # noqa: E402, F401
@@ -6,10 +6,68 @@ Firebird adapter using firebird-driver (preferred) or fdb (fallback).
6
6
 
7
7
  Requires: pip install firebird-driver (or pip install fdb for legacy)
8
8
  """
9
+ import os
9
10
  import re
10
11
  from urllib.parse import urlparse, unquote
11
12
  from tina4_python.database.adapter import DatabaseAdapter, DatabaseResult, SQLTranslator
12
13
 
14
+
15
+ # Detects a Windows drive-letter prefix like "C:/" or "C:\". The leading-slash
16
+ # variant ("/C:/...") shows up after a URL parse strips one slash off
17
+ # "firebird://host:port/C:/...".
18
+ _WIN_DRIVE_RE = re.compile(r"^/?[A-Za-z]:[/\\]")
19
+
20
+
21
+ def _normalize_firebird_db_identifier(raw_path: str) -> str:
22
+ """Turn the URL path component into a Firebird database identifier.
23
+
24
+ Firebird is the awkward one — it needs either an absolute file path
25
+ on the server, a Windows drive-letter path, or an alias name. The
26
+ classic URI form uses a double-slash to keep the leading "/" of an
27
+ absolute path through ``urlparse``::
28
+
29
+ firebird://host:port//firebird/data/app.fdb → /firebird/data/app.fdb
30
+
31
+ But that double slash is unintuitive to anyone used to the way
32
+ postgres / mysql / mssql encode the database name. We accept five
33
+ equivalent forms and normalise all of them:
34
+
35
+ * ``//abs/path/db.fdb`` → ``/abs/path/db.fdb`` (classic double-slash)
36
+ * ``/abs/path/db.fdb`` → ``/abs/path/db.fdb`` (single-slash, what most people type)
37
+ * ``/C:/Data/db.fdb`` → ``C:/Data/db.fdb`` (Windows, leading URL slash dropped)
38
+ * ``/C%3A/Data/db.fdb`` → ``C:/Data/db.fdb`` (Windows with URL-encoded colon)
39
+ * ``/employee`` → ``employee`` (alias — single token)
40
+
41
+ Aliases are detected as the leftover case: a single token with no
42
+ slashes. Anything path-like is kept as a path.
43
+ """
44
+ decoded = unquote(raw_path)
45
+
46
+ # Classic double-slash form: //abs/path → /abs/path
47
+ if decoded.startswith("//"):
48
+ decoded = decoded[1:]
49
+
50
+ # Windows drive-letter — drop the URL-introduced leading slash.
51
+ # /C:/Data/db.fdb → C:/Data/db.fdb
52
+ if _WIN_DRIVE_RE.match(decoded):
53
+ if decoded.startswith("/"):
54
+ decoded = decoded[1:]
55
+ return decoded
56
+
57
+ # Look at the content after stripping the leading slash. If it's a
58
+ # single token with no separators, it's a Firebird alias — return
59
+ # WITHOUT the leading slash (the alias name itself is the identifier).
60
+ body = decoded[1:] if decoded.startswith("/") else decoded
61
+ if body and "/" not in body and "\\" not in body:
62
+ return body
63
+
64
+ # Otherwise it's a file path. If it already has a leading slash,
65
+ # keep it. If it's a relative-looking path (slash-separated but no
66
+ # leading "/") promote it to absolute — Firebird needs absolute paths
67
+ # and we don't know the server's CWD anyway.
68
+ return decoded if decoded.startswith("/") else "/" + decoded
69
+
70
+
13
71
  # Try modern firebird-driver first, fall back to legacy fdb
14
72
  _driver = None
15
73
  _driver_name = None
@@ -65,8 +123,21 @@ class FirebirdAdapter(DatabaseAdapter):
65
123
  parsed = urlparse(connection_string)
66
124
  host = parsed.hostname or "localhost"
67
125
  port = parsed.port or 3050
68
- # Firebird database path — decode URL-encoded characters
69
- db_path = unquote(parsed.path[1:]) if parsed.path.startswith("/") else unquote(parsed.path)
126
+
127
+ # Firebird database identifier resolution two layers:
128
+ #
129
+ # 1. ``TINA4_DATABASE_FIREBIRD_PATH`` env override wins if set.
130
+ # Useful for Windows users with raw backslash paths (no URL
131
+ # encoding required) and for ops setups that keep server URL
132
+ # and DB location in separate config layers.
133
+ # 2. Otherwise normalise the URL path component — accepts every
134
+ # sensible variant (single/double slash, drive letter, alias).
135
+ env_override = os.environ.get("TINA4_DATABASE_FIREBIRD_PATH", "")
136
+ if env_override:
137
+ db_path = env_override
138
+ else:
139
+ db_path = _normalize_firebird_db_identifier(parsed.path)
140
+
70
141
  user = parsed.username or username or "SYSDBA"
71
142
  password = parsed.password or password or "masterkey"
72
143
  charset = kwargs.pop("charset", "UTF8")
File without changes
File without changes