Search code examples
pythonpyinvoke

How to use pyinvoke as a library and include the tasks in a single file?


I'd like to create a standalone python script that uses invoke and also includes the tasks to be executed. A minimal working example looks like:

#!/usr/bin/env python3

from invoke import task, Program

@task()
def foo(c):
    print("Task...")

program = Program()

program.run()

If I name the script example.py, I'd like to be able to take the script and do:

(py37) bash-3.00$ ./example.py foo
Task...

If I put the task in a separate file named tasks.py, things work. The documentation shows how to put the tasks in a separate package, but not the top-level script itself. I suspect it may be possible by providing the right namespace argument to Program(), but I haven't found a value that works.


Solution

  • You are absolutely right and so close to the solution. Program doc says...

    namespace:

    A Collection to use as this program's subcommands.

    If None (the default), the program will behave like invoke, seeking a nearby task namespace with a Loader and exposing arguments such as --list and --collection for inspecting or selecting specific namespaces.

    You need to initialise a collection, add the tasks and pass it on to the Program.

    #!/usr/bin/env python3
    
    import sys
    from invoke import task, Program, Collection
    
    
    @task()
    def foo(c):
        print("Task...")
    
    
    namespace = Collection()
    namespace.add_task(foo)
    
    program = Program(namespace=namespace)
    program.run()
    

    Save this as example.py and run as you expected.

    $ python3 example.py foo
    Task...