prefect-client 2.19.4__py3-none-any.whl → 3.0.0rc2__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.
Files changed (242) hide show
  1. prefect/__init__.py +8 -56
  2. prefect/_internal/compatibility/deprecated.py +6 -115
  3. prefect/_internal/compatibility/experimental.py +4 -79
  4. prefect/_internal/concurrency/api.py +0 -34
  5. prefect/_internal/concurrency/calls.py +0 -6
  6. prefect/_internal/concurrency/cancellation.py +0 -3
  7. prefect/_internal/concurrency/event_loop.py +0 -20
  8. prefect/_internal/concurrency/inspection.py +3 -3
  9. prefect/_internal/concurrency/threads.py +35 -0
  10. prefect/_internal/concurrency/waiters.py +0 -28
  11. prefect/_internal/pydantic/__init__.py +0 -45
  12. prefect/_internal/pydantic/v1_schema.py +21 -22
  13. prefect/_internal/pydantic/v2_schema.py +0 -2
  14. prefect/_internal/pydantic/v2_validated_func.py +18 -23
  15. prefect/_internal/schemas/bases.py +44 -177
  16. prefect/_internal/schemas/fields.py +1 -43
  17. prefect/_internal/schemas/validators.py +60 -158
  18. prefect/artifacts.py +161 -14
  19. prefect/automations.py +39 -4
  20. prefect/blocks/abstract.py +1 -1
  21. prefect/blocks/core.py +268 -148
  22. prefect/blocks/fields.py +2 -57
  23. prefect/blocks/kubernetes.py +8 -12
  24. prefect/blocks/notifications.py +40 -20
  25. prefect/blocks/redis.py +168 -0
  26. prefect/blocks/system.py +22 -11
  27. prefect/blocks/webhook.py +2 -9
  28. prefect/client/base.py +4 -4
  29. prefect/client/cloud.py +8 -13
  30. prefect/client/orchestration.py +362 -340
  31. prefect/client/schemas/actions.py +92 -86
  32. prefect/client/schemas/filters.py +20 -40
  33. prefect/client/schemas/objects.py +158 -152
  34. prefect/client/schemas/responses.py +16 -24
  35. prefect/client/schemas/schedules.py +47 -35
  36. prefect/client/subscriptions.py +2 -2
  37. prefect/client/utilities.py +5 -2
  38. prefect/concurrency/asyncio.py +4 -2
  39. prefect/concurrency/events.py +1 -1
  40. prefect/concurrency/services.py +7 -4
  41. prefect/context.py +195 -27
  42. prefect/deployments/__init__.py +5 -6
  43. prefect/deployments/base.py +7 -5
  44. prefect/deployments/flow_runs.py +185 -0
  45. prefect/deployments/runner.py +50 -45
  46. prefect/deployments/schedules.py +28 -23
  47. prefect/deployments/steps/__init__.py +0 -1
  48. prefect/deployments/steps/core.py +1 -0
  49. prefect/deployments/steps/pull.py +7 -21
  50. prefect/engine.py +12 -2422
  51. prefect/events/actions.py +17 -23
  52. prefect/events/cli/automations.py +19 -6
  53. prefect/events/clients.py +14 -37
  54. prefect/events/filters.py +14 -18
  55. prefect/events/related.py +2 -2
  56. prefect/events/schemas/__init__.py +0 -5
  57. prefect/events/schemas/automations.py +55 -46
  58. prefect/events/schemas/deployment_triggers.py +7 -197
  59. prefect/events/schemas/events.py +36 -65
  60. prefect/events/schemas/labelling.py +10 -14
  61. prefect/events/utilities.py +2 -3
  62. prefect/events/worker.py +2 -3
  63. prefect/filesystems.py +6 -517
  64. prefect/{new_flow_engine.py → flow_engine.py} +315 -74
  65. prefect/flow_runs.py +379 -7
  66. prefect/flows.py +248 -165
  67. prefect/futures.py +187 -345
  68. prefect/infrastructure/__init__.py +0 -27
  69. prefect/infrastructure/provisioners/__init__.py +5 -3
  70. prefect/infrastructure/provisioners/cloud_run.py +11 -6
  71. prefect/infrastructure/provisioners/container_instance.py +11 -7
  72. prefect/infrastructure/provisioners/ecs.py +6 -4
  73. prefect/infrastructure/provisioners/modal.py +8 -5
  74. prefect/input/actions.py +2 -4
  75. prefect/input/run_input.py +9 -9
  76. prefect/logging/formatters.py +0 -2
  77. prefect/logging/handlers.py +3 -11
  78. prefect/logging/loggers.py +2 -2
  79. prefect/manifests.py +2 -1
  80. prefect/records/__init__.py +1 -0
  81. prefect/records/cache_policies.py +179 -0
  82. prefect/records/result_store.py +42 -0
  83. prefect/records/store.py +9 -0
  84. prefect/results.py +43 -39
  85. prefect/runner/runner.py +9 -9
  86. prefect/runner/server.py +6 -10
  87. prefect/runner/storage.py +3 -8
  88. prefect/runner/submit.py +2 -2
  89. prefect/runner/utils.py +2 -2
  90. prefect/serializers.py +24 -35
  91. prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
  92. prefect/settings.py +76 -136
  93. prefect/states.py +22 -50
  94. prefect/task_engine.py +666 -56
  95. prefect/task_runners.py +272 -300
  96. prefect/task_runs.py +203 -0
  97. prefect/{task_server.py → task_worker.py} +89 -60
  98. prefect/tasks.py +358 -341
  99. prefect/transactions.py +224 -0
  100. prefect/types/__init__.py +61 -82
  101. prefect/utilities/asyncutils.py +195 -136
  102. prefect/utilities/callables.py +121 -41
  103. prefect/utilities/collections.py +23 -38
  104. prefect/utilities/dispatch.py +11 -3
  105. prefect/utilities/dockerutils.py +4 -0
  106. prefect/utilities/engine.py +140 -20
  107. prefect/utilities/importtools.py +26 -27
  108. prefect/utilities/pydantic.py +128 -38
  109. prefect/utilities/schema_tools/hydration.py +5 -1
  110. prefect/utilities/templating.py +12 -2
  111. prefect/variables.py +84 -62
  112. prefect/workers/__init__.py +0 -1
  113. prefect/workers/base.py +26 -18
  114. prefect/workers/process.py +3 -8
  115. prefect/workers/server.py +2 -2
  116. {prefect_client-2.19.4.dist-info → prefect_client-3.0.0rc2.dist-info}/METADATA +23 -21
  117. prefect_client-3.0.0rc2.dist-info/RECORD +179 -0
  118. prefect/_internal/pydantic/_base_model.py +0 -51
  119. prefect/_internal/pydantic/_compat.py +0 -82
  120. prefect/_internal/pydantic/_flags.py +0 -20
  121. prefect/_internal/pydantic/_types.py +0 -8
  122. prefect/_internal/pydantic/utilities/__init__.py +0 -0
  123. prefect/_internal/pydantic/utilities/config_dict.py +0 -72
  124. prefect/_internal/pydantic/utilities/field_validator.py +0 -150
  125. prefect/_internal/pydantic/utilities/model_construct.py +0 -56
  126. prefect/_internal/pydantic/utilities/model_copy.py +0 -55
  127. prefect/_internal/pydantic/utilities/model_dump.py +0 -136
  128. prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
  129. prefect/_internal/pydantic/utilities/model_fields.py +0 -50
  130. prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
  131. prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
  132. prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
  133. prefect/_internal/pydantic/utilities/model_validate.py +0 -75
  134. prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
  135. prefect/_internal/pydantic/utilities/model_validator.py +0 -87
  136. prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
  137. prefect/_vendor/__init__.py +0 -0
  138. prefect/_vendor/fastapi/__init__.py +0 -25
  139. prefect/_vendor/fastapi/applications.py +0 -946
  140. prefect/_vendor/fastapi/background.py +0 -3
  141. prefect/_vendor/fastapi/concurrency.py +0 -44
  142. prefect/_vendor/fastapi/datastructures.py +0 -58
  143. prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
  144. prefect/_vendor/fastapi/dependencies/models.py +0 -64
  145. prefect/_vendor/fastapi/dependencies/utils.py +0 -877
  146. prefect/_vendor/fastapi/encoders.py +0 -177
  147. prefect/_vendor/fastapi/exception_handlers.py +0 -40
  148. prefect/_vendor/fastapi/exceptions.py +0 -46
  149. prefect/_vendor/fastapi/logger.py +0 -3
  150. prefect/_vendor/fastapi/middleware/__init__.py +0 -1
  151. prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
  152. prefect/_vendor/fastapi/middleware/cors.py +0 -3
  153. prefect/_vendor/fastapi/middleware/gzip.py +0 -3
  154. prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
  155. prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
  156. prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
  157. prefect/_vendor/fastapi/openapi/__init__.py +0 -0
  158. prefect/_vendor/fastapi/openapi/constants.py +0 -2
  159. prefect/_vendor/fastapi/openapi/docs.py +0 -203
  160. prefect/_vendor/fastapi/openapi/models.py +0 -480
  161. prefect/_vendor/fastapi/openapi/utils.py +0 -485
  162. prefect/_vendor/fastapi/param_functions.py +0 -340
  163. prefect/_vendor/fastapi/params.py +0 -453
  164. prefect/_vendor/fastapi/requests.py +0 -4
  165. prefect/_vendor/fastapi/responses.py +0 -40
  166. prefect/_vendor/fastapi/routing.py +0 -1331
  167. prefect/_vendor/fastapi/security/__init__.py +0 -15
  168. prefect/_vendor/fastapi/security/api_key.py +0 -98
  169. prefect/_vendor/fastapi/security/base.py +0 -6
  170. prefect/_vendor/fastapi/security/http.py +0 -172
  171. prefect/_vendor/fastapi/security/oauth2.py +0 -227
  172. prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
  173. prefect/_vendor/fastapi/security/utils.py +0 -10
  174. prefect/_vendor/fastapi/staticfiles.py +0 -1
  175. prefect/_vendor/fastapi/templating.py +0 -3
  176. prefect/_vendor/fastapi/testclient.py +0 -1
  177. prefect/_vendor/fastapi/types.py +0 -3
  178. prefect/_vendor/fastapi/utils.py +0 -235
  179. prefect/_vendor/fastapi/websockets.py +0 -7
  180. prefect/_vendor/starlette/__init__.py +0 -1
  181. prefect/_vendor/starlette/_compat.py +0 -28
  182. prefect/_vendor/starlette/_exception_handler.py +0 -80
  183. prefect/_vendor/starlette/_utils.py +0 -88
  184. prefect/_vendor/starlette/applications.py +0 -261
  185. prefect/_vendor/starlette/authentication.py +0 -159
  186. prefect/_vendor/starlette/background.py +0 -43
  187. prefect/_vendor/starlette/concurrency.py +0 -59
  188. prefect/_vendor/starlette/config.py +0 -151
  189. prefect/_vendor/starlette/convertors.py +0 -87
  190. prefect/_vendor/starlette/datastructures.py +0 -707
  191. prefect/_vendor/starlette/endpoints.py +0 -130
  192. prefect/_vendor/starlette/exceptions.py +0 -60
  193. prefect/_vendor/starlette/formparsers.py +0 -276
  194. prefect/_vendor/starlette/middleware/__init__.py +0 -17
  195. prefect/_vendor/starlette/middleware/authentication.py +0 -52
  196. prefect/_vendor/starlette/middleware/base.py +0 -220
  197. prefect/_vendor/starlette/middleware/cors.py +0 -176
  198. prefect/_vendor/starlette/middleware/errors.py +0 -265
  199. prefect/_vendor/starlette/middleware/exceptions.py +0 -74
  200. prefect/_vendor/starlette/middleware/gzip.py +0 -113
  201. prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
  202. prefect/_vendor/starlette/middleware/sessions.py +0 -82
  203. prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
  204. prefect/_vendor/starlette/middleware/wsgi.py +0 -147
  205. prefect/_vendor/starlette/requests.py +0 -328
  206. prefect/_vendor/starlette/responses.py +0 -347
  207. prefect/_vendor/starlette/routing.py +0 -933
  208. prefect/_vendor/starlette/schemas.py +0 -154
  209. prefect/_vendor/starlette/staticfiles.py +0 -248
  210. prefect/_vendor/starlette/status.py +0 -199
  211. prefect/_vendor/starlette/templating.py +0 -231
  212. prefect/_vendor/starlette/testclient.py +0 -804
  213. prefect/_vendor/starlette/types.py +0 -30
  214. prefect/_vendor/starlette/websockets.py +0 -193
  215. prefect/agent.py +0 -698
  216. prefect/deployments/deployments.py +0 -1042
  217. prefect/deprecated/__init__.py +0 -0
  218. prefect/deprecated/data_documents.py +0 -350
  219. prefect/deprecated/packaging/__init__.py +0 -12
  220. prefect/deprecated/packaging/base.py +0 -96
  221. prefect/deprecated/packaging/docker.py +0 -146
  222. prefect/deprecated/packaging/file.py +0 -92
  223. prefect/deprecated/packaging/orion.py +0 -80
  224. prefect/deprecated/packaging/serializers.py +0 -171
  225. prefect/events/instrument.py +0 -135
  226. prefect/infrastructure/base.py +0 -323
  227. prefect/infrastructure/container.py +0 -818
  228. prefect/infrastructure/kubernetes.py +0 -920
  229. prefect/infrastructure/process.py +0 -289
  230. prefect/new_task_engine.py +0 -423
  231. prefect/pydantic/__init__.py +0 -76
  232. prefect/pydantic/main.py +0 -39
  233. prefect/software/__init__.py +0 -2
  234. prefect/software/base.py +0 -50
  235. prefect/software/conda.py +0 -199
  236. prefect/software/pip.py +0 -122
  237. prefect/software/python.py +0 -52
  238. prefect/workers/block.py +0 -218
  239. prefect_client-2.19.4.dist-info/RECORD +0 -292
  240. {prefect_client-2.19.4.dist-info → prefect_client-3.0.0rc2.dist-info}/LICENSE +0 -0
  241. {prefect_client-2.19.4.dist-info → prefect_client-3.0.0rc2.dist-info}/WHEEL +0 -0
  242. {prefect_client-2.19.4.dist-info → prefect_client-3.0.0rc2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,224 @@
1
+ from contextlib import contextmanager
2
+ from contextvars import ContextVar, Token
3
+ from typing import (
4
+ Any,
5
+ Callable,
6
+ Generator,
7
+ List,
8
+ Optional,
9
+ Type,
10
+ TypeVar,
11
+ )
12
+
13
+ from pydantic import Field
14
+
15
+ from prefect.context import ContextModel
16
+ from prefect.records import RecordStore
17
+ from prefect.utilities.collections import AutoEnum
18
+
19
+ T = TypeVar("T")
20
+
21
+
22
+ class IsolationLevel(AutoEnum):
23
+ READ_COMMITTED = AutoEnum.auto()
24
+ SERIALIZABLE = AutoEnum.auto()
25
+
26
+
27
+ class CommitMode(AutoEnum):
28
+ EAGER = AutoEnum.auto()
29
+ LAZY = AutoEnum.auto()
30
+ OFF = AutoEnum.auto()
31
+
32
+
33
+ class TransactionState(AutoEnum):
34
+ PENDING = AutoEnum.auto()
35
+ ACTIVE = AutoEnum.auto()
36
+ STAGED = AutoEnum.auto()
37
+ COMMITTED = AutoEnum.auto()
38
+ ROLLED_BACK = AutoEnum.auto()
39
+
40
+
41
+ class Transaction(ContextModel):
42
+ """
43
+ A base model for transaction state.
44
+ """
45
+
46
+ store: Optional[RecordStore] = None
47
+ key: Optional[str] = None
48
+ children: List["Transaction"] = Field(default_factory=list)
49
+ commit_mode: Optional[CommitMode] = None
50
+ state: TransactionState = TransactionState.PENDING
51
+ on_commit_hooks: List[Callable[["Transaction"], None]] = Field(default_factory=list)
52
+ on_rollback_hooks: List[Callable[["Transaction"], None]] = Field(
53
+ default_factory=list
54
+ )
55
+ overwrite: bool = False
56
+ _staged_value: Any = None
57
+ __var__ = ContextVar("transaction")
58
+
59
+ def is_committed(self) -> bool:
60
+ return self.state == TransactionState.COMMITTED
61
+
62
+ def is_rolled_back(self) -> bool:
63
+ return self.state == TransactionState.ROLLED_BACK
64
+
65
+ def is_staged(self) -> bool:
66
+ return self.state == TransactionState.STAGED
67
+
68
+ def is_pending(self) -> bool:
69
+ return self.state == TransactionState.PENDING
70
+
71
+ def is_active(self) -> bool:
72
+ return self.state == TransactionState.ACTIVE
73
+
74
+ def __enter__(self):
75
+ if self._token is not None:
76
+ raise RuntimeError(
77
+ "Context already entered. Context enter calls cannot be nested."
78
+ )
79
+ # set default commit behavior
80
+ if self.commit_mode is None:
81
+ parent = get_transaction()
82
+
83
+ # either inherit from parent or set a default of eager
84
+ if parent:
85
+ self.commit_mode = parent.commit_mode
86
+ else:
87
+ self.commit_mode = CommitMode.EAGER
88
+
89
+ # this needs to go before begin, which could set the state to committed
90
+ self.state = TransactionState.ACTIVE
91
+ self.begin()
92
+ self._token = self.__var__.set(self)
93
+ return self
94
+
95
+ def __exit__(self, exc_type, exc_val, exc_tb):
96
+ if not self._token:
97
+ raise RuntimeError(
98
+ "Asymmetric use of context. Context exit called without an enter."
99
+ )
100
+ if exc_type:
101
+ self.rollback()
102
+ self.reset()
103
+ raise exc_val
104
+
105
+ if self.commit_mode == CommitMode.EAGER:
106
+ self.commit()
107
+
108
+ # if parent, let them take responsibility
109
+ if self.get_parent():
110
+ self.reset()
111
+ return
112
+
113
+ if self.commit_mode == CommitMode.OFF:
114
+ # if no one took responsibility to commit, rolling back
115
+ # note that rollback returns if already committed
116
+ self.rollback()
117
+ elif self.commit_mode == CommitMode.LAZY:
118
+ # no one left to take responsibility for committing
119
+ self.commit()
120
+
121
+ self.reset()
122
+
123
+ def begin(self):
124
+ # currently we only support READ_COMMITTED isolation
125
+ # i.e., no locking behavior
126
+ if not self.overwrite and self.store and self.store.exists(key=self.key):
127
+ self.state = TransactionState.COMMITTED
128
+
129
+ def read(self) -> dict:
130
+ return self.store.read(key=self.key)
131
+
132
+ def reset(self) -> None:
133
+ parent = self.get_parent()
134
+
135
+ if parent:
136
+ # parent takes responsibility
137
+ parent.add_child(self)
138
+
139
+ self.__var__.reset(self._token)
140
+ self._token = None
141
+
142
+ # do this below reset so that get_transaction() returns the relevant txn
143
+ if parent and self.state == TransactionState.ROLLED_BACK:
144
+ parent.rollback()
145
+
146
+ def add_child(self, transaction: "Transaction") -> None:
147
+ self.children.append(transaction)
148
+
149
+ def get_parent(self) -> Optional["Transaction"]:
150
+ prev_var = getattr(self._token, "old_value")
151
+ if prev_var != Token.MISSING:
152
+ parent = prev_var
153
+ else:
154
+ parent = None
155
+ return parent
156
+
157
+ def commit(self) -> bool:
158
+ if self.state in [TransactionState.ROLLED_BACK, TransactionState.COMMITTED]:
159
+ return False
160
+
161
+ try:
162
+ for child in self.children:
163
+ child.commit()
164
+
165
+ for hook in self.on_commit_hooks:
166
+ hook(self)
167
+
168
+ if self.store:
169
+ self.store.write(key=self.key, value=self._staged_value)
170
+ self.state = TransactionState.COMMITTED
171
+ return True
172
+ except Exception:
173
+ self.rollback()
174
+ return False
175
+
176
+ def stage(
177
+ self, value: dict, on_rollback_hooks: list, on_commit_hooks: list
178
+ ) -> None:
179
+ """
180
+ Stage a value to be committed later.
181
+ """
182
+ if self.state != TransactionState.COMMITTED:
183
+ self._staged_value = value
184
+ self.on_rollback_hooks += on_rollback_hooks
185
+ self.on_commit_hooks += on_commit_hooks
186
+ self.state = TransactionState.STAGED
187
+
188
+ def rollback(self) -> bool:
189
+ if self.state in [TransactionState.ROLLED_BACK, TransactionState.COMMITTED]:
190
+ return False
191
+
192
+ try:
193
+ for hook in reversed(self.on_rollback_hooks):
194
+ hook(self)
195
+
196
+ self.state = TransactionState.ROLLED_BACK
197
+
198
+ for child in reversed(self.children):
199
+ child.rollback()
200
+
201
+ return True
202
+ except Exception:
203
+ return False
204
+
205
+ @classmethod
206
+ def get_active(cls: Type[T]) -> Optional[T]:
207
+ return cls.__var__.get(None)
208
+
209
+
210
+ def get_transaction() -> Transaction:
211
+ return Transaction.get_active()
212
+
213
+
214
+ @contextmanager
215
+ def transaction(
216
+ key: Optional[str] = None,
217
+ store: Optional[RecordStore] = None,
218
+ commit_mode: CommitMode = CommitMode.LAZY,
219
+ overwrite: bool = False,
220
+ ) -> Generator[Transaction, None, None]:
221
+ with Transaction(
222
+ key=key, store=store, commit_mode=commit_mode, overwrite=overwrite
223
+ ) as txn:
224
+ yield txn
prefect/types/__init__.py CHANGED
@@ -1,112 +1,91 @@
1
- from typing import Any, Callable, ClassVar, Generator
1
+ from typing import Annotated, Any, Dict, List, Union
2
+ import orjson
3
+ import pydantic
2
4
 
3
- from pydantic_core import core_schema, CoreSchema, SchemaValidator
4
- from typing_extensions import Self
5
- from datetime import timedelta
5
+ from pydantic import (
6
+ BeforeValidator,
7
+ Field,
8
+ StrictBool,
9
+ StrictFloat,
10
+ StrictInt,
11
+ StrictStr,
12
+ )
13
+ from zoneinfo import available_timezones
6
14
 
15
+ MAX_VARIABLE_NAME_LENGTH = 255
16
+ MAX_VARIABLE_VALUE_LENGTH = 5000
7
17
 
8
- class NonNegativeInteger(int):
9
- """An integer that must be greater than or equal to 0."""
18
+ timezone_set = available_timezones()
10
19
 
11
- schema: ClassVar[CoreSchema] = core_schema.int_schema(ge=0)
20
+ NonNegativeInteger = Annotated[int, Field(ge=0)]
21
+ PositiveInteger = Annotated[int, Field(gt=0)]
22
+ NonNegativeFloat = Annotated[float, Field(ge=0.0)]
23
+ TimeZone = Annotated[str, Field(default="UTC", pattern="|".join(timezone_set))]
12
24
 
13
- @classmethod
14
- def __get_validators__(cls) -> Generator[Callable[..., Any], None, None]:
15
- yield cls.validate
16
25
 
17
- @classmethod
18
- def __get_pydantic_core_schema__(
19
- cls, source_type: Any, handler: Callable[..., Any]
20
- ) -> CoreSchema:
21
- return cls.schema
26
+ BANNED_CHARACTERS = ["/", "%", "&", ">", "<"]
22
27
 
23
- @classmethod
24
- def validate(cls, v: Any) -> Self:
25
- return SchemaValidator(schema=cls.schema).validate_python(v)
28
+ WITHOUT_BANNED_CHARACTERS = r"^[^" + "".join(BANNED_CHARACTERS) + "]+$"
29
+ Name = Annotated[str, Field(pattern=WITHOUT_BANNED_CHARACTERS)]
26
30
 
31
+ WITHOUT_BANNED_CHARACTERS_EMPTY_OK = r"^[^" + "".join(BANNED_CHARACTERS) + "]*$"
32
+ NameOrEmpty = Annotated[str, Field(pattern=WITHOUT_BANNED_CHARACTERS_EMPTY_OK)]
27
33
 
28
- class PositiveInteger(int):
29
- """An integer that must be greater than 0."""
30
34
 
31
- schema: ClassVar[CoreSchema] = core_schema.int_schema(gt=0)
35
+ def non_emptyish(value: str) -> str:
36
+ if not value.strip("' \""):
37
+ raise ValueError("name cannot be an empty string")
32
38
 
33
- @classmethod
34
- def __get_validators__(cls) -> Generator[Callable[..., Any], None, None]:
35
- yield cls.validate
39
+ return value
36
40
 
37
- @classmethod
38
- def __get_pydantic_core_schema__(
39
- cls, source_type: Any, handler: Callable[..., Any]
40
- ) -> CoreSchema:
41
- return cls.schema
42
41
 
43
- @classmethod
44
- def validate(cls, v: Any) -> Self:
45
- return SchemaValidator(schema=cls.schema).validate_python(v)
46
-
47
-
48
- class NonNegativeFloat(float):
49
- schema: ClassVar[CoreSchema] = core_schema.float_schema(ge=0)
50
-
51
- @classmethod
52
- def __get_validators__(cls) -> Generator[Callable[..., Any], None, None]:
53
- yield cls.validate
54
-
55
- @classmethod
56
- def __get_pydantic_core_schema__(
57
- cls, source_type: Any, handler: Callable[..., Any]
58
- ) -> CoreSchema:
59
- return cls.schema
60
-
61
- @classmethod
62
- def validate(cls, v: Any) -> Self:
63
- return SchemaValidator(schema=cls.schema).validate_python(v)
64
-
65
-
66
- class NonNegativeDuration(timedelta):
67
- """A timedelta that must be greater than or equal to 0."""
42
+ NonEmptyishName = Annotated[
43
+ str,
44
+ Field(pattern=WITHOUT_BANNED_CHARACTERS),
45
+ BeforeValidator(non_emptyish),
46
+ ]
68
47
 
69
- schema: ClassVar = core_schema.timedelta_schema(ge=timedelta(seconds=0))
70
48
 
71
- @classmethod
72
- def __get_validators__(cls) -> Generator[Callable[..., Any], None, None]:
73
- yield cls.validate
49
+ VariableValue = Union[
50
+ StrictStr,
51
+ StrictInt,
52
+ StrictBool,
53
+ StrictFloat,
54
+ None,
55
+ Dict[str, Any],
56
+ List[Any],
57
+ ]
74
58
 
75
- @classmethod
76
- def __get_pydantic_core_schema__(
77
- cls, source_type: Any, handler: Callable[..., Any]
78
- ) -> CoreSchema:
79
- return cls.schema
80
59
 
81
- @classmethod
82
- def validate(cls, v: Any) -> Self:
83
- return SchemaValidator(schema=cls.schema).validate_python(v)
60
+ def check_variable_value(value: object) -> object:
61
+ try:
62
+ json_string = orjson.dumps(value)
63
+ except orjson.JSONEncodeError:
64
+ raise ValueError("Variable value must be serializable to JSON")
84
65
 
66
+ if value is not None and len(json_string) > MAX_VARIABLE_VALUE_LENGTH:
67
+ raise ValueError(
68
+ f"Variable value must be less than {MAX_VARIABLE_VALUE_LENGTH} characters"
69
+ )
70
+ return value
85
71
 
86
- class PositiveDuration(timedelta):
87
- """A timedelta that must be greater than 0."""
88
72
 
89
- schema: ClassVar = core_schema.timedelta_schema(gt=timedelta(seconds=0))
73
+ StrictVariableValue = Annotated[VariableValue, BeforeValidator(check_variable_value)]
90
74
 
91
- @classmethod
92
- def __get_validators__(cls) -> Generator[Callable[..., Any], None, None]:
93
- yield cls.validate
75
+ LaxUrl = Annotated[str, BeforeValidator(lambda x: str(x).strip())]
94
76
 
95
- @classmethod
96
- def __get_pydantic_core_schema__(
97
- cls, source_type: Any, handler: Callable[..., Any]
98
- ) -> CoreSchema:
99
- return cls.schema
100
77
 
101
- @classmethod
102
- def validate(cls, v: Any) -> Self:
103
- return SchemaValidator(schema=cls.schema).validate_python(v)
78
+ class SecretDict(pydantic.Secret[Dict[str, Any]]):
79
+ pass
104
80
 
105
81
 
106
82
  __all__ = [
107
83
  "NonNegativeInteger",
108
84
  "PositiveInteger",
109
85
  "NonNegativeFloat",
110
- "NonNegativeDuration",
111
- "PositiveDuration",
86
+ "Name",
87
+ "NameOrEmpty",
88
+ "NonEmptyishName",
89
+ "SecretDict",
90
+ "StrictVariableValue",
112
91
  ]