clear-skies 1.22.31__py3-none-any.whl → 2.0.1__py3-none-any.whl

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 (345) hide show
  1. {clear_skies-1.22.31.dist-info → clear_skies-2.0.1.dist-info}/METADATA +12 -14
  2. clear_skies-2.0.1.dist-info/RECORD +249 -0
  3. {clear_skies-1.22.31.dist-info → clear_skies-2.0.1.dist-info}/WHEEL +1 -1
  4. clearskies/__init__.py +42 -25
  5. clearskies/action.py +7 -0
  6. clearskies/authentication/__init__.py +8 -41
  7. clearskies/authentication/authentication.py +46 -0
  8. clearskies/authentication/authorization.py +8 -9
  9. clearskies/authentication/authorization_pass_through.py +11 -9
  10. clearskies/authentication/jwks.py +133 -58
  11. clearskies/authentication/public.py +3 -38
  12. clearskies/authentication/secret_bearer.py +516 -54
  13. clearskies/autodoc/formats/oai3_json/__init__.py +1 -1
  14. clearskies/autodoc/formats/oai3_json/oai3_json.py +9 -7
  15. clearskies/autodoc/formats/oai3_json/parameter.py +6 -3
  16. clearskies/autodoc/formats/oai3_json/request.py +7 -5
  17. clearskies/autodoc/formats/oai3_json/response.py +7 -4
  18. clearskies/autodoc/formats/oai3_json/schema/object.py +4 -1
  19. clearskies/autodoc/request/__init__.py +2 -0
  20. clearskies/autodoc/request/header.py +4 -6
  21. clearskies/autodoc/request/json_body.py +4 -6
  22. clearskies/autodoc/request/parameter.py +8 -0
  23. clearskies/autodoc/request/request.py +7 -4
  24. clearskies/autodoc/request/url_parameter.py +4 -6
  25. clearskies/autodoc/request/url_path.py +4 -6
  26. clearskies/autodoc/schema/__init__.py +4 -2
  27. clearskies/autodoc/schema/array.py +5 -6
  28. clearskies/autodoc/schema/boolean.py +4 -10
  29. clearskies/autodoc/schema/date.py +0 -3
  30. clearskies/autodoc/schema/datetime.py +1 -4
  31. clearskies/autodoc/schema/double.py +0 -3
  32. clearskies/autodoc/schema/enum.py +4 -2
  33. clearskies/autodoc/schema/integer.py +4 -9
  34. clearskies/autodoc/schema/long.py +0 -3
  35. clearskies/autodoc/schema/number.py +4 -9
  36. clearskies/autodoc/schema/object.py +5 -7
  37. clearskies/autodoc/schema/password.py +0 -3
  38. clearskies/autodoc/schema/schema.py +11 -0
  39. clearskies/autodoc/schema/string.py +4 -10
  40. clearskies/backends/__init__.py +55 -20
  41. clearskies/backends/api_backend.py +1100 -284
  42. clearskies/backends/backend.py +53 -84
  43. clearskies/backends/cursor_backend.py +236 -186
  44. clearskies/backends/memory_backend.py +519 -226
  45. clearskies/backends/secrets_backend.py +75 -31
  46. clearskies/column.py +1229 -0
  47. clearskies/columns/__init__.py +71 -0
  48. clearskies/columns/audit.py +205 -0
  49. clearskies/columns/belongs_to_id.py +483 -0
  50. clearskies/columns/belongs_to_model.py +128 -0
  51. clearskies/columns/belongs_to_self.py +105 -0
  52. clearskies/columns/boolean.py +109 -0
  53. clearskies/columns/category_tree.py +275 -0
  54. clearskies/columns/category_tree_ancestors.py +51 -0
  55. clearskies/columns/category_tree_children.py +127 -0
  56. clearskies/columns/category_tree_descendants.py +48 -0
  57. clearskies/columns/created.py +94 -0
  58. clearskies/columns/created_by_authorization_data.py +116 -0
  59. clearskies/columns/created_by_header.py +99 -0
  60. clearskies/columns/created_by_ip.py +92 -0
  61. clearskies/columns/created_by_routing_data.py +96 -0
  62. clearskies/columns/created_by_user_agent.py +92 -0
  63. clearskies/columns/date.py +230 -0
  64. clearskies/columns/datetime.py +278 -0
  65. clearskies/columns/email.py +76 -0
  66. clearskies/columns/float.py +149 -0
  67. clearskies/columns/has_many.py +505 -0
  68. clearskies/columns/has_many_self.py +56 -0
  69. clearskies/columns/has_one.py +14 -0
  70. clearskies/columns/integer.py +156 -0
  71. clearskies/columns/json.py +122 -0
  72. clearskies/columns/many_to_many_ids.py +333 -0
  73. clearskies/columns/many_to_many_ids_with_data.py +270 -0
  74. clearskies/columns/many_to_many_models.py +154 -0
  75. clearskies/columns/many_to_many_pivots.py +133 -0
  76. clearskies/columns/phone.py +158 -0
  77. clearskies/columns/select.py +91 -0
  78. clearskies/columns/string.py +98 -0
  79. clearskies/columns/timestamp.py +160 -0
  80. clearskies/columns/updated.py +110 -0
  81. clearskies/columns/uuid.py +86 -0
  82. clearskies/configs/README.md +105 -0
  83. clearskies/configs/__init__.py +162 -0
  84. clearskies/configs/actions.py +43 -0
  85. clearskies/configs/any.py +13 -0
  86. clearskies/configs/any_dict.py +22 -0
  87. clearskies/configs/any_dict_or_callable.py +23 -0
  88. clearskies/configs/authentication.py +23 -0
  89. clearskies/configs/authorization.py +23 -0
  90. clearskies/configs/boolean.py +16 -0
  91. clearskies/configs/boolean_or_callable.py +18 -0
  92. clearskies/configs/callable_config.py +18 -0
  93. clearskies/configs/columns.py +34 -0
  94. clearskies/configs/conditions.py +30 -0
  95. clearskies/configs/config.py +24 -0
  96. clearskies/configs/datetime.py +18 -0
  97. clearskies/configs/datetime_or_callable.py +19 -0
  98. clearskies/configs/endpoint.py +23 -0
  99. clearskies/configs/endpoint_list.py +28 -0
  100. clearskies/configs/float.py +16 -0
  101. clearskies/configs/float_or_callable.py +18 -0
  102. clearskies/configs/integer.py +16 -0
  103. clearskies/configs/integer_or_callable.py +18 -0
  104. clearskies/configs/joins.py +30 -0
  105. clearskies/configs/list_any_dict.py +30 -0
  106. clearskies/configs/list_any_dict_or_callable.py +31 -0
  107. clearskies/configs/model_class.py +35 -0
  108. clearskies/configs/model_column.py +65 -0
  109. clearskies/configs/model_columns.py +56 -0
  110. clearskies/configs/model_destination_name.py +25 -0
  111. clearskies/configs/model_to_id_column.py +43 -0
  112. clearskies/configs/readable_model_column.py +9 -0
  113. clearskies/configs/readable_model_columns.py +9 -0
  114. clearskies/configs/schema.py +23 -0
  115. clearskies/configs/searchable_model_columns.py +9 -0
  116. clearskies/configs/security_headers.py +39 -0
  117. clearskies/configs/select.py +26 -0
  118. clearskies/configs/select_list.py +47 -0
  119. clearskies/configs/string.py +29 -0
  120. clearskies/configs/string_dict.py +32 -0
  121. clearskies/configs/string_list.py +32 -0
  122. clearskies/configs/string_list_or_callable.py +35 -0
  123. clearskies/configs/string_or_callable.py +18 -0
  124. clearskies/configs/timedelta.py +18 -0
  125. clearskies/configs/timezone.py +18 -0
  126. clearskies/configs/url.py +23 -0
  127. clearskies/configs/validators.py +45 -0
  128. clearskies/configs/writeable_model_column.py +9 -0
  129. clearskies/configs/writeable_model_columns.py +9 -0
  130. clearskies/configurable.py +76 -0
  131. clearskies/contexts/__init__.py +8 -8
  132. clearskies/contexts/cli.py +8 -41
  133. clearskies/contexts/context.py +91 -56
  134. clearskies/contexts/wsgi.py +16 -29
  135. clearskies/contexts/wsgi_ref.py +53 -0
  136. clearskies/di/__init__.py +10 -7
  137. clearskies/di/additional_config.py +115 -4
  138. clearskies/di/additional_config_auto_import.py +12 -0
  139. clearskies/di/di.py +742 -121
  140. clearskies/di/inject/__init__.py +23 -0
  141. clearskies/di/inject/by_class.py +21 -0
  142. clearskies/di/inject/by_name.py +18 -0
  143. clearskies/di/inject/di.py +13 -0
  144. clearskies/di/inject/environment.py +14 -0
  145. clearskies/di/inject/input_output.py +20 -0
  146. clearskies/di/inject/now.py +13 -0
  147. clearskies/di/inject/requests.py +13 -0
  148. clearskies/di/inject/secrets.py +14 -0
  149. clearskies/di/inject/utcnow.py +13 -0
  150. clearskies/di/inject/uuid.py +15 -0
  151. clearskies/di/injectable.py +29 -0
  152. clearskies/di/injectable_properties.py +131 -0
  153. clearskies/end.py +183 -0
  154. clearskies/endpoint.py +1310 -0
  155. clearskies/endpoint_group.py +310 -0
  156. clearskies/endpoints/__init__.py +23 -0
  157. clearskies/endpoints/advanced_search.py +526 -0
  158. clearskies/endpoints/callable.py +388 -0
  159. clearskies/endpoints/create.py +202 -0
  160. clearskies/endpoints/delete.py +139 -0
  161. clearskies/endpoints/get.py +275 -0
  162. clearskies/endpoints/health_check.py +181 -0
  163. clearskies/endpoints/list.py +573 -0
  164. clearskies/endpoints/restful_api.py +427 -0
  165. clearskies/endpoints/simple_search.py +286 -0
  166. clearskies/endpoints/update.py +190 -0
  167. clearskies/environment.py +5 -3
  168. clearskies/exceptions/__init__.py +17 -0
  169. clearskies/{handlers/exceptions/input_error.py → exceptions/input_errors.py} +1 -1
  170. clearskies/exceptions/moved_permanently.py +3 -0
  171. clearskies/exceptions/moved_temporarily.py +3 -0
  172. clearskies/exceptions/not_found.py +2 -0
  173. clearskies/functional/__init__.py +2 -2
  174. clearskies/functional/routing.py +92 -0
  175. clearskies/functional/string.py +19 -11
  176. clearskies/functional/validations.py +61 -9
  177. clearskies/input_outputs/__init__.py +9 -7
  178. clearskies/input_outputs/cli.py +130 -142
  179. clearskies/input_outputs/exceptions/__init__.py +1 -1
  180. clearskies/input_outputs/headers.py +45 -0
  181. clearskies/input_outputs/input_output.py +91 -122
  182. clearskies/input_outputs/programmatic.py +69 -0
  183. clearskies/input_outputs/wsgi.py +23 -38
  184. clearskies/model.py +984 -183
  185. clearskies/parameters_to_properties.py +31 -0
  186. clearskies/query/__init__.py +12 -0
  187. clearskies/query/condition.py +223 -0
  188. clearskies/query/join.py +136 -0
  189. clearskies/query/query.py +196 -0
  190. clearskies/query/sort.py +27 -0
  191. clearskies/schema.py +82 -0
  192. clearskies/secrets/__init__.py +3 -31
  193. clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +15 -4
  194. clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +11 -5
  195. clearskies/secrets/akeyless.py +88 -147
  196. clearskies/secrets/secrets.py +8 -8
  197. clearskies/security_header.py +15 -0
  198. clearskies/security_headers/__init__.py +8 -8
  199. clearskies/security_headers/cache_control.py +47 -110
  200. clearskies/security_headers/cors.py +40 -95
  201. clearskies/security_headers/csp.py +76 -151
  202. clearskies/security_headers/hsts.py +14 -16
  203. clearskies/test_base.py +8 -0
  204. clearskies/typing.py +11 -0
  205. clearskies/validator.py +37 -0
  206. clearskies/validators/__init__.py +33 -0
  207. clearskies/validators/after_column.py +62 -0
  208. clearskies/validators/before_column.py +13 -0
  209. clearskies/validators/in_the_future.py +32 -0
  210. clearskies/validators/in_the_future_at_least.py +11 -0
  211. clearskies/validators/in_the_future_at_most.py +10 -0
  212. clearskies/validators/in_the_past.py +32 -0
  213. clearskies/validators/in_the_past_at_least.py +10 -0
  214. clearskies/validators/in_the_past_at_most.py +10 -0
  215. clearskies/validators/maximum_length.py +26 -0
  216. clearskies/validators/maximum_value.py +29 -0
  217. clearskies/validators/minimum_length.py +26 -0
  218. clearskies/validators/minimum_value.py +29 -0
  219. clearskies/validators/required.py +35 -0
  220. clearskies/validators/timedelta.py +59 -0
  221. clearskies/validators/unique.py +31 -0
  222. clear_skies-1.22.31.dist-info/RECORD +0 -214
  223. clearskies/application.py +0 -29
  224. clearskies/authentication/auth0_jwks.py +0 -118
  225. clearskies/authentication/auth_exception.py +0 -2
  226. clearskies/authentication/jwks_jwcrypto.py +0 -51
  227. clearskies/backends/api_get_only_backend.py +0 -48
  228. clearskies/backends/example_backend.py +0 -43
  229. clearskies/backends/file_backend.py +0 -48
  230. clearskies/backends/json_backend.py +0 -7
  231. clearskies/backends/restful_api_advanced_search_backend.py +0 -103
  232. clearskies/binding_config.py +0 -16
  233. clearskies/column_types/__init__.py +0 -203
  234. clearskies/column_types/audit.py +0 -249
  235. clearskies/column_types/belongs_to.py +0 -271
  236. clearskies/column_types/boolean.py +0 -60
  237. clearskies/column_types/category_tree.py +0 -304
  238. clearskies/column_types/column.py +0 -373
  239. clearskies/column_types/created.py +0 -26
  240. clearskies/column_types/created_by_authorization_data.py +0 -26
  241. clearskies/column_types/created_by_header.py +0 -24
  242. clearskies/column_types/created_by_ip.py +0 -17
  243. clearskies/column_types/created_by_routing_data.py +0 -25
  244. clearskies/column_types/created_by_user_agent.py +0 -17
  245. clearskies/column_types/created_micro.py +0 -26
  246. clearskies/column_types/datetime.py +0 -109
  247. clearskies/column_types/datetime_micro.py +0 -12
  248. clearskies/column_types/email.py +0 -18
  249. clearskies/column_types/float.py +0 -43
  250. clearskies/column_types/has_many.py +0 -179
  251. clearskies/column_types/has_one.py +0 -60
  252. clearskies/column_types/integer.py +0 -41
  253. clearskies/column_types/json.py +0 -25
  254. clearskies/column_types/many_to_many.py +0 -278
  255. clearskies/column_types/many_to_many_with_data.py +0 -162
  256. clearskies/column_types/phone.py +0 -48
  257. clearskies/column_types/select.py +0 -11
  258. clearskies/column_types/string.py +0 -24
  259. clearskies/column_types/timestamp.py +0 -73
  260. clearskies/column_types/updated.py +0 -26
  261. clearskies/column_types/updated_micro.py +0 -26
  262. clearskies/column_types/uuid.py +0 -25
  263. clearskies/columns.py +0 -123
  264. clearskies/condition_parser.py +0 -172
  265. clearskies/contexts/build_context.py +0 -54
  266. clearskies/contexts/convert_to_application.py +0 -190
  267. clearskies/contexts/extract_handler.py +0 -37
  268. clearskies/contexts/test.py +0 -94
  269. clearskies/decorators/__init__.py +0 -41
  270. clearskies/decorators/allow_non_json_bodies.py +0 -9
  271. clearskies/decorators/auth0_jwks.py +0 -22
  272. clearskies/decorators/authorization.py +0 -10
  273. clearskies/decorators/binding_classes.py +0 -9
  274. clearskies/decorators/binding_modules.py +0 -9
  275. clearskies/decorators/bindings.py +0 -9
  276. clearskies/decorators/create.py +0 -10
  277. clearskies/decorators/delete.py +0 -10
  278. clearskies/decorators/docs.py +0 -14
  279. clearskies/decorators/get.py +0 -10
  280. clearskies/decorators/jwks.py +0 -26
  281. clearskies/decorators/merge.py +0 -124
  282. clearskies/decorators/patch.py +0 -10
  283. clearskies/decorators/post.py +0 -10
  284. clearskies/decorators/public.py +0 -11
  285. clearskies/decorators/response_headers.py +0 -10
  286. clearskies/decorators/return_raw_response.py +0 -9
  287. clearskies/decorators/schema.py +0 -10
  288. clearskies/decorators/secret_bearer.py +0 -24
  289. clearskies/decorators/security_headers.py +0 -10
  290. clearskies/di/standard_dependencies.py +0 -151
  291. clearskies/handlers/__init__.py +0 -41
  292. clearskies/handlers/advanced_search.py +0 -271
  293. clearskies/handlers/base.py +0 -479
  294. clearskies/handlers/callable.py +0 -192
  295. clearskies/handlers/create.py +0 -35
  296. clearskies/handlers/crud_by_method.py +0 -18
  297. clearskies/handlers/database_connector.py +0 -32
  298. clearskies/handlers/delete.py +0 -61
  299. clearskies/handlers/exceptions/__init__.py +0 -5
  300. clearskies/handlers/exceptions/not_found.py +0 -3
  301. clearskies/handlers/get.py +0 -156
  302. clearskies/handlers/health_check.py +0 -59
  303. clearskies/handlers/input_processing.py +0 -79
  304. clearskies/handlers/list.py +0 -530
  305. clearskies/handlers/mygrations.py +0 -82
  306. clearskies/handlers/request_method_routing.py +0 -47
  307. clearskies/handlers/restful_api.py +0 -218
  308. clearskies/handlers/routing.py +0 -62
  309. clearskies/handlers/schema_helper.py +0 -128
  310. clearskies/handlers/simple_routing.py +0 -206
  311. clearskies/handlers/simple_routing_route.py +0 -197
  312. clearskies/handlers/simple_search.py +0 -136
  313. clearskies/handlers/update.py +0 -102
  314. clearskies/handlers/write.py +0 -193
  315. clearskies/input_requirements/__init__.py +0 -78
  316. clearskies/input_requirements/after.py +0 -36
  317. clearskies/input_requirements/before.py +0 -36
  318. clearskies/input_requirements/in_the_future_at_least.py +0 -19
  319. clearskies/input_requirements/in_the_future_at_most.py +0 -19
  320. clearskies/input_requirements/in_the_past_at_least.py +0 -19
  321. clearskies/input_requirements/in_the_past_at_most.py +0 -19
  322. clearskies/input_requirements/maximum_length.py +0 -19
  323. clearskies/input_requirements/maximum_value.py +0 -19
  324. clearskies/input_requirements/minimum_length.py +0 -22
  325. clearskies/input_requirements/minimum_value.py +0 -19
  326. clearskies/input_requirements/required.py +0 -23
  327. clearskies/input_requirements/requirement.py +0 -25
  328. clearskies/input_requirements/time_delta.py +0 -38
  329. clearskies/input_requirements/unique.py +0 -18
  330. clearskies/mocks/__init__.py +0 -7
  331. clearskies/mocks/input_output.py +0 -124
  332. clearskies/mocks/models.py +0 -142
  333. clearskies/models.py +0 -350
  334. clearskies/security_headers/base.py +0 -12
  335. clearskies/tests/simple_api/models/__init__.py +0 -2
  336. clearskies/tests/simple_api/models/status.py +0 -23
  337. clearskies/tests/simple_api/models/user.py +0 -21
  338. clearskies/tests/simple_api/users_api.py +0 -64
  339. {clear_skies-1.22.31.dist-info → clear_skies-2.0.1.dist-info}/LICENSE +0 -0
  340. /clearskies/{contexts/bash.py → autodoc/py.typed} +0 -0
  341. /clearskies/{handlers/exceptions → exceptions}/authentication.py +0 -0
  342. /clearskies/{handlers/exceptions → exceptions}/authorization.py +0 -0
  343. /clearskies/{handlers/exceptions → exceptions}/client_error.py +0 -0
  344. /clearskies/{tests/__init__.py → input_outputs/py.typed} +0 -0
  345. /clearskies/{tests/simple_api/__init__.py → py.typed} +0 -0
@@ -1,76 +1,62 @@
1
- from .base import Base
2
- from ..binding_config import BindingConfig
1
+ import clearskies.configs
2
+ import clearskies.parameters_to_properties
3
+ from clearskies.security_header import SecurityHeader
3
4
 
4
- numbers = [
5
- "max_age",
6
- "stale_if_error",
7
- "stale_while_revalidate",
8
- "s_maxage",
9
- ]
10
- bools = [
11
- "immutable",
12
- "must_understand",
13
- "no_cache",
14
- "no_store",
15
- "no_transform",
16
- "private",
17
- "public",
18
- "s_maxage",
19
- ]
20
5
 
6
+ class CacheControl(SecurityHeader):
7
+ max_age = clearskies.configs.Integer()
8
+ s_maxage = clearskies.configs.Integer()
9
+ stale_while_revalidate = clearskies.configs.Integer()
10
+ stale_if_error = clearskies.configs.Integer()
11
+ immutable = clearskies.configs.Boolean(default=False)
12
+ must_understand = clearskies.configs.Boolean(default=False)
13
+ no_cache = clearskies.configs.Boolean(default=False)
14
+ no_store = clearskies.configs.Boolean(default=False)
15
+ no_transform = clearskies.configs.Boolean(default=False)
16
+ private = clearskies.configs.Boolean(default=False)
17
+ public = clearskies.configs.Boolean(default=False)
21
18
 
22
- class CacheControl(Base):
23
- max_age = None
24
- no_cache = None
25
- no_store = None
26
- no_transform = None
27
- s_maxage = None
28
- must_understand = None
29
- private = None
30
- public = None
31
- immutable = None
32
- stale_while_revalidate = None
33
- stale_if_error = None
19
+ numbers: list[str] = [
20
+ "max_age",
21
+ "stale_if_error",
22
+ "stale_while_revalidate",
23
+ "s_maxage",
24
+ ]
25
+ bools: list[str] = [
26
+ "immutable",
27
+ "must_understand",
28
+ "no_cache",
29
+ "no_store",
30
+ "no_transform",
31
+ "private",
32
+ "public",
33
+ ]
34
34
 
35
- def __init__(self, environment):
36
- super().__init__(environment)
37
-
38
- def configure(
35
+ @clearskies.parameters_to_properties.parameters_to_properties
36
+ def __init__(
39
37
  self,
40
- no_cache=None,
41
- no_store=None,
42
- no_transform=None,
43
- max_age=None,
44
- s_maxage=None,
45
- must_revalidate=None,
46
- proxy_revalidate=None,
47
- must_understand=None,
48
- private=None,
49
- public=None,
50
- immutable=None,
51
- stale_while_revalidate=None,
52
- stale_if_error=None,
38
+ max_age: int | None = None,
39
+ s_maxage: int | None = None,
40
+ stale_while_revalidate: int | None = None,
41
+ stale_if_error: int | None = None,
42
+ immutable: bool = False,
43
+ must_understand: bool = False,
44
+ no_cache: bool = False,
45
+ no_store: bool = False,
46
+ no_transform: bool = False,
47
+ private: bool = False,
48
+ public: bool = False,
53
49
  ):
54
- self.max_age = max_age
55
- self.no_cache = no_cache
56
- self.no_store = no_store
57
- self.no_transform = no_transform
58
- self.s_maxage = s_maxage
59
- self.must_understand = must_understand
60
- self.private = private
61
- self.public = public
62
- self.immutable = immutable
63
- self.stale_while_revalidate = stale_while_revalidate
64
- self.stale_if_error = stale_if_error
50
+ self.finalize_and_validate_configuration()
65
51
 
66
52
  def set_headers_for_input_output(self, input_output):
67
53
  parts = []
68
- for variable_name in bools:
54
+ for variable_name in self.bools:
69
55
  value = getattr(self, variable_name)
70
56
  if not value:
71
57
  continue
72
58
  parts.append(variable_name.replace("_", "-"))
73
- for variable_name in numbers:
59
+ for variable_name in self.numbers:
74
60
  value = getattr(self, variable_name)
75
61
  if value is None:
76
62
  continue
@@ -78,53 +64,4 @@ class CacheControl(Base):
78
64
  parts.append(f"{key_name}={value}")
79
65
  if not parts:
80
66
  return
81
- input_output.set_header("cache-control", ", ".join(parts))
82
-
83
-
84
- # Use an explicity param list, even though long, so that Python can provide some input checking directly
85
- def cache_control(
86
- self,
87
- no_cache=None,
88
- no_store=None,
89
- no_transform=None,
90
- max_age=None,
91
- s_maxage=None,
92
- must_revalidate=None,
93
- proxy_revalidate=None,
94
- must_understand=None,
95
- private=None,
96
- public=None,
97
- immutable=None,
98
- stale_while_revalidate=None,
99
- stale_if_error=None,
100
- ):
101
- for variable_name in numbers:
102
- value = locals()[variable_name]
103
- if value is not None and type(value) != int:
104
- actual_type = type(value)
105
- raise ValueError(
106
- f"Invalid configuration value for cache control: {variable_name} should be an integer but instead is '{actual_type}'"
107
- )
108
- for variable_name in bools:
109
- value = locals()[variable_name]
110
- if value is not None and type(value) != bool:
111
- actual_type = type(value)
112
- raise ValueError(
113
- f"Invalid configuration value for cache control: {variable_name} should be True/False but instead is of type '{actual_type}'"
114
- )
115
- return BindingConfig(
116
- CacheControl,
117
- no_cache=no_cache,
118
- no_store=no_store,
119
- no_transform=no_transform,
120
- max_age=max_age,
121
- s_maxage=s_maxage,
122
- must_revalidate=must_revalidate,
123
- proxy_revalidate=proxy_revalidate,
124
- must_understand=must_understand,
125
- private=private,
126
- public=public,
127
- immutable=immutable,
128
- stale_while_revalidate=stale_while_revalidate,
129
- stale_if_error=stale_if_error,
130
- )
67
+ input_output.response_headers.add("cache-control", ", ".join(parts))
@@ -1,105 +1,50 @@
1
- from .base import Base
2
- from ..binding_config import BindingConfig
3
-
4
- lists = [
5
- "headers",
6
- "expose_headers",
7
- "methods",
8
- ]
9
-
10
-
11
- class CORS(Base):
12
- origin = None
13
- methods = None
14
- headers = None
15
- max_age = None
16
- credentials = None
17
- expose_headers = None
1
+ import clearskies.configs
2
+ import clearskies.parameters_to_properties
3
+ from clearskies.security_header import SecurityHeader
4
+
5
+
6
+ class Cors(SecurityHeader):
7
+ origin = clearskies.configs.String()
8
+ methods = clearskies.configs.StringList(default=[])
9
+ headers = clearskies.configs.StringList(default=[])
10
+ max_age = clearskies.configs.Integer(default=5)
11
+ credentials = clearskies.configs.Boolean(default=False)
12
+ expose_headers = clearskies.configs.StringList(default=[])
18
13
  is_cors = True
19
14
 
20
- def __init__(self, environment):
21
- super().__init__(environment)
22
-
23
- def configure(self, origin=None, methods=None, headers=None, max_age=None, credentials=None, expose_headers=None):
24
- self.origin = origin
25
- self.max_age = max_age
26
- self.credentials = credentials
27
- self.expose_headers = ", ".join(expose_headers) if type(expose_headers) == list else expose_headers
28
- self.set_methods(methods)
29
- self.set_headers(headers)
15
+ @clearskies.parameters_to_properties.parameters_to_properties
16
+ def __init__(
17
+ self,
18
+ credentials: bool = False,
19
+ expose_headers: list[str] = [],
20
+ headers: list[str] = [],
21
+ max_age: int = 5,
22
+ methods: list[str] = [],
23
+ origin: str = "",
24
+ ):
25
+ self.finalize_and_validate_configuration()
30
26
 
31
- def set_headers(self, headers):
32
- if type(headers) == list:
33
- headers = ", ".join(headers)
34
- self.headers = headers if headers is not None else ""
27
+ def set_headers(self, headers: list[str]):
28
+ self.headers = headers
35
29
 
36
- def add_header(self, header):
37
- if not self.headers:
38
- self.headers = header
39
- elif header not in self.headers:
40
- self.headers += ", " + header
30
+ def add_header(self, header: str):
31
+ self.headers = [*self.headers, header]
41
32
 
42
- def set_methods(self, methods):
43
- if type(methods) == list:
44
- methods = ", ".join(methods)
45
- self.methods = methods if methods is not None else ""
33
+ def set_methods(self, methods: list[str]):
34
+ self.methods = methods
46
35
 
47
- def add_method(self, method):
48
- if not self.methods:
49
- self.methods = method
50
- elif method not in self.methods:
51
- self.methods += ", " + method
36
+ def add_method(self, method: str):
37
+ self.methods = [*self.methods, method]
52
38
 
53
39
  def set_headers_for_input_output(self, input_output):
54
- for key in ["origin", "methods", "headers"]:
55
- if not getattr(self, key):
40
+ for key in ["expose_headers", "methods", "headers"]:
41
+ value = getattr(self, key)
42
+ if not value:
56
43
  continue
57
- input_output.set_header(f"access-control-allow-{key}".replace("_", "-"), getattr(self, key))
44
+ input_output.response_headers.add(f"access-control-allow-{key}".replace("_", "-"), ", ".join(value))
58
45
  if self.credentials:
59
- input_output.set_header("access-control-allow-credentials", "true")
60
- for key in ["max_age", "expose_headers"]:
61
- if not getattr(self, key):
62
- continue
63
- input_output.set_header(f"access-control-{key}".replace("_", "-"), str(getattr(self, key)))
64
-
65
-
66
- def cors(origin=None, methods=None, headers=None, max_age=None, credentials=None, expose_headers=None):
67
- # I didn't auto-pull into kwargs so that the allowed values are clearly defined.
68
- # however, checking and processing will be easier with a dict
69
- kwargs = {
70
- "origin": origin,
71
- "methods": methods,
72
- "headers": headers,
73
- "max_age": max_age,
74
- "credentials": credentials,
75
- "expose_headers": expose_headers,
76
- }
77
- allowed_types = {
78
- "origin": str,
79
- "max_age": int,
80
- "credentials": bool,
81
- }
82
- for key in lists:
83
- value = kwargs[key]
84
- if value is None:
85
- continue
86
- actual_type = type(value)
87
- if actual_type == list:
88
- if not all([type(item) == str for item in value]):
89
- raise ValueError(
90
- f"Invalid configuration value for CORS: {key} should be a list of strings, but another kind of value was found"
91
- )
92
- kwargs[key] = ", ".join(value)
93
- elif actual_type != str:
94
- raise ValueError(
95
- f"Invalid configuration value for CORS: {key} should be a string or list of strings but instead is '{actual_type}'"
96
- )
97
- for key, allowed_type in allowed_types.items():
98
- if kwargs[key] is None:
99
- continue
100
- actual_type = type(kwargs[key])
101
- if actual_type != allowed_type:
102
- raise ValueError(
103
- f"Invalid configuration value for CORS: {key} should be a {allowed_type} but instead is '{actual_type}'"
104
- )
105
- return BindingConfig(CORS, **kwargs)
46
+ input_output.response_headers.add("access-control-allow-credentials", "true")
47
+ if self.max_age:
48
+ input_output.response_headers.add("access-control-max-age", str(self.max_age))
49
+ if self.origin:
50
+ input_output.response_headers.add("access-control-allow-origin", str(self.origin))
@@ -1,169 +1,94 @@
1
- from .base import Base
2
- from ..binding_config import BindingConfig
1
+ import clearskies.configs
2
+ import clearskies.parameters_to_properties
3
+ from clearskies.security_header import SecurityHeader
3
4
 
4
- directives = [
5
- "default_src",
6
- "script_src",
7
- "style_src",
8
- "img_src",
9
- "connect_src",
10
- "font_src",
11
- "object_src",
12
- "media_src",
13
- "frame_src",
14
- "sandbox",
15
- "report_uri",
16
- "child_src",
17
- "form_action",
18
- "frame_ancestors",
19
- "plugin_types",
20
- "base_uri",
21
- "report_to",
22
- "worker_src",
23
- "manifest_src",
24
- "prefetch_src",
25
- "navigate_to",
26
- ]
27
5
 
28
-
29
- class CSP(Base):
6
+ class Csp(SecurityHeader):
30
7
  header_name = "content-security-policy"
31
- default_src = None
32
- script_src = None
33
- style_src = None
34
- img_src = None
35
- connect_src = None
36
- font_src = None
37
- object_src = None
38
- media_src = None
39
- frame_src = None
40
- sandbox = None
41
- report_uri = None
42
- child_src = None
43
- form_action = None
44
- frame_ancestors = None
45
- plugin_types = None
46
- base_uri = None
47
- report_to = None
48
- worker_src = None
49
- manifest_src = None
50
- prefetch_src = None
51
- navigate_to = None
8
+ default_src = clearskies.configs.String()
9
+ script_src = clearskies.configs.String()
10
+ style_src = clearskies.configs.String()
11
+ img_src = clearskies.configs.String()
12
+ connect_src = clearskies.configs.String()
13
+ font_src = clearskies.configs.String()
14
+ object_src = clearskies.configs.String()
15
+ media_src = clearskies.configs.String()
16
+ frame_src = clearskies.configs.String()
17
+ sandbox = clearskies.configs.String()
18
+ report_uri = clearskies.configs.String()
19
+ child_src = clearskies.configs.String()
20
+ form_action = clearskies.configs.String()
21
+ frame_ancestors = clearskies.configs.String()
22
+ plugin_types = clearskies.configs.String()
23
+ base_uri = clearskies.configs.String()
24
+ report_to = clearskies.configs.String()
25
+ worker_src = clearskies.configs.String()
26
+ manifest_src = clearskies.configs.String()
27
+ prefetch_src = clearskies.configs.String()
28
+ navigate_to = clearskies.configs.String()
52
29
 
53
- def __init__(self, environment):
54
- super().__init__(environment)
30
+ directives = [
31
+ "default_src",
32
+ "script_src",
33
+ "style_src",
34
+ "img_src",
35
+ "connect_src",
36
+ "font_src",
37
+ "object_src",
38
+ "media_src",
39
+ "frame_src",
40
+ "sandbox",
41
+ "report_uri",
42
+ "child_src",
43
+ "form_action",
44
+ "frame_ancestors",
45
+ "plugin_types",
46
+ "base_uri",
47
+ "report_to",
48
+ "worker_src",
49
+ "manifest_src",
50
+ "prefetch_src",
51
+ "navigate_to",
52
+ ]
55
53
 
56
- def configure(
54
+ @clearskies.parameters_to_properties.parameters_to_properties
55
+ def __init__(
57
56
  self,
58
- default_src=None,
59
- script_src=None,
60
- style_src=None,
61
- img_src=None,
62
- connect_src=None,
63
- font_src=None,
64
- object_src=None,
65
- media_src=None,
66
- frame_src=None,
67
- sandbox=None,
68
- report_uri=None,
69
- child_src=None,
70
- form_action=None,
71
- frame_ancestors=None,
72
- plugin_types=None,
73
- base_uri=None,
74
- report_to=None,
75
- worker_src=None,
76
- manifest_src=None,
77
- prefetch_src=None,
78
- navigate_to=None,
57
+ default_src: str = "",
58
+ script_src: str = "",
59
+ style_src: str = "",
60
+ img_src: str = "",
61
+ connect_src: str = "",
62
+ font_src: str = "",
63
+ object_src: str = "",
64
+ media_src: str = "",
65
+ frame_src: str = "",
66
+ sandbox: str = "",
67
+ report_uri: str = "",
68
+ child_src: str = "",
69
+ form_action: str = "",
70
+ frame_ancestors: str = "",
71
+ plugin_types: str = "",
72
+ base_uri: str = "",
73
+ report_to: str = "",
74
+ worker_src: str = "",
75
+ manifest_src: str = "",
76
+ prefetch_src: str = "",
77
+ navigate_to: str = "",
79
78
  ):
80
- self.default_src = default_src
81
- self.script_src = script_src
82
- self.style_src = style_src
83
- self.img_src = img_src
84
- self.connect_src = connect_src
85
- self.font_src = font_src
86
- self.object_src = object_src
87
- self.media_src = media_src
88
- self.frame_src = frame_src
89
- self.sandbox = sandbox
90
- self.report_uri = report_uri
91
- self.child_src = child_src
92
- self.form_action = form_action
93
- self.frame_ancestors = frame_ancestors
94
- self.plugin_types = plugin_types
95
- self.base_uri = base_uri
96
- self.report_to = report_to
97
- self.worker_src = worker_src
98
- self.manifest_src = manifest_src
99
- self.prefetch_src = prefetch_src
100
- self.navigate_to = navigate_to
79
+ self.finalize_and_validate_configuration()
101
80
 
102
81
  def set_headers_for_input_output(self, input_output):
103
82
  parts = []
104
- for variable_name in directives:
83
+ for variable_name in self.directives:
105
84
  value = getattr(self, variable_name)
106
85
  if not value:
107
86
  continue
87
+ if value.lower().strip() == "self":
88
+ value = "'self'"
108
89
  header_key_name = variable_name.replace("_", "-")
109
90
  parts.append(f"{header_key_name} {value}")
110
91
  if not parts:
111
92
  return
112
93
  header_value = "; ".join(parts)
113
- input_output.set_header(self.header_name, header_value)
114
-
115
-
116
- def csp(
117
- default_src=None,
118
- script_src=None,
119
- style_src=None,
120
- img_src=None,
121
- connect_src=None,
122
- font_src=None,
123
- object_src=None,
124
- media_src=None,
125
- frame_src=None,
126
- sandbox=None,
127
- report_uri=None,
128
- child_src=None,
129
- form_action=None,
130
- frame_ancestors=None,
131
- plugin_types=None,
132
- base_uri=None,
133
- report_to=None,
134
- worker_src=None,
135
- manifest_src=None,
136
- prefetch_src=None,
137
- navigate_to=None,
138
- ):
139
- for variable_name in directives:
140
- value = locals()[variable_name]
141
- if value is not None and type(value) != str:
142
- actual_type = type(value)
143
- raise ValueError(
144
- f"Invalid configuration value for CSP: {variable_name} should be a string but instead is '{actual_type}'"
145
- )
146
- return BindingConfig(
147
- CSP,
148
- default_src=default_src,
149
- script_src=script_src,
150
- style_src=style_src,
151
- img_src=img_src,
152
- connect_src=connect_src,
153
- font_src=font_src,
154
- object_src=object_src,
155
- media_src=media_src,
156
- frame_src=frame_src,
157
- sandbox=sandbox,
158
- report_uri=report_uri,
159
- child_src=child_src,
160
- form_action=form_action,
161
- frame_ancestors=frame_ancestors,
162
- plugin_types=plugin_types,
163
- base_uri=base_uri,
164
- report_to=report_to,
165
- worker_src=worker_src,
166
- manifest_src=manifest_src,
167
- prefetch_src=prefetch_src,
168
- navigate_to=navigate_to,
169
- )
94
+ input_output.response_headers.add(self.header_name, header_value)
@@ -1,24 +1,22 @@
1
- from .base import Base
2
- from ..binding_config import BindingConfig
1
+ import clearskies.configs
2
+ import clearskies.parameters_to_properties
3
+ from clearskies.security_header import SecurityHeader
3
4
 
4
5
 
5
- class HSTS(Base):
6
- max_age = None
7
- include_sub_domains = None
6
+ class Hsts(SecurityHeader):
7
+ max_age = clearskies.configs.Integer(default=31536000)
8
+ include_sub_domains = clearskies.configs.Boolean()
8
9
 
9
- def __init__(self, environment):
10
- super().__init__(environment)
11
-
12
- def configure(self, max_age=31536000, include_sub_domains=False):
13
- self.max_age = max_age
14
- self.include_sub_domains = include_sub_domains
10
+ @clearskies.parameters_to_properties.parameters_to_properties
11
+ def __init__(
12
+ self,
13
+ max_age: int = 31536000,
14
+ include_sub_domains: bool = False,
15
+ ):
16
+ self.finalize_and_validate_configuration()
15
17
 
16
18
  def set_headers_for_input_output(self, input_output):
17
19
  value = f"max-age={self.max_age} ;"
18
20
  if self.include_sub_domains:
19
21
  value += " includeSubDomains"
20
- input_output.set_header("strict-transport-security", value)
21
-
22
-
23
- def hsts(max_age=31536000, include_sub_domains=False):
24
- return BindingConfig(HSTS, max_age=max_age, include_sub_domains=include_sub_domains)
22
+ input_output.response_headers.add("strict-transport-security", value)
@@ -0,0 +1,8 @@
1
+ import unittest
2
+
3
+
4
+ class TestBase(unittest.TestCase):
5
+ def tearDown(self):
6
+ import clearskies.backends.memory_backend
7
+
8
+ clearskies.backends.memory_backend.MemoryBackend.clear_table_cache()
clearskies/typing.py ADDED
@@ -0,0 +1,11 @@
1
+ from typing import Any, Callable
2
+
3
+ from clearskies.action import Action
4
+ from clearskies.query.condition import Condition
5
+ from clearskies.validator import Validator
6
+
7
+ action = Callable[..., dict[str, Any]] | Action
8
+ condition = str | Callable | Condition
9
+ join = str | Callable[..., str]
10
+ validator = Callable[..., str] | Validator
11
+ response = str | bytes | dict[str, Any] | list[Any]
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from clearskies import configurable
7
+
8
+ if TYPE_CHECKING:
9
+ import clearskies.column
10
+ import clearskies.model
11
+
12
+
13
+ class Validator(ABC, configurable.Configurable):
14
+ """
15
+ Attach input validation rules to columns!
16
+
17
+ The validators provide a way to attach input validation logic to columns. The columns themselves already
18
+ provide basic validation (making sure strings are strings, integers are integers, etc...) but these classes
19
+ allow for more detailed rules.
20
+
21
+ It's important to understand that validators only apply to client input, which means that input validation
22
+ is only enforced by appropriate endpoints. If you inject a model into a function of your own and execute
23
+ a save operation with it, validators will **NOT** be checked.
24
+ """
25
+
26
+ is_unique = False
27
+ is_required = False
28
+
29
+ def __call__(self, model: clearskies.model.Model, column_name: str, data: dict[str, Any]) -> str:
30
+ return self.check(model, column_name, data)
31
+
32
+ @abstractmethod
33
+ def check(self, model: clearskies.model.Model, column_name: str, data: dict[str, Any]) -> str:
34
+ pass
35
+
36
+ def additional_write_columns(self, is_create=False) -> dict[str, clearskies.column.Column]:
37
+ return {}