tigrbl 0.3.16.dev2__tar.gz → 0.3.16.dev4__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 (313) hide show
  1. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/PKG-INFO +1 -1
  2. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/pyproject.toml +1 -1
  3. tigrbl-0.3.16.dev4/tigrbl/api/_router.py +490 -0
  4. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/app/transport.py +1 -17
  5. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/jsonrpc/dispatcher.py +32 -0
  6. tigrbl-0.3.16.dev2/tigrbl/api/_router.py +0 -273
  7. tigrbl-0.3.16.dev2/tigrbl/app/_routing_runtime.py +0 -24
  8. tigrbl-0.3.16.dev2/tigrbl/core/router_runtime.py +0 -164
  9. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/LICENSE +0 -0
  10. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/README.md +0 -0
  11. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/README.md +0 -0
  12. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/__init__.py +0 -0
  13. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/__init__.py +0 -0
  14. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/_api.py +0 -0
  15. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/_route.py +0 -0
  16. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/_routing.py +0 -0
  17. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/api_spec.py +0 -0
  18. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/mro_collect.py +0 -0
  19. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/resolve.py +0 -0
  20. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/shortcuts.py +0 -0
  21. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/api/tigrbl_api.py +0 -0
  22. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/app/__init__.py +0 -0
  23. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/app/_app.py +0 -0
  24. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/app/_model_registry.py +0 -0
  25. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/app/app_spec.py +0 -0
  26. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/app/mro_collect.py +0 -0
  27. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/app/shortcuts.py +0 -0
  28. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/app/tigrbl_app.py +0 -0
  29. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/__init__.py +0 -0
  30. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/api/__init__.py +0 -0
  31. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/api/common.py +0 -0
  32. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/api/include.py +0 -0
  33. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/api/resource_proxy.py +0 -0
  34. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/api/rpc.py +0 -0
  35. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/columns.py +0 -0
  36. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/handlers/__init__.py +0 -0
  37. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/handlers/builder.py +0 -0
  38. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/handlers/ctx.py +0 -0
  39. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/handlers/identifiers.py +0 -0
  40. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/handlers/namespaces.py +0 -0
  41. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/handlers/steps.py +0 -0
  42. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/hooks.py +0 -0
  43. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/model.py +0 -0
  44. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/model_helpers.py +0 -0
  45. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/model_registry.py +0 -0
  46. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/__init__.py +0 -0
  47. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/attach.py +0 -0
  48. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/collection.py +0 -0
  49. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/common.py +0 -0
  50. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/fastapi.py +0 -0
  51. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/helpers.py +0 -0
  52. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/io.py +0 -0
  53. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/io_headers.py +0 -0
  54. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/member.py +0 -0
  55. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/router.py +0 -0
  56. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rest/routing.py +0 -0
  57. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/rpc.py +0 -0
  58. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/schemas/__init__.py +0 -0
  59. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/schemas/builder.py +0 -0
  60. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/schemas/defaults.py +0 -0
  61. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/bindings/schemas/utils.py +0 -0
  62. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/README.md +0 -0
  63. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/__init__.py +0 -0
  64. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/_column.py +0 -0
  65. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/column_spec.py +0 -0
  66. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/field_spec.py +0 -0
  67. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/infer/__init__.py +0 -0
  68. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/infer/core.py +0 -0
  69. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/infer/jsonhints.py +0 -0
  70. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/infer/planning.py +0 -0
  71. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/infer/types.py +0 -0
  72. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/infer/utils.py +0 -0
  73. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/io_spec.py +0 -0
  74. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/mro_collect.py +0 -0
  75. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/shortcuts.py +0 -0
  76. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/column/storage_spec.py +0 -0
  77. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/config/__init__.py +0 -0
  78. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/config/constants.py +0 -0
  79. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/config/defaults.py +0 -0
  80. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/config/resolver.py +0 -0
  81. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/__init__.py +0 -0
  82. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/__init__.py +0 -0
  83. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/bulk.py +0 -0
  84. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/helpers/__init__.py +0 -0
  85. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/helpers/db.py +0 -0
  86. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/helpers/enum.py +0 -0
  87. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/helpers/filters.py +0 -0
  88. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/helpers/model.py +0 -0
  89. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/helpers/normalize.py +0 -0
  90. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/ops.py +0 -0
  91. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/crud/params.py +0 -0
  92. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/core/resolver.py +0 -0
  93. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/ddl/__init__.py +0 -0
  94. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/decorators.py +0 -0
  95. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/deps/__init__.py +0 -0
  96. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/deps/jinja.py +0 -0
  97. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/deps/pydantic.py +0 -0
  98. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/deps/sqlalchemy.py +0 -0
  99. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/docs/verbosity.md +0 -0
  100. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/__init__.py +0 -0
  101. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/_engine.py +0 -0
  102. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/bind.py +0 -0
  103. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/builders.py +0 -0
  104. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/capabilities.py +0 -0
  105. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/collect.py +0 -0
  106. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/decorators.py +0 -0
  107. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/docs/PLUGINS.md +0 -0
  108. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/engine_spec.py +0 -0
  109. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/plugins.py +0 -0
  110. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/registry.py +0 -0
  111. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/resolver.py +0 -0
  112. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/engine/shortcuts.py +0 -0
  113. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/headers/__init__.py +0 -0
  114. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/headers/_header.py +0 -0
  115. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/hook/__init__.py +0 -0
  116. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/hook/_hook.py +0 -0
  117. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/hook/decorators.py +0 -0
  118. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/hook/exceptions.py +0 -0
  119. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/hook/hook_spec.py +0 -0
  120. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/hook/mro_collect.py +0 -0
  121. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/hook/shortcuts.py +0 -0
  122. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/hook/types.py +0 -0
  123. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/middlewares/__init__.py +0 -0
  124. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/middlewares/base.py +0 -0
  125. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/middlewares/compose.py +0 -0
  126. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/middlewares/cors.py +0 -0
  127. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/middlewares/decorators.py +0 -0
  128. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/middlewares/middleware.py +0 -0
  129. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/middlewares/spec.py +0 -0
  130. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/__init__.py +0 -0
  131. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/_op.py +0 -0
  132. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/canonical.py +0 -0
  133. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/collect.py +0 -0
  134. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/decorators.py +0 -0
  135. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/model_registry.py +0 -0
  136. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/mro_collect.py +0 -0
  137. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/resolver.py +0 -0
  138. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/op/types.py +0 -0
  139. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/__init__.py +0 -0
  140. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/_RowBound.py +0 -0
  141. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/__init__.py +0 -0
  142. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/bootstrappable.py +0 -0
  143. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/bound.py +0 -0
  144. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/edges.py +0 -0
  145. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/fields.py +0 -0
  146. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/hierarchy.py +0 -0
  147. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/key_digest.py +0 -0
  148. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/lifecycle.py +0 -0
  149. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/locks.py +0 -0
  150. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/markers.py +0 -0
  151. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/operations.py +0 -0
  152. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/ownable.py +0 -0
  153. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/principals.py +0 -0
  154. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/tenant_bound.py +0 -0
  155. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/upsertable.py +0 -0
  156. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/mixins/utils.py +0 -0
  157. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/__init__.py +0 -0
  158. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/_base.py +0 -0
  159. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/audit.py +0 -0
  160. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/client.py +0 -0
  161. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/group.py +0 -0
  162. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/org.py +0 -0
  163. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/rbac.py +0 -0
  164. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/status.py +0 -0
  165. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/tenant.py +0 -0
  166. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/orm/tables/user.py +0 -0
  167. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/requests/__init__.py +0 -0
  168. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/requests/_request.py +0 -0
  169. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/requests/adapters.py +0 -0
  170. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/README.md +0 -0
  171. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/__init__.py +0 -0
  172. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/_response.py +0 -0
  173. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/_transport.py +0 -0
  174. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/bind.py +0 -0
  175. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/decorators.py +0 -0
  176. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/resolver.py +0 -0
  177. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/shortcuts.py +0 -0
  178. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/responses/types.py +0 -0
  179. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/rest/__init__.py +0 -0
  180. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/README.md +0 -0
  181. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/__init__.py +0 -0
  182. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/__init__.py +0 -0
  183. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/emit/__init__.py +0 -0
  184. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/emit/paired_post.py +0 -0
  185. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/emit/paired_pre.py +0 -0
  186. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/emit/readtime_alias.py +0 -0
  187. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/out/__init__.py +0 -0
  188. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/out/masking.py +0 -0
  189. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/refresh/__init__.py +0 -0
  190. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/refresh/demand.py +0 -0
  191. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/resolve/__init__.py +0 -0
  192. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/resolve/assemble.py +0 -0
  193. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/resolve/paired_gen.py +0 -0
  194. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/response/__init__.py +0 -0
  195. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/response/headers_from_payload.py +0 -0
  196. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/response/negotiate.py +0 -0
  197. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/response/negotiation.py +0 -0
  198. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/response/render.py +0 -0
  199. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/response/renderer.py +0 -0
  200. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/response/template.py +0 -0
  201. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/response/templates.py +0 -0
  202. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/schema/__init__.py +0 -0
  203. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/schema/collect_in.py +0 -0
  204. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/schema/collect_out.py +0 -0
  205. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/storage/__init__.py +0 -0
  206. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/storage/to_stored.py +0 -0
  207. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/wire/__init__.py +0 -0
  208. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/wire/build_in.py +0 -0
  209. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/wire/build_out.py +0 -0
  210. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/wire/dump.py +0 -0
  211. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/atoms/wire/validate_in.py +0 -0
  212. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/context.py +0 -0
  213. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/events.py +0 -0
  214. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/executor/__init__.py +0 -0
  215. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/executor/guards.py +0 -0
  216. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/executor/helpers.py +0 -0
  217. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/executor/invoke.py +0 -0
  218. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/executor/types.py +0 -0
  219. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/kernel.py +0 -0
  220. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/labels.py +0 -0
  221. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/opview.py +0 -0
  222. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/ordering.py +0 -0
  223. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/status/__init__.py +0 -0
  224. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/status/converters.py +0 -0
  225. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/status/exceptions.py +0 -0
  226. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/status/mappings.py +0 -0
  227. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/status/utils.py +0 -0
  228. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/system.py +0 -0
  229. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/runtime/trace.py +0 -0
  230. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/__init__.py +0 -0
  231. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/_schema.py +0 -0
  232. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/builder/__init__.py +0 -0
  233. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/builder/build_schema.py +0 -0
  234. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/builder/cache.py +0 -0
  235. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/builder/compat.py +0 -0
  236. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/builder/extras.py +0 -0
  237. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/builder/helpers.py +0 -0
  238. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/builder/list_params.py +0 -0
  239. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/builder/strip_parent_fields.py +0 -0
  240. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/collect.py +0 -0
  241. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/decorators.py +0 -0
  242. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/get_schema.py +0 -0
  243. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/schema_spec.py +0 -0
  244. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/shortcuts.py +0 -0
  245. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/types.py +0 -0
  246. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/schema/utils.py +0 -0
  247. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/__init__.py +0 -0
  248. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/dependencies.py +0 -0
  249. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/schemes/__init__.py +0 -0
  250. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/schemes/_base.py +0 -0
  251. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/schemes/api_key.py +0 -0
  252. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/schemes/http_bearer.py +0 -0
  253. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/schemes/mutual_tls.py +0 -0
  254. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/schemes/oauth2.py +0 -0
  255. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/security/schemes/openid_connect.py +0 -0
  256. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/session/README.md +0 -0
  257. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/session/__init__.py +0 -0
  258. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/session/abc.py +0 -0
  259. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/session/base.py +0 -0
  260. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/session/decorators.py +0 -0
  261. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/session/default.py +0 -0
  262. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/session/shortcuts.py +0 -0
  263. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/session/spec.py +0 -0
  264. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/shortcuts.py +0 -0
  265. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/specs.py +0 -0
  266. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/__init__.py +0 -0
  267. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/diagnostics/__init__.py +0 -0
  268. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/diagnostics/compat.py +0 -0
  269. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/diagnostics/healthz.py +0 -0
  270. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/diagnostics/hookz.py +0 -0
  271. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/diagnostics/kernelz.py +0 -0
  272. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/diagnostics/methodz.py +0 -0
  273. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/diagnostics/router.py +0 -0
  274. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/diagnostics/utils.py +0 -0
  275. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/__init__.py +0 -0
  276. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/lens.py +0 -0
  277. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/openapi/__init__.py +0 -0
  278. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/openapi/helpers.py +0 -0
  279. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/openapi/metadata.py +0 -0
  280. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/openapi/mount.py +0 -0
  281. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/openapi/schema.py +0 -0
  282. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/openrpc.py +0 -0
  283. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/docs/swagger.py +0 -0
  284. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/favicon/__init__.py +0 -0
  285. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/favicon/assets/favicon.svg +0 -0
  286. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/system/uvicorn.py +0 -0
  287. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/table/__init__.py +0 -0
  288. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/table/_base.py +0 -0
  289. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/table/_table.py +0 -0
  290. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/table/mro_collect.py +0 -0
  291. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/table/shortcuts.py +0 -0
  292. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/table/table_spec.py +0 -0
  293. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/__init__.py +0 -0
  294. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/background.py +0 -0
  295. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/httpx.py +0 -0
  296. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/jsonrpc/__init__.py +0 -0
  297. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/jsonrpc/helpers.py +0 -0
  298. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/jsonrpc/models.py +0 -0
  299. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/jsonrpc/openrpc.py +0 -0
  300. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/rest/__init__.py +0 -0
  301. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/rest/aggregator.py +0 -0
  302. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/transport/rest/decorators.py +0 -0
  303. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/__init__.py +0 -0
  304. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/allow_anon_provider.py +0 -0
  305. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/authn_abc.py +0 -0
  306. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/nested_path_provider.py +0 -0
  307. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/op.py +0 -0
  308. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/op_config_provider.py +0 -0
  309. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/op_verb_alias_provider.py +0 -0
  310. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/request_extras_provider.py +0 -0
  311. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/response_extras_provider.py +0 -0
  312. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/table_config_provider.py +0 -0
  313. {tigrbl-0.3.16.dev2 → tigrbl-0.3.16.dev4}/tigrbl/types/uuid.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tigrbl
3
- Version: 0.3.16.dev2
3
+ Version: 0.3.16.dev4
4
4
  Summary: A modern pure ASGI/WSGI Python framework for building schema-first REST and JSON-RPC APIs with SQLAlchemy models, typed validation, lifecycle hooks, and engine extension support.
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tigrbl"
3
- version = "0.3.16.dev2"
3
+ version = "0.3.16.dev4"
4
4
  description = "A modern pure ASGI/WSGI Python framework for building schema-first REST and JSON-RPC APIs with SQLAlchemy models, typed validation, lifecycle hooks, and engine extension support."
5
5
  license = "Apache-2.0"
6
6
  readme = "README.md"
@@ -0,0 +1,490 @@
1
+ """Router primitives backing ``tigrbl.api.Api`` and ``tigrbl.app.App``.
2
+
3
+ This compatibility router surface is slated for deprecation in favor of the
4
+ higher-level ``Api``/``App`` interfaces.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import inspect
10
+ from contextlib import asynccontextmanager
11
+ from typing import Any, Callable
12
+
13
+ from tigrbl.api._routing import (
14
+ add_api_route,
15
+ include_router,
16
+ merge_tags,
17
+ normalize_prefix,
18
+ route,
19
+ )
20
+ from tigrbl.api.resolve import (
21
+ invoke_dependency as _invoke_dependency_impl,
22
+ resolve_handler_kwargs as _resolve_handler_kwargs_impl,
23
+ resolve_route_dependencies as _resolve_route_dependencies_impl,
24
+ )
25
+ from tigrbl.app.transport import (
26
+ asgi_app as _asgi_app_impl,
27
+ wsgi_app as _wsgi_app_impl,
28
+ )
29
+ from tigrbl.requests.adapters import (
30
+ request_from_asgi as _request_from_asgi_impl,
31
+ request_from_wsgi as _request_from_wsgi_impl,
32
+ )
33
+ from tigrbl.responses import Response
34
+ from tigrbl.runtime.status.exceptions import HTTPException
35
+ from tigrbl.runtime.status.mappings import status
36
+ from tigrbl.transport.httpx import ensure_httpx_sync_transport
37
+
38
+ from ._route import Route
39
+ from ..system.docs.openapi import build_openapi, mount_openapi
40
+ from ..system.docs.openapi.metadata import is_metadata_route as _is_metadata_route_impl
41
+ from ..system.docs.swagger import mount_swagger
42
+ from ..requests import Request
43
+ from ..transport.rest.decorators import (
44
+ delete as rest_delete,
45
+ get as rest_get,
46
+ patch as rest_patch,
47
+ post as rest_post,
48
+ put as rest_put,
49
+ )
50
+
51
+ Handler = Callable[..., Any]
52
+
53
+
54
+ @asynccontextmanager
55
+ async def _default_lifespan_context(app: Any):
56
+ yield
57
+
58
+
59
+ class Router:
60
+ def __init__(
61
+ self,
62
+ *,
63
+ title: str = "API",
64
+ version: str = "0.1.0",
65
+ description: str | None = None,
66
+ openapi_url: str = "/openapi.json",
67
+ docs_url: str = "/docs",
68
+ debug: bool = False,
69
+ swagger_ui_version: str = "5.31.0",
70
+ prefix: str = "",
71
+ tags: list[str] | None = None,
72
+ dependencies: list[Any] | None = None,
73
+ include_docs: bool = False,
74
+ ) -> None:
75
+ self.title = title
76
+ self.version = version
77
+ self.description = description
78
+ self.openapi_url = openapi_url
79
+ self.docs_url = docs_url
80
+ self.debug = debug
81
+ self.swagger_ui_version = swagger_ui_version
82
+ self.prefix = normalize_prefix(prefix)
83
+ self.tags = list(tags or [])
84
+ self.dependencies = list(dependencies or [])
85
+ # Allow dependencies to be replaced at runtime, typically for testing
86
+ # and environment-specific wiring.
87
+ self.dependency_overrides: dict[Callable[..., Any], Callable[..., Any]] = {}
88
+ self.dependency_overrides_provider = self
89
+ self._event_handlers: dict[str, list[Callable[..., Any]]] = {
90
+ "startup": [],
91
+ "shutdown": [],
92
+ }
93
+ self.lifespan_context = self._lifespan_context
94
+
95
+ self.lifespan_context = _default_lifespan_context
96
+
97
+ self._routes: list[Route] = []
98
+ self.routes = self._routes
99
+
100
+ if include_docs:
101
+ self._install_builtin_routes()
102
+
103
+ @asynccontextmanager
104
+ async def _lifespan_context(self, _: Any):
105
+ """ASGI lifecycle context manager for startup/shutdown hooks."""
106
+ await self.run_event_handlers("startup")
107
+ try:
108
+ yield
109
+ finally:
110
+ await self.run_event_handlers("shutdown")
111
+
112
+ @property
113
+ def event_handlers(self) -> dict[str, list[Callable[..., Any]]]:
114
+ """Expose registered startup and shutdown callbacks by event name."""
115
+ return self._event_handlers
116
+
117
+ @property
118
+ def on_startup(self) -> list[Callable[..., Any]]:
119
+ """Provide direct access to startup callbacks for lifecycle runners."""
120
+ return self._event_handlers["startup"]
121
+
122
+ @property
123
+ def on_shutdown(self) -> list[Callable[..., Any]]:
124
+ """Provide direct access to shutdown callbacks for lifecycle runners."""
125
+ return self._event_handlers["shutdown"]
126
+
127
+ def add_event_handler(
128
+ self,
129
+ event_type: str,
130
+ handler: Callable[..., Any],
131
+ ) -> None:
132
+ """Register a startup or shutdown handler."""
133
+ if event_type not in self._event_handlers:
134
+ raise ValueError(
135
+ f"Unsupported event type '{event_type}'. "
136
+ f"Expected one of: {tuple(self._event_handlers.keys())}."
137
+ )
138
+ self._event_handlers[event_type].append(handler)
139
+
140
+ def on_event(
141
+ self, event_type: str
142
+ ) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
143
+ """Decorator form of :meth:`add_event_handler`."""
144
+
145
+ def _decorator(handler: Callable[..., Any]) -> Callable[..., Any]:
146
+ self.add_event_handler(event_type, handler)
147
+ return handler
148
+
149
+ return _decorator
150
+
151
+ async def run_event_handlers(self, event_type: str) -> None:
152
+ """Execute registered handlers for an event type in registration order."""
153
+ if event_type not in self._event_handlers:
154
+ raise ValueError(
155
+ f"Unsupported event type '{event_type}'. "
156
+ f"Expected one of: {tuple(self._event_handlers.keys())}."
157
+ )
158
+ for handler in self._event_handlers[event_type]:
159
+ result = handler()
160
+ if inspect.isawaitable(result):
161
+ await result
162
+
163
+ def _normalize_prefix(self, prefix: str) -> str:
164
+ return normalize_prefix(prefix)
165
+
166
+ def add_api_route(self, path: str, endpoint: Handler, **kwargs: Any) -> None:
167
+ return add_api_route(self, path, endpoint, **kwargs)
168
+
169
+ def _merge_tags(self, tags: list[str] | None) -> list[str] | None:
170
+ return merge_tags(self.tags, tags)
171
+
172
+ def route(
173
+ self, path: str, *, methods: Any, **kwargs: Any
174
+ ) -> Callable[[Handler], Handler]:
175
+ return route(self, path, methods=methods, **kwargs)
176
+
177
+ def get(self, path: str, **kwargs: Any) -> Callable[[Handler], Handler]:
178
+ return rest_get(self, path, **kwargs)
179
+
180
+ def post(self, path: str, **kwargs: Any) -> Callable[[Handler], Handler]:
181
+ return rest_post(self, path, **kwargs)
182
+
183
+ def put(self, path: str, **kwargs: Any) -> Callable[[Handler], Handler]:
184
+ return rest_put(self, path, **kwargs)
185
+
186
+ def patch(self, path: str, **kwargs: Any) -> Callable[[Handler], Handler]:
187
+ return rest_patch(self, path, **kwargs)
188
+
189
+ def delete(self, path: str, **kwargs: Any) -> Callable[[Handler], Handler]:
190
+ return rest_delete(self, path, **kwargs)
191
+
192
+ def include_router(self, other: "Router", **kwargs: Any) -> None:
193
+ return include_router(self, other, **kwargs)
194
+
195
+ def __call__(self, *args: Any, **kwargs: Any):
196
+ return self._router_call(*args, **kwargs)
197
+
198
+ def _router_call(self, *args: Any, **kwargs: Any):
199
+ """Dispatch entrypoint supporting WSGI and ASGI call conventions.
200
+
201
+ The router is designed to be directly mountable on WSGI *or* ASGI
202
+ servers without additional glue code.
203
+
204
+ Supported invocation forms
205
+ --------------------------
206
+ WSGI (PEP 3333)
207
+ ``router(environ: dict, start_response: Callable) -> list[bytes]``
208
+
209
+ ASGI 3 (single callable)
210
+ ``router(scope: dict, receive: Callable, send: Callable) -> Awaitable[None]``
211
+
212
+ ASGI 2 (callable factory)
213
+ ``router(scope: dict) -> Callable[[receive, send], Awaitable[None]]``
214
+
215
+ The protocol is inferred from positional arguments.
216
+ """
217
+
218
+ del kwargs
219
+ if len(args) == 2 and isinstance(args[0], dict) and callable(args[1]):
220
+ return self._wsgi_app(args[0], args[1])
221
+ if len(args) == 1 and isinstance(args[0], dict):
222
+ scope = args[0]
223
+
224
+ async def _asgi2_instance(receive: Callable, send: Callable) -> None:
225
+ await self._asgi_app(scope, receive, send)
226
+
227
+ return _asgi2_instance
228
+ if len(args) == 3 and isinstance(args[0], dict):
229
+ return self._asgi_app(args[0], args[1], args[2])
230
+ raise TypeError("Invalid ASGI/WSGI invocation")
231
+
232
+ def _wsgi_app(
233
+ self, environ: dict[str, Any], start_response: Callable[..., Any]
234
+ ) -> list[bytes]:
235
+ return _wsgi_app_impl(self, environ, start_response)
236
+
237
+ async def _asgi_app(
238
+ self, scope: dict[str, Any], receive: Callable, send: Callable
239
+ ) -> None:
240
+ await _asgi_app_impl(self, scope, receive, send)
241
+
242
+ def _request_from_wsgi(self, environ: dict[str, Any]) -> Request:
243
+ return _request_from_wsgi_impl(self, environ)
244
+
245
+ def _request_from_asgi(self, scope: dict[str, Any], body: bytes) -> Request:
246
+ return _request_from_asgi_impl(self, scope, body)
247
+
248
+ def _route_match_priority(self, route: Route) -> tuple[int, int, int]:
249
+ return _route_match_priority(route)
250
+
251
+ @staticmethod
252
+ def _is_http_response_like(obj: Any) -> bool:
253
+ return (
254
+ hasattr(obj, "status_code")
255
+ and hasattr(obj, "headers")
256
+ and (
257
+ hasattr(obj, "body")
258
+ or hasattr(obj, "body_iterator")
259
+ or hasattr(obj, "render")
260
+ or hasattr(obj, "path")
261
+ )
262
+ )
263
+
264
+ async def dispatch(self, req: Request) -> Response:
265
+ """Route an incoming request to the best matching handler."""
266
+
267
+ path_matches = [r for r in self._routes if r.pattern.match(req.path)]
268
+
269
+ if req.method.upper() == "OPTIONS" and path_matches:
270
+ return _build_options_response(req, path_matches)
271
+
272
+ candidates = [r for r in path_matches if req.method in r.methods]
273
+ candidates.sort(key=self._route_match_priority)
274
+ for candidate in candidates:
275
+ match = candidate.pattern.match(req.path)
276
+ if not match:
277
+ continue
278
+ req2 = Request(
279
+ method=req.method,
280
+ path=req.path,
281
+ headers=req.headers,
282
+ query=req.query,
283
+ path_params={k: v for k, v in match.groupdict().items()},
284
+ body=req.body,
285
+ script_name=req.script_name,
286
+ app=self,
287
+ state=req.state,
288
+ scope=req.scope,
289
+ )
290
+ return await self.call_handler(candidate, req2)
291
+
292
+ # If the path exists for any method, return a 405 + Allow header.
293
+ if path_matches:
294
+ allowed = {
295
+ method.upper()
296
+ for candidate in path_matches
297
+ for method in getattr(candidate, "methods", ())
298
+ }
299
+ allowed.add("OPTIONS")
300
+ return Response.json(
301
+ {"detail": "Method Not Allowed"},
302
+ status_code=status.HTTP_405_METHOD_NOT_ALLOWED,
303
+ headers={"allow": ",".join(sorted(allowed))},
304
+ )
305
+
306
+ return Response.json(
307
+ {"detail": "Not Found"},
308
+ status_code=status.HTTP_404_NOT_FOUND,
309
+ )
310
+
311
+ async def call_handler(self, route: Route, req: Request) -> Response:
312
+ """Resolve dependencies, invoke the handler, and normalize its output."""
313
+
314
+ dependency_cleanups: list[Callable[[], Any]] = []
315
+ setattr(req.state, "_dependency_cleanups", dependency_cleanups)
316
+ try:
317
+ await self._resolve_route_dependencies(route, req)
318
+ kwargs = await self._resolve_handler_kwargs(route, req)
319
+ out = route.handler(**kwargs)
320
+ if inspect.isawaitable(out):
321
+ out = await out
322
+ except HTTPException as he:
323
+ return Response.json(
324
+ {"detail": he.detail},
325
+ status_code=he.status_code,
326
+ headers=he.headers,
327
+ )
328
+ except Exception as exc:
329
+ # Normalize exception objects that provide ``status_code`` + ``detail``
330
+ # into HTTP JSON responses.
331
+ if hasattr(exc, "status_code") and hasattr(exc, "detail"):
332
+ return Response.json(
333
+ {"detail": getattr(exc, "detail")},
334
+ status_code=getattr(exc, "status_code"),
335
+ headers=getattr(exc, "headers", None),
336
+ )
337
+ raise
338
+ finally:
339
+ for cleanup in reversed(dependency_cleanups):
340
+ try:
341
+ result = cleanup()
342
+ if inspect.isawaitable(result):
343
+ await result
344
+ except Exception:
345
+ pass
346
+
347
+ if isinstance(out, Response):
348
+ return out
349
+
350
+ if self._is_http_response_like(out):
351
+ body = bytes(getattr(out, "body", b"") or b"")
352
+ if not body and hasattr(out, "body_iterator"):
353
+ chunks: list[bytes] = []
354
+ body_iter = getattr(out, "body_iterator")
355
+ if body_iter is not None:
356
+ if hasattr(body_iter, "__aiter__"):
357
+ async for chunk in body_iter:
358
+ chunks.append(
359
+ chunk.encode("utf-8")
360
+ if isinstance(chunk, str)
361
+ else bytes(chunk)
362
+ )
363
+ else:
364
+ for chunk in body_iter:
365
+ chunks.append(
366
+ chunk.encode("utf-8")
367
+ if isinstance(chunk, str)
368
+ else bytes(chunk)
369
+ )
370
+ body = b"".join(chunks)
371
+ if not body and hasattr(out, "path"):
372
+ path = getattr(out, "path")
373
+ if isinstance(path, str):
374
+ with open(path, "rb") as fp:
375
+ body = fp.read()
376
+ raw_headers = getattr(out, "headers", {})
377
+ if hasattr(raw_headers, "items"):
378
+ headers = list(raw_headers.items())
379
+ else:
380
+ headers = list(raw_headers)
381
+ media_type = getattr(out, "media_type", None)
382
+ if media_type and not any(k.lower() == "content-type" for k, _ in headers):
383
+ headers.append(("content-type", media_type))
384
+ return Response(
385
+ status_code=getattr(out, "status_code", 200),
386
+ headers=headers,
387
+ body=body,
388
+ )
389
+
390
+ code = route.status_code if route.status_code is not None else 200
391
+ if out is None:
392
+ if code == 204:
393
+ return Response(
394
+ status_code=204,
395
+ headers=[("content-length", "0")],
396
+ body=b"",
397
+ )
398
+ return Response.json(None, status_code=code)
399
+ if isinstance(out, (str, bytes, bytearray)):
400
+ return Response(
401
+ status_code=code,
402
+ headers=[("content-type", "application/octet-stream")],
403
+ body=bytes(out),
404
+ )
405
+ return Response.json(out, status_code=code)
406
+
407
+ async def _dispatch(self, req: Request):
408
+ return await self.dispatch(req)
409
+
410
+ async def _call_handler(self, route: Route, req: Request):
411
+ return await self.call_handler(route, req)
412
+
413
+ async def _resolve_route_dependencies(self, route: Route, req: Request) -> None:
414
+ return await _resolve_route_dependencies_impl(self, route, req)
415
+
416
+ def _is_metadata_route(self, route: Route) -> bool:
417
+ return _is_metadata_route_impl(self, route)
418
+
419
+ async def _resolve_handler_kwargs(
420
+ self, route: Route, req: Request
421
+ ) -> dict[str, Any]:
422
+ return await _resolve_handler_kwargs_impl(self, route, req)
423
+
424
+ async def _invoke_dependency(self, dep: Callable[..., Any], req: Request) -> Any:
425
+ return await _invoke_dependency_impl(self, dep, req)
426
+
427
+ def openapi(self) -> dict[str, Any]:
428
+ return build_openapi(self)
429
+
430
+ def _install_builtin_routes(self) -> None:
431
+ mount_openapi(self, path=self.openapi_url)
432
+ mount_swagger(self, path=self.docs_url)
433
+
434
+ def _swagger_ui_html(self, request: Request) -> str:
435
+ docs_route = next(
436
+ (route for route in self._routes if route.name == "__docs__"), None
437
+ )
438
+ if docs_route is None:
439
+ mount_swagger(self, path=self.docs_url)
440
+ docs_route = next(
441
+ (route for route in self._routes if route.name == "__docs__"), None
442
+ )
443
+ if docs_route is None:
444
+ raise RuntimeError("Unable to resolve mounted swagger docs route.")
445
+
446
+ response = docs_route.handler(request)
447
+ body = getattr(response, "body", b"")
448
+ if isinstance(body, bytes):
449
+ return body.decode("utf-8")
450
+ return str(body)
451
+
452
+
453
+ def _route_match_priority(route: Route) -> tuple[int, int, int]:
454
+ is_metadata = int(getattr(route, "name", "") in {"__openapi__", "__docs__"})
455
+ dynamic_segments = route.path_template.count("{")
456
+ path_length = -len(route.path_template)
457
+ return (-is_metadata, dynamic_segments, path_length)
458
+
459
+
460
+ def _build_options_response(req: Request, routes: list[Route]) -> Response:
461
+ """Build an automatic OPTIONS response for a matched path."""
462
+ allowed_methods = {
463
+ method.upper() for route in routes for method in getattr(route, "methods", ())
464
+ }
465
+ allowed_methods.add("OPTIONS")
466
+ allow_value = ",".join(sorted(allowed_methods))
467
+
468
+ headers: dict[str, str] = {"allow": allow_value}
469
+
470
+ origin = req.headers.get("origin")
471
+ if origin:
472
+ headers["access-control-allow-origin"] = origin
473
+ headers["vary"] = "origin"
474
+
475
+ request_headers = req.headers.get("access-control-request-headers")
476
+ if request_headers:
477
+ headers["access-control-allow-headers"] = request_headers
478
+
479
+ if origin and request_headers:
480
+ headers["vary"] = "origin,access-control-request-headers"
481
+
482
+ headers["access-control-allow-methods"] = allow_value
483
+
484
+ return Response(status_code=204, headers=headers, body=b"")
485
+
486
+
487
+ ensure_httpx_sync_transport()
488
+
489
+
490
+ APIRouter = Router
@@ -151,20 +151,4 @@ def wsgi_app(
151
151
  return [resp.body]
152
152
 
153
153
 
154
- def router_call(router: Any, *args: Any, **kwargs: Any):
155
- del kwargs
156
- if len(args) == 2 and isinstance(args[0], dict) and callable(args[1]):
157
- return wsgi_app(router, args[0], args[1])
158
- if len(args) == 1 and isinstance(args[0], dict):
159
- scope = args[0]
160
-
161
- async def _asgi2_instance(receive: Callable, send: Callable) -> None:
162
- await asgi_app(router, scope, receive, send)
163
-
164
- return _asgi2_instance
165
- if len(args) == 3 and isinstance(args[0], dict):
166
- return asgi_app(router, args[0], args[1], args[2])
167
- raise TypeError("Invalid ASGI/WSGI invocation")
168
-
169
-
170
- __all__ = ["asgi_app", "router_call", "wsgi_app"]
154
+ __all__ = ["asgi_app", "wsgi_app"]
@@ -410,7 +410,39 @@ def build_jsonrpc_router(
410
410
  err = _err(-32600, "Invalid Request", None)
411
411
  return JSONResponse(content=err)
412
412
 
413
+ async def _options_endpoint(request: Request):
414
+ allow = "OPTIONS,POST"
415
+ headers: Dict[str, str] = {
416
+ "allow": allow,
417
+ "access-control-allow-methods": allow,
418
+ }
419
+
420
+ origin = request.headers.get("origin")
421
+ if origin:
422
+ headers["access-control-allow-origin"] = origin
423
+ headers["vary"] = "origin"
424
+
425
+ req_headers = request.headers.get("access-control-request-headers")
426
+ if req_headers:
427
+ headers["access-control-allow-headers"] = req_headers
428
+ headers["vary"] = (
429
+ "origin,access-control-request-headers"
430
+ if origin
431
+ else "access-control-request-headers"
432
+ )
433
+
434
+ return Response(status_code=204, headers=headers)
435
+
413
436
  # Attach a single JSON-RPC POST route. Mount prefix controls final path.
437
+ router.add_api_route(
438
+ path="",
439
+ endpoint=_options_endpoint,
440
+ methods=["OPTIONS"],
441
+ name="jsonrpc_options",
442
+ tags=list(tags) if tags else None,
443
+ include_in_schema=False,
444
+ )
445
+
414
446
  router.add_api_route(
415
447
  path="",
416
448
  endpoint=_endpoint,