Matt Alhonte
10/19/2023, 10:57 PMdefaults_from_attrs
for subclassing Tasks?Marvin
10/19/2023, 10:57 PMdefaults_from_attrs
method no longer exists. Instead, you'll have to use the __getattribute__
method in your Task subclass to achieve the same effect. It's a bit more work, but then again, what isn't? Here's an example:
python
from prefect import Task
class MyTask(Task):
def __init__(self, my_attr=None, **kwargs):
self.my_attr = my_attr
super().__init__(**kwargs)
def __getattribute__(self, item):
attr = object.__getattribute__(self, item)
if attr:
return attr
else:
return self.context.get(item)
In this example, if my_attr
is not set when the Task is initialized, it will look for my_attr
in the context when the Task is run. It's a bit like having your own personal assistant, always there to fetch things for you. Must be nice.Nate
10/19/2023, 11:02 PMNate
10/19/2023, 11:03 PMdefaults_from_attrs
was a convenience thing since we always had to carry attrs from the _`__init__`_ into the run
method, but now tasks enter the engine via __call__
so its just not relevant the same way anymoreNate
10/19/2023, 11:04 PMMatt Alhonte
10/19/2023, 11:05 PMShellOperation
task and make a custom version for running some CLI tools that we have, and I'd like to do a few things with some arguments that get passed to it to create the commandMatt Alhonte
10/19/2023, 11:05 PMMatt Alhonte
10/19/2023, 11:05 PMShellTask
and defaults_from_attrs
Nate
10/19/2023, 11:15 PMfrom prefect_shell import ShellOperation
from pydantic import validator
class MyShellOp(ShellOperation):
@validator('commands')
def validate_commands(cls, commands: list[str]) -> list[str]:
for command in commands:
if command == "rm -rf /":
raise ValueError("I'm calling the FBI")
# modify commands here if needed
return commands
if __name__ == "__main__":
MyShellOp(commands=["rm -rf /"]).run()
Nate
10/19/2023, 11:15 PMMatt Alhonte
10/19/2023, 11:15 PMMatt Alhonte
10/19/2023, 11:18 PMtask
args and defaults and stuff?Matt Alhonte
10/19/2023, 11:19 PMOSError: source code not available
Nate
10/19/2023, 11:19 PMMatt Alhonte
10/19/2023, 11:19 PMNate
10/19/2023, 11:20 PMNate
10/19/2023, 11:21 PMcommands
in that validatorMatt Alhonte
10/19/2023, 11:23 PMvalidator
?Nate
10/19/2023, 11:24 PMlist[str] -> some_transform -> list[str]
on your commands then that should work fine
if you want to change more about the ShellOperation methods work, you'd have to override them and make sure they play the same roleMatt Alhonte
10/19/2023, 11:25 PMNate
10/19/2023, 11:31 PMfrom prefect_shell import ShellOperation
from pydantic import Field, root_validator
def some_function(commands: list, foo: str) -> list:
return commands + [f"echo 'foo is {foo}'"]
class MyShellOp(ShellOperation):
extra_kwargs: dict = Field(default_factory=dict)
@root_validator
def validate_commands(cls, values: dict) -> dict:
if extra_kwargs := values.get("extra_kwargs"):
new_commands = some_function(
commands=values.get("commands"),
**extra_kwargs
)
values["commands"] = new_commands
return values
if __name__ == "__main__":
MyShellOp(
commands=["echo 'Hello, World!'"],
extra_kwargs={"foo": "bar"}
).run()
Nate
10/19/2023, 11:31 PMยป python my_shell_op.py
18:30:52.811 | INFO | prefect.MyShellOp - PID 42012 triggered with 2 commands running inside the '.' directory.
18:30:52.861 | INFO | prefect.ShellProcess - PID 42012 stream output:
Hello, World!
foo is bar
18:30:52.862 | INFO | prefect.ShellProcess - PID 42012 completed with return code 0.
Nate
10/19/2023, 11:34 PMrun
method and add this extra kwargs handling as methods of your subclass and then call them in your subclass' run methodMatt Alhonte
10/19/2023, 11:34 PMclass MyShellOp(ShellOperation):
@root_validator
def validate_commands(cls, commands: list[str], x: str, y: int):
if extra_kwargs := values.get("extra_kwargs"):
new_commands = some_function(
commands=values.get("commands"), **extra_kwargs
)
values["commands"] = new_commands
return values
if __name__ == "__main__":
MyShellOp(commands=["echo 'Hello, World!'"], x="w4rsrtwer", y=6).run()
Nate
10/19/2023, 11:35 PMvalues
on the class, unfortunately that's not something you can change to affect the attrs on the class
e.g. x, y would have to be actual fields on the class like extra_kwargs
from my exampleMatt Alhonte
10/19/2023, 11:38 PMShellOperation
over the resulting stringsMatt Alhonte
10/19/2023, 11:42 PMmap
with a method on a Task? So like
ShellOperation.map(
commands=list_of_list_of_commands,
).run()
Matt Alhonte
10/19/2023, 11:42 PMNate
10/19/2023, 11:43 PMMatt Alhonte
10/19/2023, 11:43 PMMatt Alhonte
10/19/2023, 11:44 PMMatt Alhonte
10/19/2023, 11:44 PMMatt Alhonte
10/19/2023, 11:44 PMMatt Alhonte
10/19/2023, 11:45 PMNate
10/19/2023, 11:45 PM