prefect-client 2.17.1__py3-none-any.whl → 2.18.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. prefect/_internal/compatibility/deprecated.py +2 -0
  2. prefect/_internal/pydantic/_compat.py +1 -0
  3. prefect/_internal/pydantic/utilities/field_validator.py +25 -10
  4. prefect/_internal/pydantic/utilities/model_dump.py +1 -1
  5. prefect/_internal/pydantic/utilities/model_validate.py +1 -1
  6. prefect/_internal/pydantic/utilities/model_validator.py +11 -3
  7. prefect/_internal/schemas/fields.py +31 -12
  8. prefect/_internal/schemas/validators.py +0 -6
  9. prefect/_version.py +97 -38
  10. prefect/blocks/abstract.py +34 -1
  11. prefect/blocks/core.py +1 -1
  12. prefect/blocks/notifications.py +16 -7
  13. prefect/blocks/system.py +2 -3
  14. prefect/client/base.py +10 -5
  15. prefect/client/orchestration.py +405 -85
  16. prefect/client/schemas/actions.py +4 -3
  17. prefect/client/schemas/objects.py +6 -5
  18. prefect/client/schemas/schedules.py +2 -6
  19. prefect/client/schemas/sorting.py +9 -0
  20. prefect/client/utilities.py +25 -3
  21. prefect/concurrency/asyncio.py +11 -5
  22. prefect/concurrency/events.py +3 -3
  23. prefect/concurrency/services.py +1 -1
  24. prefect/concurrency/sync.py +9 -5
  25. prefect/deployments/__init__.py +0 -2
  26. prefect/deployments/base.py +2 -144
  27. prefect/deployments/deployments.py +29 -20
  28. prefect/deployments/runner.py +36 -28
  29. prefect/deployments/steps/core.py +3 -3
  30. prefect/deprecated/packaging/serializers.py +5 -4
  31. prefect/engine.py +3 -1
  32. prefect/events/__init__.py +45 -0
  33. prefect/events/actions.py +250 -18
  34. prefect/events/cli/automations.py +201 -0
  35. prefect/events/clients.py +179 -21
  36. prefect/events/filters.py +30 -3
  37. prefect/events/instrument.py +40 -40
  38. prefect/events/related.py +2 -1
  39. prefect/events/schemas/automations.py +126 -8
  40. prefect/events/schemas/deployment_triggers.py +23 -277
  41. prefect/events/schemas/events.py +7 -7
  42. prefect/events/utilities.py +3 -1
  43. prefect/events/worker.py +21 -8
  44. prefect/exceptions.py +1 -1
  45. prefect/flows.py +33 -18
  46. prefect/input/actions.py +9 -9
  47. prefect/input/run_input.py +49 -37
  48. prefect/logging/__init__.py +2 -2
  49. prefect/logging/loggers.py +64 -1
  50. prefect/new_flow_engine.py +293 -0
  51. prefect/new_task_engine.py +374 -0
  52. prefect/results.py +32 -12
  53. prefect/runner/runner.py +3 -2
  54. prefect/serializers.py +62 -31
  55. prefect/server/api/collections_data/views/aggregate-worker-metadata.json +44 -3
  56. prefect/settings.py +32 -10
  57. prefect/states.py +25 -19
  58. prefect/tasks.py +17 -0
  59. prefect/types/__init__.py +90 -0
  60. prefect/utilities/asyncutils.py +37 -0
  61. prefect/utilities/engine.py +6 -4
  62. prefect/utilities/pydantic.py +34 -15
  63. prefect/utilities/schema_tools/hydration.py +88 -19
  64. prefect/utilities/schema_tools/validation.py +1 -1
  65. prefect/variables.py +4 -4
  66. {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/METADATA +1 -1
  67. {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/RECORD +71 -67
  68. /prefect/{concurrency/common.py → events/cli/__init__.py} +0 -0
  69. {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/LICENSE +0 -0
  70. {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/WHEEL +0 -0
  71. {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,90 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, Callable, ClassVar, Generator
3
+
4
+ from pydantic_core import core_schema, CoreSchema, SchemaValidator
5
+ from typing_extensions import Self
6
+ from datetime import timedelta
7
+
8
+
9
+ @dataclass
10
+ class NonNegativeInteger(int):
11
+ schema: ClassVar[CoreSchema] = core_schema.int_schema(ge=0)
12
+
13
+ @classmethod
14
+ def __get_validators__(cls) -> Generator[Callable[..., Any], None, None]:
15
+ yield cls.validate
16
+
17
+ @classmethod
18
+ def __get_pydantic_core_schema__(
19
+ cls, source_type: Any, handler: Callable[..., Any]
20
+ ) -> CoreSchema:
21
+ return cls.schema
22
+
23
+ @classmethod
24
+ def validate(cls, v: Any) -> Self:
25
+ return SchemaValidator(schema=cls.schema).validate_python(v)
26
+
27
+
28
+ @dataclass
29
+ class PositiveInteger(int):
30
+ schema: ClassVar[CoreSchema] = core_schema.int_schema(gt=0)
31
+
32
+ @classmethod
33
+ def __get_validators__(cls) -> Generator[Callable[..., Any], None, None]:
34
+ yield cls.validate
35
+
36
+ @classmethod
37
+ def __get_pydantic_core_schema__(
38
+ cls, source_type: Any, handler: Callable[..., Any]
39
+ ) -> CoreSchema:
40
+ return cls.schema
41
+
42
+ @classmethod
43
+ def validate(cls, v: Any) -> Self:
44
+ return SchemaValidator(schema=cls.schema).validate_python(v)
45
+
46
+
47
+ @dataclass
48
+ class NonNegativeDuration(timedelta):
49
+ schema: ClassVar = core_schema.timedelta_schema(ge=timedelta(seconds=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
+ @dataclass
67
+ class PositiveDuration(timedelta):
68
+ schema: ClassVar = core_schema.timedelta_schema(gt=timedelta(seconds=0))
69
+
70
+ @classmethod
71
+ def __get_validators__(cls) -> Generator[Callable[..., Any], None, None]:
72
+ yield cls.validate
73
+
74
+ @classmethod
75
+ def __get_pydantic_core_schema__(
76
+ cls, source_type: Any, handler: Callable[..., Any]
77
+ ) -> CoreSchema:
78
+ return cls.schema
79
+
80
+ @classmethod
81
+ def validate(cls, v: Any) -> Self:
82
+ return SchemaValidator(schema=cls.schema).validate_python(v)
83
+
84
+
85
+ __all__ = [
86
+ "NonNegativeInteger",
87
+ "PositiveInteger",
88
+ "NonNegativeDuration",
89
+ "PositiveDuration",
90
+ ]
@@ -1,11 +1,13 @@
1
1
  """
2
2
  Utilities for interoperability with async functions and workers from various contexts.
3
3
  """
4
+
4
5
  import asyncio
5
6
  import ctypes
6
7
  import inspect
7
8
  import threading
8
9
  import warnings
10
+ from concurrent.futures import ThreadPoolExecutor
9
11
  from contextlib import asynccontextmanager
10
12
  from functools import partial, wraps
11
13
  from threading import Thread
@@ -78,6 +80,41 @@ def is_async_gen_fn(func):
78
80
  return inspect.isasyncgenfunction(func)
79
81
 
80
82
 
83
+ def run_sync(coroutine: Coroutine[Any, Any, T]) -> T:
84
+ """
85
+ Runs a coroutine from a synchronous context, either in the current event
86
+ loop or in a new one if there is no event loop running. The coroutine will
87
+ block until it is done. A thread will be spawned to run the event loop if
88
+ necessary, which allows coroutines to run in environments like Jupyter
89
+ notebooks where the event loop runs on the main thread.
90
+
91
+ Args:
92
+ coroutine: The coroutine to run.
93
+
94
+ Returns:
95
+ The return value of the coroutine.
96
+
97
+ Example:
98
+ Basic usage:
99
+ ```python
100
+ async def my_async_function(x: int) -> int:
101
+ return x + 1
102
+
103
+ run_sync(my_async_function(1))
104
+ ```
105
+ """
106
+ try:
107
+ loop = asyncio.get_running_loop()
108
+ if loop.is_running():
109
+ with ThreadPoolExecutor() as executor:
110
+ future = executor.submit(asyncio.run, coroutine)
111
+ return future.result()
112
+ else:
113
+ return asyncio.run(coroutine)
114
+ except RuntimeError:
115
+ return asyncio.run(coroutine)
116
+
117
+
81
118
  async def run_sync_in_worker_thread(
82
119
  __fn: Callable[..., T], *args: Any, **kwargs: Any
83
120
  ) -> T:
@@ -11,6 +11,7 @@ from typing import (
11
11
  Iterable,
12
12
  Optional,
13
13
  Set,
14
+ TypeVar,
14
15
  Union,
15
16
  )
16
17
  from uuid import UUID, uuid4
@@ -66,6 +67,7 @@ from prefect.utilities.text import truncated_to
66
67
  API_HEALTHCHECKS = {}
67
68
  UNTRACKABLE_TYPES = {bool, type(None), type(...), type(NotImplemented)}
68
69
  engine_logger = get_logger("engine")
70
+ T = TypeVar("T")
69
71
 
70
72
 
71
73
  async def collect_task_run_inputs(expr: Any, max_depth: int = -1) -> Set[TaskRunInput]:
@@ -308,11 +310,11 @@ async def resolve_inputs(
308
310
 
309
311
  async def propose_state(
310
312
  client: PrefectClient,
311
- state: State,
313
+ state: State[object],
312
314
  force: bool = False,
313
- task_run_id: UUID = None,
314
- flow_run_id: UUID = None,
315
- ) -> State:
315
+ task_run_id: Optional[UUID] = None,
316
+ flow_run_id: Optional[UUID] = None,
317
+ ) -> State[object]:
316
318
  """
317
319
  Propose a new state for a flow run or task run, invoking Prefect orchestration logic.
318
320
 
@@ -1,24 +1,25 @@
1
1
  from functools import partial
2
- from typing import Any, Callable, Generic, Type, TypeVar, cast, overload
3
-
4
- from prefect._internal.pydantic import HAS_PYDANTIC_V2
5
-
6
- if HAS_PYDANTIC_V2:
7
- import pydantic.v1 as pydantic
8
- else:
9
- import pydantic
2
+ from typing import Any, Callable, Dict, Generic, Optional, Type, TypeVar, cast, overload
10
3
 
11
4
  from jsonpatch import JsonPatch as JsonPatchBase
5
+ from pydantic_core import to_jsonable_python
12
6
  from typing_extensions import Self
13
7
 
8
+ from prefect._internal.pydantic.utilities.model_dump import model_dump
9
+ from prefect.pydantic import HAS_PYDANTIC_V2
14
10
  from prefect.utilities.dispatch import get_dispatch_key, lookup_type, register_base_type
15
11
  from prefect.utilities.importtools import from_qualified_name, to_qualified_name
16
12
 
13
+ if HAS_PYDANTIC_V2:
14
+ import pydantic.v1 as pydantic_v1
15
+ else:
16
+ import pydantic as pydantic_v1
17
+
17
18
  D = TypeVar("D", bound=Any)
18
- M = TypeVar("M", bound=pydantic.BaseModel)
19
+ M = TypeVar("M", bound=pydantic_v1.BaseModel)
19
20
 
20
21
 
21
- def _reduce_model(model: pydantic.BaseModel):
22
+ def _reduce_model(model: pydantic_v1.BaseModel):
22
23
  """
23
24
  Helper for serializing a cythonized model with cloudpickle.
24
25
 
@@ -82,7 +83,7 @@ def add_cloudpickle_reduction(__model_cls: Type[M] = None, **kwargs: Any):
82
83
  )
83
84
 
84
85
 
85
- def get_class_fields_only(model: Type[pydantic.BaseModel]) -> set:
86
+ def get_class_fields_only(model: Type[pydantic_v1.BaseModel]) -> set:
86
87
  """
87
88
  Gets all the field names defined on the model class but not any parent classes.
88
89
  Any fields that are on the parent but redefined on the subclass are included.
@@ -91,7 +92,7 @@ def get_class_fields_only(model: Type[pydantic.BaseModel]) -> set:
91
92
  parent_class_fields = set()
92
93
 
93
94
  for base in model.__class__.__bases__:
94
- if issubclass(base, pydantic.BaseModel):
95
+ if issubclass(base, pydantic_v1.BaseModel):
95
96
  parent_class_fields.update(base.__annotations__.keys())
96
97
 
97
98
  return (subclass_class_fields - parent_class_fields) | (
@@ -134,7 +135,7 @@ def add_type_dispatch(model_cls: Type[M]) -> Type[M]:
134
135
 
135
136
  elif defines_dispatch_key and not defines_type_field:
136
137
  # Add a type field to store the value of the dispatch key
137
- model_cls.__fields__["type"] = pydantic.fields.ModelField(
138
+ model_cls.__fields__["type"] = pydantic_v1.fields.ModelField(
138
139
  name="type",
139
140
  type_=str,
140
141
  required=True,
@@ -180,7 +181,7 @@ def add_type_dispatch(model_cls: Type[M]) -> Type[M]:
180
181
  try:
181
182
  subcls = lookup_type(cls, dispatch_key=kwargs["type"])
182
183
  except KeyError as exc:
183
- raise pydantic.ValidationError(errors=[exc], model=cls)
184
+ raise pydantic_v1.ValidationError(errors=[exc], model=cls)
184
185
  return cls_new(subcls)
185
186
  else:
186
187
  return cls_new(cls)
@@ -206,7 +207,7 @@ class PartialModel(Generic[M]):
206
207
  a field already has a value.
207
208
 
208
209
  Example:
209
- >>> class MyModel(pydantic.BaseModel):
210
+ >>> class MyModel(pydantic_v1.BaseModel):
210
211
  >>> x: int
211
212
  >>> y: str
212
213
  >>> z: float
@@ -267,3 +268,21 @@ class JsonPatch(JsonPatchBase):
267
268
  },
268
269
  }
269
270
  )
271
+
272
+
273
+ def custom_pydantic_encoder(
274
+ type_encoders: Optional[Dict[Any, Callable[[Type[Any]], Any]]], obj: Any
275
+ ) -> Any:
276
+ # Check the class type and its superclasses for a matching encoder
277
+ for base in obj.__class__.__mro__[:-1]:
278
+ try:
279
+ encoder = type_encoders[base]
280
+ except KeyError:
281
+ continue
282
+
283
+ return encoder(obj)
284
+ else: # We have exited the for loop without finding a suitable encoder
285
+ if isinstance(obj, pydantic_v1.BaseModel):
286
+ return model_dump(obj, mode="json")
287
+ else:
288
+ return to_jsonable_python(obj)
@@ -1,41 +1,53 @@
1
1
  import json
2
2
  from typing import Any, Callable, Dict, Optional
3
3
 
4
- from prefect._internal.pydantic import HAS_PYDANTIC_V2
5
-
6
- if HAS_PYDANTIC_V2:
7
- from pydantic.v1 import BaseModel, Field
8
- else:
9
- from pydantic import BaseModel, Field
10
-
4
+ import jinja2
5
+ from pydantic import BaseModel, Field
11
6
  from sqlalchemy.ext.asyncio import AsyncSession
12
7
  from typing_extensions import TypeAlias
13
8
 
14
- from prefect.server.models.variables import read_variables
9
+ from prefect.server.utilities.user_templates import (
10
+ TemplateSecurityError,
11
+ render_user_template_sync,
12
+ validate_user_template,
13
+ )
15
14
 
16
15
 
17
16
  class HydrationContext(BaseModel):
18
17
  workspace_variables: Dict[str, str] = Field(default_factory=dict)
18
+ render_workspace_variables: bool = Field(default=False)
19
19
  raise_on_error: bool = Field(default=False)
20
+ render_jinja: bool = Field(default=False)
21
+ jinja_context: Dict[str, Any] = Field(default_factory=dict)
20
22
 
21
23
  @classmethod
22
24
  async def build(
23
25
  cls,
24
26
  session: AsyncSession,
25
27
  raise_on_error: bool = False,
28
+ render_jinja: bool = False,
29
+ render_workspace_variables: bool = False,
26
30
  ) -> "HydrationContext":
27
- variables = await read_variables(
28
- session=session,
29
- )
31
+ from prefect.server.models.variables import read_variables
32
+
33
+ if render_workspace_variables:
34
+ variables = await read_variables(
35
+ session=session,
36
+ )
37
+ else:
38
+ variables = []
39
+
30
40
  return cls(
31
41
  workspace_variables={
32
42
  variable.name: variable.value for variable in variables
33
43
  },
34
44
  raise_on_error=raise_on_error,
45
+ render_jinja=render_jinja,
46
+ render_workspace_variables=render_workspace_variables,
35
47
  )
36
48
 
37
49
 
38
- Handler: TypeAlias = Callable[[Dict, HydrationContext], Any]
50
+ Handler: TypeAlias = Callable[[dict, HydrationContext], Any]
39
51
  PrefectKind: TypeAlias = Optional[str]
40
52
 
41
53
  _handlers: Dict[PrefectKind, Handler] = {}
@@ -93,6 +105,12 @@ class ValueNotFound(KeyNotFound):
93
105
  return "value"
94
106
 
95
107
 
108
+ class TemplateNotFound(KeyNotFound):
109
+ @property
110
+ def key(self):
111
+ return "template"
112
+
113
+
96
114
  class VariableNameNotFound(KeyNotFound):
97
115
  @property
98
116
  def key(self):
@@ -108,6 +126,15 @@ class InvalidJSON(HydrationError):
108
126
  return message
109
127
 
110
128
 
129
+ class InvalidJinja(HydrationError):
130
+ @property
131
+ def message(self):
132
+ message = "Invalid jinja"
133
+ if self.detail:
134
+ message += f": {self.detail}"
135
+ return message
136
+
137
+
111
138
  class WorkspaceVariableNotFound(HydrationError):
112
139
  @property
113
140
  def variable_name(self) -> str:
@@ -116,7 +143,25 @@ class WorkspaceVariableNotFound(HydrationError):
116
143
 
117
144
  @property
118
145
  def message(self):
119
- return f"Variable '{self.detail}' not found."
146
+ return f"Variable '{self.detail}' not found in workspace."
147
+
148
+
149
+ class WorkspaceVariable(Placeholder):
150
+ def __init__(self, variable_name: str):
151
+ self.variable_name = variable_name
152
+
153
+ def __eq__(self, other):
154
+ return (
155
+ isinstance(other, type(self)) and self.variable_name == other.variable_name
156
+ )
157
+
158
+
159
+ class ValidJinja(Placeholder):
160
+ def __init__(self, template: str):
161
+ self.template = template
162
+
163
+ def __eq__(self, other):
164
+ return isinstance(other, type(self)) and self.template == other.template
120
165
 
121
166
 
122
167
  def handler(kind: PrefectKind) -> Callable:
@@ -127,7 +172,7 @@ def handler(kind: PrefectKind) -> Callable:
127
172
  return decorator
128
173
 
129
174
 
130
- def call_handler(kind: PrefectKind, obj: Dict, ctx: HydrationContext) -> Any:
175
+ def call_handler(kind: PrefectKind, obj: dict, ctx: HydrationContext) -> Any:
131
176
  if kind not in _handlers:
132
177
  return (obj or {}).get("value", None)
133
178
 
@@ -138,7 +183,7 @@ def call_handler(kind: PrefectKind, obj: Dict, ctx: HydrationContext) -> Any:
138
183
 
139
184
 
140
185
  @handler("none")
141
- def null_handler(obj: Dict, ctx: HydrationContext):
186
+ def null_handler(obj: dict, ctx: HydrationContext):
142
187
  if "value" in obj:
143
188
  # null handler is a pass through, so we want to continue to hydrate
144
189
  return _hydrate(obj["value"], ctx)
@@ -147,7 +192,7 @@ def null_handler(obj: Dict, ctx: HydrationContext):
147
192
 
148
193
 
149
194
  @handler("json")
150
- def json_handler(obj: Dict, ctx: HydrationContext):
195
+ def json_handler(obj: dict, ctx: HydrationContext):
151
196
  if "value" in obj:
152
197
  if isinstance(obj["value"], dict):
153
198
  dehydrated_json = _hydrate(obj["value"], ctx)
@@ -167,14 +212,38 @@ def json_handler(obj: Dict, ctx: HydrationContext):
167
212
  return RemoveValue()
168
213
 
169
214
 
215
+ @handler("jinja")
216
+ def jinja_handler(obj: dict, ctx: HydrationContext):
217
+ if "template" in obj:
218
+ if isinstance(obj["template"], dict):
219
+ dehydrated_jinja = _hydrate(obj["template"], ctx)
220
+ else:
221
+ dehydrated_jinja = obj["template"]
222
+
223
+ try:
224
+ validate_user_template(dehydrated_jinja)
225
+ except (jinja2.exceptions.TemplateSyntaxError, TemplateSecurityError) as exc:
226
+ return InvalidJinja(detail=str(exc))
227
+
228
+ if ctx.render_jinja:
229
+ return render_user_template_sync(dehydrated_jinja, ctx.jinja_context)
230
+ else:
231
+ return ValidJinja(template=dehydrated_jinja)
232
+ else:
233
+ return TemplateNotFound()
234
+
235
+
170
236
  @handler("workspace_variable")
171
- def workspace_variable_handler(obj: Dict, ctx: HydrationContext):
237
+ def workspace_variable_handler(obj: dict, ctx: HydrationContext):
172
238
  if "variable_name" in obj:
173
239
  if isinstance(obj["variable_name"], dict):
174
240
  dehydrated_variable = _hydrate(obj["variable_name"], ctx)
175
241
  else:
176
242
  dehydrated_variable = obj["variable_name"]
177
243
 
244
+ if not ctx.render_workspace_variables:
245
+ return WorkspaceVariable(variable_name=obj["variable_name"])
246
+
178
247
  if dehydrated_variable in ctx.workspace_variables:
179
248
  return ctx.workspace_variables[dehydrated_variable]
180
249
  else:
@@ -191,7 +260,7 @@ def workspace_variable_handler(obj: Dict, ctx: HydrationContext):
191
260
  return RemoveValue()
192
261
 
193
262
 
194
- def hydrate(obj: Dict, ctx: Optional[HydrationContext] = None):
263
+ def hydrate(obj: dict, ctx: Optional[HydrationContext] = None):
195
264
  res = _hydrate(obj, ctx)
196
265
 
197
266
  if _remove_value(res):
@@ -200,7 +269,7 @@ def hydrate(obj: Dict, ctx: Optional[HydrationContext] = None):
200
269
  return res
201
270
 
202
271
 
203
- def _hydrate(obj, ctx: Optional[HydrationContext] = None):
272
+ def _hydrate(obj, ctx: Optional[HydrationContext] = None) -> Any:
204
273
  if ctx is None:
205
274
  ctx = HydrationContext()
206
275
 
@@ -232,7 +232,7 @@ def preprocess_schema(schema):
232
232
  process_properties(schema["properties"], required_fields)
233
233
 
234
234
  if "definitions" in schema: # Also process definitions for reused models
235
- for definition in schema["definitions"].values():
235
+ for definition in (schema["definitions"] or {}).values():
236
236
  if "properties" in definition:
237
237
  required_fields = definition.get("required", [])
238
238
  process_properties(definition["properties"], required_fields)
prefect/variables.py CHANGED
@@ -30,11 +30,11 @@ class Variable(VariableRequest):
30
30
  """
31
31
  Sets a new variable. If one exists with the same name, user must pass `overwrite=True`
32
32
  ```
33
- from prefect import variables
33
+ from prefect.variables import Variable
34
34
 
35
35
  @flow
36
36
  def my_flow():
37
- var = variables.Variable.set(name="my_var",value="test_value", tags=["hi", "there"], overwrite=True)
37
+ var = Variable.set(name="my_var",value="test_value", tags=["hi", "there"], overwrite=True)
38
38
  ```
39
39
  or
40
40
  ```
@@ -69,11 +69,11 @@ class Variable(VariableRequest):
69
69
  """
70
70
  Get a variable by name. If doesn't exist return the default.
71
71
  ```
72
- from prefect import variables
72
+ from prefect.variables import Variable
73
73
 
74
74
  @flow
75
75
  def my_flow():
76
- var = variables.Variable.get("my_var")
76
+ var = Variable.get("my_var")
77
77
  ```
78
78
  or
79
79
  ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prefect-client
3
- Version: 2.17.1
3
+ Version: 2.18.1
4
4
  Summary: Workflow orchestration and management.
5
5
  Home-page: https://www.prefect.io
6
6
  Author: Prefect Technologies, Inc.