Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stable #2797

Closed
wants to merge 17 commits into from
Closed

Stable #2797

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Unreleased
:issue:`2705`
- Show correct value for flag default when using ``default_map``.
:issue:`2632`
- Fix ``click.echo(color=...)`` passing ``color`` to coloroma so it can be
forced on Windows. :issue:`2606`.


Version 8.1.7
Expand Down
3 changes: 3 additions & 0 deletions docs/arguments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ file in the same folder, and upon completion, the file will be moved over to
the original location. This is useful if a file regularly read by other
users is modified.


.. _environment-variables:

Environment Variables
---------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/documentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ And what it looks like:
.. _documenting-arguments:

Documenting Arguments
~~~~~~~~~~~~~~~~~~~~~
----------------------

:func:`click.argument` does not take a ``help`` parameter. This is to
follow the general convention of Unix tools of using arguments for only
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ usage patterns.

why
quickstart
virtualenv
setuptools
parameters
options
Expand Down
112 changes: 53 additions & 59 deletions docs/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,60 @@ Parameters

.. currentmodule:: click

Click supports two types of parameters for scripts: options and arguments.
There is generally some confusion among authors of command line scripts of
when to use which, so here is a quick overview of the differences. As its
name indicates, an option is optional. While arguments can be optional
within reason, they are much more restricted in how optional they can be.

To help you decide between options and arguments, the recommendation is
to use arguments exclusively for things like going to subcommands or input
filenames / URLs, and have everything else be an option instead.

Differences
-----------

Arguments can do less than options. The following features are only
available for options:

* automatic prompting for missing input
* act as flags (boolean or otherwise)
* option values can be pulled from environment variables, arguments can not
* options are fully documented in the help page, arguments are not
(:ref:`this is intentional <documenting-arguments>` as arguments
might be too specific to be automatically documented)

On the other hand arguments, unlike options, can accept an arbitrary number
of arguments. Options can strictly ever only accept a fixed number of
arguments (defaults to 1), or they may be specified multiple times using
:ref:`multiple-options`.
Click supports only two types of parameters for scripts (by design): options and arguments.

Options
----------------

* Are optional.
* Recommended to use for everything except subcommands, urls, or files.
* Can take a fixed number of arguments. The default is 1. They may be specified multiple times using :ref:`multiple-options`.
* Are fully documented by the help page.
* Have automatic prompting for missing input.
* Can act as flags (boolean or otherwise).
* Can be pulled from environment variables.

Arguments
----------------

* Are optional with in reason, but not entirely so.
* Recommended to use for subcommands, urls, or files.
* Can take an arbitrary number of arguments.
* Are not fully documented by the help page since they may be too specific to be automatically documented. For more see :ref:`documenting-arguments`.
* Can be pulled from environment variables but only explicitly named ones. For more see :ref:`environment-variables`.

.. _parameter_names:

Parameter Names
---------------

Parameters (options and arguments) have a name that will be used as
the Python argument name when calling the decorated function with
values.

.. click:example::

@click.command()
@click.argument('filename')
@click.option('-t', '--times', type=int)
def multi_echo(filename, times):
"""Print value filename multiple times."""
for x in range(times):
click.echo(filename)

In the above example the argument's name is ``filename``. The name must match the python arg name. To provide a different name for use in help text, see :ref:`doc-meta-variables`.
The option's names are ``-t`` and ``--times``. More names are available for options and are covered in :ref:`options`.

And what it looks like when run:

.. click:run::

invoke(multi_echo, ['--times=3', 'index.txt'], prog_name='multi_echo')

Parameter Types
---------------

Parameters can be of different types. Types can be implemented with
different behavior and some are supported out of the box:
The supported parameter types are:

``str`` / :data:`click.STRING`:
The default parameter type which indicates unicode strings.
Expand Down Expand Up @@ -74,37 +95,10 @@ different behavior and some are supported out of the box:
.. autoclass:: DateTime
:noindex:

Custom parameter types can be implemented by subclassing
:class:`click.ParamType`. For simple cases, passing a Python function that
fails with a `ValueError` is also supported, though discouraged.

.. _parameter_names:

Parameter Names
---------------

Parameters (both options and arguments) have a name that will be used as
the Python argument name when calling the decorated function with
values.

Arguments take only one positional name. To provide a different name for
use in help text, see :ref:`doc-meta-variables`.

Options can have many names that may be prefixed with one or two dashes.
Names with one dash are parsed as short options, names with two are
parsed as long options. If a name is not prefixed, it is used as the
Python argument name and not parsed as an option name. Otherwise, the
first name with a two dash prefix is used, or the first with a one dash
prefix if there are none with two. The prefix is removed and dashes are
converted to underscores to get the Python argument name.


Implementing Custom Types
-------------------------
How to Implement Custom Types
-------------------------------

To implement a custom type, you need to subclass the :class:`ParamType`
class. Override the :meth:`~ParamType.convert` method to convert the
value from a string to the correct type.
To implement a custom type, you need to subclass the :class:`ParamType` class. For simple cases, passing a Python function that fails with a `ValueError` is also supported, though discouraged. Override the :meth:`~ParamType.convert` method to convert the value from a string to the correct type.

The following code implements an integer type that accepts hex and octal
numbers in addition to normal integers, and converts them into regular
Expand Down
102 changes: 16 additions & 86 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,98 +3,28 @@ Quickstart

.. currentmodule:: click

You can get the library directly from PyPI::
Install
----------------------
Install from PyPI::

pip install click

The installation into a :ref:`virtualenv` is heavily recommended.
Installing into a virtual environment is highly recommended. We suggest :ref:`virtualenv-heading`.

.. _virtualenv:

virtualenv
----------

Virtualenv is probably what you want to use for developing Click
applications.

What problem does virtualenv solve? Chances are that you want to use it
for other projects besides your Click script. But the more projects you
have, the more likely it is that you will be working with different
versions of Python itself, or at least different versions of Python
libraries. Let's face it: quite often libraries break backwards
compatibility, and it's unlikely that any serious application will have
zero dependencies. So what do you do if two or more of your projects have
conflicting dependencies?

Virtualenv to the rescue! Virtualenv enables multiple side-by-side
installations of Python, one for each project. It doesn't actually
install separate copies of Python, but it does provide a clever way to
keep different project environments isolated.

Create your project folder, then a virtualenv within it::

$ mkdir myproject
$ cd myproject
$ python3 -m venv .venv

Now, whenever you want to work on a project, you only have to activate the
corresponding environment. On OS X and Linux, do the following::

$ . .venv/bin/activate
(venv) $

If you are a Windows user, the following command is for you::

> .venv\scripts\activate
(venv) >

Either way, you should now be using your virtualenv (notice how the prompt of
your shell has changed to show the active environment).

And if you want to stop using the virtualenv, use the following command::

$ deactivate

After doing this, the prompt of your shell should be as familiar as before.

Now, let's move on. Enter the following command to get Click activated in your
virtualenv::

$ pip install click

A few seconds later and you are good to go.

Screencast and Examples
Examples
-----------------------

There is a screencast available which shows the basic API of Click and
how to build simple applications with it. It also explores how to build
commands with subcommands.

* `Building Command Line Applications with Click
<https://www.youtube.com/watch?v=kNke39OZ2k0>`_

Examples of Click applications can be found in the documentation as well
as in the GitHub repository together with readme files:

* ``inout``: `File input and output
<https://github.com/pallets/click/tree/main/examples/inout>`_
* ``naval``: `Port of docopt naval example
<https://github.com/pallets/click/tree/main/examples/naval>`_
* ``aliases``: `Command alias example
<https://github.com/pallets/click/tree/main/examples/aliases>`_
* ``repo``: `Git-/Mercurial-like command line interface
<https://github.com/pallets/click/tree/main/examples/repo>`_
* ``complex``: `Complex example with plugin loading
<https://github.com/pallets/click/tree/main/examples/complex>`_
* ``validation``: `Custom parameter validation example
<https://github.com/pallets/click/tree/main/examples/validation>`_
* ``colors``: `Color support demo
<https://github.com/pallets/click/tree/main/examples/colors>`_
* ``termui``: `Terminal UI functions demo
<https://github.com/pallets/click/tree/main/examples/termui>`_
* ``imagepipe``: `Multi command chaining demo
<https://github.com/pallets/click/tree/main/examples/imagepipe>`_
Some standalone examples of Click applications are packaged with Click. They are available in the `examples folder <https://github.com/pallets/click/tree/main/examples>`_ of the repo.

* `inout <https://github.com/pallets/click/tree/main/examples/inout>`_ : A very simple example of an application that can read from files and write to files and also accept input from stdin or write to stdout.
* `validation <https://github.com/pallets/click/tree/main/examples/validation>`_ : A simple example of an application that performs custom validation of parameters in different ways.
* `naval <https://github.com/pallets/click/tree/main/examples/naval>`_ : Port of the `docopt <http://docopt.org/>`_ naval example.
* `colors <https://github.com/pallets/click/tree/main/examples/colors>`_ : A simple example that colorizes text. Uses colorama on Windows.
* `aliases <https://github.com/pallets/click/tree/main/examples/aliases>`_ : An advanced example that implements :ref:`aliases`.
* `imagepipe <https://github.com/pallets/click/tree/main/examples/imagepipe>`_ : A complex example that implements some :ref:`multi-command-chaining` . It chains together image processing instructions. Requires pillow.
* `repo <https://github.com/pallets/click/tree/main/examples/repo>`_ : An advanced example that implements a Git-/Mercurial-like command line interface.
* `complex <https://github.com/pallets/click/tree/main/examples/complex>`_ : A very advanced example that implements loading subcommands dynamically from a plugin folder.
* `termui <https://github.com/pallets/click/tree/main/examples/termui>`_ : A simple example that showcases terminal UI helpers provided by click.

Basic Concepts - Creating a Command
-----------------------------------
Expand Down
54 changes: 54 additions & 0 deletions docs/virtualenv.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.. _virtualenv-heading:

Virtualenv
=========================

Why Use Virtualenv?
-------------------------

You should use `Virtualenv <https://virtualenv.pypa.io/en/latest/>`_ because:

* It allows you to install multiple versions of the same dependency.

* If you have an operating system version of Python, it prevents you from changing its dependencies and potentially messing up your os.

How to Use Virtualenv
-----------------------------

Create your project folder, then a virtualenv within it::

$ mkdir myproject
$ cd myproject
$ python3 -m venv .venv

Now, whenever you want to work on a project, you only have to activate the
corresponding environment.

.. tabs::

.. group-tab:: OSX/Linux

.. code-block:: text

$ . .venv/bin/activate
(venv) $

.. group-tab:: Windows

.. code-block:: text

> .venv\scripts\activate
(venv) >


You are now using your virtualenv (notice how the prompt of your shell has changed to show the active environment).

To install packages in the virtual environment::

$ pip install click

And if you want to stop using the virtualenv, use the following command::

$ deactivate

After doing this, the prompt of your shell should be as familiar as before.
1 change: 1 addition & 0 deletions src/click/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .decorators import confirmation_option as confirmation_option
from .decorators import group as group
from .decorators import help_option as help_option
from .decorators import HelpOption as HelpOption
from .decorators import make_pass_decorator as make_pass_decorator
from .decorators import option as option
from .decorators import pass_context as pass_context
Expand Down
28 changes: 12 additions & 16 deletions src/click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1285,25 +1285,19 @@ def get_help_option_names(self, ctx: Context) -> t.List[str]:
return list(all_names)

def get_help_option(self, ctx: Context) -> t.Optional["Option"]:
"""Returns the help option object."""
"""Returns the help option object.

Unless ``add_help_option`` is ``False``.
"""
help_options = self.get_help_option_names(ctx)

if not help_options or not self.add_help_option:
return None

def show_help(ctx: Context, param: "Parameter", value: str) -> None:
if value and not ctx.resilient_parsing:
echo(ctx.get_help(), color=ctx.color)
ctx.exit()

return Option(
help_options,
is_flag=True,
is_eager=True,
expose_value=False,
callback=show_help,
help=_("Show this message and exit."),
)
# Avoid circular import.
from .decorators import HelpOption

return HelpOption(help_options)

def make_parser(self, ctx: Context) -> OptionParser:
"""Creates the underlying option parser for this command."""
Expand Down Expand Up @@ -2671,7 +2665,9 @@ def _parse_decls(
if name is None:
if not expose_value:
return None, opts, secondary_opts
raise TypeError("Could not determine name for option")
raise TypeError(
f"Could not determine name for option with declarations {decls!r}"
)

if not opts and not secondary_opts:
raise TypeError(
Expand Down Expand Up @@ -3011,7 +3007,7 @@ def _parse_decls(
if not decls:
if not expose_value:
return None, [], []
raise TypeError("Could not determine name for argument")
raise TypeError("Argument is marked as exposed, but does not have a name.")
if len(decls) == 1:
name = arg = decls[0]
name = name.replace("-", "_").lower()
Expand Down
Loading