Change Log


  • Fix author metadata on PyPI package and add static check (#648)

  • Add testing for Python 3.12 beta 1 (#650)

  • Use Ruff for linting (#643)

  • Paths: Add type hinting for Path (#646)


  • Accept path-like objects (#627)

  • Move the build backend to hatchling and hatch-vcs. Users should be unaffected. Third-party packaging may need to adapt to the new build system. (#607)


  • Drop Python 2.7 and 3.5 support, add 3.11 support (#573)

  • Lots of extended checks and fixes for problems exposed.

  • Color: support NO_COLOR/FORCE_COLOR (#575)

  • Commands: New iter_lines buffer_size parameter (#582)

  • Commands: cache remote commands (#583)

  • SSH: Support reverse tunnels and dynamically allocated ports (#608)

  • CLI: add Set(..., all_markers={"*", "all"}) and fix support for other separators (#619)

  • CLI: support future annotations (#621)

  • Color: fix the ABC (#617)

  • Exceptions: fix for exception pickling (#586)

  • Fix for StdinDataRedirection and modifiers (#605)


  • Commands: avoid issue mktemp issue on some BSD variants (#571)

  • Better specification of dependency on pywin32 (#568)

  • Some DeprecationWarnings changed to FutureWarnings (#567)


  • Paths: glob with local paths no longer expands the existing path too (#552)

  • Paramiko: support reverse tunnels (#562)

  • SSHMachine: support forwarding Unix sockets in .tunnel() (#550)

  • CLI: Support COLOR_GROUP_TITLES (#553)

  • Fix a deprecated in Python 3.10 warning (#563)

  • Extended testing and checking on Python 3.10 and various PyPy versions. Nox is supported for easier new-user development.


  • Commands: support .with_cwd() (#513)

  • Commands: make iter_lines deal with decoding errors during iteration (#525)

  • Commands: fix handling of env-vars passed to plumbum BoundEnvCommands (#513)

  • Commands: fix support for win32 in iter_lines (#500)

  • Paths: fix incorrect __getitem__ method in Path (#506)

  • Paths: Remote path stat had odd OSError (#505)

  • Paths: Fix RemotePath.copy() (#527)

  • Paths: missing __fspath__ added (#498)

  • SSH: better error reporting on SshSession error (#515)

  • Internal: redesigned CI, major cleanup to setuptools distribution, Black formatting, style checking throughout.


  • Last version to support Python 2.6; added python_requires for future versions (#507)

  • Paths: Fix bug with subscription operations (#498), (#506)

  • Paths: Fix resolve (#492)

  • Commands: Fix resolve (#491)

  • Commands: Add context manager on popen (#495)

  • Several smaller fixes (#500), (#505)


  • Exceptions: Changed ProcessExecutionError’s formatting to be more user-friendly (#456)

  • Commands: support for per-line timeout with iter_lines (#454)

  • Commands: support for piping stdout/stderr to a logger (#454)

  • Paths: support composing paths using subscription operations (#455)

  • CLI: Improved ‘Set’ validator to allow non-string types, and CSV params (#452)

  • TypedEnv: Facility for modeling environment-variables into python data types (#451)

  • Commands: execute local/remote commands via a magic .cmd attribute (#450)


  • Commands: Added run_* methods as an alternative to modifiers (#386)

  • CLI: Added support for ALLOW_ABREV (#401)

  • CLI: Added DESCRIPTION_MORE, preserves spacing (#378)

  • Color: Avoid throwing error in atexit in special cases (like pytest) (#393)

  • Including Python 3.7 in testing matrix.

  • Smaller bugfixes and other testing improvements.


  • Critical Bugfix: High-speed (English) translations could break the CLI module (#371)

  • Small improvement to wheels packaging


  • Critical Bugfix: Syntax error in image script could break pip installs (#366)

  • CLI: Regression fix: English apps now load as fast as in 1.6.3 (#364)

  • CLI: Missing colon restored in group names

  • Regression fix: Restored non-setuptools installs (but really, why would you not have setuptools?) (#367)


  • CLI: Support for localization (#339), with:

    • Russian by Pavel Pletenev (#339) 🇷🇺

    • Dutch by Roel Aaij (#351) 🇳🇱

    • French by Joel Closier (#352) 🇫🇷

    • German by Christoph Hasse (#353) 🇩🇪

    • Pulls with more languages welcome!

  • CLI: Support for MakeDirectory (#339)

  • Commands: Fixed unicode input/output on Python 2 (#341)

  • Paths: More updates for pathlib compatibility (#325)

  • Terminal: Changed prompt()’s default value for type parameter from int to str to match existing docs (#327)

  • Remote: Support ~ in PATH for a remote (#293)

  • Remote: Fixes for globbing with spaces in filename on a remote server (#322)

  • Color: Fixes to image plots, better separation (#324)

  • Python 3.3 has been removed from Travis and Appveyor.

  • Several bugs fixed


  • Python 3.6 is now supported, critical bug fixed (#302)

  • Commands: Better handling of return codes for pipelines (#288)

  • Paths: Return split support (regression) (#286) - also supports dummy args for better str compatibility

  • Paths: Added support for Python 3.6 path protocol

  • Paths: Support Python’s in syntax

  • CLI: Added Config parser (provisional) (#304)

  • Color: image plots with python -m plumbum.cli.image (#304)

  • SSH: No longer hangs for timeout seconds on failure (#306)

  • Test improvements, especially on non-linux systems


  • CLI: Progress now has a clear keyword that hides the bar on completion

  • CLI: Progress without clear now starts on next line without having to manually add \n.

  • Commands: modifiers now accept a timeout parameter (#281)

  • Commands: BG modifier now allows stdout/stderr redirection (to screen, for example) (#258)

  • Commands: Modifiers no longer crash on repr (see #262)

  • Remote: nohup works again, typo fixed (#261)

  • Added better support for SunOS and other OS’s. (#260)

  • Colors: Context manager flushes stream now, provides more consistent results

  • Other smaller bugfixes, better support for Python 3.6+


  • CLI: Application subclasses can now be run directly, instead of calling .run(), to facilitate using as entry points (#237)

  • CLI: gui_open added to allow easy opening of paths in default gui editor (#239)

  • CLI: More control over help message (#233)

  • Remote: cwd is now stashed to reduce network usage (similar to Plumbum <1.6 behavior), and absolute paths are faster, (#238)

  • Bugfix: Pipelined return codes now give correct attribution (#243)

  • Bugfix: Progress works on Python 2.6 (#230)

  • Bugfix: Colors now work with more terminals (#231)

  • Bugfix: Getting an executable no longer returns a directory (#234)

  • Bugfix: Iterdir now works on Python <3.5

  • Testing is now expanded and fully written in Pytest, with coverage reporting.

  • Added support for Conda ( as of 1.6.2, use the -c conda-forge channel)


  • Added support for Python 3.5, PyPy, and better Windows and Mac support, with CI testing (#218, #217, #226)

  • Colors: Added colors module, support for colors added to cli (#213)

  • Machines: Added .get() method for checking several commands. (#205)

  • Machines: local.cwd now is the current directory even if you change the directory with non-Plumbum methods (fixes unexpected behavior). (#207)

  • SSHMachine: Better error message for SSH (#211)

  • SSHMachine: Support for FreeBSD remote (#220)

  • Paths: Now a subclass of str, can be opened directly (#228)

  • Paths: Improved pathlib compatibility with several additions and renames (#223)

  • Paths: Added globbing multiple patterns at once (#221)

  • Commands: added NOHUP modifier (#221)

  • CLI: added positional argument validation (#225)

  • CLI: added envname, which allows you specify an environment variable for a SwitchAttr (#216)

  • CLI terminal: added Progress, a command line progress bar for iterators and ranges (#214)

  • Continued to clean out Python 2.5 hacks


  • Removed support for Python 2.5. (Travis CI does not support it anymore)

  • CLI: add invoke, which allows you to programmatically run applications (#149)

  • CLI: add --help-all and various cosmetic fixes: (#125), (#126), (#127)

  • CLI: add root_app property (#141)

  • Machines: getattr now raises AttributeError instead of CommandNotFound (#135)

  • Paramiko: keep_alive support (#186)

  • Paramiko: does not support piping explicitly now (#160)

  • Parmaiko: Added pure SFTP backend, gives STFP v4+ support (#188)

  • Paths: bugfix to cwd interaction with Path (#142)

  • Paths: read/write now accept an optional encoding parameter (#148)

  • Paths: Suffix support similar to the Python 3.4 standard library pathlib (#198)

  • Commands: renamed setenv to with_env (#143)

  • Commands: pipelines will now fail with ProcessExecutionError if the source process fails (#145)

  • Commands: added TF and RETCODE modifiers (#202)

  • Experimental concurrent machine support in experimental/

  • Several minor bug fixes, including Windows and Python 3 fixes (#199, #195)


  • Paramiko now supports Python 3, enabled support in Plumbum

  • Terminal: added prompt(), bugfix to get_terminal_size() (#113)

  • CLI: added cleanup(), which is called after main() returns

  • CLI: bugfix to CountOf (#118)

  • Commands: Add a TEE modifier (#117)

  • Remote machines: bugfix to which, bugfix to remote environment variables (#122)

  • Path: read()/write() now operate on bytes


  • Force /bin/sh to be the shell in SshMachine.session() (#111)

  • Added islink() and unlink() to path objects (#100, #103)

  • Added access to path objects

  • Faster which implementation (#98)

  • Several minor bug fixes


  • Moved atomic and unixutils into the new fs package (file-system related utilities)

  • Dropped plumbum.utils legacy shortcut in favor of plumbum.path.utils

  • Bugfix: the left-hand-side process of a pipe wasn’t waited on, leading to zombies (#89)

  • Added RelativePath (the result of Path.relative_to)

  • Fixed more text alignment issues in

  • Introduced ask() and choose to cli.terminal

  • Bugfix: Path comparison operators were wrong

  • Added connection timeout to RemoteMachine


  • Command.popen: a new argument, new_session may be passed to Command.popen, which runs the given in a new session (setsid on POSIX, CREATE_NEW_PROCESS_GROUP on Windows)

  • Command.Popen: args can now also be a list (previously, it was required to be a tuple). See

  • local.daemonize: run commands as full daemons (double-fork and setsid) on POSIX systems, or detached from their controlling console and parent (on Windows).

  • list_processes: return a list of running process (local/remote machines)

  • SshMachine.nohup: “daemonize” remote commands via nohup (not really a daemon, but good enough)

  • atomic: Atomic file operations (AtomicFile, AtomicCounterFile and PidFile)

  • copy and move: the src argument can now be a list of files to move, e.g., copy(["foo", "bar"], "/usr/bin")

  • list local and remote processes

  • cli: better handling of text wrapping in the generated help message

  • cli: add a default main() method that checks for unknown subcommands

  • terminal: initial commit (get_terminal_size)

  • packaging: the package was split into subpackages; it grew too big for a flat namespace. imports are not expected to be broken by this change

  • SshMachine: added password parameter, which relies on sshpass to feed the password to ssh. This is a security risk, but it’s occasionally necessary. Use this with caution!

  • Commands now have a machine attribute that points to the machine they run on

  • Commands gained setenv, which creates a command with a bound environment

  • Remote path: several fixes to stat (StatRes)

  • cli: add lazily-loaded subcommands (e.g., MainApp.subcommand("foo", "")), which are imported on demand

  • Paths: added relative_to and split, which (respectively) computes the difference between two paths and splits paths into lists of nodes

  • cli: Predicate became a class decorator (it exists solely for pretty-printing anyway)

  • PuttyMachine: bugfix



  • Paramiko integration (#10)

  • CLI: now with built-in support for sub-commands. See also: #43

  • The “import hack” has moved to the package’s, to make it importable directly (#45)

  • Paths now support chmod (on POSIX platform) (#49)

  • The argument name of a SwitchAttr can now be given to it (defaults to VALUE) (#46)


  • Windows: path are no longer converted to lower-case, but __eq__ and __hash__ operate on the lower-cased result (#38)

  • Properly handle empty strings in the argument list (#41)

  • Relaxed type-checking of LocalPath and RemotePath (#35)

  • Added PuttyMachine for Windows users that relies on plink and pscp (instead of ssh and scp) (#37)


  • Rename cli.CountingAttr to cli.CountOf

  • Moved to Travis continuous integration

  • Added unixutils

  • Added chown and uid/gid

  • Lots of fixes and updates to the doc

  • Full list of issues


Initial release