Search code examples
pythonpython-3.xinvokefabriccontextmanager

invoke.context.Context is giving an odd error for missing positional argument


I am trying to change directories in my python program within a context manager. using invoke.context.Context seems like the proper way to do it, got from the Fabric documentation and using a regular with os.chdir will not work.

However, when I try to do something such as

from invoke import Context

with Context.cd("/etc"):
    subprocess.run(["ls"])

I get an error back that says:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-40b28af3213a> in <module>
----> 1 with Context.cd("/etc"):
      2     subprocess.run(["ls"])
      3

~/miniconda3/envs/python3/lib/python3.7/contextlib.py in helper(*args, **kwds)
    237     @wraps(func)
    238     def helper(*args, **kwds):
--> 239         return _GeneratorContextManager(func, args, kwds)
    240     return helper
    241

~/miniconda3/envs/python3/lib/python3.7/contextlib.py in __init__(self, func, args, kwds)
     80
     81     def __init__(self, func, args, kwds):
---> 82         self.gen = func(*args, **kwds)
     83         self.func, self.args, self.kwds = func, args, kwds
     84         # Issue 19330: ensure context manager instances have good docstrings

TypeError: cd() missing 1 required positional argument: 'path'

The documentation makes this seem correct (http://docs.pyinvoke.org/en/latest/api/context.html#invoke.context.Context), but i'm a little lost.

Any advice is helpful.


Solution

  • Looking at the documentation, it seems like you're supposed to create your own instance of Context, instead of using the Context class directly.

    They also use the run() method on the Context instance instead of subprocess.run().

    Try this:

    from invoke import Context
    
    c = Context()
    with c.cd("/etc"):
        c.run("ls")