File: faq.rst

package info (click to toggle)
python-invoke 0.11.1%2Bdfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 1,136 kB
  • ctags: 1,702
  • sloc: python: 5,614; makefile: 37; sh: 36
file content (142 lines) | stat: -rw-r--r-- 5,672 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
==========================
Frequently asked questions
==========================


General project questions
=========================

Why was Invoke split off from the `Fabric <http://fabfile.org>`_ project?
-------------------------------------------------------------------------

Fabric (1.x and earlier) was a hybrid project implementing two feature sets:
task execution (organization of task functions, execution of them via CLI, and
local shell commands) and high level SSH actions (organization of
servers/hosts, remote shell commands, and file transfer).

For use cases requiring both feature sets, this arrangement worked well.
However, over time it became clear many users only needed one or the other,
with local-only users resenting heavy SSH/crypto install requirements, and
remote-focused users struggling with API limitations caused by the hybrid
codebase.

When planning Fabric 2.x, having the "local" feature set as a standalone
library made sense, and it seemed plausible to design the SSH component as a
separate layer above. Thus, Invoke was created to focus exclusively on local
and abstract concerns, leaving Fabric 2.x concerned only with servers and
network commands.

Fabric 2 will leverage parts of Invoke's API, and allow (but not require!) use
of Invoke's CLI features, allowing multiple use cases (build tool, high level
SSH lib, hybrid build/orchestration tool) to coexist without negatively
impacting each other.

For more info on how this relates to Fabric specifically, please see `Fabric's
roadmap <http://fabfile.org/roadmap.html>`_.


Defining/executing tasks
========================

.. _bad-first-arg:

My task's first argument isn't showing up in ``--help``!
--------------------------------------------------------

Make sure your task isn't :ref:`contextualized <concepts-context>`
unexpectedly! Put another way, this problem pops up if you're using `@ctask
<invoke.tasks.ctask>` and forget to define an initial context argument for
your task.

For example, can you spot the problem in this sample task file?

::

    from invoke import ctask as task

    @task
    def build(ctx, where, clean=False):
        pass

    @task
    def clean(what):
        pass

This task file doesn't cause obvious errors when sanity-checking it with
``inv --list`` or ``inv --help``. However, ``clean`` forgot to set aside its
first argument for the context - so Invoke is treating ``what`` as the context
argument! This means it doesn't show up in help output or other command-line
parsing stages.


The command line says my task's first argument is invalid!
----------------------------------------------------------

See :ref:`bad-first-arg` - it's probably the same issue.



Running local shell commands (``run``)
======================================

Calling Python or Python scripts prints all the output at the end of the run!
-----------------------------------------------------------------------------

.. note::
    This is typically a problem under Python 3 only.

The symptom is easy to spot - you're running a command that takes a few seconds
or more to execute, it usually prints lines of text as it goes, but via
`~invoke.run` nothing appears to happen at first, and then all the output
prints once it's done executing.

This is usually due to Python - the "inner" Python executable you're invoking,
not the one Invoke is running under - performing unwanted buffering of its
output streams. It does this when it thinks it's being called in a
non-interactive fashion.

The fix is simple - force Invoke to run the command in a pseudoterminal by
saying ``pty=True`` (e.g. ``run("python foo", pty=True)``).

Alternately, since both Invoke and the inner command are Python, you could try
loading the inner Python module directly in your Invoke-using code, and call
whichever methods its command-line stub is using - instead of using
`~invoke.run`. This can often have other benefits too.


Why is my command behaving differently under Invoke versus being run by hand?
-----------------------------------------------------------------------------

99% of the time, adding ``pty=True`` to your ``run`` call will make things work
as you were expecting. Read on for why this is (and why ``pty=True`` is not the
default).

Command-line programs often change behavior depending on whether a controlling
terminal is present; a common example is the use or disuse of colored output.
When the recipient of your output is a human at a terminal, you may want to use
color, tailor line length to match terminal width, etc.

Conversely, when your output is being sent to another program (shell pipe, CI
server, file, etc) color escape codes and other terminal-specific behaviors can
result in unwanted garbage.

Invoke's use cases span both of the above - sometimes you only want data
displayed directly, sometimes you only want to capture it as a string; often
you want both. Because of this, there is no "correct" default behavior re: use
of a pseudo-terminal - some large chunk of use cases will be inconvenienced
either way.

For use cases which don't care, direct invocation without a pseudo-terminal is
faster & cleaner, so it is the default.


Everything just exits silently after I run a command!
-----------------------------------------------------

Double check the command's exit code! By default, any nonzero exit code results
in Invoke halting execution & exiting with that same exit code. Some programs
(pylint, Nagios check scripts, etc) use exit codes to indicate non-fatal
status, which can be confusing.

The solution here is simple: add ``warn=True`` to your `~invoke.run` call,
which disables the automatic exit behavior.