summaryrefslogtreecommitdiff
path: root/docs/advanced.rst
blob: 400bcab5826fcdf589a93bad6fa6b2aed644ec2d (plain)
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
Advanced Patterns
=================

.. currentmodule:: click

In addition to common functionality that is implemented in the library
itself, there are countless patterns that can be implemented by extending
click.  This page should give some insight into what can be accomplished.

.. _aliases:

Command Aliases
---------------

Many tools support aliases for commands.  For instance, you can configure
``git`` to accept ``git ci`` as alias for ``git commit``.  Other tools
also support auto-discovery for aliases by automatically shortening them.

Click does not support this out of the box, but it's very easy to customize
the :class:`Group` or any other :class:`MultiCommand` to provide this
functionality.

As explained in :ref:`custom-multi-commands`, a multi command can provide
two methods: :meth:`~MultiCommand.list_commands` and
:meth:`~MultiCommand.get_command`.  In this particular case, you only need
to override the latter as you generally don't want to enumerate the
aliases on the help page in order to avoid confusion.

This following example implements a subclass of :class:`Group` that
accepts a prefix for a command.  If there were a command called ``push``,
it would accept ``pus`` as an alias (so long as it was unique):

.. click:example::

    class AliasedGroup(click.Group):

        def get_command(self, ctx, cmd_name):
            rv = click.Group.get_command(self, ctx, cmd_name)
            if rv is not None:
                return rv
            matches = [x for x in self.list_commands(ctx)
                       if x.startswith(cmd_name)]
            if not matches:
                return None
            elif len(matches) == 1:
                return click.Group.get_command(self, ctx, matches[0])
            ctx.fail('Too many matches: %s' % ', '.join(sorted(matches)))

And it can then be used like this:

.. click:example::

    @click.command(cls=AliasedGroup)
    def cli():
        pass

    @cli.command()
    def push():
        pass

    @cli.command()
    def pop():
        pass

Token Normalization
-------------------

.. versionadded:: 2.0

Starting with click 2.0, it's possible to provide a function that is used
for normalizing tokens.  Tokens are option names, choice values, or command
values.  This can be used to implement case insensitive options, for
instance.

In order to use this feature, the context needs to be passed a function that
performs the normalization of the token.  For instance, you could have a
function that converts the token to lowercase:

.. click:example::

    CONTEXT_SETTINGS = dict(token_normalize_func=lambda x: x.lower())

    @click.command(context_settings=CONTEXT_SETTINGS)
    @click.option('--name', default='Pete')
    def cli(name):
        click.echo('Name: %s' % name)

And how it works on the command line:

.. click:run::

    invoke(cli, prog_name='cli', args=['--NAME=Pete'])

Invoking Other Commands
-----------------------

Sometimes, it might be interesting to invoke one command from another
command.  This is a pattern that is generally discouraged with click, but
possible nonetheless.  For this, you can use the :func:`Context.invoke`
or :func:`Context.forward` methods.

They work similarly, but the difference is that :func:`Context.invoke` merely
invokes another command with the arguments you provide as a caller,
whereas :func:`Context.forward` fills in the arguments from the current
command.  Both accept the command as the first argument and everything else
is passed onwards as you would expect.

Example:

.. click:example::

    cli = click.Group()

    @cli.command()
    @click.option('--count', default=1)
    def test(count):
        click.echo('Count: %d' % count)

    @cli.command()
    @click.option('--count', default=1)
    @click.pass_context
    def dist(ctx, count):
        ctx.forward(test)
        ctx.invoke(test, count=42)

And what it looks like:

.. click:run::

    invoke(cli, prog_name='cli', args=['dist'])


.. _callback-evaluation-order:

Callback Evaluation Order
-------------------------

Click works a bit differently than some other command line parsers in that
it attempts to reconcile the order of arguments as defined by the
programmer with the order of arguments as defined by the user before
invoking any callbacks.

This is an important concept to understand when porting complex
patterns to click from optparse or other systems.  A parameter
callback invocation in optparse happens as part of the parsing step,
whereas a callback invocation in click happens after the parsing.

The main difference is that in optparse, callbacks are invoked with the raw
value as it happens, whereas a callback in click is invoked after the
value has been fully converted.

Generally, the order of invocation is driven by the order in which the user
provides the arguments to the script; if there is an option called ``--foo``
and an option called ``--bar`` and the user calls it as ``--bar
--foo``, then the callback for ``bar`` will fire before the one for ``foo``.

There are two exceptions to this rule which are important to know:

Eagerness:
    An option can be set to be "eager".  All eager parameters are
    evaluated before all non-eager parameters, but again in the order as
    they were provided on the command line by the user.

    This is important for parameters that execute and exit like ``--help``
    and ``--version``.  Both are eager parameters, but whatever parameter
    comes first on the command line will win and exit the program.

Repeated parameters:
    If an option or argument is split up on the command line into multiple
    places because it is repeated -- for instance, ``--exclude foo --include
    baz --exclude bar`` -- the callback will fire based on the position of
    the first option.  In this case, the callback will fire for
    ``exclude`` and it will be passed both options (``foo`` and
    ``bar``), then the callback for ``include`` will fire with ``baz``
    only.

    Note that even if a parameter does not allow multiple versions, click
    will still accept the position of the first, but it will ignore every
    value except the first.  The reason for this is to allow composability
    through shell aliases that set defaults.

Missing parameters:
    If a parameter is not defined on the command line, the callback will
    still fire.  This is different from how it works in optparse where
    undefined values do not fire the callback.  Missing parameters fire
    their callbacks at the very end which makes it possible for them to
    default to values from a parameter that came before.

Most of the time you do not need to be concerned about any of this,
but it is important to know how it works for some advanced cases.