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,14 +1,18 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
4
  from types import ModuleType
3
- from typing import Any, Callable
5
+ from typing import TYPE_CHECKING, Any, Callable
4
6
  from wsgiref.simple_server import make_server
5
7
  from wsgiref.util import setup_testing_defaults
6
8
 
7
- import clearskies.endpoint
8
- import clearskies.endpoint_group
9
9
  from clearskies.contexts.context import Context
10
- from clearskies.di import AdditionalConfig
11
- from clearskies.input_outputs import Wsgi as WsgiInputOutput
10
+
11
+ if TYPE_CHECKING:
12
+ from clearskies.di import AdditionalConfig
13
+ from clearskies.endpoint import Endpoint
14
+ from clearskies.endpoint_group import EndpointGroup
15
+ from clearskies.input_outputs import Wsgi as WsgiInputOutput
12
16
 
13
17
 
14
18
  class WsgiRef(Context):
@@ -26,9 +30,11 @@ class WsgiRef(Context):
26
30
  #!/usr/bin/env python
27
31
  import clearskies
28
32
 
33
+
29
34
  def hello_world(name):
30
35
  return f"Hello {name}!"
31
36
 
37
+
32
38
  wsgi = clearskies.contexts.WsgiRef(
33
39
  clearskies.endpoints.Callable(
34
40
  hello_world,
@@ -49,7 +55,7 @@ class WsgiRef(Context):
49
55
 
50
56
  def __init__(
51
57
  self,
52
- application: Callable | clearskies.endpoint.Endpoint | clearskies.endpoint_group.EndpointGroup,
58
+ application: Callable | Endpoint | EndpointGroup,
53
59
  port: int = 8080,
54
60
  classes: type | list[type] = [],
55
61
  modules: ModuleType | list[ModuleType] = [],
clearskies/decorators.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import inspect
4
4
 
5
- import wrapt # type: ignore
5
+ import wrapt
6
6
 
7
7
 
8
8
  @wrapt.decorator
@@ -0,0 +1,10 @@
1
+ # decorators.pyi
2
+ from typing import Any, Callable, TypeVar
3
+
4
+ # A TypeVar is used to say "whatever kind of function comes in,
5
+ # the same kind of function goes out."
6
+ _F = TypeVar("_F", bound=Callable[..., Any])
7
+
8
+ # This is the type signature for your decorator.
9
+ # It tells Pylance that it preserves the signature of the function it wraps.
10
+ def parameters_to_properties(wrapped: _F) -> _F: ...
clearskies/di/di.py CHANGED
@@ -11,7 +11,6 @@ from requests.adapters import HTTPAdapter
11
11
  from requests.packages.urllib3.util.retry import Retry # type: ignore
12
12
 
13
13
  import clearskies.input_outputs.input_output
14
- import clearskies.secrets
15
14
  from clearskies.di.additional_config import AdditionalConfig
16
15
  from clearskies.di.additional_config_auto_import import AdditionalConfigAutoImport
17
16
  from clearskies.environment import Environment
@@ -350,9 +349,9 @@ class Di:
350
349
  import my_module
351
350
 
352
351
  di = Di()
353
- di.add_modules([
354
- my_module
355
- ]) # also equivalent: di.add_modules(my_module), or Di(modules=[my_module])
352
+ di.add_modules(
353
+ [my_module]
354
+ ) # also equivalent: di.add_modules(my_module), or Di(modules=[my_module])
356
355
 
357
356
 
358
357
  def my_function(my_class):
@@ -956,6 +955,8 @@ class Di:
956
955
  return uuid
957
956
 
958
957
  def provide_secrets(self):
958
+ import clearskies.secrets
959
+
959
960
  return clearskies.secrets.Secrets()
960
961
 
961
962
  def provide_memory_backend_default_data(self):
@@ -964,8 +965,8 @@ class Di:
964
965
  def provide_global_table_prefix(self):
965
966
  return ""
966
967
 
967
- def provide_akeyless(self):
968
- import akeyless # type: ignore
968
+ def provide_akeyles_sdk(self):
969
+ import akeyless # type: ignore[import-untyped]
969
970
 
970
971
  return akeyless
971
972
 
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from typing import Any
2
4
 
3
5
  from clearskies.di.injectable import Injectable
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from typing import Any
2
4
 
3
5
  from clearskies.di.injectable import Injectable
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from typing import Any
2
4
 
3
5
  from clearskies.di.injectable import Injectable
@@ -1,4 +1,4 @@
1
- import requests
1
+ from __future__ import annotations
2
2
 
3
3
  from clearskies.di.injectable import Injectable
4
4
  from clearskies.environment import Environment as EnvironmentDependency
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
4
 
3
5
  from clearskies.di.injectable import Injectable
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import requests
2
4
 
3
5
  from clearskies.di.injectable import Injectable
@@ -1,7 +1,7 @@
1
- import datetime
1
+ from __future__ import annotations
2
2
 
3
3
  from clearskies.di.injectable import Injectable
4
- from clearskies.secrets import Secrets as SecretsHelper
4
+ from clearskies.secrets.secrets import Secrets as SecretsHelper
5
5
 
6
6
 
7
7
  class Secrets(Injectable):
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
4
 
3
5
  from clearskies.di.injectable import Injectable
@@ -1,6 +1,6 @@
1
- import datetime
1
+ from __future__ import annotations
2
+
2
3
  import types
3
- import uuid
4
4
 
5
5
  from clearskies.di.injectable import Injectable
6
6
 
clearskies/end.py CHANGED
@@ -1,17 +1,22 @@
1
- # type: ignore
2
1
  from __future__ import annotations
3
2
 
4
3
  from abc import ABC
5
4
  from typing import TYPE_CHECKING, Any
6
5
 
7
6
  if TYPE_CHECKING:
8
- from clearskies.input_output import InputOutput
7
+ from clearskies import typing
8
+ from clearskies.input_outputs import InputOutput
9
9
 
10
- from clearskies import exceptions
10
+ from clearskies import configs, configurable, di, exceptions
11
+ from clearskies.authentication import Authorization, Public
11
12
  from clearskies.functional import string
12
13
 
13
14
 
14
- class End(ABC):
15
+ class End(
16
+ ABC,
17
+ configurable.Configurable,
18
+ di.InjectableProperties,
19
+ ):
15
20
  """
16
21
  DRY for endpoint and endpoint groups.
17
22
 
@@ -20,6 +25,24 @@ class End(ABC):
20
25
  from the other.
21
26
  """
22
27
 
28
+ di = di.inject.Di()
29
+
30
+ url = configs.String(required=False, default="")
31
+
32
+ authentication = configs.Authentication(default=None)
33
+
34
+ authorization = configs.Authorization(default=None)
35
+
36
+ internal_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
37
+ external_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
38
+ response_headers = configs.StringListOrCallable(default=[])
39
+ authentication = configs.Authentication(default=Public())
40
+ authorization = configs.Authorization(default=Authorization())
41
+ security_headers = configs.SecurityHeaders(default=[])
42
+
43
+ cors_header: SecurityHeader = None # type: ignore
44
+ has_cors: bool = False
45
+
23
46
  def add_url_prefix(self, prefix: str) -> None:
24
47
  self.url = (prefix.rstrip("/") + "/" + self.url.lstrip("/")).lstrip("/")
25
48
 
@@ -41,7 +64,7 @@ class End(ABC):
41
64
  if not self.authorization.gate(input_output.authorization_data, input_output):
42
65
  raise exceptions.Authorization("Not Authorized")
43
66
  except exceptions.ClientError as client_error:
44
- raise exception.Authorization(str(client_error))
67
+ raise exceptions.Authorization(str(client_error))
45
68
 
46
69
  def __call__(self, input_output: InputOutput) -> Any:
47
70
  """
@@ -116,7 +139,7 @@ class End(ABC):
116
139
  for index, response_header in enumerate(response_headers):
117
140
  if not isinstance(response_header, str):
118
141
  raise TypeError(
119
- f"Invalid response header in entry #{index + 1}: the header should be a string, but I was given a type of '{header.__class__.__name__}' instead."
142
+ f"Invalid response header in entry #{index + 1}: the header should be a string, but I was given a type of '{response_header.__class__.__name__}' instead."
120
143
  )
121
144
  parts = response_header.split(":", 1)
122
145
  if len(parts) != 2:
@@ -127,7 +150,7 @@ class End(ABC):
127
150
  for security_header in self.security_headers:
128
151
  security_header.set_headers_for_input_output(input_output)
129
152
 
130
- def respond(self, input_output: InputOutput, response: clearskies.typing.response, status_code: int) -> Any:
153
+ def respond(self, input_output: InputOutput, response: typing.response, status_code: int) -> Any:
131
154
  self.add_response_headers(input_output)
132
155
  return input_output.respond(response, status_code)
133
156
 
@@ -181,3 +204,18 @@ class End(ABC):
181
204
  self.external_casing,
182
205
  self.internal_casing,
183
206
  )
207
+
208
+ def error(self, input_output: InputOutput, message: str, status_code: int) -> Any:
209
+ """Return a client-side error (e.g. 400)."""
210
+ return self.respond_json(input_output, {"status": "client_error", "error": message}, status_code)
211
+
212
+ def input_errors(self, input_output: InputOutput, errors: dict[str, str], status_code: int = 200) -> Any:
213
+ """Return input errors to the client."""
214
+ return self.respond_json(input_output, {"status": "input_errors", "input_errors": errors}, status_code)
215
+
216
+ def redirect(self, input_output: InputOutput, location: str, status_code: int) -> Any:
217
+ """Return a redirect response (e.g. 302)."""
218
+ return self.respond_json(input_output, {"status": "redirect", "location": location}, status_code)
219
+
220
+ def handle(self, input_output: InputOutput) -> Any:
221
+ raise NotImplementedError()
clearskies/endpoint.py CHANGED
@@ -3,16 +3,9 @@ from __future__ import annotations
3
3
  import inspect
4
4
  import urllib.parse
5
5
  from collections import OrderedDict
6
- from typing import TYPE_CHECKING, Any, Callable
7
-
8
- import clearskies.column
9
- import clearskies.configs
10
- import clearskies.configurable
11
- import clearskies.decorators
12
- import clearskies.di
13
- import clearskies.end
14
- import clearskies.typing
15
- from clearskies import autodoc, exceptions
6
+ from typing import TYPE_CHECKING, Any, Callable, Optional
7
+
8
+ from clearskies import autodoc, column, configs, configurable, decorators, di, end, exceptions
16
9
  from clearskies.authentication import Authentication, Authorization, Public
17
10
  from clearskies.autodoc import schema
18
11
  from clearskies.autodoc.request import Parameter, Request
@@ -27,12 +20,12 @@ if TYPE_CHECKING:
27
20
 
28
21
 
29
22
  class Endpoint(
30
- clearskies.end.End, # type: ignore
31
- clearskies.configurable.Configurable,
32
- clearskies.di.InjectableProperties,
23
+ end.End, # type: ignore
24
+ configurable.Configurable,
25
+ di.InjectableProperties,
33
26
  ):
34
27
  """
35
- Automating drudgery!
28
+ Automating drudgery.
36
29
 
37
30
  With clearskies, endpoints exist to offload some drudgery and make your life easier, but they can also
38
31
  get out of your way when you don't need them. Think of them as pre-built endpoints that can execute
@@ -47,7 +40,7 @@ class Endpoint(
47
40
  """
48
41
  The dependency injection container
49
42
  """
50
- di = clearskies.di.inject.Di()
43
+ di = di.inject.Di()
51
44
 
52
45
  """
53
46
  Whether or not this endpoint can handle CORS
@@ -57,7 +50,7 @@ class Endpoint(
57
50
  """
58
51
  The actual CORS header
59
52
  """
60
- cors_header: Cors | None = None
53
+ cors_header: Optional[Cors] = None
61
54
 
62
55
  """
63
56
  Set some response headers that should be returned for this endpoint.
@@ -82,7 +75,7 @@ class Endpoint(
82
75
  wsgi()
83
76
  ```
84
77
  """
85
- response_headers = clearskies.configs.StringListOrCallable(default=[])
78
+ response_headers = configs.StringListOrCallable(default=[])
86
79
 
87
80
  """
88
81
  Set the URL for the endpoint
@@ -161,7 +154,7 @@ class Endpoint(
161
154
  ```
162
155
 
163
156
  """
164
- url = clearskies.configs.Url(default="")
157
+ url = configs.Url(default="")
165
158
 
166
159
  """
167
160
  The allowed request methods for this endpoint.
@@ -204,7 +197,7 @@ class Endpoint(
204
197
  }
205
198
  ```
206
199
  """
207
- request_methods = clearskies.configs.SelectList(
200
+ request_methods = configs.SelectList(
208
201
  allowed_values=["GET", "POST", "PUT", "DELETE", "PATCH", "QUERY"], default=["GET"]
209
202
  )
210
203
 
@@ -214,7 +207,7 @@ class Endpoint(
214
207
  Use this to attach an instance of `clearskies.authentication.Authentication` to an endpoint, which enforces authentication.
215
208
  For more details, see the dedicated documentation section on authentication and authorization. By default, all endpoints are public.
216
209
  """
217
- authentication = clearskies.configs.Authentication(default=Public())
210
+ authentication = configs.Authentication(default=Public())
218
211
 
219
212
  """
220
213
  The authorization rules for this endpoint
@@ -222,7 +215,7 @@ class Endpoint(
222
215
  Use this to attach an instance of `clearskies.authentication.Authorization` to an endpoint, which enforces authorization.
223
216
  For more details, see the dedicated documentation section on authentication and authorization. By default, no authorization is enforced.
224
217
  """
225
- authorization = clearskies.configs.Authorization(default=Authorization())
218
+ authorization = configs.Authorization(default=Authorization())
226
219
 
227
220
  """
228
221
  An override of the default model-to-json mapping for endpoints that auto-convert models to json.
@@ -329,7 +322,7 @@ class Endpoint(
329
322
  ```
330
323
 
331
324
  """
332
- output_map = clearskies.configs.Callable(default=None)
325
+ output_map = configs.Callable(default=None)
333
326
 
334
327
  """
335
328
  A schema that describes the expected output to the client.
@@ -338,14 +331,14 @@ class Endpoint(
338
331
  Note that this is typically not required - when returning models and relying on clearskies to auto-convert to JSON,
339
332
  it will also automatically generate your documentation.
340
333
  """
341
- output_schema = clearskies.configs.Schema(default=None)
334
+ output_schema = configs.Schema(default=None)
342
335
 
343
336
  """
344
337
  The model class used by this endpoint.
345
338
 
346
339
  The endpoint will use this to fetch/save/validate incoming data as needed.
347
340
  """
348
- model_class = clearskies.configs.ModelClass(default=None)
341
+ model_class = configs.ModelClass(default=None)
349
342
 
350
343
  """
351
344
  Columns from the model class that should be returned to the client.
@@ -421,7 +414,7 @@ class Endpoint(
421
414
 
422
415
  ```
423
416
  """
424
- readable_column_names = clearskies.configs.ReadableModelColumns("model_class", default=[])
417
+ readable_column_names = configs.ReadableModelColumns("model_class", default=[])
425
418
 
426
419
  """
427
420
  Specifies which columns from a model class can be set by the client.
@@ -486,14 +479,14 @@ class Endpoint(
486
479
  ```
487
480
 
488
481
  """
489
- writeable_column_names = clearskies.configs.WriteableModelColumns("model_class", default=[])
482
+ writeable_column_names = configs.WriteableModelColumns("model_class", default=[])
490
483
 
491
484
  """
492
485
  Columns from the model class that can be searched by the client.
493
486
 
494
487
  Sets which columns the client is allowed to search (for endpoints that support searching).
495
488
  """
496
- searchable_column_names = clearskies.configs.SearchableModelColumns("model_class", default=[])
489
+ searchable_column_names = configs.SearchableModelColumns("model_class", default=[])
497
490
 
498
491
  """
499
492
  A function to call to add custom input validation logic.
@@ -557,7 +550,7 @@ class Endpoint(
557
550
  ```
558
551
 
559
552
  """
560
- input_validation_callable = clearskies.configs.Callable(default=None)
553
+ input_validation_callable = configs.Callable(default=None)
561
554
 
562
555
  """
563
556
  A dictionary with columns that should override columns in the model.
@@ -579,7 +572,7 @@ class Endpoint(
579
572
  )
580
573
  ```
581
574
  """
582
- column_overrides = clearskies.configs.Columns(default={})
575
+ column_overrides = configs.Columns(default={})
583
576
 
584
577
  """
585
578
  Used in conjunction with external_casing to change the casing of the key names in the outputted JSON of the endpoint.
@@ -638,14 +631,14 @@ class Endpoint(
638
631
  }
639
632
  ```
640
633
  """
641
- internal_casing = clearskies.configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
634
+ internal_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
642
635
 
643
636
  """
644
637
  Used in conjunction with internal_casing to change the casing of the key names in the outputted JSON of the endpoint.
645
638
 
646
639
  See the docs for `internal_casing` for more details and usage examples.
647
640
  """
648
- external_casing = clearskies.configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
641
+ external_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
649
642
 
650
643
  """
651
644
  Configure standard security headers to be sent along in the response from this endpoint.
@@ -689,19 +682,19 @@ class Endpoint(
689
682
  ```
690
683
 
691
684
  """
692
- security_headers = clearskies.configs.SecurityHeaders(default=[])
685
+ security_headers = configs.SecurityHeaders(default=[])
693
686
 
694
687
  """
695
688
  A description for this endpoint. This is added to any auto-documentation
696
689
  """
697
- description = clearskies.configs.String(default="")
690
+ description = configs.String(default="")
698
691
 
699
692
  """
700
693
  Whether or not the routing data should also be persisted to the model. Defaults to False.
701
694
 
702
695
  Note: this is only relevant for handlers that accept request data
703
696
  """
704
- include_routing_data_in_request_data = clearskies.configs.Boolean(default=False)
697
+ include_routing_data_in_request_data = configs.Boolean(default=False)
705
698
 
706
699
  """
707
700
  Additional conditions to always add to the results.
@@ -783,7 +776,7 @@ class Endpoint(
783
776
  and note that neither Greg nor Ann are returned. Ann because she doesn't make the grade criteria, and Greg because
784
777
  he won't graduate.
785
778
  """
786
- where = clearskies.configs.Conditions(default=[])
779
+ where = configs.Conditions(default=[])
787
780
 
788
781
  """
789
782
  Additional joins to always add to the query.
@@ -868,18 +861,18 @@ class Endpoint(
868
861
  e.g., the inner join reomves all the students that don't have an entry in the PastRecord model.
869
862
 
870
863
  """
871
- joins = clearskies.configs.Joins(default=[])
864
+ joins = configs.Joins(default=[])
872
865
 
873
866
  cors_header: Cors = None # type: ignore
874
- _model: clearskies.model.Model = None # type: ignore
875
- _columns: dict[str, clearskies.column.Column] = None # type: ignore
876
- _readable_columns: dict[str, clearskies.column.Column] = None # type: ignore
877
- _writeable_columns: dict[str, clearskies.column.Column] = None # type: ignore
878
- _searchable_columns: dict[str, clearskies.column.Column] = None # type: ignore
879
- _sortable_columns: dict[str, clearskies.column.Column] = None # type: ignore
880
- _as_json_map: dict[str, clearskies.column.Column] = None # type: ignore
881
-
882
- @clearskies.decorators.parameters_to_properties
867
+ _model: Model = None # type: ignore
868
+ _columns: dict[str, column.Column] = None # type: ignore
869
+ _readable_columns: dict[str, column.Column] = None # type: ignore
870
+ _writeable_columns: dict[str, column.Column] = None # type: ignore
871
+ _searchable_columns: dict[str, column.Column] = None # type: ignore
872
+ _sortable_columns: dict[str, column.Column] = None # type: ignore
873
+ _as_json_map: dict[str, column.Column] = None # type: ignore
874
+
875
+ @decorators.parameters_to_properties
883
876
  def __init__(
884
877
  self,
885
878
  url: str = "",
@@ -972,9 +965,6 @@ class Endpoint(
972
965
  )
973
966
  return self.authorization.filter_model(model, input_output.authorization_data, input_output)
974
967
 
975
- def handle(self, input_output: InputOutput) -> Any:
976
- raise NotImplementedError()
977
-
978
968
  def matches_request(self, input_output: InputOutput, allow_partial=False) -> bool:
979
969
  """Whether or not we can handle an incoming request based on URL and request method."""
980
970
  # soo..... this excessively duplicates the logic in __call__, but I'm being lazy right now
@@ -1012,20 +1002,14 @@ class Endpoint(
1012
1002
  def failure(self, input_output: InputOutput) -> Any:
1013
1003
  return self.respond_json(input_output, {"status": "failure"}, 500)
1014
1004
 
1015
- def input_errors(self, input_output: InputOutput, errors: dict[str, str], status_code: int = 200) -> Any:
1016
- """Return input errors to the client."""
1017
- return self.respond_json(input_output, {"status": "input_errors", "input_errors": errors}, status_code)
1018
-
1019
- def error(self, input_output: InputOutput, message: str, status_code: int) -> Any:
1020
- """Return a client-side error (e.g. 400)."""
1021
- return self.respond_json(input_output, {"status": "client_error", "error": message}, status_code)
1022
-
1023
1005
  def redirect(self, input_output: InputOutput, location: str, status_code: int) -> Any:
1024
1006
  """Return a redirect."""
1025
1007
  input_output.response_headers.add("content-type", "text/html")
1026
1008
  input_output.response_headers.add("location", location)
1027
1009
  return self.respond(
1028
- '<meta http-equiv="refresh" content="0; url=' + urllib.parse.quote(location) + '">Redirecting', status_code
1010
+ input_output,
1011
+ '<meta http-equiv="refresh" content="0; url=' + urllib.parse.quote(location) + '">Redirecting',
1012
+ status_code,
1029
1013
  )
1030
1014
 
1031
1015
  def success(
@@ -1053,7 +1037,7 @@ class Endpoint(
1053
1037
 
1054
1038
  return self.respond_json(input_output, response_data, 200)
1055
1039
 
1056
- def model_as_json(self, model: clearskies.model.Model, input_output: InputOutput) -> dict[str, Any]:
1040
+ def model_as_json(self, model: Model, input_output: InputOutput) -> dict[str, Any]:
1057
1041
  if self.output_map:
1058
1042
  return self.di.call_function(self.output_map, model=model, **input_output.get_context_for_callables())
1059
1043
 
@@ -1070,7 +1054,7 @@ class Endpoint(
1070
1054
  json[self.auto_case_column_name(key, True)] = value
1071
1055
  return json
1072
1056
 
1073
- def _build_as_json_map(self, model: clearskies.model.Model) -> dict[str, clearskies.column.Column]:
1057
+ def _build_as_json_map(self, model: Model) -> dict[str, column.Column]:
1074
1058
  conversion_map = {}
1075
1059
  if not self.readable_column_names:
1076
1060
  raise ValueError(
@@ -2,10 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any, Callable, Self
4
4
 
5
- import clearskies.configurable
6
- import clearskies.di
7
- import clearskies.end
8
- from clearskies import exceptions
5
+ from clearskies import configs, configurable, decorators, di, end
9
6
  from clearskies.authentication import Authentication, Authorization, Public
10
7
  from clearskies.endpoint import Endpoint
11
8
  from clearskies.functional import routing
@@ -16,9 +13,9 @@ if TYPE_CHECKING:
16
13
 
17
14
 
18
15
  class EndpointGroup(
19
- clearskies.end.End, # type: ignore
20
- clearskies.configurable.Configurable,
21
- clearskies.di.InjectableProperties,
16
+ end.End, # type: ignore
17
+ configurable.Configurable,
18
+ di.InjectableProperties,
22
19
  ):
23
20
  """
24
21
  An endpoint group brings endpoints together: it basically handles routing.
@@ -216,32 +213,32 @@ class EndpointGroup(
216
213
  """
217
214
  The dependency injection container
218
215
  """
219
- di = clearskies.di.inject.Di()
216
+ di = di.inject.Di()
220
217
 
221
218
  """
222
219
  The base URL for the endpoint group.
223
220
 
224
221
  This URL is added as a prefix to all endpoints attached to the group. This includes any named URL parameters:
225
222
  """
226
- url = clearskies.configs.String(default="")
223
+ url = configs.String(default="")
227
224
 
228
225
  """
229
226
  The list of endpoints connected to this endpoint group
230
227
  """
231
- endpoints = clearskies.configs.EndpointList()
228
+ endpoints = configs.EndpointList()
232
229
 
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")
235
- response_headers = clearskies.configs.StringListOrCallable(default=[])
236
- authentication = clearskies.configs.Authentication(default=Public())
237
- authorization = clearskies.configs.Authorization(default=Authorization())
238
- security_headers = clearskies.configs.SecurityHeaders(default=[])
230
+ internal_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
231
+ external_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="snake_case")
232
+ response_headers = configs.StringListOrCallable(default=[])
233
+ authentication = configs.Authentication(default=Public())
234
+ authorization = configs.Authorization(default=Authorization())
235
+ security_headers = configs.SecurityHeaders(default=[])
239
236
 
240
237
  cors_header: SecurityHeader = None # type: ignore
241
238
  has_cors: bool = False
242
239
  endpoints_initialized = False
243
240
 
244
- @clearskies.decorators.parameters_to_properties
241
+ @decorators.parameters_to_properties
245
242
  def __init__(
246
243
  self,
247
244
  endpoints: list[Endpoint | Self],
@@ -325,7 +322,7 @@ class EndpointGroup(
325
322
  return self.respond_json(input_output, {"status": "client_error", "error": message}, status_code)
326
323
 
327
324
  def all_endpoints(self) -> list[Endpoint]:
328
- """Returns the full (recursive) list of all endpoints associated with this endpoint group"""
325
+ """Return the full (recursive) list of all endpoints associated with this endpoint group."""
329
326
  all_endpoints: list[Endpoint] = []
330
327
  for endpoint in self.endpoints:
331
328
  if hasattr(endpoint, "all_endpoints"):