clear-skies 2.0.7__py3-none-any.whl → 2.0.9__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 (153) hide show
  1. {clear_skies-2.0.7.dist-info → clear_skies-2.0.9.dist-info}/METADATA +1 -1
  2. clear_skies-2.0.9.dist-info/RECORD +256 -0
  3. clearskies/__init__.py +2 -2
  4. clearskies/authentication/authentication.py +1 -3
  5. clearskies/authentication/authorization.py +12 -5
  6. clearskies/authentication/authorization_pass_through.py +5 -3
  7. clearskies/authentication/jwks.py +25 -23
  8. clearskies/authentication/secret_bearer.py +15 -17
  9. clearskies/autodoc/schema/schema.py +1 -1
  10. clearskies/backends/api_backend.py +50 -56
  11. clearskies/backends/backend.py +14 -14
  12. clearskies/backends/cursor_backend.py +17 -23
  13. clearskies/backends/memory_backend.py +27 -30
  14. clearskies/backends/secrets_backend.py +13 -18
  15. clearskies/column.py +44 -56
  16. clearskies/columns/audit.py +14 -13
  17. clearskies/columns/belongs_to_id.py +10 -15
  18. clearskies/columns/belongs_to_model.py +6 -9
  19. clearskies/columns/belongs_to_self.py +13 -9
  20. clearskies/columns/boolean.py +13 -16
  21. clearskies/columns/category_tree.py +9 -11
  22. clearskies/columns/category_tree_children.py +2 -3
  23. clearskies/columns/category_tree_descendants.py +1 -1
  24. clearskies/columns/created.py +8 -11
  25. clearskies/columns/created_by_authorization_data.py +7 -9
  26. clearskies/columns/created_by_header.py +12 -8
  27. clearskies/columns/created_by_ip.py +6 -8
  28. clearskies/columns/created_by_routing_data.py +12 -7
  29. clearskies/columns/created_by_user_agent.py +6 -9
  30. clearskies/columns/date.py +12 -14
  31. clearskies/columns/datetime.py +19 -17
  32. clearskies/columns/email.py +3 -1
  33. clearskies/columns/float.py +10 -14
  34. clearskies/columns/has_many.py +8 -10
  35. clearskies/columns/has_many_self.py +13 -7
  36. clearskies/columns/has_one.py +2 -0
  37. clearskies/columns/integer.py +9 -11
  38. clearskies/columns/json.py +10 -12
  39. clearskies/columns/many_to_many_ids.py +14 -16
  40. clearskies/columns/many_to_many_ids_with_data.py +16 -16
  41. clearskies/columns/many_to_many_models.py +5 -7
  42. clearskies/columns/many_to_many_pivots.py +3 -5
  43. clearskies/columns/phone.py +12 -9
  44. clearskies/columns/select.py +12 -9
  45. clearskies/columns/string.py +1 -1
  46. clearskies/columns/timestamp.py +15 -15
  47. clearskies/columns/updated.py +8 -10
  48. clearskies/columns/uuid.py +7 -10
  49. clearskies/configs/__init__.py +8 -0
  50. clearskies/configs/any.py +2 -0
  51. clearskies/configs/any_dict.py +2 -0
  52. clearskies/configs/any_dict_or_callable.py +2 -0
  53. clearskies/configs/boolean.py +2 -0
  54. clearskies/configs/boolean_or_callable.py +2 -0
  55. clearskies/configs/callable_config.py +2 -0
  56. clearskies/configs/config.py +2 -0
  57. clearskies/configs/datetime.py +2 -0
  58. clearskies/configs/datetime_or_callable.py +2 -0
  59. clearskies/configs/email.py +10 -0
  60. clearskies/configs/email_list.py +17 -0
  61. clearskies/configs/email_list_or_callable.py +19 -0
  62. clearskies/configs/email_or_email_list_or_callable.py +59 -0
  63. clearskies/configs/float.py +2 -0
  64. clearskies/configs/float_or_callable.py +2 -0
  65. clearskies/configs/integer.py +2 -0
  66. clearskies/configs/integer_or_callable.py +2 -0
  67. clearskies/configs/list_any_dict.py +2 -0
  68. clearskies/configs/list_any_dict_or_callable.py +2 -0
  69. clearskies/configs/model_column.py +2 -0
  70. clearskies/configs/model_columns.py +2 -0
  71. clearskies/configs/model_destination_name.py +2 -1
  72. clearskies/configs/model_to_id_column.py +2 -0
  73. clearskies/configs/readable_model_column.py +2 -0
  74. clearskies/configs/readable_model_columns.py +2 -0
  75. clearskies/configs/searchable_model_columns.py +2 -0
  76. clearskies/configs/select.py +2 -0
  77. clearskies/configs/select_list.py +2 -0
  78. clearskies/configs/string.py +4 -2
  79. clearskies/configs/string_dict.py +2 -0
  80. clearskies/configs/string_list.py +17 -2
  81. clearskies/configs/string_list_or_callable.py +13 -0
  82. clearskies/configs/timedelta.py +2 -0
  83. clearskies/configs/timezone.py +2 -0
  84. clearskies/configs/url.py +2 -0
  85. clearskies/configs/writeable_model_column.py +2 -0
  86. clearskies/configs/writeable_model_columns.py +2 -0
  87. clearskies/configurable.py +2 -0
  88. clearskies/contexts/cli.py +9 -1
  89. clearskies/contexts/context.py +13 -14
  90. clearskies/contexts/wsgi.py +12 -10
  91. clearskies/contexts/wsgi_ref.py +12 -6
  92. clearskies/decorators.py +1 -1
  93. clearskies/decorators.pyi +10 -0
  94. clearskies/di/di.py +7 -6
  95. clearskies/di/inject/by_class.py +2 -0
  96. clearskies/di/inject/by_name.py +2 -0
  97. clearskies/di/inject/di.py +2 -0
  98. clearskies/di/inject/environment.py +1 -1
  99. clearskies/di/inject/now.py +2 -0
  100. clearskies/di/inject/requests.py +2 -0
  101. clearskies/di/inject/secrets.py +2 -2
  102. clearskies/di/inject/utcnow.py +2 -0
  103. clearskies/di/inject/uuid.py +2 -2
  104. clearskies/end.py +45 -7
  105. clearskies/endpoint.py +43 -59
  106. clearskies/endpoint_group.py +15 -18
  107. clearskies/endpoints/advanced_search.py +19 -26
  108. clearskies/endpoints/callable.py +10 -16
  109. clearskies/endpoints/create.py +6 -10
  110. clearskies/endpoints/delete.py +5 -11
  111. clearskies/endpoints/get.py +11 -15
  112. clearskies/endpoints/health_check.py +9 -11
  113. clearskies/endpoints/list.py +29 -36
  114. clearskies/endpoints/restful_api.py +43 -53
  115. clearskies/endpoints/schema.py +14 -18
  116. clearskies/endpoints/simple_search.py +5 -12
  117. clearskies/endpoints/update.py +6 -11
  118. clearskies/environment.py +2 -0
  119. clearskies/input_outputs/cli.py +2 -0
  120. clearskies/input_outputs/headers.py +2 -0
  121. clearskies/input_outputs/input_output.py +15 -15
  122. clearskies/input_outputs/programmatic.py +2 -2
  123. clearskies/input_outputs/wsgi.py +2 -2
  124. clearskies/model.py +120 -25
  125. clearskies/query/query.py +1 -4
  126. clearskies/secrets/__init__.py +2 -1
  127. clearskies/secrets/akeyless.py +16 -11
  128. clearskies/secrets/secrets.py +7 -2
  129. clearskies/security_header.py +4 -2
  130. clearskies/security_headers/cache_control.py +15 -14
  131. clearskies/security_headers/cors.py +10 -9
  132. clearskies/security_headers/csp.py +25 -24
  133. clearskies/security_headers/hsts.py +6 -5
  134. clearskies/typing.py +1 -1
  135. clearskies/validator.py +5 -6
  136. clearskies/validators/after_column.py +6 -7
  137. clearskies/validators/before_column.py +2 -0
  138. clearskies/validators/in_the_future.py +5 -8
  139. clearskies/validators/in_the_future_at_least.py +2 -0
  140. clearskies/validators/in_the_future_at_most.py +2 -0
  141. clearskies/validators/in_the_past.py +5 -8
  142. clearskies/validators/in_the_past_at_least.py +2 -0
  143. clearskies/validators/in_the_past_at_most.py +2 -0
  144. clearskies/validators/maximum_length.py +4 -5
  145. clearskies/validators/maximum_value.py +4 -4
  146. clearskies/validators/minimum_length.py +4 -4
  147. clearskies/validators/minimum_value.py +4 -4
  148. clearskies/validators/required.py +2 -4
  149. clearskies/validators/timedelta.py +8 -9
  150. clearskies/validators/unique.py +2 -3
  151. clear_skies-2.0.7.dist-info/RECORD +0 -251
  152. {clear_skies-2.0.7.dist-info → clear_skies-2.0.9.dist-info}/WHEEL +0 -0
  153. {clear_skies-2.0.7.dist-info → clear_skies-2.0.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,19 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- import inspect
4
- from collections import OrderedDict
5
- from typing import TYPE_CHECKING, Any, Type
3
+ from typing import TYPE_CHECKING, Any
6
4
 
7
- import clearskies.configs
8
- import clearskies.exceptions
9
- from clearskies import authentication, autodoc, typing
5
+ from clearskies import exceptions
10
6
  from clearskies.endpoints.simple_search import SimpleSearch
11
- from clearskies.functional import string
12
- from clearskies.input_outputs import InputOutput
13
7
 
14
8
  if TYPE_CHECKING:
15
- from clearskies import SecurityHeader
16
- from clearskies.model import Model
9
+ from clearskies import Model, autodoc
17
10
 
18
11
 
19
12
  class AdvancedSearch(SimpleSearch):
@@ -350,12 +343,12 @@ class AdvancedSearch(SimpleSearch):
350
343
  if pagination_data:
351
344
  error = self.model.validate_pagination_data(pagination_data, self.auto_case_internal_column_name)
352
345
  if error:
353
- raise clearskies.exceptions.ClientError(error)
346
+ raise exceptions.ClientError(error)
354
347
  if query_parameters:
355
- raise clearskies.exceptions.ClientError("Query parameters were found but are not supported.")
348
+ raise exceptions.ClientError("Query parameters were found but are not supported.")
356
349
  for key in request_data.keys():
357
350
  if key not in self.allowed_request_keys:
358
- raise clearskies.exceptions.ClientError(
351
+ raise exceptions.ClientError(
359
352
  f"Invalid request parameter found in request body: '{key}'. Expected parameters: "
360
353
  + ", ".join([self.auto_case_internal_column_name(key) for key in self.allowed_request_keys])
361
354
  )
@@ -363,7 +356,7 @@ class AdvancedSearch(SimpleSearch):
363
356
  sort_key_name = self.auto_case_internal_column_name("sort")
364
357
  sort = request_data.get(sort_key_name, [])
365
358
  if not isinstance(sort, list):
366
- raise clearskies.exceptions.ClientError(
359
+ raise exceptions.ClientError(
367
360
  f"'{sort_key_name}' property in request body should be a list, but I found a value of type "
368
361
  + sort.__class__.__name
369
362
  )
@@ -372,25 +365,25 @@ class AdvancedSearch(SimpleSearch):
372
365
  direction_key_name = self.auto_case_internal_column_name("direction")
373
366
  for index, sort_entry in enumerate(sort):
374
367
  if not isinstance(sort_entry, dict):
375
- raise clearskies.exceptions.ClientError(
368
+ raise exceptions.ClientError(
376
369
  f"'{sort_key_name}' should be a list of dictionaries, but entry #{index + 1} is a value of type '{sort_entry.__class__.__name}', not a dict"
377
370
  )
378
371
  for key_name in [column_key_name, direction_key_name]:
379
372
  if not sort_entry.get(key_name):
380
- raise clearskies.exceptions.ClientError(
373
+ raise exceptions.ClientError(
381
374
  f"Each entry in the sort list should contain both '{column_key_name}' and '{direction_key_name}' but entry #{index + 1} is missing '{key_name}'"
382
375
  )
383
376
  if not isinstance(sort_entry[key_name], str):
384
- raise clearskies.exceptions.ClientError(
377
+ raise exceptions.ClientError(
385
378
  f"{key_name}' must be a string, but for entry #{index + 1} it is a value of type "
386
379
  + sort_entry[key_name].__class__.__name__
387
380
  )
388
381
  if sort_entry[direction_key_name].lower() not in ["asc", "desc"]:
389
- raise clearskies.exceptions.ClientError(
382
+ raise exceptions.ClientError(
390
383
  f"{direction_key_name}' must be either 'ASC' or 'DESC', but a different value was found for entry #{index + 1}"
391
384
  )
392
385
  if self.auto_case_column_name(sort_entry[column_key_name], False) not in self.sortable_column_names:
393
- raise clearskies.exceptions.ClientError(
386
+ raise exceptions.ClientError(
394
387
  f"Invalid sort column for entry #{index + 1}. Allowed values are: "
395
388
  + ", ".join(
396
389
  [
@@ -402,7 +395,7 @@ class AdvancedSearch(SimpleSearch):
402
395
  where_key_name = self.auto_case_internal_column_name("where")
403
396
  where = request_data.get(where_key_name, [])
404
397
  if not isinstance(where, list):
405
- raise clearskies.exceptions.ClientError(
398
+ raise exceptions.ClientError(
406
399
  f"'{where_key_name}' property in request body should be a list, but I found a value of type "
407
400
  + where.__class__.__name
408
401
  )
@@ -412,21 +405,21 @@ class AdvancedSearch(SimpleSearch):
412
405
  value_key_name = self.auto_case_internal_column_name("value")
413
406
  for index, where_entry in enumerate(where):
414
407
  if not isinstance(where_entry, dict):
415
- raise clearskies.exceptions.ClientError(
408
+ raise exceptions.ClientError(
416
409
  f"'{where_key_name}' should be a list of dictionaries, but entry #{index + 1} is a value of type '{where_entry.__class__.__name}', not a dict"
417
410
  )
418
411
  for key_name in [column_key_name, operator_key_name, value_key_name]:
419
412
  if key_name not in where_entry:
420
- raise clearskies.exceptions.ClientError(
413
+ raise exceptions.ClientError(
421
414
  f"Each entry in the where list should contain '{column_key_name}', '{operator_key_name}', and '{value_key_name}', but entry #{index + 1} is missing '{key_name}'"
422
415
  )
423
416
  if key_name != value_key_name and not isinstance(where_entry[key_name], str):
424
- raise clearskies.exceptions.ClientError(
417
+ raise exceptions.ClientError(
425
418
  f"{key_name}' must be a string, but for entry #{index + 1} it is a value of type "
426
419
  + sort_entry[key_name].__class__.__name__
427
420
  )
428
421
  if where_entry[column_key_name] not in self.searchable_column_names:
429
- raise clearskies.exceptions.ClientError(
422
+ raise exceptions.ClientError(
430
423
  f"Invalid where column for entry #{index + 1}. Allowed values are: "
431
424
  + ", ".join(
432
425
  [
@@ -462,12 +455,12 @@ class AdvancedSearch(SimpleSearch):
462
455
  value if operator != "in" else value[0], where_entry[operator_key_name]
463
456
  )
464
457
  if error_allowed_operators:
465
- raise clearskies.exceptions.ClientError(
458
+ raise exceptions.ClientError(
466
459
  f"Invalid operator for entry #{index + 1}. Allowed operators are: "
467
460
  + ", ".join(column.allowed_search_operators(relationship_reference=column_name))
468
461
  )
469
462
  if error:
470
- raise clearskies.exceptions.ClientError(f"Invalid search value for entry #{index + 1}: {error}")
463
+ raise exceptions.ClientError(f"Invalid search value for entry #{index + 1}: {error}")
471
464
 
472
465
  def configure_model_from_request_data(
473
466
  self,
@@ -1,22 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
- import inspect
4
- from collections import OrderedDict
5
3
  from typing import TYPE_CHECKING, Any
6
4
  from typing import Callable as CallableType
7
5
 
8
- import clearskies.configs
9
- import clearskies.exceptions
10
- from clearskies import authentication, autodoc, typing
6
+ from clearskies import authentication, autodoc, configs, decorators, exceptions
11
7
  from clearskies.endpoint import Endpoint
12
8
  from clearskies.functional import string
13
- from clearskies.input_outputs import InputOutput
14
9
 
15
10
  if TYPE_CHECKING:
16
- from clearskies import Column, SecurityHeader
11
+ from clearskies import Column, Model, Schema, SecurityHeader
17
12
  from clearskies.authentication import Authentication, Authorization
18
- from clearskies.model import Model
19
- from clearskies.schema import Schema
13
+ from clearskies.input_outputs import InputOutput
20
14
 
21
15
 
22
16
  class Callable(Endpoint):
@@ -114,7 +108,7 @@ class Callable(Endpoint):
114
108
  """
115
109
  The callable to execute when the endpoint is invoked
116
110
  """
117
- to_call = clearskies.configs.Callable(default=None)
111
+ to_call = configs.Callable(default=None)
118
112
 
119
113
  """
120
114
  A schema that describes the expected input from the client.
@@ -172,7 +166,7 @@ class Callable(Endpoint):
172
166
  ```
173
167
 
174
168
  """
175
- input_schema = clearskies.configs.Schema(default=None)
169
+ input_schema = configs.Schema(default=None)
176
170
 
177
171
  """
178
172
  Whether or not the return value is meant to be wrapped up in the standard clearskies response schema.
@@ -232,20 +226,20 @@ class Callable(Endpoint):
232
226
  Note that you can also return strings this way instead of objects/JSON.
233
227
 
234
228
  """
235
- return_standard_response = clearskies.configs.Boolean(default=True)
229
+ return_standard_response = configs.Boolean(default=True)
236
230
 
237
231
  """
238
232
  Set to true if the callable will be returning multiple records (used when building the auto-documentation)
239
233
  """
240
- return_records = clearskies.configs.Boolean(default=False)
234
+ return_records = configs.Boolean(default=False)
241
235
 
242
- @clearskies.decorators.parameters_to_properties
236
+ @decorators.parameters_to_properties
243
237
  def __init__(
244
238
  self,
245
239
  to_call: CallableType,
246
240
  url: str = "",
247
241
  request_methods: list[str] = ["GET"],
248
- model_class: type[clearskies.model.Model] | None = None,
242
+ model_class: type[Model] | None = None,
249
243
  readable_column_names: list[str] = [],
250
244
  writeable_column_names: list[str] = [],
251
245
  input_schema: type[Schema] | None = None,
@@ -281,7 +275,7 @@ class Callable(Endpoint):
281
275
  else:
282
276
  input_errors = self.find_input_errors_from_callable(input_output.request_data, input_output)
283
277
  if input_errors:
284
- raise clearskies.exceptions.InputErrors(input_errors)
278
+ raise exceptions.InputErrors(input_errors)
285
279
  response = self.di.call_function(self.to_call, **input_output.get_context_for_callables())
286
280
 
287
281
  if not self.return_standard_response:
@@ -1,18 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
- import inspect
4
- from collections import OrderedDict
5
3
  from typing import TYPE_CHECKING, Any, Callable
6
4
 
7
- import clearskies.configs
8
- import clearskies.exceptions
9
- from clearskies import authentication, autodoc, typing
5
+ from clearskies import authentication, autodoc, decorators, exceptions
10
6
  from clearskies.endpoint import Endpoint
11
7
  from clearskies.functional import string
12
- from clearskies.input_outputs import InputOutput
13
8
 
14
9
  if TYPE_CHECKING:
15
- from clearskies import Column, SecurityHeader
10
+ from clearskies import Column, Schema, SecurityHeader
11
+ from clearskies.input_outputs import InputOutput
16
12
  from clearskies.model import Model
17
13
 
18
14
 
@@ -102,7 +98,7 @@ class Create(Endpoint):
102
98
  5. We provided an extra column (`not_a_column`) that wasn't in the list of allowed columns.
103
99
  """
104
100
 
105
- @clearskies.decorators.parameters_to_properties
101
+ @decorators.parameters_to_properties
106
102
  def __init__(
107
103
  self,
108
104
  model_class: type[Model],
@@ -114,7 +110,7 @@ class Create(Endpoint):
114
110
  request_methods: list[str] = ["POST"],
115
111
  response_headers: list[str | Callable[..., list[str]]] = [],
116
112
  output_map: Callable[..., dict[str, Any]] | None = None,
117
- output_schema: clearskies.Schema | None = None,
113
+ output_schema: Schema | None = None,
118
114
  column_overrides: dict[str, Column] = {},
119
115
  internal_casing: str = "snake_case",
120
116
  external_casing: str = "snake_case",
@@ -137,7 +133,7 @@ class Create(Endpoint):
137
133
  def handle(self, input_output: InputOutput) -> Any:
138
134
  request_data = self.get_request_data(input_output)
139
135
  if not request_data and input_output.has_body():
140
- raise clearskies.exceptions.ClientError("Request body was not valid JSON")
136
+ raise exceptions.ClientError("Request body was not valid JSON")
141
137
  self.validate_input_against_schema(request_data, input_output, self.model_class)
142
138
  new_model = self.model.create(request_data, columns=self.columns)
143
139
  return self.success(input_output, self.model_as_json(new_model, input_output))
@@ -1,19 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
- import inspect
4
- from collections import OrderedDict
5
- from typing import TYPE_CHECKING, Any, Callable, Type
3
+ from typing import TYPE_CHECKING, Any, Callable
6
4
 
7
- import clearskies.configs
8
- import clearskies.exceptions
9
- from clearskies import authentication, autodoc, typing
5
+ from clearskies import authentication, autodoc, decorators
10
6
  from clearskies.endpoints.get import Get
11
- from clearskies.functional import routing, string
12
- from clearskies.input_outputs import InputOutput
13
7
 
14
8
  if TYPE_CHECKING:
15
- from clearskies import SecurityHeader
16
- from clearskies.model import Model, Schema
9
+ from clearskies import Model, SecurityHeader, typing
10
+ from clearskies.input_outputs import InputOutput
17
11
 
18
12
 
19
13
  class Delete(Get):
@@ -73,7 +67,7 @@ class Delete(Get):
73
67
  ```
74
68
  """
75
69
 
76
- @clearskies.decorators.parameters_to_properties
70
+ @decorators.parameters_to_properties
77
71
  def __init__(
78
72
  self,
79
73
  model_class: type[Model],
@@ -1,19 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
- import inspect
4
- from collections import OrderedDict
5
- from typing import TYPE_CHECKING, Any, Callable, Type
6
-
7
- import clearskies.configs
8
- import clearskies.exceptions
9
- from clearskies import authentication, autodoc, typing
10
- from clearskies.authentication import Authentication, Authorization
3
+ from typing import TYPE_CHECKING, Any, Callable
4
+
5
+ from clearskies import autodoc, configs, decorators, exceptions
6
+ from clearskies.authentication import Authentication, Authorization, Public
11
7
  from clearskies.endpoint import Endpoint
12
8
  from clearskies.functional import routing, string
13
- from clearskies.input_outputs import InputOutput
14
9
 
15
10
  if TYPE_CHECKING:
16
- from clearskies import Column, Schema, SecurityHeader
11
+ from clearskies import Column, Schema, SecurityHeader, typing
12
+ from clearskies.input_outputs import InputOutput
17
13
  from clearskies.model import Model
18
14
 
19
15
 
@@ -157,9 +153,9 @@ class Get(Endpoint):
157
153
  }
158
154
  ```
159
155
  """
160
- record_lookup_column_name = clearskies.configs.ReadableModelColumn("model_class", default=None)
156
+ record_lookup_column_name = configs.ReadableModelColumn("model_class", default=None)
161
157
 
162
- @clearskies.decorators.parameters_to_properties
158
+ @decorators.parameters_to_properties
163
159
  def __init__(
164
160
  self,
165
161
  model_class: type[Model],
@@ -177,8 +173,8 @@ class Get(Endpoint):
177
173
  description: str = "",
178
174
  where: typing.condition | list[typing.condition] = [],
179
175
  joins: typing.join | list[typing.join] = [],
180
- authentication: Authentication = authentication.Public(),
181
- authorization: Authorization = authentication.Authorization(),
176
+ authentication: Authentication = Public(),
177
+ authorization: Authorization = Authorization(),
182
178
  ):
183
179
  try:
184
180
  # we will set the value for this if it isn't already set, and the easiest way is to just fetch it and see if it blows up
@@ -211,7 +207,7 @@ class Get(Endpoint):
211
207
  self.record_lookup_column_name + "=" + lookup_column_value
212
208
  )
213
209
  if not model:
214
- raise clearskies.exceptions.NotFound("Not Found")
210
+ raise exceptions.NotFound("Not Found")
215
211
  return model
216
212
 
217
213
  def handle(self, input_output: InputOutput) -> Any:
@@ -1,14 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- import inspect
4
- from typing import Any, Callable, Type
3
+ from typing import TYPE_CHECKING, Any, Callable
5
4
 
6
- import clearskies.configs
7
- import clearskies.exceptions
8
- from clearskies import autodoc, typing
5
+ from clearskies import autodoc, configs, decorators
9
6
  from clearskies.endpoint import Endpoint
10
- from clearskies.functional import routing, string
11
- from clearskies.input_outputs import InputOutput
7
+
8
+ if TYPE_CHECKING:
9
+ from clearskies.input_outputs import InputOutput
12
10
 
13
11
 
14
12
  class HealthCheck(Endpoint):
@@ -80,7 +78,7 @@ class HealthCheck(Endpoint):
80
78
  If any exceptions are raised when building the dependency injection parameters, the health check will return
81
79
  failure.
82
80
  """
83
- dependency_injection_names = clearskies.configs.StringList(default=[])
81
+ dependency_injection_names = configs.StringList(default=[])
84
82
 
85
83
  """
86
84
  A list of classes to build with the dependency injection system.
@@ -104,7 +102,7 @@ class HealthCheck(Endpoint):
104
102
  wsgi()
105
103
  ```
106
104
  """
107
- classes_to_build = clearskies.configs.Any(default=[])
105
+ classes_to_build = configs.Any(default=[])
108
106
 
109
107
  """
110
108
  A list of callables to invoke.
@@ -128,9 +126,9 @@ class HealthCheck(Endpoint):
128
126
  wsgi()
129
127
  ```
130
128
  """
131
- callables = clearskies.configs.Any(default=[])
129
+ callables = configs.Any(default=[])
132
130
 
133
- @clearskies.decorators.parameters_to_properties
131
+ @decorators.parameters_to_properties
134
132
  def __init__(
135
133
  self,
136
134
  dependency_injection_names: list[str] = [],
@@ -1,20 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
- import inspect
4
- from collections import OrderedDict
5
3
  from typing import TYPE_CHECKING, Any, Callable
6
4
 
7
- import clearskies.configs
8
- import clearskies.exceptions
9
- from clearskies import authentication, autodoc, typing
5
+ from clearskies import authentication, autodoc, configs, decorators, exceptions
10
6
  from clearskies.endpoint import Endpoint
11
7
  from clearskies.functional import string
12
- from clearskies.input_outputs import InputOutput
13
8
 
14
9
  if TYPE_CHECKING:
15
- from clearskies import Schema, SecurityHeader
16
- from clearskies.column import Column
17
- from clearskies.model import Model
10
+ from clearskies import Column, Model, Schema, SecurityHeader, typing
11
+ from clearskies.input_outputs import InputOutput
18
12
 
19
13
 
20
14
  class List(Endpoint):
@@ -35,6 +29,7 @@ class List(Endpoint):
35
29
  ```python
36
30
  import clearskies
37
31
 
32
+
38
33
  class User(clearskies.Model):
39
34
  id_column_name = "id"
40
35
  backend = clearskies.backends.MemoryBackend()
@@ -154,35 +149,33 @@ class List(Endpoint):
154
149
  """
155
150
  The default column to sort by.
156
151
  """
157
- default_sort_column_name = clearskies.configs.ModelColumn("model_class")
152
+ default_sort_column_name = configs.ModelColumn("model_class")
158
153
 
159
154
  """
160
155
  The default sort direction (ASC or DESC).
161
156
  """
162
- default_sort_direction = clearskies.configs.Select(["ASC", "DESC"], default="ASC")
157
+ default_sort_direction = configs.Select(["ASC", "DESC"], default="ASC")
163
158
 
164
159
  """
165
160
  The number of records returned if the client doesn't specify a different number of records (default: 50).
166
161
  """
167
- default_limit = clearskies.configs.Integer(default=50)
162
+ default_limit = configs.Integer(default=50)
168
163
 
169
164
  """
170
165
  The maximum number of records the client is allowed to request (0 == no limit)
171
166
  """
172
- maximum_limit = clearskies.configs.Integer(default=200)
167
+ maximum_limit = configs.Integer(default=200)
173
168
 
174
169
  """
175
170
  A column to group by.
176
171
  """
177
- group_by_column_name = clearskies.configs.ModelColumn("model_class")
172
+ group_by_column_name = configs.ModelColumn("model_class")
178
173
 
179
- readable_column_names = clearskies.configs.ReadableModelColumns("model_class")
180
- sortable_column_names = clearskies.configs.ReadableModelColumns("model_class", allow_relationship_references=True)
181
- searchable_column_names = clearskies.configs.SearchableModelColumns(
182
- "model_class", allow_relationship_references=True
183
- )
174
+ readable_column_names = configs.ReadableModelColumns("model_class")
175
+ sortable_column_names = configs.ReadableModelColumns("model_class", allow_relationship_references=True)
176
+ searchable_column_names = configs.SearchableModelColumns("model_class", allow_relationship_references=True)
184
177
 
185
- @clearskies.decorators.parameters_to_properties
178
+ @decorators.parameters_to_properties
186
179
  def __init__(
187
180
  self,
188
181
  model_class: type[Model],
@@ -236,16 +229,16 @@ class List(Endpoint):
236
229
  def handle(self, input_output: InputOutput):
237
230
  model = self.fetch_model_with_base_query(input_output)
238
231
  if not input_output.request_data and input_output.has_body():
239
- raise clearskies.exceptions.ClientError("Request body was not valid JSON")
232
+ raise exceptions.ClientError("Request body was not valid JSON")
240
233
  if input_output.request_data and not isinstance(input_output.request_data, dict):
241
- raise clearskies.exceptions.ClientError("When present, request body must be a JSON dictionary")
234
+ raise exceptions.ClientError("When present, request body must be a JSON dictionary")
242
235
  request_data = self.map_input_to_internal_names(input_output.request_data) # type: ignore
243
236
  query_parameters = self.map_input_to_internal_names(input_output.query_parameters)
244
237
  pagination_data = {}
245
238
  for key in model.allowed_pagination_keys():
246
239
  if key in request_data and key in query_parameters:
247
240
  original_name = self.auto_case_internal_column_name(key)
248
- raise clearskies.exceptions.ClientError(
241
+ raise exceptions.ClientError(
249
242
  f"Ambiguous request: key '{original_name}' is present in both the JSON body and URL data"
250
243
  )
251
244
  if key in request_data:
@@ -340,49 +333,49 @@ class List(Endpoint):
340
333
  if pagination_data:
341
334
  error = self.model.validate_pagination_data(pagination_data, self.auto_case_internal_column_name)
342
335
  if error:
343
- raise clearskies.exceptions.ClientError(error)
336
+ raise exceptions.ClientError(error)
344
337
  for key in request_data.keys():
345
338
  if key not in self.allowed_request_keys:
346
- raise clearskies.exceptions.ClientError(f"Invalid request parameter found in request body: '{key}'")
339
+ raise exceptions.ClientError(f"Invalid request parameter found in request body: '{key}'")
347
340
  for key in query_parameters.keys():
348
341
  if key not in self.allowed_request_keys:
349
- raise clearskies.exceptions.ClientError(f"Invalid request parameter found in URL data: '{key}'")
342
+ raise exceptions.ClientError(f"Invalid request parameter found in URL data: '{key}'")
350
343
  if key in request_data:
351
- raise clearskies.exceptions.ClientError(
344
+ raise exceptions.ClientError(
352
345
  f"Ambiguous request: '{key}' was found in both the request body and URL data"
353
346
  )
354
347
  self.validate_limit(request_data, query_parameters)
355
348
  sort = self.from_either(request_data, query_parameters, "sort")
356
349
  direction = self.from_either(request_data, query_parameters, "direction")
357
350
  if sort and type(sort) != str:
358
- raise clearskies.exceptions.ClientError("Invalid request: 'sort' should be a string")
351
+ raise exceptions.ClientError("Invalid request: 'sort' should be a string")
359
352
  if direction and type(direction) != str:
360
- raise clearskies.exceptions.ClientError("Invalid request: 'direction' should be a string")
353
+ raise exceptions.ClientError("Invalid request: 'direction' should be a string")
361
354
  if sort or direction:
362
355
  if (sort and not direction) or (direction and not sort):
363
- raise clearskies.exceptions.ClientError(
356
+ raise exceptions.ClientError(
364
357
  "You must specify 'sort' and 'direction' together in the request - not just one of them"
365
358
  )
366
359
  if sort not in self.sortable_column_names:
367
- raise clearskies.exceptions.ClientError(f"Invalid request: invalid sort column")
360
+ raise exceptions.ClientError(f"Invalid request: invalid sort column")
368
361
  if direction.lower() not in ["asc", "desc"]:
369
- raise clearskies.exceptions.ClientError("Invalid request: direction must be 'asc' or 'desc'")
362
+ raise exceptions.ClientError("Invalid request: direction must be 'asc' or 'desc'")
370
363
  self.check_search_in_request_data(request_data, query_parameters)
371
364
 
372
365
  def validate_limit(self, request_data: dict[str, Any], query_parameters: dict[str, Any]) -> None:
373
366
  limit = self.from_either(request_data, query_parameters, "limit")
374
367
  if limit is not None and type(limit) != int and type(limit) != float and type(limit) != str:
375
- raise clearskies.exceptions.ClientError("Invalid request: 'limit' should be an integer")
368
+ raise exceptions.ClientError("Invalid request: 'limit' should be an integer")
376
369
  if limit:
377
370
  try:
378
371
  limit = int(limit)
379
372
  except ValueError:
380
- raise clearskies.exceptions.ClientError("Invalid request: 'limit' should be an integer")
373
+ raise exceptions.ClientError("Invalid request: 'limit' should be an integer")
381
374
  if limit:
382
375
  if limit > self.maximum_limit:
383
- raise clearskies.exceptions.ClientError(f"Invalid request: 'limit' must be at most {self.max_limit}")
376
+ raise exceptions.ClientError(f"Invalid request: 'limit' must be at most {self.maximum_limit}")
384
377
  if limit < 0:
385
- raise clearskies.exceptions.ClientError(f"Invalid request: 'limit' must be positive")
378
+ raise exceptions.ClientError(f"Invalid request: 'limit' must be positive")
386
379
 
387
380
  def check_search_in_request_data(self, request_data: dict[str, Any], query_parameters: dict[str, Any]):
388
381
  return None