[Feature]: Allow the configuration system to override which
Executor subclass to use when executing tasks (via an
import-oriented string).

Specifically, it’s now possible to alter execution by distributing such a
subclass alongside, for example, a repository-local config file which sets
tasks.executor_class; previously, this sort of thing required use of
custom binaries.

[Bug]#466: Update the parsing and CLI-program mechanisms so that all
core arguments may be given within task CLI contexts; previously this
functionality only worked for the --help flag, and other core arguments
given after task names (such as --echo) were silently ignored.

[Feature]#301: (via #414) Overhaul tab completion mechanisms so users
can print a completion script which
automatically matches the emitting binary’s configured names (compared to the
previous hardcoded scripts, which only worked for inv/invoke by
default). Thanks to Nicolas Höning for the foundational patchset.

[Feature]#543: Implemented support for using INVOKE_RUNTIME_CONFIG env
var as an alternate method of supplying a runtime configuration file path
(effectively, an env var based version of using the -f/--config
option). Feature request via Kevin J. Qiu.

[Feature]: Add a klass kwarg to @task to allow
extending codebases the ability to create their own variants on
@task/Task.

[Feature]: Remove overzealous argument checking in @task, instead just handing any extra kwargs into the task
class constructor. The high level behavior for truly invalid kwargs is the
same (TypeError) but now extending codebases can add kwargs to their
versions of @task without issue.

[Feature]: Refactor Call internals slightly, exposing some
previously internal logic as the clone_data method; this is useful for
client codebases when extending Call and friends.

[Feature]: Enhance Call with a new method
(clone_data) and new kwarg to an existing method (clone grew
with_) to assist subclassers when extending.

[Support]: Fixed some inaccuracies in the API docs around
Executor and its core kwarg (was erroneously referring
to ParserContext instead of
ParseResult). Includes related cleaning-up of
docstrings and tests.

[Bug]: As part of solving #528 we found a related bug, where
unnamed subcollections also caused issues with inv--list--list-format=json. Specifically, Collection.serialized sorts subcollections by name,
which is problematic when that name is None. This is now fixed.

[Bug]#528: Around Invoke 0.23 we broke the ability to weave in subcollections
via keyword arguments to Collection, though it primarily
manifests as NoneType related errors during inv--list. This was
unintentional and has been fixed. Report submitted by Tuukka Mustonen.

[Bug]: Fix up the __repr__ of Call to reference dynamic
class name instead of hardcoding "Call"; this allows subclasses’
__repr__ output to be correct instead of confusing.

[Bug]#270: (also #551) None values in config levels (most
commonly caused by empty configuration files) would raise AttributeError
when merge_dicts was used to merge config levels together.
This has been fixed. Thanks to Tyler Hoffman and Vlad Frolov for the reports.

[Support]: Fixed some inaccuracies in the API docs around
Executor and its core kwarg (was erroneously referring
to ParserContext instead of
ParseResult). Includes related cleaning-up of
docstrings and tests.

[Bug]: Tweaked the innards of
Config/DataProxy to prevent accessing
properties & other attributes’ values during __setattr__ (the code in
question only needed the names). This should have no noticeable effect on
user code (besides a marginal speed increase) but fixed some minor test
coverage issues.

[Bug]: Removed an old, unused and untested (but, regrettably,
documented and public) method that doesn’t seem to be much use:
invoke.config.Config.paths. Please reach out if you were actually using
it and we may consider adding some form of it back.

Warning

This is a backwards incompatible change if you were using Config.paths.

[Bug]#516: Remove the CLI parser ambiguity rule regarding flag-like
tokens which are seen after an optional-value flag (e.g. invtask--optionally-takes-a-value--some-other-flag.) Previously, any flag-like
value in such a spot was considered ambiguous and raised a
ParseError. Now, the surrounding parse context is used
to resolve the ambiguity, and no error is raised.

Warning

This behavior is backwards incompatible, but only if you had the minority
case where users frequently and erroneously give otherwise-legitimate
flag-like values to optional-value arguments, and you rely on the parse
errors to notify them of their mistake. (If you don’t understand what this
means, don’t worry, you almost certainly don’t need to care!)

[Bug]: Integer-type CLI arguments were not displaying placeholder
text in --help output (i.e. they appeared as --myint instead of
--myint=INT.) This has been fixed.

[Bug]:Collection had some minor bugs or
oversights in how it responds to things like repr(), ==; boolean
behavior; how docstrings appear when created from a Python module; etc. All
are now fixed. If you’re not sure whether this affects you, it does not :)

[Bug]: Previously, some error conditions (such as invalid task or
collection names being supplied by the user) printed to standard output,
instead of standard error. Standard error seems more appropriate here, so
this has been fixed.

Warning

This is backwards incompatible if you were explicitly checking the standard
output of the inv[oke] program for some of these error messages.

Warning

If your code is manually raising or introspecting instances of
Exit, note that its signature has changed from
Exit(code=0) to Exit(message=None,code=None). (Thus, this will
only impact you if you were calling its constructor instead of raising the
class object itself.)

[Support]: Rename invoke.platform to invoke.terminals; it was
inadvertently shadowing the platform standard library builtin module.
This was not causing any bugs we are aware of, but it is still poor hygiene.

Warning

This change is technically backwards incompatible. We don’t expect many
users import invoke.platform directly, but if you are, take note.

[Support]#515: Ported the test suite from spec (nose) to pytest-relaxed (pytest) as pytest basically won the test-runner war against
nose & has greater mindshare, more shiny toys, etc.

[Support]: (partially re: #33) Renamed the --root CLI flag to
--search-root, partly for clarity (#33 will be adding namespace
display-root related flags, which would make --root ambiguous) and partly
for consistency with the config option, which was already named
search_root. (The short version of the flag, -r, is unchanged.)

Warning

This is a backwards incompatible change. To fix, simply use
--search-root anywhere you were previously using --root.

[Bug]#488: Account for additional I/O related OSError error strings
when attempting to capture only this specific subtype of error. This should
fix some issues with less common libc implementations such as musl (as
found on e.g. Alpine Linux.) Thanks to Rajitha Perera for the report.

[Bug]#342: Accidentally hardcoded Collection instead of cls in
Collection.from_module (an
alternate constructor and therefore a classmethod.) This made it rather hard
to properly subclass Collection. Report and initial
patch courtesy of Luc Saffre.

[Bug]: Iterable-type CLI args were actually still somewhat broken &
were ‘eating’ values after themselves in the parser stream (thus e.g.
preventing parsing of subsequent tasks or flags.) This has been fixed.

[Bug]#407: (also #494, #67) Update the default value of
the run.shell config value so that it reflects a Windows-appropriate
value (specifically, the COMSPEC env var or a fallback of cmd.exe) on
Windows platforms. This prevents Windows users from being forced to always
ship around configuration-level overrides.

Thanks to Maciej ‘maQ’ Kusz for the original patchset, and to @thebjorn
and Garrett Jenkins for providing lots of feedback.

[Support]#364: Drop Python 2.6 and Python 3.3 support, as these versions now
account for only very low percentages of the userbase and are unsupported (or
about to be unsupported) by the rest of the ecosystem, including pip.

This includes updating documentation & packaging metadata as well as taking
advantage of basic syntax additions like set literals/comprehensions ({1,2,3} instead of set([1,2,3])) and removing positional string
argument specifiers ("{}".format(val) instead of "{0}".format(val)).

[Feature]#132: Implement ‘iterable’ and ‘incrementable’ CLI flags, allowing
for invocations like invmytask--listyfoo--listybar (resulting in a
call like mytask(listy=['foo','bar'])) or invmytask-vvv (resulting
in e.g. mytask(verbose=3). Specifically, these require use of the new
iterable and incrementable arguments to @task - see
those links to the conceptual docs for details.

[Bug]: The behavior of Config when lazy=True
didn’t match that described in the API docs, after the recent updates to its
lifecycle. (Specifically, any config data given to the constructor was not
visible in the resulting instance until merge() was explicitly called.)
This has been fixed, along with other related minor issues.

[Bug]#467: (Arguably also a feature, but since it enables behavior users
clearly found intuitive, we’re considering it a bug.) Split up the parsing
machinery of Program and pushed the Collection-making out of Loader. Combined, this allows us to honor the project-level
config file before the second (task-oriented) CLI parsing step, instead of
after.

For example, this means you can turn off auto_dash_names in your
per-project configs and not only in your system or user configs.

Report again courtesy of Luke Orland.

Warning

This is a backwards incompatible change if you were subclassing and
overriding any of the affected methods in the Program or Loader
classes.

This can help prevent problems when running Invoke under systems that have no
useful standard input and which otherwise defeat our pty/fileno related
detection.

[Feature]#329: All task and collection names now have underscores turned into
dashes automatically, as task parameters have been for some time. This
impacts --list, --help, and of course the parser. For details, see
Dashes vs underscores.

This behavior is controlled by a new config setting,
tasks.auto_dash_names, which can be set to False to go back to the
classic behavior.

[Feature]: (required to support #310 and #329) Break up the
Config lifecycle some more, allowing it to gradually load
configuration vectors; this allows the CLI machinery
(Executor) to honor configuration settings from config
files which impact how CLI parsing and task loading behaves.

Specifically, this adds more public Config.load_* methods, which in
tandem with the lazy kwarg to __init__ (formerly defer_post_init,
see below) allow full control over exactly when each config level is loaded.

Warning

This change may be backwards incompatible if you were using or subclassing
the Config class in any of the following ways:

If you were passing __init__ kwargs such as project_home or
runtime_path and expecting those files to auto-load, they no longer
do; you must explicitly call load_project and/or
load_runtime explicitly.

The defer_post_init keyword argument to Config.__init__ has been
renamed to lazy, and controls whether system/user config files are
auto-loaded.

Config.post_init has been removed, in favor of explicit/granular use
of the load_* family of methods.

All load_* methods now call Config.merge automatically by default
(previously, merging was deferred to the end of most config related
workflows.)

This should only be a problem if your config contents are extremely large
(it’s an entirely in-memory dict-traversal operation) and can be avoided
by specifying merge=False to any such method. (Note that you must, at
some point, call merge in order for the config
object to work normally!)

[Bug]: Display of hidden subprocess output when a command
execution failed (end-of-session output starting with Encounteredabadcommandexitcode!) was liable to display encoding errors (e.g. 'ascii'codeccan'tencodecharacter...) when that output was not
ASCII-compatible.

This problem was previously solved for non-hidden (mirrored) subprocess
output, but the fix (encode the data with the local encoding) had not been
applied to exception display. Now it’s applied in both cases.

[Bug]#396:Collection.add_task(task,aliases=('other','names') was
listed in the conceptual documentation, but not implemented (technically, it
was removed at some point and never reinstated.) It has been (re-)added and
now exists. Thanks to @jenisys for the report.

Warning

This technically changes argument order for Collection.add_task, so be aware if you were using
positional arguments!

Tasks with their own --help flags won’t be able to leverage this
feature - the parser will still interpret the flag as being per-task and
not global. This may change in the future to simply throw an exception
complaining about the ambiguity. (Feedback welcome.)

[Feature]#446: Implement cd and
prefix context managers (as methods on the
not-that-one-the-other-one Context class.) These are based
on similar functionality in Fabric 1.x. Credit: Ryan P Kilby.

[Support]#448: Fix up some config-related tests that have been failing on
Windows for some time. Thanks to Ryan P Kilby.

[Bug]#439: Avoid placing stdin into bytewise read mode when it looks
like Invoke has been placed in the background by a shell’s job control
system; doing so was causing the shell to pause the Invoke process (e.g. with
a message like suspended(ttyoutput).) Reported by Tuukka Mustonen.

[Feature]:Result and UnexpectedExit objects now have a more useful repr()
(and in the case of UnexpectedExit, a distinct repr() from their
preexisting str().)

[Feature]:Context.sudo no longer prompts
the user when the configured sudo password is empty; thus, an empty sudo
password and a sudo program configured to require one will result in an
exception.

The runtime prompting for a missing password was a temporary holdover from
Fabric v1, and in retrospect is undesirable. We may add it back in as an
opt-in behavior (probably via subclassing) in the future if anybody misses
it.

Warning

This is a backwards incompatible change, if you were relying on
sudo() prompting you for your password (vs configuring it). If you
were doing that, you can simply switch to run("sudo<command>") and
respond to the subprocess’ sudo prompt by hand instead.

[Feature]: Switched the order of the first two arguments of
Config.__init__, so that the overrides
kwarg becomes the first positional argument.

This supports the common use case of making a Config
object that honors the system’s core/global defaults; previously, because
defaults was the first argument, you’d end up replacing those core
defaults instead of merging with them.

Warning

This is a backwards incompatible change if you were creating custom
Config objects via positional, instead of keyword, arguments. It should
have no effect otherwise.

[Feature]#309: Overhaul how task execution contexts/configs are handled, such
that all contexts in a session now share the same config object, and thus
user modifications are preserved between tasks. This has been done in a
manner that should not break things like collection-based config (which may
still differ from task to task.)

Warning

This is a backwards incompatible change if you were relying on the
post-0.12 behavior of cloning config objects between each task execution.
Make sure to investigate if you find tasks affecting one another in
unexpected ways!

[Feature]#418: Enhance ability of client libraries to override config
filename prefixes. This includes modifications to related functionality, such
as how env var prefixes are configured.

Warning

This is a backwards incompatible change if:

you were relying on the env_prefix keyword argument to
Config.__init__; it is now the
prefix or env_prefix class attribute, depending.

or the kwarg/attribute of the same name in Program.__init__; you should now be subclassing
Config and using its env_prefix attribute;

or if you were relying on how standalone Config objects defaulted to
having a None value for env_prefix, and thus loaded env vars
without an INVOKE_ style prefix.

[Feature]#232: Add support for .yml-suffixed config files (in addition to
.yaml, .json and .py.) Thanks to Matthias Lehmann for the
original request & Greg Back for an early patch.

[Bug]#430: Fallback importing of PyYAML when Invoke has been installed
without its vendor directory, was still trying to import the vendorized
module names (e.g. yaml2 or yaml3 instead of simply yaml). This
has been fixed, thanks to Athmane Madjoudj.

[Bug]#432: Tighten application of IO thread join timeouts (in run) to only happen when #351 appears
actually present. Otherwise, slow/overworked IO threads had a chance of being
joined before truly reading all data from the subprocess’ pipe.

[Feature]:Config.clone grew a new into
kwarg allowing client libraries with their own Config
subclasses to easily “upgrade” vanilla Invoke config objects into their local
variety.

[Feature]#421: Updated Config.clone (and a few
other related areas) to replace use of copy.deepcopy with a less-rigorous
but also less-likely-to-explode recursive dict copier. This prevents
frustrating TypeErrors while still preserving barriers between different
tasks’ configuration values.

[Feature]:Config’s internals got cleaned up
somewhat; end users should not see much of a difference, but advanced
users or authors of extension code may notice the following:

Direct modification of config data (e.g. myconfig.section.subsection.key='value' in user/task code) is now stored in its own config ‘level’/data
structure; previously such modifications simply mutated the central,
‘merged’ config cache. This makes it much easier to determine where a final
observed value came from, and prevents accidental data loss.

Ditto for deleted values.

Merging/reconciliation of the config levels now happens automatically when
data is loaded or modified, which not only simplifies the object’s
lifecycle a bit but allows the previous change to function without
requiring users to call .merge() after every modification.

Creating new configuration keys via attribute access wasn’t possible: one
had to do config['foo']='bar' because config.foo='bar' would
set a real attribute instead of touching configuration.

Supertypes’ attributes weren’t being considered during the “is this a real
attribute on self?” test, leading to different behavior between a
nested config-value-as-attribute and a top-level Context/Config one.

[Bug]: Fix configuration framework such that nested or dict-like
config values may be compared with regular dicts. Previously, doing so caused
an AttributeError (as regular dicts lack a .config).

The conceptual docs about CLI parsing mentioned
them, but didn’t actually show via example how to enable the feature,
implying (incorrectly) that they were active always by default. An example
has been added.

Even when enabled, they did not function correctly when their default
values were of type bool; in this situation, trying to give a value (vs
just giving the flag name by itself) caused a parser error. This has been
fixed.

Thanks to @ouroboroscoding for the report.

[Bug]: Configuration keys named config were inadvertently
exposing the internal dict representation of the containing config object,
instead of displaying the actual value stored in that key. (Thus, a set
config of mycontext.foo.bar.config would act as if it was the key/value
contents of the mycontext.foo.bar subtree.) This has been fixed.

[Bug]: Python 3’s hashing rules differ from Python 2, specifically:

A class that overrides __eq__() and does not define __hash__() will
have its __hash__() implicitly set to None.

Config (specifically, its foundational class
DataProxy) only defined __eq__ which,
combined with the above behavior, meant that Config objects appeared to
hash successfully on Python 2 but yielded TypeErrors on Python 3.

This has been fixed by explicitly setting __hash__=None so that the
objects do not hash on either interpreter (there are no good immutable
attributes by which to define hashability).

[Support]#204: (via #412) Fall back to globally-installed copies of
our vendored dependencies, if the import from the vendor tree fails. In
normal situations this won’t happen, but it allows advanced users or
downstream maintainers to nuke vendor/ and prefer explicitly installed
packages of e.g. six, pyyaml or fluidity. Thanks to Athmane
Madjoudj for the patch.

[Feature]#369: Overhaul the autoresponse functionality for run so
it’s significantly more extensible, both for its own sake and as part of
implementing #294 (see its own changelog entry for details).

Warning

This is a backwards incompatible change: the responses kwarg to
run() is now watchers, and accepts a list of
StreamWatcher objects (such as
Responder) instead of a dict.

If you were using run(...,responses={'pattern':'response'}
previously, just update to instead use run(...,watchers=[Responder('pattern','response')]).

[Feature]#294: Implement Context.sudo, which
wraps run inside a sudo command. It is capable
of auto-responding to sudo’s password prompt with a configured password,
and raises a specific exception (AuthFailure) if that
password is rejected.

[Feature]: Update implementation of Result so it has
default values for all parameters/attributes. This allows it to be more
easily used when mocking run calls in client libraries’ tests.

Warning

This is a backwards incompatible change if you are manually instantiating
Result objects with positional arguments: positional
argument order has changed. (Compare the API docs between versions to see
exactly how.)

[Feature]#406: Update handling of Ctrl-C/KeyboardInterrupt, and
subprocess exit status pass-through, to be more correct than before:

Submit the interrupt byte sequence \x03 to stdin of all subprocesses,
instead of sending SIGINT.

This results in behavior closer to that of truly pressing Ctrl-C when
running subprocesses directly; for example, interactive programs like
vim or python now behave normally instead of prematurely
exiting.

Of course, programs that would normally exit on Ctrl-C will still do
so!

The exit statuses of subprocesses run with pty=True are more rigorously
checked (using os.WIFEXITED and friends), allowing us to surface the real
exit values of interrupted programs instead of manually assuming exit code
130.

Typically, this will be exit code -2, but it is system dependent.

Other, non-Ctrl-C-driven signal-related exits under PTYs should behave
better now as well - previously they could appear to exit 0!

Non-subprocess-related KeyboardInterrupt (i.e. those generated when
running top level Python code outside of any run function calls)
will now trigger exit code 1, as that is how the Python interpreter
typically behaves if you KeyboardInterrupt it outside of a live
REPL.

Warning

These changes are backwards incompatible if you were relying on the
“exits 130” behavior added in version 0.13, or on the (incorrect)
SIGINT method of killing pty-driven subprocesses on Ctrl-C.

[Feature]: Expose the (normalized) value of run’s
hide parameter in its return-value Result objects.

[Bug]: Fix a bug in Config.clone where
it was instantiating a new Config instead of a member of the subclass.

[Bug]: Correctly raise TypeError when unexpected keyword
arguments are given to run.

[Bug]#58: Work around bugs in select() when handling subprocess
stream reads, which was causing poor behavior in many nontrivial interactive
programs (such as vim and other fullscreen editors, python and other
REPLs/shells, etc). Such programs should now be largely indistinguishable
from their behavior when run directly from a user’s shell.

[Bug]: Fix DataProxy (used within Context and
Config) so that real attributes and methods which are
shadowed by configuration keys, aren’t proxied to the config during regular
attribute get/set. (Such config keys are thus required to be accessed via
dict-style only, or (on Context) via the explicit
.config attribute.)

[Bug]#283: Fix the concepts/library docs so the example of an explicit
namespace= argument correctly shows wrapping an imported task module in a
Collection. Thanks to @zaiste for the report.

[Bug]#288: Address a bug preventing reuse of Invoke as a custom
binstub, by moving --list into the “core args” set of flags present on
all Invoke-derived binstubs. Thanks to Jordon Mears for catch & patch.

[Bug]#349: Display the string representation of
UnexpectedExit when handling it inside of
Program (including regular inv), if any output was
hidden during the run that generated it.

Previously, we only exited with the exception’s stored exit code, meaning
failures of run(...,hide=True) commands were unexpectedly silent.
(Library-style use of the codebase didn’t have this problem, since tracebacks
aren’t muted.)

While implementing this change, we also tweaked the overall display of
UnexpectedExit so it’s a bit more consistent & useful:

noting “hey, you ran with pty=True, so there’s no stderr”;

showing only the last 10 lines of captured output in the error message
(users can, of course, always manually handle the error & access the full
thing if desired);

only showing a given stream when it was not already printed to the user’s
terminal (i.e. if hide=False, no captured output is shown in the error
text; if hide='stdout', only stdout is shown in the error text; etc.)

[Feature]#67: Added shell option to run,
allowing control of the shell used when invoking commands. Previously,
pty=True used /bin/bash and pty=False (the default) used
/bin/sh; the new unified default value is /bin/bash.

Thanks to Jochen Breuer for the report.

[Feature]#259: (also #280) Allow updating (or replacing) subprocess
shell environments, via the env and replace_env kwargs to
run. Thanks to Fotis Gimian for the report,
@philtay for an early version of the final patch, and Erich Heine & Vlad
Frolov for feedback.

[Feature]#114: Ripped off the band-aid and removed non-contextualized tasks
as an option; all tasks must now be contextualized (defined as defmytask(context,...) - see Defining and running task functions) even
if not using the context. This simplifies the implementation as well as
users’ conceptual models. Thanks to Bay Grabowski for the patch.

Warning

This is a backwards incompatible change!

[Bug]#152: (also #251, #331) Correctly handle
KeyboardInterrupt during run, re: both mirroring
the interrupt signal to the subprocess and capturing the local exception
within Invoke’s CLI handler (so there’s no messy traceback, just exiting with
code 130).

Thanks to Peter Darrow for the report, and to Mika Eloranta & Máté Farkas for
early versions of the patchset.

[Bug]#351: Protect against run deadlocks involving exceptions in
I/O threads & nontrivial amounts of unread data in the corresponding
subprocess pipe(s). This situation should now always result in exceptions
instead of hangs.

[Bug]#303: Make sure run waits for its IO worker threads to cleanly
exit (such as allowing a finally block to revert TTY settings) when
KeyboardInterrupt (or similar) aborts execution in the main thread.
Thanks to Tony S Yu and Máté Farkas for the report.

[Bug]#308: Earlier changes to TTY detection & its use in determining features
such as stdin pass-through, were insufficient to handle edge cases such as
nested Invoke sessions or piped stdin to Invoke processes. This manifested as
hangs and OSError messages about broken pipes.

The issue has been fixed by overhauling all related code to use more specific
and accurate checks (e.g. examining just fileno and/or just isatty).

Thanks to Tuukka Mustonen and Máté Farkas for the report (and for enduring
the subsequent flood of the project maintainer’s stream-of-consciousness
ticket updates).

[Feature]#173: Overhauled top level CLI functionality to allow reusing
Invoke for distinct binaries, optionally with bundled task namespaces as
subcommands. As a side effect, this functionality is now much more extensible
to boot. Thanks to Erich Heine for feedback/suggestions during development.

Warning

This change is backwards incompatible if you imported anything from the
invoke.cli module (which is now rearchitected as
Program). It should be transparent to everybody else.

[Bug]: Fixed a bug in the parser where invoke--takes-optional-argavalue--anotherflag was incorrectly considering --anotherflag to be an
ambiguity error (as if avalue had not been given to
--takes-optional-arg.

[Bug]#295: Make sure that run’s hide=True also disables
echoing. Otherwise, “hidden” helper run calls will still pollute output
when run as e.g. invoke--echo....

[Bug]#257: Fix a RecursionError under Python 3 due to lack of
__deepcopy__ on Call objects. Thanks to Markus
Zapke-Gründemann for initial report and Máté Farkas for the patch.

[Support]: Fix incorrect changelog URL in package metadata.

[Support]: Removed the -H short flag, leaving just --hide. This was
done to avoid conflicts with Fabric’s host-oriented -H flag. Favoritism
is real! Apologies.

Warning

This change is backwards compatible if you used -H.

[Support]: Removed official Python 3.2 support; sibling projects also did
this recently, it’s simply not worth the annoyance given the userbase size.

[Support]#144: Add code-coverage reporting to our CI builds (albeit CodeCov instead of coveralls.io).
Includes rejiggering our project-specific coverage-generating tasks. Thanks
to David Baumgold for the original request/PR and to Justin Abrahms for the
tipoff re: CodeCov.

[Feature]#235: Allow custom stream objects to be used in run calls,
to be used instead of the defaults of sys.stdout/sys.stderr.

Warning

This change required a major cleanup/rearchitecture of the command
execution implementation. The vendored pexpect module has been
completely removed and the API of the Runner class has
changed dramatically (though the API for run() itself has not).

Be aware there may be edge-case terminal behaviors which have changed or
broken as a result of removing pexpect. Please report these as bugs! We
expect to crib small bits of what pexpect does but need concrete test
cases first.

[Feature]: Detect local controlling terminal size
(pty_size) and apply that information when creating
pseudoterminals in run when pty=True.

[Feature]: Add a .command attribute to Result to
preserve the command executed for post-execution introspection.

[Bug]#238: (partial fix) Update the zsh completion script to
account for use of the --collection core flag.

[Bug]#239: Completion erroneously presented core flags instead of
per-task flags when both are present in the invocation being completed (e.g.
inv--debugmy_task-<tab>). This has been fixed.

[Bug]#237: Completion output lacked “inverse” flag names (e.g.
--no-myoption as a boolean negative version of a defaulting-to-True
boolean myoption). This has been corrected.

[Bug]#234: (also #243) Preserve task-module load location when
creating explicit collections with
from_module; when this was not done,
project-local config files were not loading correctly. Thanks to @brutus
and Jan Willems for initial report & troubleshooting, and to Greg Back for
identifying the fix.

[Bug]: Capture & reraise exceptions generated by command execution I/O
threads, in the main thread, as a ThreadException.

[Bug]: Display stdout instead of stderr in the repr() of
Failure objects, when a pseudo-terminal was used.
Previously, failure display focused on the stderr stream, which is always
empty under pseudo-terminals.

[Support]: Tweak README to reflect recent(-ish) changes in
pip re: users who install the development version via pip instead of
using git.

[Support]: Additional rearranging of run/Runner related concerns
for improved subclassing, organization, and use in other libraries,
including:

Changed the name of the runner module to runners.

Moved the top level run function from its original home in
invoke.runner to invoke.__init__, to reflect the fact that
it’s now simply a convenience wrapper around Runner.

Tweaked the implementation of Runner so it can
reference Context objects (useful for anticipated
subclasses).

Warning

These are backwards incompatible changes if your code was doing any imports
from the invoke.runner module (including especially
invoke.runner.run, which is now only invoke.run). Function
signatures have not changed.

[Feature]#147: Drastically overhaul/expand the configuration system to
account for multiple configuration levels including (but not limited to) file
paths, environment variables, and Python-level constructs (previously the
only option). See Configuration for details. Thanks to Erich Heine for
his copious feedback on this topic.

Warning

This is technically a backwards incompatible change, though some existing
user config-setting code may continue to work as-is. In addition, this
system may see further updates before 1.0.

[Feature]#219: Fall back to non-PTY command execution in situations where
pty=True but no PTY appears present. See Local for
details.

[Feature]#104: Add core CLI flag --complete to support shell tab
completion scripts, and add some ‘blessed’ such scripts for bash (3 and 4)
and zsh. Thanks to Ivan Malison and Andrew Roberts for providing discussion &
early patchsets.

[Bug]#175:autoprint did not function correctly for tasks stored
in sub-collections; this has been fixed. Credit: Matthias Lehmann.

[Bug]#180: Empty invocation (e.g. just invoke with no flags or
tasks, and when no default task is defined) no longer printed help output,
instead complaining about the lack of default task. It now prints help again.
Thanks to Brent O’Connor for the catch.

[Bug]#183: Task docstrings whose first line started on the same line as
the opening quote(s) were incorrectly presented in invoke--help<task>.
This has been fixed by using inspect.getdoc. Thanks to Pekka Klärck for the
catch & suggested fix.

[Bug]#201: (also #211) Replace the old, first-draft gross
monkeypatched Popen code used for invoke.runner.run with a
non-monkeypatched approach that works better on non-POSIX platforms like
Windows, and also attempts to handle encoding and locale issues more
gracefully (meaning: at all gracefully).

Specifically, the new approach uses threading instead of select.select,
and performs explicit encoding/decoding based on detected or explicitly
expressed encodings.

Major thanks to Paul Moore for an enormous amount of
testing/experimentation/discussion, as well as the bulk of the code changes
themselves.

Warning

The top level invoke.runner.run function has had a minor signature
change: the sixth positional argument used to be runner and is now
encoding (with runner now being the seventh positional argument).

[Support]#212: Implement basic linting support using flake8, and apply
formatting changes to satisfy said linting. As part of this shakeup, also
changed all old-style (%s) string formatting to new-style ({0}).
Thanks to Collin Anderson for the foundational patch.

This includes backwards incompatible changes to the API signature of most
members of the invoke.runner module, including invoke.runner.run.
(However, in the case of invoke.runner.run, the changes are mostly in
the later, optional keyword arguments.)

[Feature]#136: Added the autoprint flag to
invoke.tasks.Task/@task, allowing users to set up
tasks which act as both subroutines & “print a result” CLI tasks. Thanks to
Matthias Lehmann for the original patch.

[Bug]: Fixed a sub-case of the already-mostly-fixed #149 so
the error message works usefully even with no explicit collection name given.

[Bug]#142: The refactored Loader class failed to account for the behavior of
imp.find_module when run against packages (vs modules) and was exploding at
load time. This has been fixed. Thanks to David Baumgold for catch & patch.

[Bug]#140: Revert incorrect changes to our setup.py regarding detection
of sub-packages such as the vendor tree & the parser. Also add additional
scripting to our Travis-CI config to catch this class of error in future.
Thanks to Steven Loria and James Cox for the reports.

[Feature]#124: Add a --debug flag to the core parser to enable easier
debugging (on top of existing INVOKE_DEBUG env var.)

[Feature]#87: (also #92) Rework the loader module such that recursive
filesystem searching is implemented, and is used instead of searching
sys.path.

This adds the behavior most users expect or are familiar with from Fabric 1
or similar tools; and it avoids nasty surprise collisions with other
installed packages containing files named tasks.py.

Thanks to Michael Hahn for the original report & PR, and to Matt Iversen for
providing the discovery algorithm used in the final version of this change.

Warning

This is technically a backwards incompatible change (reminder: we’re not
at 1.0 yet!). You’ll only notice if you were relying on adding your tasks
module to sys.path and then calling Invoke elsewhere on the
filesystem.

[Feature]#110: Add task docstrings’ 1st lines to --list output. Thanks to
Hiroki Kiyohara for the original PR (with assists from Robert Read and James
Thigpen.)

[Feature]#115: Make it easier to reuse Invoke’s primary CLI machinery in
other (non-Invoke-distributed) bin-scripts. Thanks to Noah Kantrowitz.

[Bug]#131: Make sure one’s local tasks module is always first in
sys.path, even if its parent directory was already somewhere else in
sys.path. This ensures that local tasks modules never become hidden by
third-party ones. Thanks to @crccheck for the early report and to Dorian
Puła for assistance fixing.

[Feature]#57: Optional-value flags added - e.g. --foo tells the parser to
set the foo option value to True; --foomyval sets the value to
“myval”. The built-in --help option now leverages this feature for
per-task help (e.g. --help displays global help, --helpmytask
displays help for mytask only.)

[Bug]#55: A bug in our vendored copy of pexpect clashed with a
Python 2->3 change in import behavior to prevent Invoke from running on
Python 3 unless the six module was installed in one’s environment. This
was fixed - our vendored pexpect now always loads its sibling vendored
six correctly.