The Local Object

So far we’ve only seen running local commands, but there’s more to the local object than this; it aims to “fully represent” the local machine.

First, you should get acquainted with which, which performs program name resolution in the system PATH and returns the first match (or raises an exception if no match is found):

>>> local.which("ls")
<LocalPath C:\Program Files\Git\bin\ls.exe>
>>> local.which("nonexistent")
Traceback (most recent call last):
   [...]
plumbum.commands.CommandNotFound: ('nonexistent', [...])

Another member is python, which is a command object that points to the current interpreter (sys.executable):

>>> local.python
<LocalCommand c:\python310\python.exe>
>>> local.python("-c", "import sys;print(sys.version)")
'3.10.0 (default, Feb 2 2022, 02:22:22) [MSC v.1931 64 bit (Intel)]\r\n'

Working Directory

The local.cwd attribute represents the current working directory. You can change it like so:

>>> local.cwd
<Workdir d:\workspace\plumbum>
>>> local.cwd.chdir("d:\\workspace\\plumbum\\docs")
>>> local.cwd
<Workdir d:\workspace\plumbum\docs>

You can also use it as a context manager, so it behaves like pushd/popd:

>>> ls_l = ls | wc["-l"]
>>> with local.cwd("c:\\windows"):
...     print(f"{local.cwd}:{ls_l()}")
...     with local.cwd("c:\\windows\\system32"):
...         print(f"{local.cwd}:{ls_l()}")
...
c:\windows: 105
c:\windows\system32: 3013
>>> print(f"{local.cwd}:{ls_l()}")
d:\workspace\plumbum: 9

Finally, A more explicit and thread-safe way of running a command in a different directory is using the .with_cwd() method:

>>> ls_in_docs = local.cmd.ls.with_cwd("docs")
>>> ls_in_docs()
'api\nchangelog.rst\n_cheatsheet.rst\ncli.rst\ncolorlib.rst\n_color_list.html\ncolors.rst\nconf.py\nindex.rst\nlocal_commands.rst\nlocal_machine.rst\nmake.bat\nMakefile\n_news.rst\npaths.rst\nquickref.rst\nremote.rst\n_static\n_templates\ntyped_env.rst\nutils.rst\n'

Environment

Much like cwd, local.env represents the local environment. It is a dictionary-like object that holds environment variables, which you can get/set intuitively:

>>> local.env["JAVA_HOME"]
'C:\\Program Files\\Java\\jdk1.6.0_20'
>>> local.env["JAVA_HOME"] = "foo"

And similarity to cwd is the context-manager nature of env; each level would have it’s own private copy of the environment:

>>> with local.env(FOO="BAR"):
...     local.python("-c", "import os; print(os.environ['FOO'])")
...     with local.env(FOO="SPAM"):
...         local.python("-c", "import os; print(os.environ['FOO'])")
...     local.python("-c", "import os; print(os.environ['FOO'])")
...
'BAR\r\n'
'SPAM\r\n'
'BAR\r\n'
>>> local.python("-c", "import os;print(os.environ['FOO'])")
Traceback (most recent call last):
   [...]
ProcessExecutionError: Unexpected exit code: 1
Command line: | /usr/bin/python3 -c "import os; print(os.environ['FOO'])"
Stderr:       | Traceback (most recent call last):
              |   File "<string>", line 1, in <module>
              |   File "/usr/lib/python3.10/os.py", line 725, in __getitem__
              |     raise KeyError(key) from None
              | KeyError: 'FOO'

In order to make cross-platform-ness easier, the local.env object provides some convenience properties for getting the username (.user), the home path (.home), and the executable path (path) as a list. For instance:

>>> local.env.user
'sebulba'
>>> local.env.home
<Path c:\Users\sebulba>
>>> local.env.path
[<Path c:\python39\lib\site-packages\gtk-2.0\runtime\bin>, <Path c:\Users\sebulba\bin>, ...]
>>>
>>> local.which("python")
<Path c:\python39\python.exe>
>>> local.env.path.insert(0, "c:\\python310")
>>> local.which("python")
<Path c:\python310\python.exe>

For further information, see the api docs.