tina4-python 3.13.128__tar.gz → 3.13.129__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 (170) hide show
  1. {tina4_python-3.13.128 → tina4_python-3.13.129}/PKG-INFO +1 -1
  2. {tina4_python-3.13.128 → tina4_python-3.13.129}/pyproject.toml +1 -1
  3. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/__init__.py +1 -1
  4. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/cli/__init__.py +54 -14
  5. {tina4_python-3.13.128 → tina4_python-3.13.129}/.gitignore +0 -0
  6. {tina4_python-3.13.128 → tina4_python-3.13.129}/README.md +0 -0
  7. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/CLAUDE.md +0 -0
  8. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/HtmlElement.py +0 -0
  9. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/Testing.py +0 -0
  10. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/_import_helper.py +0 -0
  11. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/ai/__init__.py +0 -0
  12. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/ai/client.py +0 -0
  13. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/api/__init__.py +0 -0
  14. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/auth/__init__.py +0 -0
  15. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/cache/__init__.py +0 -0
  16. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/container/__init__.py +0 -0
  17. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/context/__init__.py +0 -0
  18. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/context/chunker.py +0 -0
  19. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/__init__.py +0 -0
  20. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/cache.py +0 -0
  21. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/constants.py +0 -0
  22. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/events.py +0 -0
  23. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/middleware.py +0 -0
  24. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/port_takeover.py +0 -0
  25. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/rate_limiter.py +0 -0
  26. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/request.py +0 -0
  27. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/response.py +0 -0
  28. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/router.py +0 -0
  29. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/core/server.py +0 -0
  30. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/crud/__init__.py +0 -0
  31. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/__init__.py +0 -0
  32. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/adapter.py +0 -0
  33. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/connection.py +0 -0
  34. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/database_url.py +0 -0
  35. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/firebird.py +0 -0
  36. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/mongodb.py +0 -0
  37. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/mssql.py +0 -0
  38. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/mysql.py +0 -0
  39. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/odbc.py +0 -0
  40. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/postgres.py +0 -0
  41. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/sql_translator.py +0 -0
  42. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/database/sqlite.py +0 -0
  43. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/debug/__init__.py +0 -0
  44. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/debug/error_overlay.py +0 -0
  45. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/dev_admin/__init__.py +0 -0
  46. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/dev_admin/metrics.py +0 -0
  47. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/dev_admin/plan.py +0 -0
  48. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/dev_admin/project_index.py +0 -0
  49. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/docs.py +0 -0
  50. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/docstore/__init__.py +0 -0
  51. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/dotenv/__init__.py +0 -0
  52. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/env.py +0 -0
  53. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/frond/FROND.md +0 -0
  54. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/frond/__init__.py +0 -0
  55. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/frond/compiler.py +0 -0
  56. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/frond/engine.py +0 -0
  57. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/frond/parser.py +0 -0
  58. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/auth/meta.json +0 -0
  59. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
  60. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/database/meta.json +0 -0
  61. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
  62. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/error-overlay/meta.json +0 -0
  63. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
  64. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/orm/meta.json +0 -0
  65. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
  66. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
  67. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/queue/meta.json +0 -0
  68. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
  69. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/rest-api/meta.json +0 -0
  70. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
  71. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/templates/meta.json +0 -0
  72. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
  73. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
  74. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/graph/__init__.py +0 -0
  75. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/graph/adapter.py +0 -0
  76. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/graph/adapters/__init__.py +0 -0
  77. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/graph/adapters/arango.py +0 -0
  78. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/graph/adapters/bolt.py +0 -0
  79. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/graph/adapters/ultipa.py +0 -0
  80. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/graph/graph_url.py +0 -0
  81. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/graphql/__init__.py +0 -0
  82. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/i18n/__init__.py +0 -0
  83. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/mcp/__init__.py +0 -0
  84. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/mcp/protocol.py +0 -0
  85. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/mcp/tools.py +0 -0
  86. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/messenger/__init__.py +0 -0
  87. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/migration/__init__.py +0 -0
  88. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/migration/runner.py +0 -0
  89. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/mqtt/__init__.py +0 -0
  90. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/mqtt/message.py +0 -0
  91. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/orm/__init__.py +0 -0
  92. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/orm/fields.py +0 -0
  93. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/orm/model.py +0 -0
  94. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/orm/point.py +0 -0
  95. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/__feedback/widget.js +0 -0
  96. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/css/tina4.css +0 -0
  97. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/css/tina4.min.css +0 -0
  98. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/favicon.ico +0 -0
  99. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/images/logo.svg +0 -0
  100. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
  101. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/js/frond.js +0 -0
  102. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/js/frond.min.js +0 -0
  103. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
  104. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/js/tina4.min.js +0 -0
  105. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/js/tina4js.min.js +0 -0
  106. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/swagger/index.html +0 -0
  107. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
  108. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/query_builder/__init__.py +0 -0
  109. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue/__init__.py +0 -0
  110. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue/amqp_url.py +0 -0
  111. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue/job.py +0 -0
  112. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue/kafka_backend.py +0 -0
  113. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue/lite_backend.py +0 -0
  114. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue/mongo_backend.py +0 -0
  115. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue/rabbitmq_backend.py +0 -0
  116. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue_backends/__init__.py +0 -0
  117. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue_backends/kafka_backend.py +0 -0
  118. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue_backends/mongo_backend.py +0 -0
  119. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
  120. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/realtime/__init__.py +0 -0
  121. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/realtime/models/Attachment.py +0 -0
  122. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/realtime/models/Channel.py +0 -0
  123. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/realtime/models/ChannelMember.py +0 -0
  124. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/realtime/models/Message.py +0 -0
  125. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/realtime/models/Workspace.py +0 -0
  126. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/realtime/models/__init__.py +0 -0
  127. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/realtime/storage.py +0 -0
  128. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/seeder/__init__.py +0 -0
  129. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/service/__init__.py +0 -0
  130. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/session/__init__.py +0 -0
  131. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/session_handlers/__init__.py +0 -0
  132. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/session_handlers/memcached_handler.py +0 -0
  133. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/session_handlers/mongodb_handler.py +0 -0
  134. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/session_handlers/redis_handler.py +0 -0
  135. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/session_handlers/valkey_handler.py +0 -0
  136. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/sso.py +0 -0
  137. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/swagger/__init__.py +0 -0
  138. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/components/crud.twig +0 -0
  139. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
  140. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
  141. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/docker/python/Dockerfile +0 -0
  142. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/docker/uv/Dockerfile +0 -0
  143. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/errors/302.twig +0 -0
  144. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/errors/401.twig +0 -0
  145. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/errors/403.twig +0 -0
  146. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/errors/404.twig +0 -0
  147. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/errors/500.twig +0 -0
  148. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/errors/502.twig +0 -0
  149. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/errors/503.twig +0 -0
  150. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/errors/base.twig +0 -0
  151. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/frontend/README.md +0 -0
  152. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/templates/readme.md +0 -0
  153. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/test/__init__.py +0 -0
  154. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/test_client/__init__.py +0 -0
  155. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
  156. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
  157. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  158. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
  159. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
  160. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
  161. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  162. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
  163. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
  164. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
  165. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
  166. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
  167. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/validator/__init__.py +0 -0
  168. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/websocket/__init__.py +0 -0
  169. {tina4_python-3.13.128 → tina4_python-3.13.129}/tina4_python/websocket/backplane.py +0 -0
  170. {tina4_python-3.13.128 → tina4_python-3.13.129}/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.128
3
+ Version: 3.13.129
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.128"
3
+ version = "3.13.129"
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.128"
54
+ return "3.13.129"
55
55
 
56
56
 
57
57
  __version__ = _resolve_version()
@@ -95,6 +95,46 @@ def _to_table(name: str) -> str:
95
95
  return table
96
96
 
97
97
 
98
+ def _resolve_table(name: str, flags: dict | None = None, *, announce: bool = False) -> str:
99
+ """The table name a generator uses, honouring ``--table-name`` and speaking up
100
+ instead of renaming silently.
101
+
102
+ ``announce`` prints the note/warning; it is True only for ``_gen_model`` (where
103
+ the table is born). Composite generators (crud) let the model sub-call
104
+ announce, and generators that target an EXISTING table (route/seeder/form/view)
105
+ still honour ``--table-name`` but stay quiet so the note is not repeated.
106
+
107
+ * ``--table-name <name>`` wins verbatim. If that name is ITSELF a reserved
108
+ word, warn loudly: Tina4 interpolates table names UNQUOTED, so the ORM's
109
+ generated SQL will fail on it and quoting it in raw SQL + migrations is now
110
+ the developer's job (we do not silently quote -- identifier quoting is a
111
+ global storage invariant, not a local fix).
112
+ * Otherwise fall back to :func:`_to_table`. When that auto-pluralises a
113
+ reserved-word class name (``Order`` -> ``orders``), print a one-line note
114
+ naming the rename and the ``--table-name`` escape hatch, so the developer is
115
+ informed rather than surprised.
116
+
117
+ Called once per generate (``_gen_model`` threads the result into the migration
118
+ and test), so the note prints once.
119
+ """
120
+ flags = flags or {}
121
+ override = flags.get("table-name")
122
+ if override and not isinstance(override, bool):
123
+ if announce and _to_snake(override) in SQL_RESERVED_TABLE_NAMES:
124
+ print(f" ! table_name '{override}' is a SQL reserved word. Tina4 interpolates "
125
+ f"table names UNQUOTED, so the ORM's generated SQL will fail on it -- "
126
+ f"quote it yourself in raw SQL and migrations.")
127
+ return override
128
+ bare = _to_snake(name)
129
+ if bare in SQL_RESERVED_TABLE_NAMES:
130
+ table = _pluralize_table(bare)
131
+ if announce:
132
+ print(f" · '{bare}' is a SQL reserved word; using table_name '{table}' "
133
+ f"(Tina4 interpolates table names unquoted). Override with --table-name <name>.")
134
+ return table
135
+ return bare
136
+
137
+
98
138
  def _parse_fields(fields_str: str) -> list[tuple[str, str]]:
99
139
  """Parse 'name:string,price:float' → [('name','string'), ('price','float')]."""
100
140
  if not fields_str or not fields_str.strip():
@@ -129,7 +169,7 @@ def _parse_flags(args: list[str]) -> tuple[dict, list[str]]:
129
169
  """Parse --key value and --flag from args. Returns (flags, positional)."""
130
170
  # Boolean-only flags that never take a value argument
131
171
  boolean_flags = {"no-browser", "no-reload", "no-kill", "production", "managed", "all", "clear",
132
- "json", "public", "no-migration", "once", "dry-run", "quote", "fix", "no-install"}
172
+ "json", "public", "no-migration", "once", "dry-run", "fix", "no-install"}
133
173
 
134
174
  flags = {}
135
175
  positional = []
@@ -1273,7 +1313,7 @@ def _resolve_generation(target: str, name: str, flags: dict,
1273
1313
 
1274
1314
  if target == "model":
1275
1315
  raw_table = _to_snake(name)
1276
- table = _to_table(name)
1316
+ table = _resolve_table(name, flags)
1277
1317
  transformations = []
1278
1318
  if raw_table in SQL_RESERVED_TABLE_NAMES and raw_table != table:
1279
1319
  transformations.append({
@@ -1282,8 +1322,8 @@ def _resolve_generation(target: str, name: str, flags: dict,
1282
1322
  "to": table,
1283
1323
  "reason": f"SQL reserved word '{raw_table}' would break CREATE TABLE",
1284
1324
  "override": (
1285
- f"--table {raw_table} --quote (requires quoted-identifier "
1286
- "mode, not yet implemented)"
1325
+ "--table-name <name> (table names interpolate unquoted; "
1326
+ "forcing a reserved name is yours to quote in raw SQL)"
1287
1327
  ),
1288
1328
  })
1289
1329
  migration_filename = f"{ts}_create_{table}.sql"
@@ -1437,11 +1477,11 @@ def _format_resolution_block(name: str, target: str, resolution: dict,
1437
1477
 
1438
1478
  if pluralize:
1439
1479
  lines.append("")
1440
- lines.append(f" To keep the raw name '{pluralize['from']}' as the table:")
1480
+ lines.append(" To set the table name yourself:")
1481
+ lines.append(f" tina4 generate {target} {name} --table-name <name>")
1441
1482
  lines.append(
1442
- f" tina4 generate {target} {name} "
1443
- f"--table {pluralize['from']} --quote "
1444
- "(opt-in, ADR-0062 forthcoming)"
1483
+ f" Tina4 interpolates table names unquoted; if you force the "
1484
+ f"reserved '{pluralize['from']}', you own the quoting in raw SQL."
1445
1485
  )
1446
1486
 
1447
1487
  # ADR-0063 additive sections. Each renders only when there is content, so
@@ -1637,7 +1677,7 @@ def _gen_model(name: str, flags: dict, *, emit_test: bool = True):
1637
1677
  and emit their own broader test instead.
1638
1678
  """
1639
1679
  fields = _fields_or_default(flags.get("fields", ""))
1640
- table = _to_table(name)
1680
+ table = _resolve_table(name, flags, announce=True)
1641
1681
 
1642
1682
  # Determine which ORM field types we need to import
1643
1683
  used_types = {"IntegerField"} # always need for id
@@ -1919,7 +1959,7 @@ def _gen_crud(name: str, flags: dict):
1919
1959
  tina4python generate crud Product --fields "name:string,price:float"
1920
1960
  """
1921
1961
  fields = _fields_or_default(flags.get("fields", ""))
1922
- table = _to_table(name)
1962
+ table = _resolve_table(name, flags)
1923
1963
  route_name = table + "s" # routes are plural
1924
1964
 
1925
1965
  print(f"\n Generating CRUD for {name}...\n")
@@ -3017,7 +3057,7 @@ def _gen_seeder(name: str, flags: dict = None):
3017
3057
 
3018
3058
  tina4python generate seeder Product
3019
3059
  """
3020
- table = _to_table(name)
3060
+ table = _resolve_table(name, flags)
3021
3061
  target = Path("src/seeds")
3022
3062
  target.mkdir(parents=True, exist_ok=True)
3023
3063
  path = target / f"{table}_seeder.py"
@@ -3193,7 +3233,7 @@ def _gen_form(name: str, flags: dict = None):
3193
3233
  """
3194
3234
  flags = flags or {}
3195
3235
  fields = _fields_or_default(flags.get("fields", ""))
3196
- table = _to_table(name)
3236
+ table = _resolve_table(name, flags)
3197
3237
  route_name = table + "s"
3198
3238
 
3199
3239
  # Input type mapping
@@ -3277,7 +3317,7 @@ def _gen_view(name: str, flags: dict = None):
3277
3317
  """
3278
3318
  flags = flags or {}
3279
3319
  fields = _fields_or_default(flags.get("fields", ""))
3280
- table = _to_table(name)
3320
+ table = _resolve_table(name, flags)
3281
3321
  route_name = table + "s"
3282
3322
 
3283
3323
  target = Path("src/templates/pages")
@@ -3822,7 +3862,7 @@ def _commands(args=None):
3822
3862
  # "subcommands"?: [str]} # sub-names for the manifest (generate)
3823
3863
 
3824
3864
  GENERATORS = {
3825
- "model": {"handler": _gen_model, "usage": '<Name> [--fields "name:string,price:float"]', "summary": "ORM model + matching migration"},
3865
+ "model": {"handler": _gen_model, "usage": '<Name> [--fields "name:string,price:float"] [--table-name <name>]', "summary": "ORM model + matching migration"},
3826
3866
  "route": {"handler": _gen_route, "usage": "<name> [--model Name] [--public]", "summary": "CRUD route file, secure by default (--public opens writes)"},
3827
3867
  "crud": {"handler": _gen_crud, "usage": '<Name> [--fields "..."] [--public]', "summary": "Model + migration + routes + form + view + test"},
3828
3868
  "migration": {"handler": _gen_migration, "usage": "<description>", "summary": "Timestamped migration file (UP/DOWN)"},