pyinvoke / invoke

Pythonic task management & command execution.
http://pyinvoke.org
BSD 2-Clause "Simplified" License
4.31k stars 365 forks source link

Is it possible to extend the Context class's run method with my own? #905

Open red8888 opened 1 year ago

red8888 commented 1 year ago

This might be more a general python question, but any tips would be great!

I want to add my own custom parameters to the context class's run method. I guess I could patch it, but wondering if there is a better supported way?

I want to be able to do this: ctx.run("mycommand", hide=False, myCustomArg="somevalue")

So I can add my own functionality.

Is it possible to extend the Context class with my own and use my own class?

D3f0 commented 1 year ago

Hey @red8888, the method run delegates the execution to a Runner class, which by default is an instance of invoke.runners.Local.

A way to accomplish this is making your Collection/namespace explicit (ns) and configuring its "local" runner. Note that you don't need to do the auto discovery, but it's handy since you don't have to explicitly do a [.add_task](https://docs.pyinvoke.org/en/stable/api/collection.html#invoke.collection.Collection.add_task()).

# tasks.py
from invoke import task, Task, Context
from invoke.collection import Collection
from invoke.runners import Local

class MyRunner(Local):
    def run(self, command, myCustomArg=False, **kwargs):
        print(f"{myCustomArg=}")
        return super().run(command, **kwargs)

@task()
def use_custom_runner(ctx: Context, myCustomArg=False):
    ctx.run("ls", myCustomArg=myCustomArg)

# A bit long, but automatic task discovery, which happens magically in invoke when we don't
# need to override much
ns = Collection(
    *(
        task_function
        for name, task_function in locals().items()
        if isinstance(task_function, Task)
    ),
)
ns.configure(
    {
        "runners": {"local": MyRunner},
    }
)