clear-skies 2.0.2__tar.gz → 2.0.4__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.

Potentially problematic release.


This version of clear-skies might be problematic. Click here for more details.

Files changed (253) hide show
  1. {clear_skies-2.0.2 → clear_skies-2.0.4}/PKG-INFO +1 -11
  2. {clear_skies-2.0.2 → clear_skies-2.0.4}/README.md +0 -10
  3. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/__init__.py +2 -0
  4. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/__init__.py +2 -2
  5. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/oai3_json.py +2 -2
  6. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/schema/object.py +6 -0
  7. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/request/request.py +9 -0
  8. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/backends/backend.py +1 -1
  9. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/belongs_to_id.py +3 -3
  10. clear_skies-2.0.4/src/clearskies/contexts/cli.py +117 -0
  11. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/contexts/context.py +1 -0
  12. clear_skies-2.0.4/src/clearskies/contexts/wsgi.py +76 -0
  13. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/contexts/wsgi_ref.py +29 -0
  14. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/di.py +6 -1
  15. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoint.py +16 -12
  16. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoint_group.py +28 -0
  17. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/__init__.py +2 -0
  18. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/callable.py +1 -1
  19. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/create.py +6 -3
  20. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/delete.py +1 -1
  21. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/get.py +2 -6
  22. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/health_check.py +3 -1
  23. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/list.py +1 -0
  24. clear_skies-2.0.4/src/clearskies/endpoints/schema.py +189 -0
  25. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/simple_search.py +2 -2
  26. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/update.py +6 -3
  27. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/exceptions/__init__.py +2 -0
  28. clear_skies-2.0.4/src/clearskies/exceptions/missing_dependency.py +2 -0
  29. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/cli.py +5 -4
  30. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/model.py +116 -6
  31. clear_skies-2.0.2/src/clearskies/contexts/cli.py +0 -11
  32. clear_skies-2.0.2/src/clearskies/contexts/wsgi.py +0 -20
  33. {clear_skies-2.0.2 → clear_skies-2.0.4}/LICENSE +0 -0
  34. {clear_skies-2.0.2 → clear_skies-2.0.4}/pyproject.toml +0 -0
  35. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/action.py +0 -0
  36. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/authentication/__init__.py +0 -0
  37. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/authentication/authentication.py +0 -0
  38. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/authentication/authorization.py +0 -0
  39. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/authentication/authorization_pass_through.py +0 -0
  40. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/authentication/jwks.py +0 -0
  41. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/authentication/public.py +0 -0
  42. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/authentication/secret_bearer.py +0 -0
  43. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/__init__.py +0 -0
  44. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/__init__.py +0 -0
  45. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/oai3_schema_resolver.py +0 -0
  46. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/parameter.py +0 -0
  47. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/request.py +0 -0
  48. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/response.py +0 -0
  49. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/schema/__init__.py +0 -0
  50. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/schema/array.py +0 -0
  51. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/schema/default.py +0 -0
  52. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/schema/enum.py +0 -0
  53. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/formats/oai3_json/test.json +0 -0
  54. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/py.typed +0 -0
  55. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/request/__init__.py +0 -0
  56. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/request/header.py +0 -0
  57. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/request/json_body.py +0 -0
  58. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/request/parameter.py +0 -0
  59. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/request/url_parameter.py +0 -0
  60. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/request/url_path.py +0 -0
  61. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/response/__init__.py +0 -0
  62. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/response/response.py +0 -0
  63. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/__init__.py +0 -0
  64. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/array.py +0 -0
  65. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/base64.py +0 -0
  66. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/boolean.py +0 -0
  67. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/date.py +0 -0
  68. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/datetime.py +0 -0
  69. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/double.py +0 -0
  70. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/enum.py +0 -0
  71. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/integer.py +0 -0
  72. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/long.py +0 -0
  73. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/number.py +0 -0
  74. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/object.py +0 -0
  75. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/password.py +0 -0
  76. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/schema.py +0 -0
  77. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/autodoc/schema/string.py +0 -0
  78. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/backends/__init__.py +0 -0
  79. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/backends/api_backend.py +0 -0
  80. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/backends/cursor_backend.py +0 -0
  81. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/backends/memory_backend.py +0 -0
  82. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/backends/secrets_backend.py +0 -0
  83. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/column.py +0 -0
  84. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/__init__.py +0 -0
  85. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/audit.py +0 -0
  86. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/belongs_to_model.py +0 -0
  87. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/belongs_to_self.py +0 -0
  88. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/boolean.py +0 -0
  89. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/category_tree.py +0 -0
  90. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/category_tree_ancestors.py +0 -0
  91. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/category_tree_children.py +0 -0
  92. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/category_tree_descendants.py +0 -0
  93. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/created.py +0 -0
  94. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/created_by_authorization_data.py +0 -0
  95. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/created_by_header.py +0 -0
  96. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/created_by_ip.py +0 -0
  97. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/created_by_routing_data.py +0 -0
  98. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/created_by_user_agent.py +0 -0
  99. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/date.py +0 -0
  100. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/datetime.py +0 -0
  101. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/email.py +0 -0
  102. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/float.py +0 -0
  103. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/has_many.py +0 -0
  104. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/has_many_self.py +0 -0
  105. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/has_one.py +0 -0
  106. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/integer.py +0 -0
  107. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/json.py +0 -0
  108. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/many_to_many_ids.py +0 -0
  109. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/many_to_many_ids_with_data.py +0 -0
  110. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/many_to_many_models.py +0 -0
  111. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/many_to_many_pivots.py +0 -0
  112. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/phone.py +0 -0
  113. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/select.py +0 -0
  114. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/string.py +0 -0
  115. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/timestamp.py +0 -0
  116. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/updated.py +0 -0
  117. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/columns/uuid.py +0 -0
  118. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/README.md +0 -0
  119. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/__init__.py +0 -0
  120. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/actions.py +0 -0
  121. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/any.py +0 -0
  122. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/any_dict.py +0 -0
  123. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/any_dict_or_callable.py +0 -0
  124. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/authentication.py +0 -0
  125. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/authorization.py +0 -0
  126. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/boolean.py +0 -0
  127. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/boolean_or_callable.py +0 -0
  128. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/callable_config.py +0 -0
  129. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/columns.py +0 -0
  130. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/conditions.py +0 -0
  131. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/config.py +0 -0
  132. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/datetime.py +0 -0
  133. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/datetime_or_callable.py +0 -0
  134. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/endpoint.py +0 -0
  135. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/endpoint_list.py +0 -0
  136. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/float.py +0 -0
  137. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/float_or_callable.py +0 -0
  138. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/integer.py +0 -0
  139. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/integer_or_callable.py +0 -0
  140. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/joins.py +0 -0
  141. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/list_any_dict.py +0 -0
  142. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/list_any_dict_or_callable.py +0 -0
  143. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/model_class.py +0 -0
  144. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/model_column.py +0 -0
  145. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/model_columns.py +0 -0
  146. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/model_destination_name.py +0 -0
  147. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/model_to_id_column.py +0 -0
  148. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/readable_model_column.py +0 -0
  149. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/readable_model_columns.py +0 -0
  150. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/schema.py +0 -0
  151. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/searchable_model_columns.py +0 -0
  152. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/security_headers.py +0 -0
  153. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/select.py +0 -0
  154. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/select_list.py +0 -0
  155. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/string.py +0 -0
  156. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/string_dict.py +0 -0
  157. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/string_list.py +0 -0
  158. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/string_list_or_callable.py +0 -0
  159. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/string_or_callable.py +0 -0
  160. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/timedelta.py +0 -0
  161. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/timezone.py +0 -0
  162. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/url.py +0 -0
  163. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/validators.py +0 -0
  164. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/writeable_model_column.py +0 -0
  165. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configs/writeable_model_columns.py +0 -0
  166. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/configurable.py +0 -0
  167. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/contexts/__init__.py +0 -0
  168. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/decorators.py +0 -0
  169. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/__init__.py +0 -0
  170. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/additional_config.py +0 -0
  171. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/additional_config_auto_import.py +0 -0
  172. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/__init__.py +0 -0
  173. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/by_class.py +0 -0
  174. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/by_name.py +0 -0
  175. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/di.py +0 -0
  176. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/environment.py +0 -0
  177. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/input_output.py +0 -0
  178. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/now.py +0 -0
  179. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/requests.py +0 -0
  180. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/secrets.py +0 -0
  181. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/utcnow.py +0 -0
  182. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/inject/uuid.py +0 -0
  183. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/injectable.py +0 -0
  184. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/injectable_properties.py +0 -0
  185. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/test_module/__init__.py +0 -0
  186. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/test_module/another_module/__init__.py +0 -0
  187. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/di/test_module/module_class.py +0 -0
  188. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/end.py +0 -0
  189. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/advanced_search.py +0 -0
  190. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/endpoints/restful_api.py +0 -0
  191. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/environment.py +0 -0
  192. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/exceptions/authentication.py +0 -0
  193. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/exceptions/authorization.py +0 -0
  194. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/exceptions/client_error.py +0 -0
  195. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/exceptions/input_errors.py +0 -0
  196. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/exceptions/moved_permanently.py +0 -0
  197. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/exceptions/moved_temporarily.py +0 -0
  198. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/exceptions/not_found.py +0 -0
  199. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/functional/__init__.py +0 -0
  200. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/functional/routing.py +0 -0
  201. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/functional/string.py +0 -0
  202. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/functional/validations.py +0 -0
  203. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/__init__.py +0 -0
  204. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/exceptions/__init__.py +0 -0
  205. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/exceptions/cli_input_error.py +0 -0
  206. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/exceptions/cli_not_found.py +0 -0
  207. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/headers.py +0 -0
  208. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/input_output.py +0 -0
  209. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/programmatic.py +0 -0
  210. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/py.typed +0 -0
  211. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/input_outputs/wsgi.py +0 -0
  212. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/py.typed +0 -0
  213. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/query/__init__.py +0 -0
  214. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/query/condition.py +0 -0
  215. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/query/join.py +0 -0
  216. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/query/query.py +0 -0
  217. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/query/sort.py +0 -0
  218. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/schema.py +0 -0
  219. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/secrets/__init__.py +0 -0
  220. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/secrets/additional_configs/__init__.py +0 -0
  221. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +0 -0
  222. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +0 -0
  223. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/secrets/akeyless.py +0 -0
  224. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/secrets/exceptions/__init__.py +0 -0
  225. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/secrets/exceptions/not_found.py +0 -0
  226. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/secrets/secrets.py +0 -0
  227. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/security_header.py +0 -0
  228. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/security_headers/__init__.py +0 -0
  229. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/security_headers/cache_control.py +0 -0
  230. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/security_headers/cors.py +0 -0
  231. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/security_headers/csp.py +0 -0
  232. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/security_headers/hsts.py +0 -0
  233. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/security_headers/x_content_type_options.py +0 -0
  234. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/security_headers/x_frame_options.py +0 -0
  235. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/test_base.py +0 -0
  236. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/typing.py +0 -0
  237. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validator.py +0 -0
  238. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/__init__.py +0 -0
  239. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/after_column.py +0 -0
  240. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/before_column.py +0 -0
  241. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/in_the_future.py +0 -0
  242. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/in_the_future_at_least.py +0 -0
  243. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/in_the_future_at_most.py +0 -0
  244. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/in_the_past.py +0 -0
  245. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/in_the_past_at_least.py +0 -0
  246. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/in_the_past_at_most.py +0 -0
  247. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/maximum_length.py +0 -0
  248. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/maximum_value.py +0 -0
  249. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/minimum_length.py +0 -0
  250. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/minimum_value.py +0 -0
  251. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/required.py +0 -0
  252. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/timedelta.py +0 -0
  253. {clear_skies-2.0.2 → clear_skies-2.0.4}/src/clearskies/validators/unique.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: clear-skies
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: A framework for building backends in the cloud
5
5
  License: MIT
6
6
  Author: Conor Mancone
@@ -32,15 +32,5 @@ Description-Content-Type: text/markdown
32
32
 
33
33
  clearskies is a very opinionated Python framework intended for developing microservices in the cloud via declarative programming principles. It is mainly intended for backend services and so is designed for RESTful API endpoints, queue listeners, scheduled tasks, and the like.
34
34
 
35
- ## Installation, Documentation, and Usage
36
-
37
- To install:
38
-
39
- ```bash
40
- pip3 install clear-skies
41
- ```
42
-
43
- Documentation is under construction here:
44
-
45
35
  [https://clearskies.info](https://clearskies.info)
46
36
 
@@ -2,14 +2,4 @@
2
2
 
3
3
  clearskies is a very opinionated Python framework intended for developing microservices in the cloud via declarative programming principles. It is mainly intended for backend services and so is designed for RESTful API endpoints, queue listeners, scheduled tasks, and the like.
4
4
 
5
- ## Installation, Documentation, and Usage
6
-
7
- To install:
8
-
9
- ```bash
10
- pip3 install clear-skies
11
- ```
12
-
13
- Documentation is under construction here:
14
-
15
5
  [https://clearskies.info](https://clearskies.info)
@@ -10,6 +10,7 @@ from . import (
10
10
  endpoints,
11
11
  exceptions,
12
12
  functional,
13
+ input_outputs,
13
14
  query,
14
15
  # secrets,
15
16
  security_headers,
@@ -39,6 +40,7 @@ __all__ = [
39
40
  "Configurable",
40
41
  "contexts",
41
42
  "di",
43
+ "input_outputs",
42
44
  "End",
43
45
  "Endpoint",
44
46
  "EndpointGroup",
@@ -1,7 +1,7 @@
1
- from .oai3_json import OAI3JSON
1
+ from .oai3_json import Oai3Json
2
2
  from .oai3_schema_resolver import OAI3SchemaResolver
3
3
 
4
4
  __all__ = [
5
5
  "OAI3SchemaResolver",
6
- "OAI3JSON",
6
+ "Oai3Json",
7
7
  ]
@@ -4,7 +4,7 @@ from typing import Any
4
4
  from .request import Request
5
5
 
6
6
 
7
- class OAI3JSON:
7
+ class Oai3Json:
8
8
  requests: Any = None
9
9
  formatted: Any = None
10
10
  models: Any = None
@@ -67,7 +67,7 @@ class OAI3JSON:
67
67
  path_data = request.convert()
68
68
  for request_method, path_doc in path_data.items():
69
69
  if request_method in paths[absolute_path]:
70
- raise ValueError(f"Two routes had the same path and method: {absolute_path} - {request_method}")
70
+ continue
71
71
  paths[absolute_path][request_method] = path_doc
72
72
 
73
73
  data: dict[str, Any] = {
@@ -4,6 +4,12 @@ from typing import Any
4
4
  class Object:
5
5
  def __init__(self, schema, oai3_schema_resolver):
6
6
  self.schema = schema
7
+ # shhhh
8
+ self.schema.children = [
9
+ child[0] if (isinstance(child, tuple) or isinstance(child, list)) else child
10
+ for child in self.schema.children
11
+ ]
12
+
7
13
  self.oai3_schema_resolver = oai3_schema_resolver
8
14
 
9
15
  def convert(self, include_required=False):
@@ -1,3 +1,4 @@
1
+ import re
1
2
  from typing import Any
2
3
 
3
4
 
@@ -12,6 +13,14 @@ class Request:
12
13
  def __init__(
13
14
  self, description, responses, relative_path="", request_methods="GET", parameters=None, root_properties=None
14
15
  ):
16
+ # clearskies supports path parameters via {parameter} and :parameter but we want to normalize to {paramter} for
17
+ # autodoc purposes
18
+ if ":" in relative_path:
19
+ relative_path = "/" + relative_path.strip("/") + "/"
20
+ for match in re.findall("/(:[^/]+)/", relative_path):
21
+ name = match[1:]
22
+ relative_path = relative_path.replace(f"/:{name}/", "/{" + name + "}/")
23
+
15
24
  self.description = description
16
25
  self.responses = responses
17
26
  self.relative_path = relative_path.lstrip("/")
@@ -10,7 +10,7 @@ from clearskies.autodoc.schema import Schema as AutoDocSchema
10
10
 
11
11
  class Backend(ABC):
12
12
  """
13
- Conecting models to their data since 2020!
13
+ Connecting models to their data since 2020!.
14
14
 
15
15
  The backend system acts as a flexible layer between models and their data sources. By changing the backend attached to a model,
16
16
  you change where the model fetches and saves data. This might be a database, an in-memory data store, a dynamodb table,
@@ -356,11 +356,11 @@ class BelongsToId(String):
356
356
  parent_model = self.parent_model
357
357
  matching_parents = parent_model.where(f"{parent_model.id_column_name}={value}")
358
358
  matching_parents = self.apply_wheres(matching_parents)
359
- matching_parents = matching_parents.where_for_request(
359
+ matching_parents = matching_parents.where_for_request_all(
360
360
  matching_parents,
361
- self.input_output.routing_data,
362
- self.input_output.authorization_data,
363
361
  self.input_output,
362
+ routing_data=self.input_output.routing_data,
363
+ authorization_data=self.input_output.authorization_data,
364
364
  )
365
365
  if not len(matching_parents):
366
366
  return f"Invalid selection for {self.name}: record does not exist"
@@ -0,0 +1,117 @@
1
+ from clearskies.contexts.context import Context
2
+ from clearskies.input_outputs import Cli as CliInputOutput
3
+
4
+
5
+ class Cli(Context):
6
+ """
7
+ Run an application via a CLI command
8
+
9
+ This context converts a clearskies application into a CLI command. Here's a simple example:
10
+
11
+ ```
12
+ #!/usr/bin/env python
13
+ import clearskies
14
+
15
+ def my_function():
16
+ return "Hello World!"
17
+
18
+ cli = clearskies.contexts.Cli(my_function)
19
+ cli()
20
+ ```
21
+
22
+ Which you can then run as expected:
23
+
24
+ ```
25
+ $ ./example.py
26
+ Hello World!
27
+ ```
28
+
29
+ Routing is still supported, with routes and route parameters becoming CLI args:
30
+
31
+ ```
32
+ #!/usr/bin/env python
33
+ import clearskies
34
+
35
+ def my_function(name):
36
+ return f"Hello {name}!"
37
+
38
+ cli = clearskies.contexts.Cli(
39
+ clearskies.endpoints.Callable(
40
+ my_function,
41
+ url="/hello/:name",
42
+ return_standard_response=False,
43
+ )
44
+ )
45
+ cli()
46
+ ```
47
+
48
+ With a url of `/hello/:name` you would invoke like so:
49
+
50
+ ```
51
+ ./example.py hello Bob
52
+ Hello Bob!
53
+ ```
54
+
55
+ If the endpoint expects a request method you can provide it by setting the `-X` or `--request_method=`
56
+ kwargs. So for tihs example:
57
+
58
+ ```
59
+ #!/usr/bin/env python
60
+ import clearskies
61
+
62
+ def my_function(name):
63
+ return f"Hello {name}!"
64
+
65
+ cli = clearskies.contexts.Cli(
66
+ clearskies.endpoints.Callable(
67
+ my_function,
68
+ url="/hello/:name",
69
+ request_methods=["POST"],
70
+ )
71
+ )
72
+ cli()
73
+ ```
74
+
75
+ And then calling it successfully:
76
+
77
+ ```
78
+ ./example.py hello Bob --request_method=POST
79
+
80
+ ./example.py hello Bob -X POST
81
+ ```
82
+
83
+ You can pass data as a json string with the -d flag or set individual named arguments. The following
84
+ example just reflects the request data back to the client:
85
+
86
+ ```
87
+ #!/usr/bin/env python
88
+ import clearskies
89
+
90
+ def my_function(request_data):
91
+ return request_data
92
+
93
+ cli = clearskies.contexts.Cli(
94
+ clearskies.endpoints.Callable(
95
+ my_function,
96
+ )
97
+ )
98
+ cli()
99
+ ```
100
+
101
+ And these three calls are identical:
102
+
103
+ ```
104
+ ./example.py -d '{"hello": "world"}'
105
+
106
+ echo '{"hello": "world"}' | ./test.py
107
+
108
+ ./test.py --hello=world
109
+ ```
110
+
111
+ Although note that the first two are going to be preferred over the third, simply because with the
112
+ third there's simply no way to specify the type of a variable. As a result, you may run into issues
113
+ with strict type checking on endpoints.
114
+ """
115
+
116
+ def __call__(self): # type: ignore
117
+ return self.execute_application(CliInputOutput())
@@ -48,6 +48,7 @@ class Context:
48
48
  bindings=bindings,
49
49
  additional_configs=additional_configs,
50
50
  class_overrides=class_overrides,
51
+ overrides=overrides,
51
52
  now=now,
52
53
  utcnow=utcnow,
53
54
  )
@@ -0,0 +1,76 @@
1
+ import datetime
2
+ from types import ModuleType
3
+ from typing import Any, Callable
4
+ from wsgiref.simple_server import make_server
5
+ from wsgiref.util import setup_testing_defaults
6
+
7
+ import clearskies.endpoint
8
+ import clearskies.endpoint_group
9
+ from clearskies.contexts.context import Context
10
+ from clearskies.di import AdditionalConfig
11
+ from clearskies.input_outputs import Wsgi as WsgiInputOutput
12
+
13
+
14
+ class Wsgi(Context):
15
+ """
16
+ Connect your application to a WSGI server.
17
+
18
+ The Wsgi context is used to connect a clearskies application to a WSGI server of your choice. As with all
19
+ contexts, you first create it and pass in the application (a callable, endpoint, or endpoint group) as well
20
+ as any dependency injection parameters. Then, you call the context from inside of the function invoked by
21
+ your WSGI server, passing along the `environment` and `start_response` variables, and returning the response
22
+ from the context. Here's a simple example:
23
+
24
+ ```
25
+ import clearskies
26
+
27
+ def hello_world():
28
+ return "Hello World!"
29
+
30
+ wsgi = clearskies.contexts.Wsgi(hello_world)
31
+
32
+ def application(environment, start_response):
33
+ return wsgi(environment, start_response)
34
+ ```
35
+
36
+ You would then launch your WSGI server. For instance, here's how to launch it with uwsgi, which automatically
37
+ looks for a function called `application` and treats that as the WSGI starting point:
38
+
39
+ ```
40
+ uwsgi --http :9090 --wsgi-file test.py
41
+ ```
42
+
43
+ You could then:
44
+
45
+ ```
46
+ curl 'http://localhost:9090'
47
+ ```
48
+
49
+ And see the response from this "hello world" app. Note than in the above example I create the context outside
50
+ of the application function. Of course, you can do the opposite:
51
+
52
+ ```
53
+ import clearskies
54
+
55
+ def hello_world():
56
+ return "Hello World!"
57
+
58
+ def application(environment, start_response):
59
+ wsgi = clearskies.contexts.Wsgi(hello_world)
60
+ return wsgi(environment, start_response)
61
+ ```
62
+
63
+ The difference is that most wsgi servers will cache any objects created outside of the handler function (e.g. `application`
64
+ in this case). When you first create the context clearskies will configure and validate any endpoints attached.
65
+ Also, it will create an instance of the dependency injection container and cache it. If the context object is created
66
+ outside of the handler, and the server caches objects in this csae, then this validation will only happen once and
67
+ the DI cache will store objects in between HTTP calls. If you create your context inside the handler function, then
68
+ you'll end up with an empty cache everytime and you'll have slower responses because of clearskies checking the
69
+ application configuration everytime. Note that the DI system for clearskies grants you full cache control, so
70
+ by and large it's normal and expected that you'll persist the cache between requests by creating the context outside
71
+ of any handler functions.
72
+
73
+ """
74
+
75
+ def __call__(self, env, start_response): # type: ignore
76
+ return self.execute_application(WsgiInputOutput(env, start_response))
@@ -14,6 +14,35 @@ from clearskies.input_outputs import Wsgi as WsgiInputOutput
14
14
  class WsgiRef(Context):
15
15
  """
16
16
  Use a built in WSGI server (for development purposes only).
17
+
18
+ This context will launch a built-in HTTP server for you, so you can run applications locally
19
+ without having to install extra dependencies. Note that this server is not intended for production
20
+ usage, so this is best used for simple tests/demonstration purposes. Unlike the WSGI context, where
21
+ you define the application handler and invoke the context from inside of it (passing along the
22
+ environment and start_response variables), in this case you simply directly invoke the context to
23
+ launch the server. The default port is 8080:
24
+
25
+ ```
26
+ #!/usr/bin/env python
27
+ import clearskies
28
+
29
+ def hello_world(name):
30
+ return f"Hello {name}!"
31
+
32
+ wsgi = clearskies.contexts.WsgiRef(
33
+ clearskies.endpoints.Callable(
34
+ hello_world,
35
+ url="/hello/:name",
36
+ )
37
+ )
38
+ wsgi()
39
+ ```
40
+
41
+ And to invoke it:
42
+
43
+ ```
44
+ curl 'http://localhost:8080/hello/Friend'
45
+ ```
17
46
  """
18
47
 
19
48
  port: int = 8080
@@ -15,6 +15,7 @@ import clearskies.secrets
15
15
  from clearskies.di.additional_config import AdditionalConfig
16
16
  from clearskies.di.additional_config_auto_import import AdditionalConfigAutoImport
17
17
  from clearskies.environment import Environment
18
+ from clearskies.exceptions import MissingDependency
18
19
  from clearskies.functional import string
19
20
 
20
21
 
@@ -83,6 +84,7 @@ class Di:
83
84
  | connection_details | - | A dictionary containing credentials that pymysql should use when connecting to a database |
84
85
  | connection | - | A pymysql connection object |
85
86
  | cursor | - | A pymysql cursor object |
87
+ | endpoint_groups | - | The list of endpoint groups handling the request |
86
88
 
87
89
  Note: for dependencies with an injection name but no injection type, this means that to inject those values you
88
90
  must name your argument with the given injection name. In all of the above cases though you can still add type
@@ -635,7 +637,7 @@ class Di:
635
637
  return self._prepared[name]
636
638
 
637
639
  context_note = f" for {context}" if context else ""
638
- raise ValueError(
640
+ raise MissingDependency(
639
641
  f"I was asked to build {name}{context_note} but there is no added class, configured binding, "
640
642
  + f"or a corresponding 'provide_{name}' method for this name."
641
643
  )
@@ -966,3 +968,6 @@ class Di:
966
968
  import akeyless # type: ignore
967
969
 
968
970
  return akeyless
971
+
972
+ def provide_endpoint_groups(self):
973
+ return []
@@ -963,11 +963,11 @@ class Endpoint(
963
963
  model = self.di.call_function(where, model=model, **input_output.get_context_for_callables())
964
964
  else:
965
965
  model = model.where(where)
966
- model = model.where_for_request(
966
+ model = model.where_for_request_all(
967
967
  model,
968
+ input_output,
968
969
  input_output.routing_data,
969
970
  input_output.authorization_data,
970
- input_output,
971
971
  overrides=self.column_overrides,
972
972
  )
973
973
  return self.authorization.filter_model(model, input_output.authorization_data, input_output)
@@ -1261,8 +1261,9 @@ class Endpoint(
1261
1261
  ) -> list[schema.Schema]:
1262
1262
  if schema is None:
1263
1263
  schema = self.model_class
1264
- if column_names is None and self.readable_column_names:
1265
- readable_column_names: list[str] = self.readable_column_names
1264
+ readable_column_names = [*column_names]
1265
+ if not readable_column_names and self.readable_column_names:
1266
+ readable_column_names: list[str] = self.readable_column_names # type: ignore
1266
1267
  properties = []
1267
1268
 
1268
1269
  columns = schema.get_columns()
@@ -1289,16 +1290,19 @@ class Endpoint(
1289
1290
 
1290
1291
  model_name = string.camel_case_to_snake_case(schema.__name__)
1291
1292
  columns = schema.get_columns()
1292
- return [
1293
- autodoc.request.JSONBody(
1294
- columns[column_name].documentation(name=self.auto_case_column_name(column_name, True)),
1295
- description=f"Set '{column_name}' for the {model_name}",
1296
- required=columns[column_name].is_required,
1293
+ parameters = []
1294
+ for column_name in column_names:
1295
+ columns[column_name].injectable_properties(self.di)
1296
+ parameters.append(
1297
+ autodoc.request.JSONBody(
1298
+ columns[column_name].documentation(name=self.auto_case_column_name(column_name, True)),
1299
+ description=f"Set '{column_name}' for the {model_name}",
1300
+ required=columns[column_name].is_required,
1301
+ )
1297
1302
  )
1298
- for column_name in column_names
1299
- ]
1303
+ return parameters # type: ignore
1300
1304
 
1301
- def standard_url_request_parameters(self) -> list[Parameter]:
1305
+ def documentation_url_parameters(self) -> list[Parameter]:
1302
1306
  parameter_names = routing.extract_url_parameter_name_map(self.url.strip("/"))
1303
1307
  return [
1304
1308
  autodoc.request.URLPath(
@@ -230,6 +230,8 @@ class EndpointGroup(
230
230
  """
231
231
  endpoints = clearskies.configs.EndpointList()
232
232
 
233
+ internal_casing = clearskies.configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
234
+ external_casing = clearskies.configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
233
235
  response_headers = clearskies.configs.StringListOrCallable(default=[])
234
236
  authentication = clearskies.configs.Authentication(default=Public())
235
237
  authorization = clearskies.configs.Authorization(default=Authorization())
@@ -238,6 +240,8 @@ class EndpointGroup(
238
240
  cors_header: SecurityHeader = None # type: ignore
239
241
  has_cors: bool = False
240
242
  endpoints_initialized = False
243
+ external_casing = "snake_case"
244
+ internal_casing = "snake_case"
241
245
 
242
246
  @clearskies.decorators.parameters_to_properties
243
247
  def __init__(
@@ -246,6 +250,8 @@ class EndpointGroup(
246
250
  url: str = "",
247
251
  response_headers: list[str | Callable[..., list[str]]] = [],
248
252
  security_headers: list[SecurityHeader] = [],
253
+ internal_casing: str = "snake_case",
254
+ external_casing: str = "snake_case",
249
255
  authentication: Authentication = Public(),
250
256
  authorization: Authorization = Authorization(),
251
257
  ):
@@ -273,6 +279,11 @@ class EndpointGroup(
273
279
  if self.url.strip("/"):
274
280
  endpoint.add_url_prefix(self.url)
275
281
 
282
+ def add_url_prefix(self, prefix: str) -> None:
283
+ self.url = (prefix.rstrip("/") + "/" + self.url.lstrip("/")).lstrip("/")
284
+ for endpoint in self.endpoints:
285
+ endpoint.add_url_prefix(self.url)
286
+
276
287
  def matches_request(self, input_output: InputOutput, allow_partial=True) -> bool:
277
288
  """Whether or not we can handle an incoming request based on URL and request method."""
278
289
  expected_url = self.url.strip("/")
@@ -303,8 +314,25 @@ class EndpointGroup(
303
314
  return self.error(input_output, "Not Found", 404)
304
315
 
305
316
  self.add_response_headers(input_output)
317
+
318
+ # "register" ourself with the DI system
319
+ current_endpoint_groups = self.di.build_from_name("endpoint_groups", cache=True)
320
+ current_endpoint_groups.append(self)
321
+ self.di.add_binding("endpoint_groups", current_endpoint_groups)
322
+
306
323
  return endpoint(input_output)
307
324
 
308
325
  def error(self, input_output: InputOutput, message: str, status_code: int) -> Any:
309
326
  """Return a client-side error (e.g. 400)."""
310
327
  return self.respond_json(input_output, {"status": "client_error", "error": message}, status_code)
328
+
329
+ def all_endpoints(self) -> list[Endpoint]:
330
+ """Returns the full (recursive) list of all endpoints associated with this endpoint group"""
331
+ all_endpoints: list[Endpoint] = []
332
+ for endpoint in self.endpoints:
333
+ if hasattr(endpoint, "all_endpoints"):
334
+ all_endpoints = [*all_endpoints, *endpoint.all_endpoints()]
335
+ else:
336
+ all_endpoints.append(endpoint)
337
+
338
+ return all_endpoints
@@ -6,6 +6,7 @@ from clearskies.endpoints.get import Get
6
6
  from clearskies.endpoints.health_check import HealthCheck
7
7
  from clearskies.endpoints.list import List
8
8
  from clearskies.endpoints.restful_api import RestfulApi
9
+ from clearskies.endpoints.schema import Schema
9
10
  from clearskies.endpoints.simple_search import SimpleSearch
10
11
  from clearskies.endpoints.update import Update
11
12
 
@@ -18,6 +19,7 @@ __all__ = [
18
19
  "HealthCheck",
19
20
  "List",
20
21
  "RestfulApi",
22
+ "Schema",
21
23
  "SimpleSearch",
22
24
  "Update",
23
25
  ]
@@ -359,7 +359,7 @@ class Callable(Endpoint):
359
359
  request_methods=self.request_methods,
360
360
  parameters=[
361
361
  *self.documentation_request_parameters(),
362
- *self.standard_url_parameters(),
362
+ *self.documentation_url_parameters(),
363
363
  ],
364
364
  root_properties={
365
365
  "security": self.documentation_request_security(),
@@ -155,7 +155,11 @@ class Create(Endpoint):
155
155
  )
156
156
 
157
157
  authentication = self.authentication
158
- standard_error_responses = [self.documentation_input_error_response()]
158
+ # Many swagger UIs will only allow one response per status code, and we use the same status code (200)
159
+ # for both a success response and an input error response. This could be fixed by changing the status
160
+ # code for input error responses, but there's not actually a great HTTP status code for that, so :shrug:
161
+ # standard_error_responses = [self.documentation_input_error_response()]
162
+ standard_error_responses = []
159
163
  if not getattr(authentication, "is_public", False):
160
164
  standard_error_responses.append(self.documentation_access_denied_response())
161
165
  if getattr(authentication, "can_authorize", False):
@@ -176,7 +180,7 @@ class Create(Endpoint):
176
180
  request_methods=self.request_methods,
177
181
  parameters=[
178
182
  *self.documentation_request_parameters(),
179
- *self.standard_url_parameters(),
183
+ *self.documentation_url_parameters(),
180
184
  ],
181
185
  root_properties={
182
186
  "security": self.documentation_request_security(),
@@ -187,7 +191,6 @@ class Create(Endpoint):
187
191
  def documentation_request_parameters(self) -> list[autodoc.request.Parameter]:
188
192
  return [
189
193
  *self.standard_json_request_parameters(self.model_class),
190
- *(self.standard_url_request_parameters() if self.include_routing_data_in_request_data else []),
191
194
  ]
192
195
 
193
196
  def documentation_models(self) -> dict[str, autodoc.schema.Schema]:
@@ -127,7 +127,7 @@ class Delete(Get):
127
127
  relative_path=self.url,
128
128
  request_methods=self.request_methods,
129
129
  parameters=[
130
- *self.documentation_routing_parameters(),
130
+ *self.documentation_url_parameters(),
131
131
  ],
132
132
  root_properties={
133
133
  "security": self.documentation_request_security(),
@@ -231,7 +231,7 @@ class Get(Endpoint):
231
231
  )
232
232
 
233
233
  authentication = self.authentication
234
- standard_error_responses = [self.documentation_input_error_response()]
234
+ standard_error_responses = []
235
235
  if not getattr(authentication, "is_public", False):
236
236
  standard_error_responses.append(self.documentation_access_denied_response())
237
237
  if getattr(authentication, "can_authorize", False):
@@ -251,8 +251,7 @@ class Get(Endpoint):
251
251
  relative_path=self.url,
252
252
  request_methods=self.request_methods,
253
253
  parameters=[
254
- *self.documentation_routing_parameters(),
255
- *self.standard_url_parameters(),
254
+ *self.documentation_url_parameters(),
256
255
  ],
257
256
  root_properties={
258
257
  "security": self.documentation_request_security(),
@@ -260,9 +259,6 @@ class Get(Endpoint):
260
259
  ),
261
260
  ]
262
261
 
263
- def documentation_routing_parameters(self) -> list[autodoc.request.Parameter]:
264
- return self.standard_url_request_parameters()
265
-
266
262
  def documentation_models(self) -> dict[str, autodoc.schema.Schema]:
267
263
  output_schema = self.output_schema if self.output_schema else self.model_class
268
264
  schema_model_name = string.camel_case_to_snake_case(output_schema.__name__)
@@ -162,7 +162,6 @@ class HealthCheck(Endpoint):
162
162
 
163
163
  def documentation(self) -> list[autodoc.request.Request]:
164
164
  output_schema = self.model_class
165
- nice_model = string.camel_case_to_words(output_schema.__name__)
166
165
  output_autodoc = (autodoc.schema.Object(self.auto_case_internal_column_name("data"), children=[]),)
167
166
 
168
167
  description = self.description if self.description else "Health Check"
@@ -177,5 +176,8 @@ class HealthCheck(Endpoint):
177
176
  ],
178
177
  relative_path=self.url,
179
178
  request_methods=self.request_methods,
179
+ parameters=[
180
+ *self.documentation_url_parameters(),
181
+ ],
180
182
  ),
181
183
  ]
@@ -476,6 +476,7 @@ class List(Endpoint):
476
476
  *self.documentation_url_sort_parameters(),
477
477
  *self.documentation_url_search_parameters(),
478
478
  *self.documentation_json_search_parameters(),
479
+ *self.documentation_url_parameters(),
479
480
  ]
480
481
 
481
482
  def documentation_models(self) -> dict[str, autodoc.schema.Schema]: