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_attrsNate
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 availableNate
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