Compare commits
No commits in common. "debian/master" and "pristine-tar" have entirely different histories.
debian/mas
...
pristine-t
|
@ -1,13 +0,0 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
max_line_length = 88
|
||||
|
||||
[*.{yml,yaml,json,js,css,html}]
|
||||
indent_size = 2
|
27
.github/ISSUE_TEMPLATE/bug-report.md
vendored
27
.github/ISSUE_TEMPLATE/bug-report.md
vendored
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Report a bug in Click (not other projects which depend on Click)
|
||||
---
|
||||
|
||||
<!--
|
||||
This issue tracker is a tool to address bugs in Click itself. Please use
|
||||
Pallets Discord or Stack Overflow for questions about your own code.
|
||||
|
||||
Replace this comment with a clear outline of what the bug is.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Describe how to replicate the bug.
|
||||
|
||||
Include a minimal reproducible example that demonstrates the bug.
|
||||
Include the full traceback if there was an exception.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Describe the expected behavior that should have happened but didn't.
|
||||
-->
|
||||
|
||||
Environment:
|
||||
|
||||
- Python version:
|
||||
- Click version:
|
11
.github/ISSUE_TEMPLATE/config.yml
vendored
11
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,11 +0,0 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Security issue
|
||||
url: security@palletsprojects.com
|
||||
about: Do not report security issues publicly. Email our security contact.
|
||||
- name: Questions
|
||||
url: https://stackoverflow.com/questions/tagged/python-click?tab=Frequent
|
||||
about: Search for and ask questions about your code on Stack Overflow.
|
||||
- name: Questions and discussions
|
||||
url: https://discord.gg/pallets
|
||||
about: Discuss questions about your code on our Discord chat.
|
15
.github/ISSUE_TEMPLATE/feature-request.md
vendored
15
.github/ISSUE_TEMPLATE/feature-request.md
vendored
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest a new feature for Click
|
||||
---
|
||||
|
||||
<!--
|
||||
Replace this comment with a description of what the feature should do.
|
||||
Include details such as links relevant specs or previous discussions.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Replace this comment with an example of the problem which this feature
|
||||
would resolve. Is this problem solvable without changes to Click,
|
||||
such as by subclassing or using an extension?
|
||||
-->
|
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
|
@ -1,9 +0,0 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
day: "monday"
|
||||
time: "16:00"
|
||||
timezone: "UTC"
|
30
.github/pull_request_template.md
vendored
30
.github/pull_request_template.md
vendored
|
@ -1,30 +0,0 @@
|
|||
<!--
|
||||
Before opening a PR, open a ticket describing the issue or feature the
|
||||
PR will address. Follow the steps in CONTRIBUTING.rst.
|
||||
|
||||
Replace this comment with a description of the change. Describe how it
|
||||
addresses the linked ticket.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Link to relevant issues or previous PRs, one per line. Use "fixes" to
|
||||
automatically close an issue.
|
||||
-->
|
||||
|
||||
- fixes #<issue number>
|
||||
|
||||
<!--
|
||||
Ensure each step in CONTRIBUTING.rst is complete by adding an "x" to
|
||||
each box below.
|
||||
|
||||
If only docs were changed, these aren't relevant and can be removed.
|
||||
-->
|
||||
|
||||
Checklist:
|
||||
|
||||
- [ ] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
|
||||
- [ ] Add or update relevant docs, in the docs folder and in code.
|
||||
- [ ] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
|
||||
- [ ] Add `.. versionchanged::` entries in any relevant code docs.
|
||||
- [ ] Run `pre-commit` hooks and fix any issues.
|
||||
- [ ] Run `pytest` and `tox`, no tests failed.
|
15
.github/workflows/lock.yaml
vendored
15
.github/workflows/lock.yaml
vendored
|
@ -1,15 +0,0 @@
|
|||
name: 'Lock threads'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: 14
|
||||
pr-inactive-days: 14
|
55
.github/workflows/tests.yaml
vendored
55
.github/workflows/tests.yaml
vendored
|
@ -1,55 +0,0 @@
|
|||
name: Tests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- '*.x'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- '*.rst'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- '*.x'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- '*.rst'
|
||||
jobs:
|
||||
tests:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {name: Linux, python: '3.10', os: ubuntu-latest, tox: py310}
|
||||
- {name: Windows, python: '3.10', os: windows-latest, tox: py310}
|
||||
- {name: Mac, python: '3.10', os: macos-latest, tox: py310}
|
||||
- {name: '3.11-dev', python: '3.11-dev', os: ubuntu-latest, tox: py311}
|
||||
- {name: '3.9', python: '3.9', os: ubuntu-latest, tox: py39}
|
||||
- {name: '3.8', python: '3.8', os: ubuntu-latest, tox: py38}
|
||||
- {name: '3.7', python: '3.7', os: ubuntu-latest, tox: py37}
|
||||
- {name: 'PyPy', python: 'pypy-3.7', os: ubuntu-latest, tox: pypy37}
|
||||
- {name: Typing, python: '3.10', os: ubuntu-latest, tox: typing}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/*.txt'
|
||||
- name: update pip
|
||||
run: |
|
||||
pip install -U wheel
|
||||
pip install -U setuptools
|
||||
python -m pip install -U pip
|
||||
- name: cache mypy
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ./.mypy_cache
|
||||
key: mypy|${{ matrix.python }}|${{ hashFiles('setup.cfg') }}
|
||||
if: matrix.tox == 'typing'
|
||||
- run: pip install tox
|
||||
- run: tox -e ${{ matrix.tox }}
|
16
.gitignore
vendored
16
.gitignore
vendored
|
@ -1,16 +0,0 @@
|
|||
/.idea/
|
||||
/.vscode/
|
||||
.DS_Store/
|
||||
/env/
|
||||
/venv/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.egg-info/
|
||||
/build/
|
||||
/dist/
|
||||
/.pytest_cache/
|
||||
/.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
/htmlcov/
|
||||
/docs/_build/
|
|
@ -1,32 +0,0 @@
|
|||
ci:
|
||||
autoupdate_branch: "8.1.x"
|
||||
autoupdate_schedule: monthly
|
||||
repos:
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.32.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ["--py37-plus"]
|
||||
- repo: https://github.com/asottile/reorder_python_imports
|
||||
rev: v3.1.0
|
||||
hooks:
|
||||
- id: reorder-python-imports
|
||||
args: ["--application-directories", "src"]
|
||||
additional_dependencies: ["setuptools>60.9"]
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 4.0.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
- flake8-bugbear
|
||||
- flake8-implicit-str-concat
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.2.0
|
||||
hooks:
|
||||
- id: fix-byte-order-marker
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
|
@ -1,13 +0,0 @@
|
|||
version: 2
|
||||
build:
|
||||
os: ubuntu-20.04
|
||||
tools:
|
||||
python: "3.10"
|
||||
python:
|
||||
install:
|
||||
- requirements: requirements/docs.txt
|
||||
- method: pip
|
||||
path: .
|
||||
sphinx:
|
||||
builder: dirhtml
|
||||
fail_on_warning: true
|
1044
CHANGES.rst
1044
CHANGES.rst
|
@ -1,1044 +0,0 @@
|
|||
.. currentmodule:: click
|
||||
|
||||
Version 8.1.3
|
||||
-------------
|
||||
|
||||
Released 2022-04-28
|
||||
|
||||
- Use verbose form of ``typing.Callable`` for ``@command`` and
|
||||
``@group``. :issue:`2255`
|
||||
- Show error when attempting to create an option with
|
||||
``multiple=True, is_flag=True``. Use ``count`` instead.
|
||||
:issue:`2246`
|
||||
|
||||
|
||||
Version 8.1.2
|
||||
-------------
|
||||
|
||||
Released 2022-03-31
|
||||
|
||||
- Fix error message for readable path check that was mixed up with the
|
||||
executable check. :pr:`2236`
|
||||
- Restore parameter order for ``Path``, placing the ``executable``
|
||||
parameter at the end. It is recommended to use keyword arguments
|
||||
instead of positional arguments. :issue:`2235`
|
||||
|
||||
|
||||
Version 8.1.1
|
||||
-------------
|
||||
|
||||
Released 2022-03-30
|
||||
|
||||
- Fix an issue with decorator typing that caused type checking to
|
||||
report that a command was not callable. :issue:`2227`
|
||||
|
||||
|
||||
Version 8.1.0
|
||||
-------------
|
||||
|
||||
Released 2022-03-28
|
||||
|
||||
- Drop support for Python 3.6. :pr:`2129`
|
||||
- Remove previously deprecated code. :pr:`2130`
|
||||
|
||||
- ``Group.resultcallback`` is renamed to ``result_callback``.
|
||||
- ``autocompletion`` parameter to ``Command`` is renamed to
|
||||
``shell_complete``.
|
||||
- ``get_terminal_size`` is removed, use
|
||||
``shutil.get_terminal_size`` instead.
|
||||
- ``get_os_args`` is removed, use ``sys.argv[1:]`` instead.
|
||||
|
||||
- Rely on :pep:`538` and :pep:`540` to handle selecting UTF-8 encoding
|
||||
instead of ASCII. Click's locale encoding detection is removed.
|
||||
:issue:`2198`
|
||||
- Single options boolean flags with ``show_default=True`` only show
|
||||
the default if it is ``True``. :issue:`1971`
|
||||
- The ``command`` and ``group`` decorators can be applied with or
|
||||
without parentheses. :issue:`1359`
|
||||
- The ``Path`` type can check whether the target is executable.
|
||||
:issue:`1961`
|
||||
- ``Command.show_default`` overrides ``Context.show_default``, instead
|
||||
of the other way around. :issue:`1963`
|
||||
- Parameter decorators and ``@group`` handles ``cls=None`` the same as
|
||||
not passing ``cls``. ``@option`` handles ``help=None`` the same as
|
||||
not passing ``help``. :issue:`#1959`
|
||||
- A flag option with ``required=True`` requires that the flag is
|
||||
passed instead of choosing the implicit default value. :issue:`1978`
|
||||
- Indentation in help text passed to ``Option`` and ``Command`` is
|
||||
cleaned the same as using the ``@option`` and ``@command``
|
||||
decorators does. A command's ``epilog`` and ``short_help`` are also
|
||||
processed. :issue:`1985`
|
||||
- Store unprocessed ``Command.help``, ``epilog`` and ``short_help``
|
||||
strings. Processing is only done when formatting help text for
|
||||
output. :issue:`2149`
|
||||
- Allow empty str input for ``prompt()`` when
|
||||
``confirmation_prompt=True`` and ``default=""``. :issue:`2157`
|
||||
- Windows glob pattern expansion doesn't fail if a value is an invalid
|
||||
pattern. :issue:`2195`
|
||||
- It's possible to pass a list of ``params`` to ``@command``. Any
|
||||
params defined with decorators are appended to the passed params.
|
||||
:issue:`2131`.
|
||||
- ``@command`` decorator is annotated as returning the correct type if
|
||||
a ``cls`` argument is used. :issue:`2211`
|
||||
- A ``Group`` with ``invoke_without_command=True`` and ``chain=False``
|
||||
will invoke its result callback with the group function's return
|
||||
value. :issue:`2124`
|
||||
- ``to_info_dict`` will not fail if a ``ParamType`` doesn't define a
|
||||
``name``. :issue:`2168`
|
||||
- Shell completion prioritizes option values with option prefixes over
|
||||
new options. :issue:`2040`
|
||||
- Options that get an environment variable value using
|
||||
``autoenvvar_prefix`` treat an empty value as ``None``, consistent
|
||||
with a direct ``envvar``. :issue:`2146`
|
||||
|
||||
|
||||
Version 8.0.4
|
||||
-------------
|
||||
|
||||
Released 2022-02-18
|
||||
|
||||
- ``open_file`` recognizes ``Path("-")`` as a standard stream, the
|
||||
same as the string ``"-"``. :issue:`2106`
|
||||
- The ``option`` and ``argument`` decorators preserve the type
|
||||
annotation of the decorated function. :pr:`2155`
|
||||
- A callable default value can customize its help text by overriding
|
||||
``__str__`` instead of always showing ``(dynamic)``. :issue:`2099`
|
||||
- Fix a typo in the Bash completion script that affected file and
|
||||
directory completion. If this script was generated by a previous
|
||||
version, it should be regenerated. :issue:`2163`
|
||||
- Fix typing for ``echo`` and ``secho`` file argument.
|
||||
:issue:`2174, 2185`
|
||||
|
||||
|
||||
Version 8.0.3
|
||||
-------------
|
||||
|
||||
Released 2021-10-10
|
||||
|
||||
- Fix issue with ``Path(resolve_path=True)`` type creating invalid
|
||||
paths. :issue:`2088`
|
||||
- Importing ``readline`` does not cause the ``confirm()`` prompt to
|
||||
disappear when pressing backspace. :issue:`2092`
|
||||
- Any default values injected by ``invoke()`` are cast to the
|
||||
corresponding parameter's type. :issue:`2089, 2090`
|
||||
|
||||
|
||||
Version 8.0.2
|
||||
-------------
|
||||
|
||||
Released 2021-10-08
|
||||
|
||||
- ``is_bool_flag`` is not set to ``True`` if ``is_flag`` is ``False``.
|
||||
:issue:`1925`
|
||||
- Bash version detection is locale independent. :issue:`1940`
|
||||
- Empty ``default`` value is not shown for ``multiple=True``.
|
||||
:issue:`1969`
|
||||
- Fix shell completion for arguments that start with a forward slash
|
||||
such as absolute file paths. :issue:`1929`
|
||||
- ``Path`` type with ``resolve_path=True`` resolves relative symlinks
|
||||
to be relative to the containing directory. :issue:`1921`
|
||||
- Completion does not skip Python's resource cleanup when exiting,
|
||||
avoiding some unexpected warning output. :issue:`1738, 2017`
|
||||
- Fix type annotation for ``type`` argument in ``prompt`` function.
|
||||
:issue:`2062`
|
||||
- Fix overline and italic styles, which were incorrectly added when
|
||||
adding underline. :pr:`2058`
|
||||
- An option with ``count=True`` will not show "[x>=0]" in help text.
|
||||
:issue:`2072`
|
||||
- Default values are not cast to the parameter type twice during
|
||||
processing. :issue:`2085`
|
||||
- Options with ``multiple`` and ``flag_value`` use the flag value
|
||||
instead of leaving an internal placeholder. :issue:`2001`
|
||||
|
||||
|
||||
Version 8.0.1
|
||||
-------------
|
||||
|
||||
Released 2021-05-19
|
||||
|
||||
- Mark top-level names as exported so type checking understand imports
|
||||
in user projects. :issue:`1879`
|
||||
- Annotate ``Context.obj`` as ``Any`` so type checking allows all
|
||||
operations on the arbitrary object. :issue:`1885`
|
||||
- Fix some types that weren't available in Python 3.6.0. :issue:`1882`
|
||||
- Fix type checking for iterating over ``ProgressBar`` object.
|
||||
:issue:`1892`
|
||||
- The ``importlib_metadata`` backport package is installed on Python <
|
||||
3.8. :issue:`1889`
|
||||
- Arguments with ``nargs=-1`` only use env var value if no command
|
||||
line values are given. :issue:`1903`
|
||||
- Flag options guess their type from ``flag_value`` if given, like
|
||||
regular options do from ``default``. :issue:`1886`
|
||||
- Added documentation that custom parameter types may be passed
|
||||
already valid values in addition to strings. :issue:`1898`
|
||||
- Resolving commands returns the name that was given, not
|
||||
``command.name``, fixing an unintended change to help text and
|
||||
``default_map`` lookups. When using patterns like ``AliasedGroup``,
|
||||
override ``resolve_command`` to change the name that is returned if
|
||||
needed. :issue:`1895`
|
||||
- If a default value is invalid, it does not prevent showing help
|
||||
text. :issue:`1889`
|
||||
- Pass ``windows_expand_args=False`` when calling the main command to
|
||||
disable pattern expansion on Windows. There is no way to escape
|
||||
patterns in CMD, so if the program needs to pass them on as-is then
|
||||
expansion must be disabled. :issue:`1901`
|
||||
|
||||
|
||||
Version 8.0.0
|
||||
-------------
|
||||
|
||||
Released 2021-05-11
|
||||
|
||||
- Drop support for Python 2 and 3.5.
|
||||
- Colorama is always installed on Windows in order to provide style
|
||||
and color support. :pr:`1784`
|
||||
- Adds a repr to Command, showing the command name for friendlier
|
||||
debugging. :issue:`1267`, :pr:`1295`
|
||||
- Add support for distinguishing the source of a command line
|
||||
parameter. :issue:`1264`, :pr:`1329`
|
||||
- Add an optional parameter to ``ProgressBar.update`` to set the
|
||||
``current_item``. :issue:`1226`, :pr:`1332`
|
||||
- ``version_option`` uses ``importlib.metadata`` (or the
|
||||
``importlib_metadata`` backport) instead of ``pkg_resources``. The
|
||||
version is detected based on the package name, not the entry point
|
||||
name. The Python package name must match the installed package
|
||||
name, or be passed with ``package_name=``. :issue:`1582`
|
||||
- If validation fails for a prompt with ``hide_input=True``, the value
|
||||
is not shown in the error message. :issue:`1460`
|
||||
- An ``IntRange`` or ``FloatRange`` option shows the accepted range in
|
||||
its help text. :issue:`1525`, :pr:`1303`
|
||||
- ``IntRange`` and ``FloatRange`` bounds can be open (``<``) instead
|
||||
of closed (``<=``) by setting ``min_open`` and ``max_open``. Error
|
||||
messages have changed to reflect this. :issue:`1100`
|
||||
- An option defined with duplicate flag names (``"--foo/--foo"``)
|
||||
raises a ``ValueError``. :issue:`1465`
|
||||
- ``echo()`` will not fail when using pytest's ``capsys`` fixture on
|
||||
Windows. :issue:`1590`
|
||||
- Resolving commands returns the canonical command name instead of the
|
||||
matched name. This makes behavior such as help text and
|
||||
``Context.invoked_subcommand`` consistent when using patterns like
|
||||
``AliasedGroup``. :issue:`1422`
|
||||
- The ``BOOL`` type accepts the values "on" and "off". :issue:`1629`
|
||||
- A ``Group`` with ``invoke_without_command=True`` will always invoke
|
||||
its result callback. :issue:`1178`
|
||||
- ``nargs == -1`` and ``nargs > 1`` is parsed and validated for
|
||||
values from environment variables and defaults. :issue:`729`
|
||||
- Detect the program name when executing a module or package with
|
||||
``python -m name``. :issue:`1603`
|
||||
- Include required parent arguments in help synopsis of subcommands.
|
||||
:issue:`1475`
|
||||
- Help for boolean flags with ``show_default=True`` shows the flag
|
||||
name instead of ``True`` or ``False``. :issue:`1538`
|
||||
- Non-string objects passed to ``style()`` and ``secho()`` will be
|
||||
converted to string. :pr:`1146`
|
||||
- ``edit(require_save=True)`` will detect saves for editors that exit
|
||||
very fast on filesystems with 1 second resolution. :pr:`1050`
|
||||
- New class attributes make it easier to use custom core objects
|
||||
throughout an entire application. :pr:`938`
|
||||
|
||||
- ``Command.context_class`` controls the context created when
|
||||
running the command.
|
||||
- ``Context.invoke`` creates new contexts of the same type, so a
|
||||
custom type will persist to invoked subcommands.
|
||||
- ``Context.formatter_class`` controls the formatter used to
|
||||
generate help and usage.
|
||||
- ``Group.command_class`` changes the default type for
|
||||
subcommands with ``@group.command()``.
|
||||
- ``Group.group_class`` changes the default type for subgroups
|
||||
with ``@group.group()``. Setting it to ``type`` will create
|
||||
subgroups of the same type as the group itself.
|
||||
- Core objects use ``super()`` consistently for better support of
|
||||
subclassing.
|
||||
|
||||
- Use ``Context.with_resource()`` to manage resources that would
|
||||
normally be used in a ``with`` statement, allowing them to be used
|
||||
across subcommands and callbacks, then cleaned up when the context
|
||||
ends. :pr:`1191`
|
||||
- The result object returned by the test runner's ``invoke()`` method
|
||||
has a ``return_value`` attribute with the value returned by the
|
||||
invoked command. :pr:`1312`
|
||||
- Required arguments with the ``Choice`` type show the choices in
|
||||
curly braces to indicate that one is required (``{a|b|c}``).
|
||||
:issue:`1272`
|
||||
- If only a name is passed to ``option()``, Click suggests renaming it
|
||||
to ``--name``. :pr:`1355`
|
||||
- A context's ``show_default`` parameter defaults to the value from
|
||||
the parent context. :issue:`1565`
|
||||
- ``click.style()`` can output 256 and RGB color codes. Most modern
|
||||
terminals support these codes. :pr:`1429`
|
||||
- When using ``CliRunner.invoke()``, the replaced ``stdin`` file has
|
||||
``name`` and ``mode`` attributes. This lets ``File`` options with
|
||||
the ``-`` value match non-testing behavior. :issue:`1064`
|
||||
- When creating a ``Group``, allow passing a list of commands instead
|
||||
of a dict. :issue:`1339`
|
||||
- When a long option name isn't valid, use ``difflib`` to make better
|
||||
suggestions for possible corrections. :issue:`1446`
|
||||
- Core objects have a ``to_info_dict()`` method. This gathers
|
||||
information about the object's structure that could be useful for a
|
||||
tool generating user-facing documentation. To get the structure of
|
||||
an entire CLI, use ``Context(cli).to_info_dict()``. :issue:`461`
|
||||
- Redesign the shell completion system. :issue:`1484`, :pr:`1622`
|
||||
|
||||
- Support Bash >= 4.4, Zsh, and Fish, with the ability for
|
||||
extensions to add support for other shells.
|
||||
- Allow commands, groups, parameters, and types to override their
|
||||
completions suggestions.
|
||||
- Groups complete the names commands were registered with, which
|
||||
can differ from the name they were created with.
|
||||
- The ``autocompletion`` parameter for options and arguments is
|
||||
renamed to ``shell_complete``. The function must take
|
||||
``ctx, param, incomplete``, must do matching rather than return
|
||||
all values, and must return a list of strings or a list of
|
||||
``CompletionItem``. The old name and behavior is deprecated and
|
||||
will be removed in 8.1.
|
||||
- The env var values used to start completion have changed order.
|
||||
The shell now comes first, such as ``{shell}_source`` rather
|
||||
than ``source_{shell}``, and is always required.
|
||||
|
||||
- Completion correctly parses command line strings with incomplete
|
||||
quoting or escape sequences. :issue:`1708`
|
||||
- Extra context settings (``obj=...``, etc.) are passed on to the
|
||||
completion system. :issue:`942`
|
||||
- Include ``--help`` option in completion. :pr:`1504`
|
||||
- ``ParameterSource`` is an ``enum.Enum`` subclass. :issue:`1530`
|
||||
- Boolean and UUID types strip surrounding space before converting.
|
||||
:issue:`1605`
|
||||
- Adjusted error message from parameter type validation to be more
|
||||
consistent. Quotes are used to distinguish the invalid value.
|
||||
:issue:`1605`
|
||||
- The default value for a parameter with ``nargs`` > 1 and
|
||||
``multiple=True`` must be a list of tuples. :issue:`1649`
|
||||
- When getting the value for a parameter, the default is tried in the
|
||||
same section as other sources to ensure consistent processing.
|
||||
:issue:`1649`
|
||||
- All parameter types accept a value that is already the correct type.
|
||||
:issue:`1649`
|
||||
- For shell completion, an argument is considered incomplete if its
|
||||
value did not come from the command line args. :issue:`1649`
|
||||
- Added ``ParameterSource.PROMPT`` to track parameter values that were
|
||||
prompted for. :issue:`1649`
|
||||
- Options with ``nargs`` > 1 no longer raise an error if a default is
|
||||
not given. Parameters with ``nargs`` > 1 default to ``None``, and
|
||||
parameters with ``multiple=True`` or ``nargs=-1`` default to an
|
||||
empty tuple. :issue:`472`
|
||||
- Handle empty env vars as though the option were not passed. This
|
||||
extends the change introduced in 7.1 to be consistent in more cases.
|
||||
:issue:`1285`
|
||||
- ``Parameter.get_default()`` checks ``Context.default_map`` to
|
||||
handle overrides consistently in help text, ``invoke()``, and
|
||||
prompts. :issue:`1548`
|
||||
- Add ``prompt_required`` param to ``Option``. When set to ``False``,
|
||||
the user will only be prompted for an input if no value was passed.
|
||||
:issue:`736`
|
||||
- Providing the value to an option can be made optional through
|
||||
``is_flag=False``, and the value can instead be prompted for or
|
||||
passed in as a default value.
|
||||
:issue:`549, 736, 764, 921, 1015, 1618`
|
||||
- Fix formatting when ``Command.options_metavar`` is empty. :pr:`1551`
|
||||
- Revert adding space between option help text that wraps.
|
||||
:issue:`1831`
|
||||
- The default value passed to ``prompt`` will be cast to the correct
|
||||
type like an input value would be. :pr:`1517`
|
||||
- Automatically generated short help messages will stop at the first
|
||||
ending of a phrase or double linebreak. :issue:`1082`
|
||||
- Skip progress bar render steps for efficiency with very fast
|
||||
iterators by setting ``update_min_steps``. :issue:`676`
|
||||
- Respect ``case_sensitive=False`` when doing shell completion for
|
||||
``Choice`` :issue:`1692`
|
||||
- Use ``mkstemp()`` instead of ``mktemp()`` in pager implementation.
|
||||
:issue:`1752`
|
||||
- If ``Option.show_default`` is a string, it is displayed even if
|
||||
``default`` is ``None``. :issue:`1732`
|
||||
- ``click.get_terminal_size()`` is deprecated and will be removed in
|
||||
8.1. Use :func:`shutil.get_terminal_size` instead. :issue:`1736`
|
||||
- Control the location of the temporary directory created by
|
||||
``CLIRunner.isolated_filesystem`` by passing ``temp_dir``. A custom
|
||||
directory will not be removed automatically. :issue:`395`
|
||||
- ``click.confirm()`` will prompt until input is given if called with
|
||||
``default=None``. :issue:`1381`
|
||||
- Option prompts validate the value with the option's callback in
|
||||
addition to its type. :issue:`457`
|
||||
- ``confirmation_prompt`` can be set to a custom string. :issue:`723`
|
||||
- Allow styled output in Jupyter on Windows. :issue:`1271`
|
||||
- ``style()`` supports the ``strikethrough``, ``italic``, and
|
||||
``overline`` styles. :issue:`805, 1821`
|
||||
- Multiline marker is removed from short help text. :issue:`1597`
|
||||
- Restore progress bar behavior of echoing only the label if the file
|
||||
is not a TTY. :issue:`1138`
|
||||
- Progress bar output is shown even if execution time is less than 0.5
|
||||
seconds. :issue:`1648`
|
||||
- Progress bar ``item_show_func`` shows the current item, not the
|
||||
previous item. :issue:`1353`
|
||||
- The ``Path`` param type can be passed ``path_type=pathlib.Path`` to
|
||||
return a path object instead of a string. :issue:`405`
|
||||
- ``TypeError`` is raised when parameter with ``multiple=True`` or
|
||||
``nargs > 1`` has non-iterable default. :issue:`1749`
|
||||
- Add a ``pass_meta_key`` decorator for passing a key from
|
||||
``Context.meta``. This is useful for extensions using ``meta`` to
|
||||
store information. :issue:`1739`
|
||||
- ``Path`` ``resolve_path`` resolves symlinks on Windows Python < 3.8.
|
||||
:issue:`1813`
|
||||
- Command deprecation notice appears at the start of the help text, as
|
||||
well as in the short help. The notice is not in all caps.
|
||||
:issue:`1791`
|
||||
- When taking arguments from ``sys.argv`` on Windows, glob patterns,
|
||||
user dir, and env vars are expanded. :issue:`1096`
|
||||
- Marked messages shown by the CLI with ``gettext()`` to allow
|
||||
applications to translate Click's built-in strings. :issue:`303`
|
||||
- Writing invalid characters to ``stderr`` when using the test runner
|
||||
does not raise a ``UnicodeEncodeError``. :issue:`848`
|
||||
- Fix an issue where ``readline`` would clear the entire ``prompt()``
|
||||
line instead of only the input when pressing backspace. :issue:`665`
|
||||
- Add all kwargs passed to ``Context.invoke()`` to ``ctx.params``.
|
||||
Fixes an inconsistency when nesting ``Context.forward()`` calls.
|
||||
:issue:`1568`
|
||||
- The ``MultiCommand.resultcallback`` decorator is renamed to
|
||||
``result_callback``. The old name is deprecated. :issue:`1160`
|
||||
- Fix issues with ``CliRunner`` output when using ``echo_stdin=True``.
|
||||
:issue:`1101`
|
||||
- Fix a bug of ``click.utils.make_default_short_help`` for which the
|
||||
returned string could be as long as ``max_width + 3``. :issue:`1849`
|
||||
- When defining a parameter, ``default`` is validated with
|
||||
``multiple`` and ``nargs``. More validation is done for values being
|
||||
processed as well. :issue:`1806`
|
||||
- ``HelpFormatter.write_text`` uses the full line width when wrapping
|
||||
text. :issue:`1871`
|
||||
|
||||
|
||||
Version 7.1.2
|
||||
-------------
|
||||
|
||||
Released 2020-04-27
|
||||
|
||||
- Revert applying shell quoting to commands for ``echo_with_pager``
|
||||
and ``edit``. This was intended to allows spaces in commands, but
|
||||
caused issues if the string was actually a command and arguments, or
|
||||
on Windows. Instead, the string must be quoted manually as it should
|
||||
appear on the command line. :issue:`1514`
|
||||
|
||||
|
||||
Version 7.1.1
|
||||
-------------
|
||||
|
||||
Released 2020-03-09
|
||||
|
||||
- Fix ``ClickException`` output going to stdout instead of stderr.
|
||||
:issue:`1495`
|
||||
|
||||
|
||||
Version 7.1
|
||||
-----------
|
||||
|
||||
Released 2020-03-09
|
||||
|
||||
- Fix PyPI package name, "click" is lowercase again.
|
||||
- Fix link in ``unicode_literals`` error message. :pr:`1151`
|
||||
- Add support for colored output on UNIX Jupyter notebooks.
|
||||
:issue:`1185`
|
||||
- Operations that strip ANSI controls will strip the cursor hide/show
|
||||
sequences. :issue:`1216`
|
||||
- Remove unused compat shim for ``bytes``. :pr:`1195`
|
||||
- Expand testing around termui, especially getchar on Windows.
|
||||
:issue:`1116`
|
||||
- Fix output on Windows Python 2.7 built with MSVC 14. :pr:`1342`
|
||||
- Fix ``OSError`` when running in MSYS2. :issue:`1338`
|
||||
- Fix ``OSError`` when redirecting to ``NUL`` stream on Windows.
|
||||
:issue:`1065`
|
||||
- Fix memory leak when parsing Unicode arguments on Windows.
|
||||
:issue:`1136`
|
||||
- Fix error in new AppEngine environments. :issue:`1462`
|
||||
- Always return one of the passed choices for ``click.Choice``
|
||||
:issue:`1277`, :pr:`1318`
|
||||
- Add ``no_args_is_help`` option to ``click.Command``, defaults to
|
||||
False :pr:`1167`
|
||||
- Add ``show_default`` parameter to ``Context`` to enable showing
|
||||
defaults globally. :issue:`1018`
|
||||
- Handle ``env MYPATH=''`` as though the option were not passed.
|
||||
:issue:`1196`
|
||||
- It is once again possible to call ``next(bar)`` on an active
|
||||
progress bar instance. :issue:`1125`
|
||||
- ``open_file`` with ``atomic=True`` retains permissions of existing
|
||||
files and respects the current umask for new files. :issue:`1376`
|
||||
- When using the test ``CliRunner`` with ``mix_stderr=False``, if
|
||||
``result.stderr`` is empty it will not raise a ``ValueError``.
|
||||
:issue:`1193`
|
||||
- Remove the unused ``mix_stderr`` parameter from
|
||||
``CliRunner.invoke``. :issue:`1435`
|
||||
- Fix ``TypeError`` raised when using bool flags and specifying
|
||||
``type=bool``. :issue:`1287`
|
||||
- Newlines in option help text are replaced with spaces before
|
||||
re-wrapping to avoid uneven line breaks. :issue:`834`
|
||||
- ``MissingParameter`` exceptions are printable in the Python
|
||||
interpreter. :issue:`1139`
|
||||
- Fix how default values for file-type options are shown during
|
||||
prompts. :issue:`914`
|
||||
- Fix environment variable automatic generation for commands
|
||||
containing ``-``. :issue:`1253`
|
||||
- Option help text replaces newlines with spaces when rewrapping, but
|
||||
preserves paragraph breaks, fixing multiline formatting.
|
||||
:issue:`834, 1066, 1397`
|
||||
- Option help text that is wrapped adds an extra newline at the end to
|
||||
distinguish it from the next option. :issue:`1075`
|
||||
- Consider ``sensible-editor`` when determining the editor to use for
|
||||
``click.edit()``. :pr:`1469`
|
||||
- Arguments to system calls such as the executable path passed to
|
||||
``click.edit`` can contains spaces. :pr:`1470`
|
||||
- Add ZSH completion autoloading and error handling. :issue:`1348`
|
||||
- Add a repr to ``Command``, ``Group``, ``Option``, and ``Argument``,
|
||||
showing the name for friendlier debugging. :issue:`1267`
|
||||
- Completion doesn't consider option names if a value starts with
|
||||
``-`` after the ``--`` separator. :issue:`1247`
|
||||
- ZSH completion escapes special characters in values. :pr:`1418`
|
||||
- Add completion support for Fish shell. :pr:`1423`
|
||||
- Decoding bytes option values falls back to UTF-8 in more cases.
|
||||
:pr:`1468`
|
||||
- Make the warning about old 2-arg parameter callbacks a deprecation
|
||||
warning, to be removed in 8.0. This has been a warning since Click
|
||||
2.0. :pr:`1492`
|
||||
- Adjust error messages to standardize the types of quotes used so
|
||||
they match error messages from Python.
|
||||
|
||||
|
||||
Version 7.0
|
||||
-----------
|
||||
|
||||
Released 2018-09-25
|
||||
|
||||
- Drop support for Python 2.6 and 3.3. :pr:`967, 976`
|
||||
- Wrap ``click.Choice``'s missing message. :issue:`202`, :pr:`1000`
|
||||
- Add native ZSH autocompletion support. :issue:`323`, :pr:`865`
|
||||
- Document that ANSI color info isn't parsed from bytearrays in Python
|
||||
2. :issue:`334`
|
||||
- Document byte-stripping behavior of ``CliRunner``. :issue:`334`,
|
||||
:pr:`1010`
|
||||
- Usage errors now hint at the ``--help`` option. :issue:`393`,
|
||||
:pr:`557`
|
||||
- Implement streaming pager. :issue:`409`, :pr:`889`
|
||||
- Extract bar formatting to its own method. :pr:`414`
|
||||
- Add ``DateTime`` type for converting input in given date time
|
||||
formats. :pr:`423`
|
||||
- ``secho``'s first argument can now be ``None``, like in ``echo``.
|
||||
:pr:`424`
|
||||
- Fixes a ``ZeroDivisionError`` in ``ProgressBar.make_step``, when the
|
||||
arg passed to the first call of ``ProgressBar.update`` is 0.
|
||||
:issue:`447`, :pr:`1012`
|
||||
- Show progressbar only if total execution time is visible. :pr:`487`
|
||||
- Added the ability to hide commands and options from help. :pr:`500`
|
||||
- Document that options can be ``required=True``. :issue:`514`,
|
||||
:pr:`1022`
|
||||
- Non-standalone calls to ``Context.exit`` return the exit code,
|
||||
rather than calling ``sys.exit``. :issue:`667`, :pr:`533, 1098`
|
||||
- ``click.getchar()`` returns Unicode in Python 3 on Windows,
|
||||
consistent with other platforms. :issue:`537, 821, 822, 1088`,
|
||||
:pr:`1108`
|
||||
- Added ``FloatRange`` type. :pr:`538, 553`
|
||||
- Added support for bash completion of ``type=click.Choice`` for
|
||||
``Options`` and ``Arguments``. :issue:`535`, :pr:`681`
|
||||
- Only allow one positional arg for ``Argument`` parameter
|
||||
declaration. :issue:`568, 574`, :pr:`1014`
|
||||
- Add ``case_sensitive=False`` as an option to Choice. :issue:`569`
|
||||
- ``click.getchar()`` correctly raises ``KeyboardInterrupt`` on "^C"
|
||||
and ``EOFError`` on "^D" on Linux. :issue:`583`, :pr:`1115`
|
||||
- Fix encoding issue with ``click.getchar(echo=True)`` on Linux.
|
||||
:pr:`1115`
|
||||
- ``param_hint`` in errors now derived from param itself.
|
||||
:issue:`598, 704`, :pr:`709`
|
||||
- Add a test that ensures that when an argument is formatted into a
|
||||
usage error, its metavar is used, not its name. :pr:`612`
|
||||
- Allow setting ``prog_name`` as extra in ``CliRunner.invoke``.
|
||||
:issue:`616`, :pr:`999`
|
||||
- Help text taken from docstrings truncates at the ``\f`` form feed
|
||||
character, useful for hiding Sphinx-style parameter documentation.
|
||||
:pr:`629, 1091`
|
||||
- ``launch`` now works properly under Cygwin. :pr:`650`
|
||||
- Update progress after iteration. :issue:`651`, :pr:`706`
|
||||
- ``CliRunner.invoke`` now may receive ``args`` as a string
|
||||
representing a Unix shell command. :pr:`664`
|
||||
- Make ``Argument.make_metavar()`` default to type metavar. :pr:`675`
|
||||
- Add documentation for ``ignore_unknown_options``. :pr:`684`
|
||||
- Add bright colors support for ``click.style`` and fix the reset
|
||||
option for parameters ``fg`` and ``bg``. :issue:`703`, :pr:`809`
|
||||
- Add ``show_envvar`` for showing environment variables in help.
|
||||
:pr:`710`
|
||||
- Avoid ``BrokenPipeError`` during interpreter shutdown when stdout or
|
||||
stderr is a closed pipe. :issue:`712`, :pr:`1106`
|
||||
- Document customizing option names. :issue:`725`, :pr:`1016`
|
||||
- Disable ``sys._getframes()`` on Python interpreters that don't
|
||||
support it. :pr:`728`
|
||||
- Fix bug in test runner when calling ``sys.exit`` with ``None``.
|
||||
:pr:`739`
|
||||
- Clarify documentation on command line options. :issue:`741`,
|
||||
:pr:`1003`
|
||||
- Fix crash on Windows console. :issue:`744`
|
||||
- Fix bug that caused bash completion to give improper completions on
|
||||
chained commands. :issue:`754`, :pr:`774`
|
||||
- Added support for dynamic bash completion from a user-supplied
|
||||
callback. :pr:`755`
|
||||
- Added support for bash completions containing spaces. :pr:`773`
|
||||
- Allow autocompletion function to determine whether or not to return
|
||||
completions that start with the incomplete argument. :issue:`790`,
|
||||
:pr:`806`
|
||||
- Fix option naming routine to match documentation and be
|
||||
deterministic. :issue:`793`, :pr:`794`
|
||||
- Fix path validation bug. :issue:`795`, :pr:`1020`
|
||||
- Add test and documentation for ``Option`` naming: functionality.
|
||||
:pr:`799`
|
||||
- Update doc to match arg name for ``path_type``. :pr:`801`
|
||||
- Raw strings added so correct escaping occurs. :pr:`807`
|
||||
- Fix 16k character limit of ``click.echo`` on Windows. :issue:`816`,
|
||||
:pr:`819`
|
||||
- Overcome 64k character limit when writing to binary stream on
|
||||
Windows 7. :issue:`825`, :pr:`830`
|
||||
- Add bool conversion for "t" and "f". :pr:`842`
|
||||
- ``NoSuchOption`` errors take ``ctx`` so that ``--help`` hint gets
|
||||
printed in error output. :pr:`860`
|
||||
- Fixed the behavior of Click error messages with regards to Unicode
|
||||
on 2.x and 3.x. Message is now always Unicode and the str and
|
||||
Unicode special methods work as you expect on that platform.
|
||||
:issue:`862`
|
||||
- Progress bar now uses stderr by default. :pr:`863`
|
||||
- Add support for auto-completion documentation. :issue:`866`,
|
||||
:pr:`869`
|
||||
- Allow ``CliRunner`` to separate stdout and stderr. :pr:`868`
|
||||
- Fix variable precedence. :issue:`873`, :pr:`874`
|
||||
- Fix invalid escape sequences. :pr:`877`
|
||||
- Fix ``ResourceWarning`` that occurs during some tests. :pr:`878`
|
||||
- When detecting a misconfigured locale, don't fail if the ``locale``
|
||||
command fails. :pr:`880`
|
||||
- Add ``case_sensitive=False`` as an option to ``Choice`` types.
|
||||
:pr:`887`
|
||||
- Force stdout/stderr writable. This works around issues with badly
|
||||
patched standard streams like those from Jupyter. :pr:`918`
|
||||
- Fix completion of subcommand options after last argument
|
||||
:issue:`919`, :pr:`930`
|
||||
- ``_AtomicFile`` now uses the ``realpath`` of the original filename
|
||||
so that changing the working directory does not affect it. :pr:`920`
|
||||
- Fix incorrect completions when defaults are present :issue:`925`,
|
||||
:pr:`930`
|
||||
- Add copy option attrs so that custom classes can be re-used.
|
||||
:issue:`926`, :pr:`994`
|
||||
- "x" and "a" file modes now use stdout when file is ``"-"``.
|
||||
:pr:`929`
|
||||
- Fix missing comma in ``__all__`` list. :pr:`935`
|
||||
- Clarify how parameters are named. :issue:`949`, :pr:`1009`
|
||||
- Stdout is now automatically set to non blocking. :pr:`954`
|
||||
- Do not set options twice. :pr:`962`
|
||||
- Move ``fcntl`` import. :pr:`965`
|
||||
- Fix Google App Engine ``ImportError``. :pr:`995`
|
||||
- Better handling of help text for dynamic default option values.
|
||||
:pr:`996`
|
||||
- Fix ``get_winter_size()`` so it correctly returns ``(0,0)``.
|
||||
:pr:`997`
|
||||
- Add test case checking for custom param type. :pr:`1001`
|
||||
- Allow short width to address cmd formatting. :pr:`1002`
|
||||
- Add details about Python version support. :pr:`1004`
|
||||
- Added deprecation flag to commands. :pr:`1005`
|
||||
- Fixed issues where ``fd`` was undefined. :pr:`1007`
|
||||
- Fix formatting for short help. :pr:`1008`
|
||||
- Document how ``auto_envvar_prefix`` works with command groups.
|
||||
:pr:`1011`
|
||||
- Don't add newlines by default for progress bars. :pr:`1013`
|
||||
- Use Python sorting order for ZSH completions. :issue:`1047`,
|
||||
:pr:`1059`
|
||||
- Document that parameter names are converted to lowercase by default.
|
||||
:pr:`1055`
|
||||
- Subcommands that are named by the function now automatically have
|
||||
the underscore replaced with a dash. If you register a function
|
||||
named ``my_command`` it becomes ``my-command`` in the command line
|
||||
interface.
|
||||
- Hide hidden commands and options from completion. :issue:`1058`,
|
||||
:pr:`1061`
|
||||
- Fix absolute import blocking Click from being vendored into a
|
||||
project on Windows. :issue:`1068`, :pr:`1069`
|
||||
- Fix issue where a lowercase ``auto_envvar_prefix`` would not be
|
||||
converted to uppercase. :pr:`1105`
|
||||
|
||||
|
||||
Version 6.7
|
||||
-----------
|
||||
|
||||
Released 2017-01-06
|
||||
|
||||
- Make ``click.progressbar`` work with ``codecs.open`` files.
|
||||
:pr:`637`
|
||||
- Fix bug in bash completion with nested subcommands. :pr:`639`
|
||||
- Fix test runner not saving caller env correctly. :pr:`644`
|
||||
- Fix handling of SIGPIPE. :pr:`62`
|
||||
- Deal with broken Windows environments such as Google App Engine's.
|
||||
:issue:`711`
|
||||
|
||||
|
||||
Version 6.6
|
||||
-----------
|
||||
|
||||
Released 2016-04-04
|
||||
|
||||
- Fix bug in ``click.Path`` where it would crash when passed a ``-``.
|
||||
:issue:`551`
|
||||
|
||||
|
||||
Version 6.4
|
||||
-----------
|
||||
|
||||
Released 2016-03-24
|
||||
|
||||
- Fix bug in bash completion where click would discard one or more
|
||||
trailing arguments. :issue:`471`
|
||||
|
||||
|
||||
Version 6.3
|
||||
-----------
|
||||
|
||||
Released 2016-02-22
|
||||
|
||||
- Fix argument checks for interpreter invoke with ``-m`` and ``-c`` on
|
||||
Windows.
|
||||
- Fixed a bug that cased locale detection to error out on Python 3.
|
||||
|
||||
|
||||
Version 6.2
|
||||
-----------
|
||||
|
||||
Released 2015-11-27
|
||||
|
||||
- Correct fix for hidden progress bars.
|
||||
|
||||
|
||||
Version 6.1
|
||||
-----------
|
||||
|
||||
Released 2015-11-27
|
||||
|
||||
- Resolved an issue with invisible progress bars no longer rendering.
|
||||
- Disable chain commands with subcommands as they were inherently
|
||||
broken.
|
||||
- Fix ``MissingParameter`` not working without parameters passed.
|
||||
|
||||
|
||||
Version 6.0
|
||||
-----------
|
||||
|
||||
Released 2015-11-24, codename "pow pow"
|
||||
|
||||
- Optimized the progressbar rendering to not render when it did not
|
||||
actually change.
|
||||
- Explicitly disallow ``nargs=-1`` with a set default.
|
||||
- The context is now closed before it's popped from the stack.
|
||||
- Added support for short aliases for the false flag on toggles.
|
||||
- Click will now attempt to aid you with debugging locale errors
|
||||
better by listing with the help of the OS what locales are
|
||||
available.
|
||||
- Click used to return byte strings on Python 2 in some unit-testing
|
||||
situations. This has been fixed to correctly return unicode strings
|
||||
now.
|
||||
- For Windows users on Python 2, Click will now handle Unicode more
|
||||
correctly handle Unicode coming in from the system. This also has
|
||||
the disappointing side effect that filenames will now be always
|
||||
unicode by default in the ``Path`` type which means that this can
|
||||
introduce small bugs for code not aware of this.
|
||||
- Added a ``type`` parameter to ``Path`` to force a specific string
|
||||
type on the value.
|
||||
- For users running Python on Windows the ``echo`` and ``prompt``
|
||||
functions now work with full unicode functionality in the Python
|
||||
windows console by emulating an output stream. This also applies to
|
||||
getting the virtual output and input streams via
|
||||
``click.get_text_stream(...)``.
|
||||
- Unittests now always force a certain virtual terminal width.
|
||||
- Added support for allowing dashes to indicate standard streams to
|
||||
the ``Path`` type.
|
||||
- Multi commands in chain mode no longer propagate arguments left over
|
||||
from parsing to the callbacks. It's also now disallowed through an
|
||||
exception when optional arguments are attached to multi commands if
|
||||
chain mode is enabled.
|
||||
- Relaxed restriction that disallowed chained commands to have other
|
||||
chained commands as child commands.
|
||||
- Arguments with positive nargs can now have defaults implemented.
|
||||
Previously this configuration would often result in slightly
|
||||
unexpected values be returned.
|
||||
|
||||
|
||||
Version 5.1
|
||||
-----------
|
||||
|
||||
Released 2015-08-17
|
||||
|
||||
- Fix a bug in ``pass_obj`` that would accidentally pass the context
|
||||
too.
|
||||
|
||||
|
||||
Version 5.0
|
||||
-----------
|
||||
|
||||
Released 2015-08-16, codename "tok tok"
|
||||
|
||||
- Removed various deprecated functionality.
|
||||
- Atomic files now only accept the ``w`` mode.
|
||||
- Change the usage part of help output for very long commands to wrap
|
||||
their arguments onto the next line, indented by 4 spaces.
|
||||
- Fix a bug where return code and error messages were incorrect when
|
||||
using ``CliRunner``.
|
||||
- Added ``get_current_context``.
|
||||
- Added a ``meta`` dictionary to the context which is shared across
|
||||
the linked list of contexts to allow click utilities to place state
|
||||
there.
|
||||
- Introduced ``Context.scope``.
|
||||
- The ``echo`` function is now threadsafe: It calls the ``write``
|
||||
method of the underlying object only once.
|
||||
- ``prompt(hide_input=True)`` now prints a newline on ``^C``.
|
||||
- Click will now warn if users are using ``unicode_literals``.
|
||||
- Click will now ignore the ``PAGER`` environment variable if it is
|
||||
empty or contains only whitespace.
|
||||
- The ``click-contrib`` GitHub organization was created.
|
||||
|
||||
|
||||
Version 4.1
|
||||
-----------
|
||||
|
||||
Released 2015-07-14
|
||||
|
||||
- Fix a bug where error messages would include a trailing ``None``
|
||||
string.
|
||||
- Fix a bug where Click would crash on docstrings with trailing
|
||||
newlines.
|
||||
- Support streams with encoding set to ``None`` on Python 3 by barfing
|
||||
with a better error.
|
||||
- Handle ^C in less-pager properly.
|
||||
- Handle return value of ``None`` from ``sys.getfilesystemencoding``
|
||||
- Fix crash when writing to unicode files with ``click.echo``.
|
||||
- Fix type inference with multiple options.
|
||||
|
||||
|
||||
Version 4.0
|
||||
-----------
|
||||
|
||||
Released 2015-03-31, codename "zoom zoom"
|
||||
|
||||
- Added ``color`` parameters to lots of interfaces that directly or
|
||||
indirectly call into echoing. This previously was always
|
||||
autodetection (with the exception of the ``echo_via_pager``
|
||||
function). Now you can forcefully enable or disable it, overriding
|
||||
the auto detection of Click.
|
||||
- Added an ``UNPROCESSED`` type which does not perform any type
|
||||
changes which simplifies text handling on 2.x / 3.x in some special
|
||||
advanced usecases.
|
||||
- Added ``NoSuchOption`` and ``BadOptionUsage`` exceptions for more
|
||||
generic handling of errors.
|
||||
- Added support for handling of unprocessed options which can be
|
||||
useful in situations where arguments are forwarded to underlying
|
||||
tools.
|
||||
- Added ``max_content_width`` parameter to the context which can be
|
||||
used to change the maximum width of help output. By default Click
|
||||
will not format content for more than 80 characters width.
|
||||
- Added support for writing prompts to stderr.
|
||||
- Fix a bug when showing the default for multiple arguments.
|
||||
- Added support for custom subclasses to ``option`` and ``argument``.
|
||||
- Fix bug in ``clear()`` on Windows when colorama is installed.
|
||||
- Reject ``nargs=-1`` for options properly. Options cannot be
|
||||
variadic.
|
||||
- Fixed an issue with bash completion not working properly for
|
||||
commands with non ASCII characters or dashes.
|
||||
- Added a way to manually update the progressbar.
|
||||
- Changed the formatting of missing arguments. Previously the internal
|
||||
argument name was shown in error messages, now the metavar is shown
|
||||
if passed. In case an automated metavar is selected, it's stripped
|
||||
of extra formatting first.
|
||||
|
||||
|
||||
Version 3.3
|
||||
-----------
|
||||
|
||||
Released 2014-09-08
|
||||
|
||||
- Fixed an issue with error reporting on Python 3 for invalid
|
||||
forwarding of commands.
|
||||
|
||||
|
||||
Version 3.2
|
||||
-----------
|
||||
|
||||
Released 2014-08-22
|
||||
|
||||
- Added missing ``err`` parameter forwarding to the ``secho``
|
||||
function.
|
||||
- Fixed default parameters not being handled properly by the context
|
||||
invoke method. This is a backwards incompatible change if the
|
||||
function was used improperly. See :ref:`upgrade-to-3.2` for more
|
||||
information.
|
||||
- Removed the ``invoked_subcommands`` attribute largely. It is not
|
||||
possible to provide it to work error free due to how the parsing
|
||||
works so this API has been deprecated. See :ref:`upgrade-to-3.2` for
|
||||
more information.
|
||||
- Restored the functionality of ``invoked_subcommand`` which was
|
||||
broken as a regression in 3.1.
|
||||
|
||||
|
||||
Version 3.1
|
||||
-----------
|
||||
|
||||
Released 2014-08-13
|
||||
|
||||
- Fixed a regression that caused contexts of subcommands to be created
|
||||
before the parent command was invoked which was a regression from
|
||||
earlier Click versions.
|
||||
|
||||
|
||||
Version 3.0
|
||||
-----------
|
||||
|
||||
Released 2014-08-12, codename "clonk clonk"
|
||||
|
||||
- Formatter now no longer attempts to accommodate for terminals
|
||||
smaller than 50 characters. If that happens it just assumes a
|
||||
minimal width.
|
||||
- Added a way to not swallow exceptions in the test system.
|
||||
- Added better support for colors with pagers and ways to override the
|
||||
autodetection.
|
||||
- The CLI runner's result object now has a traceback attached.
|
||||
- Improved automatic short help detection to work better with dots
|
||||
that do not terminate sentences.
|
||||
- When defining options without actual valid option strings now,
|
||||
Click will give an error message instead of silently passing. This
|
||||
should catch situations where users wanted to created arguments
|
||||
instead of options.
|
||||
- Restructured Click internally to support vendoring.
|
||||
- Added support for multi command chaining.
|
||||
- Added support for defaults on options with ``multiple`` and options
|
||||
and arguments with ``nargs != 1``.
|
||||
- Label passed to ``progressbar`` is no longer rendered with
|
||||
whitespace stripped.
|
||||
- Added a way to disable the standalone mode of the ``main`` method on
|
||||
a Click command to be able to handle errors better.
|
||||
- Added support for returning values from command callbacks.
|
||||
- Added simplifications for printing to stderr from ``echo``.
|
||||
- Added result callbacks for groups.
|
||||
- Entering a context multiple times defers the cleanup until the last
|
||||
exit occurs.
|
||||
- Added ``open_file``.
|
||||
|
||||
|
||||
Version 2.6
|
||||
-----------
|
||||
|
||||
Released 2014-08-11
|
||||
|
||||
- Fixed an issue where the wrapped streams on Python 3 would be
|
||||
reporting incorrect values for seekable.
|
||||
|
||||
|
||||
Version 2.5
|
||||
-----------
|
||||
|
||||
Released 2014-07-28
|
||||
|
||||
- Fixed a bug with text wrapping on Python 3.
|
||||
|
||||
|
||||
Version 2.4
|
||||
-----------
|
||||
|
||||
Released 2014-07-04
|
||||
|
||||
- Corrected a bug in the change of the help option in 2.3.
|
||||
|
||||
|
||||
Version 2.3
|
||||
-----------
|
||||
|
||||
Released 2014-07-03
|
||||
|
||||
- Fixed an incorrectly formatted help record for count options.
|
||||
- Add support for ansi code stripping on Windows if colorama is not
|
||||
available.
|
||||
- Restored the Click 1.0 handling of the help parameter for certain
|
||||
edge cases.
|
||||
|
||||
|
||||
Version 2.2
|
||||
-----------
|
||||
|
||||
Released 2014-06-26
|
||||
|
||||
- Fixed tty detection on PyPy.
|
||||
- Fixed an issue that progress bars were not rendered when the context
|
||||
manager was entered.
|
||||
|
||||
|
||||
Version 2.1
|
||||
-----------
|
||||
|
||||
Released 2014-06-14
|
||||
|
||||
- Fixed the :func:`launch` function on windows.
|
||||
- Improved the colorama support on windows to try hard to not screw up
|
||||
the console if the application is interrupted.
|
||||
- Fixed windows terminals incorrectly being reported to be 80
|
||||
characters wide instead of 79
|
||||
- Use colorama win32 bindings if available to get the correct
|
||||
dimensions of a windows terminal.
|
||||
- Fixed an issue with custom function types on Python 3.
|
||||
- Fixed an issue with unknown options being incorrectly reported in
|
||||
error messages.
|
||||
|
||||
|
||||
Version 2.0
|
||||
-----------
|
||||
|
||||
Released 2014-06-06, codename "tap tap tap"
|
||||
|
||||
- Added support for opening stdin/stdout on Windows in binary mode
|
||||
correctly.
|
||||
- Added support for atomic writes to files by going through a
|
||||
temporary file.
|
||||
- Introduced :exc:`BadParameter` which can be used to easily perform
|
||||
custom validation with the same error messages as in the type
|
||||
system.
|
||||
- Added :func:`progressbar`; a function to show progress bars.
|
||||
- Added :func:`get_app_dir`; a function to calculate the home folder
|
||||
for configs.
|
||||
- Added transparent handling for ANSI codes into the :func:`echo`
|
||||
function through ``colorama``.
|
||||
- Added :func:`clear` function.
|
||||
- Breaking change: parameter callbacks now get the parameter object
|
||||
passed as second argument. There is legacy support for old callbacks
|
||||
which will warn but still execute the script.
|
||||
- Added :func:`style`, :func:`unstyle` and :func:`secho` for ANSI
|
||||
styles.
|
||||
- Added an :func:`edit` function that invokes the default editor.
|
||||
- Added an :func:`launch` function that launches browsers and
|
||||
applications.
|
||||
- Nargs of -1 for arguments can now be forced to be a single item
|
||||
through the required flag. It defaults to not required.
|
||||
- Setting a default for arguments now implicitly makes it non
|
||||
required.
|
||||
- Changed "yN" / "Yn" to "y/N" and "Y/n" in confirmation prompts.
|
||||
- Added basic support for bash completion.
|
||||
- Added :func:`getchar` to fetch a single character from the terminal.
|
||||
- Errors now go to stderr as intended.
|
||||
- Fixed various issues with more exotic parameter formats like
|
||||
DOS/Windows style arguments.
|
||||
- Added :func:`pause` which works similar to the Windows ``pause`` cmd
|
||||
built-in but becomes an automatic noop if the application is not run
|
||||
through a terminal.
|
||||
- Added a bit of extra information about missing choice parameters.
|
||||
- Changed how the help function is implemented to allow global
|
||||
overriding of the help option.
|
||||
- Added support for token normalization to implement case insensitive
|
||||
handling.
|
||||
- Added support for providing defaults for context settings.
|
||||
|
||||
|
||||
Version 1.1
|
||||
-----------
|
||||
|
||||
Released 2014-05-23
|
||||
|
||||
- Fixed a bug that caused text files in Python 2 to not accept native
|
||||
strings.
|
||||
|
||||
|
||||
Version 1.0
|
||||
-----------
|
||||
|
||||
Released 2014-05-21
|
||||
|
||||
- Initial release.
|
|
@ -1,76 +0,0 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at report@palletsprojects.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
222
CONTRIBUTING.rst
222
CONTRIBUTING.rst
|
@ -1,222 +0,0 @@
|
|||
How to contribute to Click
|
||||
==========================
|
||||
|
||||
Thank you for considering contributing to Click!
|
||||
|
||||
|
||||
Support questions
|
||||
-----------------
|
||||
|
||||
Please don't use the issue tracker for this. The issue tracker is a tool
|
||||
to address bugs and feature requests in Click itself. Use one of the
|
||||
following resources for questions about using Click or issues with your
|
||||
own code:
|
||||
|
||||
- The ``#get-help`` channel on our Discord chat:
|
||||
https://discord.gg/pallets
|
||||
- The mailing list flask@python.org for long term discussion or larger
|
||||
issues.
|
||||
- Ask on `Stack Overflow`_. Search with Google first using:
|
||||
``site:stackoverflow.com python click {search term, exception message, etc.}``
|
||||
|
||||
.. _Stack Overflow: https://stackoverflow.com/questions/tagged/python-click?tab=Frequent
|
||||
|
||||
|
||||
Reporting issues
|
||||
----------------
|
||||
|
||||
Include the following information in your post:
|
||||
|
||||
- Describe what you expected to happen.
|
||||
- If possible, include a `minimal reproducible example`_ to help us
|
||||
identify the issue. This also helps check that the issue is not with
|
||||
your own code.
|
||||
- Describe what actually happened. Include the full traceback if there
|
||||
was an exception.
|
||||
- List your Python and Click versions. If possible, check if this
|
||||
issue is already fixed in the latest releases or the latest code in
|
||||
the repository.
|
||||
|
||||
.. _minimal reproducible example: https://stackoverflow.com/help/minimal-reproducible-example
|
||||
|
||||
|
||||
Submitting patches
|
||||
------------------
|
||||
|
||||
If there is not an open issue for what you want to submit, prefer
|
||||
opening one for discussion before working on a PR. You can work on any
|
||||
issue that doesn't have an open PR linked to it or a maintainer assigned
|
||||
to it. These show up in the sidebar. No need to ask if you can work on
|
||||
an issue that interests you.
|
||||
|
||||
Include the following in your patch:
|
||||
|
||||
- Use `Black`_ to format your code. This and other tools will run
|
||||
automatically if you install `pre-commit`_ using the instructions
|
||||
below.
|
||||
- Include tests if your patch adds or changes code. Make sure the test
|
||||
fails without your patch.
|
||||
- Update any relevant docs pages and docstrings. Docs pages and
|
||||
docstrings should be wrapped at 72 characters.
|
||||
- Add an entry in ``CHANGES.rst``. Use the same style as other
|
||||
entries. Also include ``.. versionchanged::`` inline changelogs in
|
||||
relevant docstrings.
|
||||
|
||||
.. _Black: https://black.readthedocs.io
|
||||
.. _pre-commit: https://pre-commit.com
|
||||
|
||||
|
||||
First time setup
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- Download and install the `latest version of git`_.
|
||||
- Configure git with your `username`_ and `email`_.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git config --global user.name 'your name'
|
||||
$ git config --global user.email 'your email'
|
||||
|
||||
- Make sure you have a `GitHub account`_.
|
||||
- Fork Click to your GitHub account by clicking the `Fork`_ button.
|
||||
- `Clone`_ the main repository locally.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone https://github.com/pallets/click
|
||||
$ cd click
|
||||
|
||||
- Add your fork as a remote to push your work to. Replace
|
||||
``{username}`` with your username. This names the remote "fork", the
|
||||
default Pallets remote is "origin".
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git remote add fork https://github.com/{username}/click
|
||||
|
||||
- Create a virtualenv.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python3 -m venv env
|
||||
$ . env/bin/activate
|
||||
|
||||
On Windows, activating is different.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
> env\Scripts\activate
|
||||
|
||||
- Upgrade pip and setuptools.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python -m pip install --upgrade pip setuptools
|
||||
|
||||
- Install the development dependencies, then install Click in
|
||||
editable mode.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pip install -r requirements/dev.txt && pip install -e .
|
||||
|
||||
- Install the pre-commit hooks.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pre-commit install
|
||||
|
||||
.. _latest version of git: https://git-scm.com/downloads
|
||||
.. _username: https://docs.github.com/en/github/using-git/setting-your-username-in-git
|
||||
.. _email: https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/setting-your-commit-email-address
|
||||
.. _GitHub account: https://github.com/join
|
||||
.. _Fork: https://github.com/pallets/click/fork
|
||||
.. _Clone: https://docs.github.com/en/github/getting-started-with-github/fork-a-repo#step-2-create-a-local-clone-of-your-fork
|
||||
|
||||
|
||||
Start coding
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- Create a branch to identify the issue you would like to work on. If
|
||||
you're submitting a bug or documentation fix, branch off of the
|
||||
latest ".x" branch.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git fetch origin
|
||||
$ git checkout -b your-branch-name origin/8.0.x
|
||||
|
||||
If you're submitting a feature addition or change, branch off of the
|
||||
"main" branch.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git fetch origin
|
||||
$ git checkout -b your-branch-name origin/main
|
||||
|
||||
- Using your favorite editor, make your changes,
|
||||
`committing as you go`_.
|
||||
- Include tests that cover any code changes you make. Make sure the
|
||||
test fails without your patch. Run the tests as described below.
|
||||
- Push your commits to your fork on GitHub and
|
||||
`create a pull request`_. Link to the issue being addressed with
|
||||
``fixes #123`` in the pull request.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git push --set-upstream fork your-branch-name
|
||||
|
||||
.. _committing as you go: https://dont-be-afraid-to-commit.readthedocs.io/en/latest/git/commandlinegit.html#commit-your-changes
|
||||
.. _create a pull request: https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request
|
||||
|
||||
|
||||
Running the tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Run the basic test suite with pytest.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pytest
|
||||
|
||||
This runs the tests for the current environment, which is usually
|
||||
sufficient. CI will run the full suite when you submit your pull
|
||||
request. You can run the full test suite with tox if you don't want to
|
||||
wait.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ tox
|
||||
|
||||
|
||||
Running test coverage
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Generating a report of lines that do not have test coverage can indicate
|
||||
where to start contributing. Run ``pytest`` using ``coverage`` and
|
||||
generate a report.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pip install coverage
|
||||
$ coverage run -m pytest
|
||||
$ coverage html
|
||||
|
||||
Open ``htmlcov/index.html`` in your browser to explore the report.
|
||||
|
||||
Read more about `coverage <https://coverage.readthedocs.io>`__.
|
||||
|
||||
|
||||
Building the docs
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Build the docs in the ``docs`` directory using Sphinx.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ cd docs
|
||||
$ make html
|
||||
|
||||
Open ``_build/html/index.html`` in your browser to view the docs.
|
||||
|
||||
Read more about `Sphinx <https://www.sphinx-doc.org/en/stable/>`__.
|
28
LICENSE.rst
28
LICENSE.rst
|
@ -1,28 +0,0 @@
|
|||
Copyright 2014 Pallets
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
10
MANIFEST.in
10
MANIFEST.in
|
@ -1,10 +0,0 @@
|
|||
include CHANGES.rst
|
||||
include tox.ini
|
||||
include requirements/*.txt
|
||||
graft artwork
|
||||
graft docs
|
||||
prune docs/_build
|
||||
graft examples
|
||||
graft tests
|
||||
include src/click/py.typed
|
||||
global-exclude *.pyc
|
80
README.rst
80
README.rst
|
@ -1,80 +0,0 @@
|
|||
\$ click\_
|
||||
==========
|
||||
|
||||
Click is a Python package for creating beautiful command line interfaces
|
||||
in a composable way with as little code as necessary. It's the "Command
|
||||
Line Interface Creation Kit". It's highly configurable but comes with
|
||||
sensible defaults out of the box.
|
||||
|
||||
It aims to make the process of writing command line tools quick and fun
|
||||
while also preventing any frustration caused by the inability to
|
||||
implement an intended CLI API.
|
||||
|
||||
Click in three points:
|
||||
|
||||
- Arbitrary nesting of commands
|
||||
- Automatic help page generation
|
||||
- Supports lazy loading of subcommands at runtime
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
Install and update using `pip`_:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pip install -U click
|
||||
|
||||
.. _pip: https://pip.pypa.io/en/stable/getting-started/
|
||||
|
||||
|
||||
A Simple Example
|
||||
----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
@click.option("--count", default=1, help="Number of greetings.")
|
||||
@click.option("--name", prompt="Your name", help="The person to greet.")
|
||||
def hello(count, name):
|
||||
"""Simple program that greets NAME for a total of COUNT times."""
|
||||
for _ in range(count):
|
||||
click.echo(f"Hello, {name}!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
hello()
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python hello.py --count=3
|
||||
Your name: Click
|
||||
Hello, Click!
|
||||
Hello, Click!
|
||||
Hello, Click!
|
||||
|
||||
|
||||
Donate
|
||||
------
|
||||
|
||||
The Pallets organization develops and supports Click and other popular
|
||||
packages. In order to grow the community of contributors and users, and
|
||||
allow the maintainers to devote more time to the projects, `please
|
||||
donate today`_.
|
||||
|
||||
.. _please donate today: https://palletsprojects.com/donate
|
||||
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
- Documentation: https://click.palletsprojects.com/
|
||||
- Changes: https://click.palletsprojects.com/changes/
|
||||
- PyPI Releases: https://pypi.org/project/click/
|
||||
- Source Code: https://github.com/pallets/click
|
||||
- Issue Tracker: https://github.com/pallets/click/issues
|
||||
- Website: https://palletsprojects.com/p/click
|
||||
- Twitter: https://twitter.com/PalletsTeam
|
||||
- Chat: https://discord.gg/pallets
|
|
@ -1,75 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="237.36929"
|
||||
height="110.7928"
|
||||
id="svg4837"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="New document 8">
|
||||
<defs
|
||||
id="defs4839" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="259.76814"
|
||||
inkscape:cy="40.769955"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="10"
|
||||
fit-margin-left="10"
|
||||
fit-margin-right="10"
|
||||
fit-margin-bottom="10"
|
||||
inkscape:window-width="1676"
|
||||
inkscape:window-height="1006"
|
||||
inkscape:window-x="4"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata4842">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-255.43458,-207.38101)">
|
||||
<path
|
||||
style="fill:#000000"
|
||||
d="m 466.33424,306.48462 0,-1.6892 3.16724,0 3.16723,0 0,1.6892 0,1.68919 -3.16723,0 -3.16724,0 0,-1.68919 z m -3.37839,-5.06759 0,-3.37839 1.47804,0 1.47805,0 0,3.37839 0,3.37839 -1.47805,0 -1.47804,0 0,-3.37839 z m 10.13516,0 0,-3.37839 1.47804,0 1.47805,0 0,3.37839 0,3.37839 -1.47805,0 -1.47804,0 0,-3.37839 z m -30.82778,-28.92744 0,-28.92744 1.68919,0 c 1.68919,0 1.68919,0 1.68919,1.68919 0,1.6892 0,1.6892 1.6892,1.6892 1.68919,0 1.68919,0 1.68919,1.68919 0,1.6892 0,1.6892 1.6892,1.6892 1.68919,0 1.68919,0 1.68919,1.68919 0,1.6892 0,1.6892 -1.68919,1.6892 -1.6892,0 -1.6892,0 -1.6892,-1.6892 0,-1.68919 0,-1.68919 -1.68919,-1.68919 l -1.6892,0 0,23.85986 0,23.85985 1.6892,0 c 1.68919,0 1.68919,0 1.68919,1.6892 l 0,1.68919 -3.37839,0 -3.37838,0 0,-28.92744 z m 7.00029,25.22951 c -0.13394,-0.13393 -0.24352,-0.87696 -0.24352,-1.65118 0,-1.36423 0.0529,-1.40766 1.71469,-1.40766 l 1.71468,0 -0.13106,1.58362 c -0.12024,1.45279 -0.24178,1.5892 -1.47117,1.65118 -0.73706,0.0372 -1.44968,-0.042 -1.58362,-0.17596 z m 10.14204,-0.0392 c -0.13814,-0.22352 -0.20454,-1.7545 -0.14756,-3.40219 l 0.10361,-2.99581 1.60373,0 1.60374,0 -0.12334,3.27282 -0.12334,3.27281 -1.33284,0.12938 c -0.73305,0.0712 -1.44586,-0.0535 -1.584,-0.27702 z m 10.30707,-3.03247 0,-3.36553 1.47803,0 1.47805,0 0,3.30997 0,3.30996 -1.47805,0.0556 -1.47803,0.0556 0,-3.36553 z m -17.03271,-0.26872 c -0.15484,-0.15483 -0.28153,-0.91497 -0.28153,-1.68919 0,-1.36073 0.0563,-1.40766 1.68919,-1.40766 1.6892,0 1.6892,0 1.6892,1.6892 0,1.63289 -0.0469,1.68919 -1.40766,1.68919 -0.77422,0 -1.53436,-0.12669 -1.6892,-0.28154 z m 3.09686,-4.99719 c 0,-1.44286 0.0402,-1.47804 1.68919,-1.47804 1.64898,0 1.68919,0.0352 1.68919,1.47804 0,1.44285 -0.0402,1.47805 -1.68919,1.47805 -1.64898,0 -1.68919,-0.0352 -1.68919,-1.47805 z m 10.55746,-1.68919 0,-3.16724 6.75677,0 6.75678,0 0,-1.68919 c 0,-1.64898 0.0351,-1.6892 1.47804,-1.6892 l 1.47804,0 0,3.15652 0,3.15651 -6.6512,0.1163 -6.65119,0.1163 -0.13108,1.58361 c -0.12394,1.49763 -0.20994,1.58363 -1.58361,1.58363 l -1.45255,0 0,-3.16724 z m 10.13516,-8.44597 c 0,-1.40766 0.0704,-1.47804 1.47804,-1.47804 1.40766,0 1.47805,0.0704 1.47805,1.47804 0,1.40766 -0.0704,1.47804 -1.47805,1.47804 -1.40766,0 -1.47804,-0.0704 -1.47804,-1.47804 z m -3.37839,-3.37839 c 0,-1.40766 0.0704,-1.47804 1.47804,-1.47804 1.40767,0 1.47805,0.0704 1.47805,1.47804 0,1.40767 -0.0704,1.47805 -1.47805,1.47805 -1.40765,0 -1.47804,-0.0704 -1.47804,-1.47805 z m -3.37838,-3.37839 c 0,-1.40765 0.0704,-1.47804 1.47803,-1.47804 1.40767,0 1.47805,0.0704 1.47805,1.47804 0,1.40767 -0.0704,1.47805 -1.47805,1.47805 -1.40765,0 -1.47803,-0.0704 -1.47803,-1.47805 z m -3.37839,-3.48871 c 0,-1.52897 0.0553,-1.58931 1.47804,-1.61346 1.43567,-0.0244 1.47804,0.0211 1.47804,1.58838 0,1.56241 -0.0467,1.61345 -1.47804,1.61345 -1.42721,0 -1.47804,-0.0546 -1.47804,-1.58837 z m -3.37839,-3.47921 c 0,-1.64897 0.0351,-1.68919 1.47804,-1.68919 1.44285,0 1.47805,0.0402 1.47805,1.68919 0,1.64898 -0.0352,1.6892 -1.47805,1.6892 -1.44285,0 -1.47804,-0.0403 -1.47804,-1.6892 z m -3.45076,-3.37839 c 0.15328,-1.60738 0.23052,-1.68919 1.59478,-1.68919 1.3911,0 1.43368,0.0502 1.43368,1.68919 0,1.67253 -0.0157,1.6892 -1.59478,1.6892 l -1.59477,0 0.16109,-1.6892 z m -3.30601,-3.37838 c 0,-1.64898 0.0351,-1.6892 1.47804,-1.6892 1.44285,0 1.47804,0.0402 1.47804,1.6892 0,1.64897 -0.0352,1.68919 -1.47804,1.68919 -1.44286,0 -1.47804,-0.0402 -1.47804,-1.68919 z m -3.72061,-3.27282 c 0.12395,-1.49762 0.21706,-1.59073 1.71468,-1.71468 l 1.58363,-0.13107 0,1.71469 0,1.71468 -1.71469,0 -1.71468,0 0.13106,-1.58362 z"
|
||||
id="path4856"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#000000"
|
||||
d="m 271.34527,247.46047 c 0,-1.32826 -0.94153,-2.12734 -3.05297,-2.59109 -4.04056,-0.88746 -3.19986,-3.08429 1.01754,-2.65894 9.32239,0.94022 10.81407,-3.50307 2.60795,-7.76831 -2.71012,-1.40862 -5.36388,-3.27897 -5.89726,-4.15634 -1.47604,-2.42802 -0.0246,-6.42458 2.80076,-7.7119 1.48697,-0.67751 2.52398,-1.98054 2.52398,-3.17144 0,-1.13017 0.66136,-2.02144 1.5,-2.02144 0.825,0 1.5,0.85122 1.5,1.89159 0,1.19765 0.94321,2.12832 2.57104,2.53688 3.91591,0.98283 2.39946,3.10499 -1.95093,2.73019 -6.99788,-0.60291 -8.93527,3.8291 -2.87011,6.5657 9.0905,4.10163 11.015,9.73021 4.5,13.16112 -1.2375,0.65169 -2.25,2.06905 -2.25,3.1497 0,1.08065 -0.675,1.96482 -1.5,1.96482 -0.825,0 -1.5,-0.86425 -1.5,-1.92054 z m 38.357,-3.07104 c -4.57947,-1.84804 -6.77791,-8.48491 -4.32736,-13.06381 2.11183,-3.94599 10.30093,-6.28597 13.9414,-3.98367 2.2687,1.43477 0.36183,2.48777 -3.94232,2.177 -6.96682,-0.50302 -10.61631,6.27447 -5.91184,10.97894 1.71218,1.71218 2.95483,2.02243 6.5,1.62284 3.13626,-0.35351 4.38312,-0.13272 4.38312,0.77613 0,2.4062 -6.21813,3.27822 -10.643,1.49257 z m 21.1997,-1.23093 c -1.16379,-1.66155 -1.5567,-4.81653 -1.5567,-12.5 l 0,-10.27749 -2.5,0 c -1.55556,0 -2.5,-0.56667 -2.5,-1.5 0,-1.08333 1.11111,-1.5 4,-1.5 l 4,0 0.0153,11.25 c 0.008,6.1875 0.41056,11.87411 0.89363,12.63691 0.54214,0.85607 1.88505,1.19446 3.50856,0.88411 2.94677,-0.56331 4.58181,0.98192 2.46061,2.32547 -2.5829,1.63598 -6.70984,0.98184 -8.32141,-1.319 z m 20.4433,0.22251 c -1.55556,-1.55556 -2,-3.33333 -2,-8 0,-5.73333 -0.11111,-6 -2.5,-6 -1.55556,0 -2.5,-0.56667 -2.5,-1.5 0,-1.08333 1.11111,-1.5 4,-1.5 l 4,0 0.0153,6.75 c 0.0183,8.04891 0.82623,9.70461 4.40219,9.02102 2.94677,-0.56331 4.58181,0.98192 2.46061,2.32547 -2.3358,1.47948 -5.78176,0.99986 -7.87811,-1.09649 z m 18.357,1.00842 c -4.57947,-1.84804 -6.77791,-8.48491 -4.32736,-13.06381 2.11183,-3.94599 10.30093,-6.28597 13.9414,-3.98367 2.2687,1.43477 0.36183,2.48777 -3.94232,2.177 -6.96682,-0.50302 -10.61631,6.27447 -5.91184,10.97894 1.71218,1.71218 2.95483,2.02243 6.5,1.62284 3.13626,-0.35351 4.38312,-0.13272 4.38312,0.77613 0,2.4062 -6.21813,3.27822 -10.643,1.49257 z m 15.86478,-12.67646 c 0.20032,-9.84119 0.6282,-13.78431 1.52822,-14.08333 0.9358,-0.31091 1.25628,1.80502 1.275,8.41804 l 0.025,8.83333 4.01111,-4.25 c 2.32594,-2.46446 4.92367,-4.25 6.18321,-4.25 1.8968,0 1.6121,0.57059 -2.24643,4.50214 l -4.41851,4.50213 4.92271,4.99787 c 3.84161,3.90023 4.49929,4.99786 2.99467,4.99786 -1.06044,0 -4.08102,-2.12058 -6.71241,-4.71241 l -4.78435,-4.71241 0,4.71241 c 0,3.56082 -0.37346,4.71241 -1.52822,4.71241 -1.30999,0 -1.48849,-1.95179 -1.25,-13.66804 z m -37.85759,-9.82527 c -0.34636,-0.90262 -0.15025,-2.12063 0.43581,-2.70669 1.52361,-1.52361 4.41041,-0.13109 4.01242,1.93549 -0.4433,2.30188 -3.64766,2.85743 -4.44823,0.7712 z"
|
||||
id="path4887"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||
d="m 411.32164,243.39982 c 7.38153,0.15924 14.76525,0.0821 22.14736,0.0136 -3.6814,3.83663 -9.42739,1.45689 -14.06576,2.07921 -3.69684,-0.007 -7.3939,0.0151 -11.09,0.0923 1.0029,-0.72825 2.00505,-1.45754 3.0084,-2.18514 z"
|
||||
id="path4889"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 8.5 KiB |
250
debian/changelog
vendored
250
debian/changelog
vendored
|
@ -1,250 +0,0 @@
|
|||
python-click (8.1.3-2~bpo11+1~evo) bullseye-backports; urgency=medium
|
||||
|
||||
* Rebuild for bullseye-backports.
|
||||
|
||||
-- David Prévot <taffit@debian.org> Fri, 03 Mar 2023 14:20:57 +0100
|
||||
|
||||
python-click (8.1.3-2) unstable; urgency=medium
|
||||
|
||||
* remove excessive changes not coordinated with the current maintainer.
|
||||
* debian/copyright
|
||||
- extend packaging copyright years
|
||||
* debian/control
|
||||
- bump Standards-Version to 4.6.2.0 (no changes needed)
|
||||
|
||||
-- Sandro Tosi <morph@debian.org> Tue, 10 Jan 2023 01:12:21 -0500
|
||||
|
||||
python-click (8.1.3-1) unstable; urgency=medium
|
||||
|
||||
* Team upload
|
||||
|
||||
[ Sandro Tosi ]
|
||||
* Add autopkgtest
|
||||
|
||||
[ Carsten Schoenert ]
|
||||
* d/gbp.conf: Add some more defaults
|
||||
* New upstream version 8.1.3
|
||||
* Add patch queue from patch-queue branch
|
||||
Added patch:
|
||||
docs-Use-local-Python-intersphinx-inventary.patch
|
||||
* d/control: Switch and small update on build dependencies
|
||||
* d/control: Bump Standards-Version to 4.6.1
|
||||
No further modifications needed.
|
||||
* d/control: Sorting binary packages alphabetical
|
||||
No modifications to the control fields.
|
||||
* d/copyright: Small updates on content
|
||||
* d/u/metadata: Adding entries for FAQ and Documentation
|
||||
* d/rules: Tune sphinxdoc build a bit
|
||||
* d/rules: Remove unneded VCS file from package
|
||||
* autopkgtest: Run test really on all python versions
|
||||
* d/README.source: Addings some information about source
|
||||
* d/control: Set Rules-Requires-Root: no
|
||||
|
||||
-- Carsten Schoenert <c.schoenert@t-online.de> Wed, 30 Nov 2022 11:16:40 +0100
|
||||
|
||||
python-click (8.0.3-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
* debian/copyright
|
||||
- extend packaging copyright years
|
||||
* debian/control
|
||||
- add Breaks: python3-click-threading (<< 0.5.0); Closes: #994391
|
||||
- bump Standards-Version to 4.6.0.1 (no changes needed)
|
||||
|
||||
-- Sandro Tosi <morph@debian.org> Sun, 02 Jan 2022 20:58:40 -0500
|
||||
|
||||
python-click (8.0.2-1) unstable; urgency=low
|
||||
|
||||
[ Debian Janitor ]
|
||||
* Apply multi-arch hints.
|
||||
+ python-click-doc: Add Multi-Arch: foreign.
|
||||
|
||||
[ Ondřej Nový ]
|
||||
* d/control: Update Vcs-* fields with new Debian Python Team Salsa
|
||||
layout.
|
||||
|
||||
[ Sandro Tosi ]
|
||||
* New upstream release
|
||||
* Use the new Debian Python Team contact name and address
|
||||
* debian/watch
|
||||
- track github releases
|
||||
* debian/rules
|
||||
- exclude test_expand_args, it fails and upstream is not interested in
|
||||
helping out what may be wrong
|
||||
* debian/control
|
||||
- merge b-d-i into b-d
|
||||
- add sphinx-tabs to b-d, needed by doc
|
||||
- set versioned dep on pallets-sphinx-themes to >= 2.0.1, needed for
|
||||
ethicalads.html template
|
||||
|
||||
-- Sandro Tosi <morph@debian.org> Sat, 09 Oct 2021 22:41:33 -0400
|
||||
|
||||
python-click (7.1.2-1) unstable; urgency=medium
|
||||
|
||||
[ Debian Janitor ]
|
||||
* Bump debhelper from deprecated 9 to 12.
|
||||
* Set upstream metadata fields: Bug-Database, Bug-Submit, Repository,
|
||||
Repository-Browse.
|
||||
* Update standards version to 4.5.0, no changes needed.
|
||||
|
||||
[ Sandro Tosi ]
|
||||
* New upstream release
|
||||
* debian/copyright
|
||||
- extend packaging copyright years
|
||||
- update upstream copyright information
|
||||
* debian/control
|
||||
- wrap-and-sort
|
||||
- add sphinxcontrib-log-cabinet to b-d, needed by doc
|
||||
- add sphinx.issues to b-d, needed by doc
|
||||
- dh compat to 13
|
||||
* debian/rules
|
||||
- properly build doc and installd it in the right -doc location
|
||||
- install examples
|
||||
* debian/python-click-doc.doc-base
|
||||
- adjust doc-base to new doc location
|
||||
|
||||
-- Sandro Tosi <morph@debian.org> Sun, 23 Aug 2020 23:18:54 -0400
|
||||
|
||||
python-click (7.0-3) unstable; urgency=medium
|
||||
|
||||
[ Ondřej Nový ]
|
||||
* Use debhelper-compat instead of debian/compat.
|
||||
* Bump Standards-Version to 4.4.1.
|
||||
|
||||
[ Sandro Tosi ]
|
||||
* Drop python2 support; Closes: #937648
|
||||
|
||||
-- Sandro Tosi <morph@debian.org> Thu, 02 Jan 2020 22:56:09 -0500
|
||||
|
||||
python-click (7.0-2) unstable; urgency=medium
|
||||
|
||||
* debian/control
|
||||
- adopt under DPMT umbrella; Thanks Alexandre for your previous work!
|
||||
Closes: #940333
|
||||
- bump Standards-Version to 4.4.0 (no changes needed)
|
||||
- Update Vcs-* fields to DPMT location
|
||||
* debian/copyright
|
||||
- add packaging copyright
|
||||
|
||||
-- Sandro Tosi <morph@debian.org> Thu, 19 Sep 2019 19:24:24 -0400
|
||||
|
||||
python-click (7.0-1) unstable; urgency=medium
|
||||
|
||||
[ Ondřej Nový ]
|
||||
* Use 'python3 -m sphinx' instead of sphinx-build for building docs
|
||||
|
||||
[ Alexandre Viau ]
|
||||
* New upstream version. (Closes: #918561)
|
||||
* d/watch: support Click and click.
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Mon, 07 Jan 2019 11:53:07 -0500
|
||||
|
||||
python-click (6.7+git20180829-1) unstable; urgency=medium
|
||||
|
||||
* New upstream snapshot.
|
||||
* Remove unneeded patches.
|
||||
* Depend on python3-pallets-sphinx-themes.
|
||||
* d/rules: no longer clean artwork/.
|
||||
* d/rules: override_dh_sphinxdoc. (Closes: #906550)
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Thu, 06 Sep 2018 15:21:26 -0400
|
||||
|
||||
python-click (6.7-5) unstable; urgency=medium
|
||||
|
||||
* Sphinx 1.7 support. (Closes: #896630)
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Thu, 28 Jun 2018 20:37:56 -0400
|
||||
|
||||
python-click (6.7-4) unstable; urgency=medium
|
||||
|
||||
* Correct homepage field (Closes: #895277).
|
||||
* Fix insecure-copyright-format-uri.
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Fri, 13 Apr 2018 09:12:35 -0400
|
||||
|
||||
python-click (6.7-3.1) unstable; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Ship documentation subpackage (Closes: #844432).
|
||||
* Reduce short description length.
|
||||
* Declare compliance with Debian policy 4.1.3.
|
||||
|
||||
-- Athos Ribeiro <athoscribeiro@gmail.com> Fri, 23 Mar 2018 23:25:00 +0000
|
||||
|
||||
python-click (6.7-3) unstable; urgency=medium
|
||||
|
||||
* Fix dead VCS-Git URL.
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Sun, 07 Jan 2018 13:59:09 -0500
|
||||
|
||||
python-click (6.7-2) unstable; urgency=medium
|
||||
|
||||
* Move to salsa.debian.org.
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Fri, 29 Dec 2017 01:02:22 -0500
|
||||
|
||||
python-click (6.7-1) unstable; urgency=medium
|
||||
|
||||
[ Ondřej Nový ]
|
||||
* Enabled autopkgtest-pkg-python testsuite
|
||||
* Standards-Version is 3.9.8 now (no changes needed)
|
||||
* d/watch: Use https protocol
|
||||
|
||||
[ Alexandre Viau ]
|
||||
* New upstream version (Closes: #856581)
|
||||
* d/watch: exclude dev versions
|
||||
* Create skip_test_legacy_callbacks.patch (Closes: #868816)
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Wed, 19 Jul 2017 14:22:51 -0400
|
||||
|
||||
python-click (6.6-1) unstable; urgency=medium
|
||||
|
||||
[ Adrian Alves ]
|
||||
* New upstream release
|
||||
* upstream fixed debian patch fix-locale-check.patch
|
||||
|
||||
[ Alexandre Viau ]
|
||||
* Changed version to 6.6
|
||||
* Changed Vcs-Browser and Vcs-Git to secure (https) urls
|
||||
* Bumped Standards-Version to 3.9.7
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Fri, 25 Mar 2016 09:33:30 -0500
|
||||
|
||||
python-click (6.2-2) unstable; urgency=medium
|
||||
|
||||
* Fixed locale detection error (Closes: #812713)
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Tue, 26 Jan 2016 09:33:30 -0500
|
||||
|
||||
python-click (6.2-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
* changed my email to @debian.org
|
||||
|
||||
-- Alexandre Viau <aviau@debian.org> Thu, 17 Dec 2015 08:54:36 -0500
|
||||
|
||||
python-click (5.1-1) unstable; urgency=low
|
||||
|
||||
* New upstream release
|
||||
* Moved appropriate dependencies to Build-Depends-Indep
|
||||
* Re-licensed debian packaging to BSD
|
||||
|
||||
-- Alexandre Viau <alexandre@alexandreviau.net> Sat, 22 Aug 2015 21:10:55 -0400
|
||||
|
||||
python-click (4.1-1) unstable; urgency=medium
|
||||
|
||||
* Upstream 4.1 release
|
||||
|
||||
-- Alexandre Viau <alexandre@alexandreviau.net> Thu, 16 Jul 2015 08:28:32 -0400
|
||||
|
||||
python-click (3.3-2) unstable; urgency=low
|
||||
|
||||
* Set UTF-8 before building (Closes: #772605)
|
||||
|
||||
-- Alexandre Viau <alexandre@alexandreviau.net> Tue, 09 Dec 2014 00:22:06 -0500
|
||||
|
||||
python-click (3.3-1) unstable; urgency=low
|
||||
|
||||
* Initial release (Closes: #764953)
|
||||
|
||||
-- Alexandre Viau <alexandre@alexandreviau.net> Fri, 10 Oct 2014 12:56:09 -0400
|
61
debian/control
vendored
61
debian/control
vendored
|
@ -1,61 +0,0 @@
|
|||
Source: python-click
|
||||
Section: python
|
||||
Priority: optional
|
||||
Maintainer: Sandro Tosi <morph@debian.org>
|
||||
Uploaders: Debian Python Team <team+python@tracker.debian.org>,
|
||||
Build-Depends: debhelper-compat (= 13),
|
||||
dh-sequence-python3,
|
||||
python3-all,
|
||||
python3-doc <!nodoc>,
|
||||
python3-colorama,
|
||||
python3-docutils,
|
||||
python3-pallets-sphinx-themes (>= 2.0.1) <!nodoc>,
|
||||
python3-pytest <!nocheck>,
|
||||
python3-requests,
|
||||
python3-setuptools,
|
||||
python3-sphinx <!nodoc>,
|
||||
python3-sphinx-issues <!nodoc>,
|
||||
python3-sphinx-tabs <!nodoc>,
|
||||
python3-sphinxcontrib-log-cabinet <!nodoc>,
|
||||
Standards-Version: 4.6.2.0
|
||||
Vcs-Browser: https://salsa.debian.org/python-team/packages/python-click
|
||||
Vcs-Git: https://salsa.debian.org/python-team/packages/python-click.git
|
||||
Homepage: https://github.com/pallets/click
|
||||
Rules-Requires-Root: no
|
||||
Testsuite: autopkgtest-pkg-python
|
||||
|
||||
Package: python3-click
|
||||
Architecture: all
|
||||
Depends: python3-colorama,
|
||||
${misc:Depends},
|
||||
${python3:Depends},
|
||||
Breaks: python3-click-threading (<< 0.5.0),
|
||||
Description: Wrapper around optparse for command line utilities - Python 3.x
|
||||
Click is a Python package for creating beautiful command line interfaces
|
||||
in a composable way with as little code as necessary. It's the "Command
|
||||
Line Interface Creation Kit". It's highly configurable but comes with
|
||||
sensible defaults out of the box.
|
||||
.
|
||||
It aims to make the process of writing command line tools quick and fun
|
||||
while also preventing any frustration caused by the inability to implement
|
||||
an intended CLI API.
|
||||
.
|
||||
This is the Python 3 compatible package.
|
||||
|
||||
Package: python-click-doc
|
||||
Section: doc
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends},
|
||||
${sphinxdoc:Depends},
|
||||
Multi-Arch: foreign
|
||||
Description: Wrapper around optparse for command line utilities - documentation
|
||||
Click is a Python package for creating beautiful command line interfaces
|
||||
in a composable way with as little code as necessary. It's the "Command
|
||||
Line Interface Creation Kit". It's highly configurable but comes with
|
||||
sensible defaults out of the box.
|
||||
.
|
||||
It aims to make the process of writing command line tools quick and fun
|
||||
while also preventing any frustration caused by the inability to implement
|
||||
an intended CLI API.
|
||||
.
|
||||
This package contains the documentation for Click.
|
48
debian/copyright
vendored
48
debian/copyright
vendored
|
@ -1,48 +0,0 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Contact: contact@palletsprojects.com
|
||||
Upstream-Name: click
|
||||
Source: https://github.com/pallets/click
|
||||
|
||||
Files: *
|
||||
Copyright: Copyright 2014 Pallets
|
||||
2016-2022 David Lord <davidism@gmail.com>
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: src/click/parser.py
|
||||
Copyright: 2001-2006 Gregory P. Ward
|
||||
2002-2006 Python Software Foundation
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2014 Alexandre Viau <alexandre@alexandreviau.net>
|
||||
Copyright (C) 2019-2023 Sandro Tosi <morph@debian.org>
|
||||
License: BSD-3-clause
|
||||
|
||||
License: BSD-3-clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
.
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
.
|
||||
* The names of the contributors may not be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,22 +0,0 @@
|
|||
From: Carsten Schoenert <c.schoenert@t-online.de>
|
||||
Date: Wed, 30 Nov 2022 10:04:35 +0100
|
||||
Subject: docs: Use local Python intersphinx inventary
|
||||
|
||||
Forwarded: Not-Needed
|
||||
---
|
||||
docs/conf.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/docs/conf.py b/docs/conf.py
|
||||
index b0ed9ff..f4eab7a 100644
|
||||
--- a/docs/conf.py
|
||||
+++ b/docs/conf.py
|
||||
@@ -25,7 +25,7 @@ extensions = [
|
||||
"sphinx_tabs.tabs",
|
||||
]
|
||||
autodoc_typehints = "description"
|
||||
-intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)}
|
||||
+intersphinx_mapping = {"python": ("/usr/share/doc/python3-doc/html", None)}
|
||||
issues_github_path = "pallets/click"
|
||||
|
||||
# HTML -----------------------------------------------------------------
|
1
debian/patches/series
vendored
1
debian/patches/series
vendored
|
@ -1 +0,0 @@
|
|||
docs-Use-local-Python-intersphinx-inventary.patch
|
15
debian/python-click-doc.doc-base
vendored
15
debian/python-click-doc.doc-base
vendored
|
@ -1,15 +0,0 @@
|
|||
Document: python-click
|
||||
Title: Click Documentation
|
||||
Author: Armin Ronacher
|
||||
Abstract: Manual for Click
|
||||
Section: Programming/Python
|
||||
|
||||
Format: text
|
||||
Files: /usr/share/doc/python-click-doc/html/_sources/*.rst.txt
|
||||
|
||||
Format: HTML
|
||||
Index: /usr/share/doc/python-click-doc/html/index.html
|
||||
Files:
|
||||
/usr/share/doc/python-click-doc/html/_static/*
|
||||
/usr/share/doc/python-click-doc/html/*.html
|
||||
|
34
debian/rules
vendored
34
debian/rules
vendored
|
@ -1,34 +0,0 @@
|
|||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
include /usr/share/dpkg/pkg-info.mk
|
||||
|
||||
BUILD_DATE = $(shell LC_ALL=C date -u "+%d %B %Y" -d "@$(SOURCE_DATE_EPOCH)")
|
||||
SPHINXOPTS := -E -N -D html_last_updated_fmt="$(BUILD_DATE)"
|
||||
|
||||
export LC_ALL=C.UTF-8
|
||||
export LANG=C.UTF-8
|
||||
|
||||
export PYBUILD_NAME=click
|
||||
export PYBUILD_TEST_PYTEST=1
|
||||
export PYBUILD_TEST_ARGS=-k 'not test_expand_args' {dir}/tests/
|
||||
|
||||
export SOURCE = $(CURDIR)/debian/
|
||||
|
||||
%:
|
||||
dh $@ --with sphinxdoc --buildsystem=pybuild
|
||||
|
||||
override_dh_sphinxdoc:
|
||||
ifeq (,$(findstring nodoc, $(DEB_BUILD_OPTIONS)))
|
||||
PYTHONPATH=src/ python3 -m sphinx -b html $(SPHINXOPTS) docs/ debian/python-click-doc/usr/share/doc/python-click-doc/html/
|
||||
dh_sphinxdoc
|
||||
endif
|
||||
|
||||
override_dh_installexamples:
|
||||
dh_installexamples -ppython-click-doc examples/*
|
||||
|
||||
override_dh_fixperms:
|
||||
dh_fixperms
|
||||
rm -f debian/python-click-doc/usr/share/doc/python-click-doc/examples/imagepipe/.gitignore
|
1
debian/source/format
vendored
1
debian/source/format
vendored
|
@ -1 +0,0 @@
|
|||
3.0 (quilt)
|
4
debian/tests/control
vendored
4
debian/tests/control
vendored
|
@ -1,4 +0,0 @@
|
|||
Tests: unittests
|
||||
Depends: @,
|
||||
@builddeps@,
|
||||
Restrictions: allow-stderr
|
18
debian/tests/unittests
vendored
18
debian/tests/unittests
vendored
|
@ -1,18 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -efu
|
||||
|
||||
pys="$(py3versions -s 2> /dev/null)"
|
||||
|
||||
cp -a setup.cfg tests "$AUTOPKGTEST_TMP"
|
||||
|
||||
# needed by `test_expand_args`
|
||||
mkdir $AUTOPKGTEST_TMP/docs
|
||||
cp -a docs/conf.py $AUTOPKGTEST_TMP/docs
|
||||
cp -a setup.cfg "$AUTOPKGTEST_TMP"
|
||||
|
||||
cd "$AUTOPKGTEST_TMP"
|
||||
|
||||
for py in $pys; do
|
||||
echo "=== $py ==="
|
||||
$py -m pytest tests 2>&1
|
||||
done
|
5
debian/upstream/metadata
vendored
5
debian/upstream/metadata
vendored
|
@ -1,5 +0,0 @@
|
|||
Bug-Database: https://github.com/pallets/click/issues
|
||||
Bug-Submit: https://github.com/pallets/click/issues/new
|
||||
Documentation: https://click.palletsprojects.com
|
||||
Repository: https://github.com/pallets/click.git
|
||||
Repository-Browse: https://github.com/pallets/click
|
3
debian/watch
vendored
3
debian/watch
vendored
|
@ -1,3 +0,0 @@
|
|||
version=4
|
||||
opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%python-click-$1.tar.gz%" \
|
||||
https://github.com/pallets/click/tags (?:.*?/)?v?(\d[\d.]*)\.tar\.gz
|
|
@ -1,20 +0,0 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = Jinja
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
BIN
docs/_static/click-icon.png
vendored
BIN
docs/_static/click-icon.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 625 B |
BIN
docs/_static/click-logo-sidebar.png
vendored
BIN
docs/_static/click-logo-sidebar.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 4.1 KiB |
BIN
docs/_static/click-logo.png
vendored
BIN
docs/_static/click-logo.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
|
@ -1,488 +0,0 @@
|
|||
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 (see `Command alias example
|
||||
<https://github.com/pallets/click/tree/main/examples/aliases>`_).
|
||||
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(f"Too many matches: {', '.join(sorted(matches))}")
|
||||
|
||||
def resolve_command(self, ctx, args):
|
||||
# always return the full command name
|
||||
_, cmd, args = super().resolve_command(ctx, args)
|
||||
return cmd.name, cmd, args
|
||||
|
||||
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
|
||||
|
||||
Parameter Modifications
|
||||
-----------------------
|
||||
|
||||
Parameters (options and arguments) are forwarded to the command callbacks
|
||||
as you have seen. One common way to prevent a parameter from being passed
|
||||
to the callback is the `expose_value` argument to a parameter which hides
|
||||
the parameter entirely. The way this works is that the :class:`Context`
|
||||
object has a :attr:`~Context.params` attribute which is a dictionary of
|
||||
all parameters. Whatever is in that dictionary is being passed to the
|
||||
callbacks.
|
||||
|
||||
This can be used to make up addition parameters. Generally this pattern
|
||||
is not recommended but in some cases it can be useful. At the very least
|
||||
it's good to know that the system works this way.
|
||||
|
||||
.. click:example::
|
||||
|
||||
import urllib
|
||||
|
||||
def open_url(ctx, param, value):
|
||||
if value is not None:
|
||||
ctx.params['fp'] = urllib.urlopen(value)
|
||||
return value
|
||||
|
||||
@click.command()
|
||||
@click.option('--url', callback=open_url)
|
||||
def cli(url, fp=None):
|
||||
if fp is not None:
|
||||
click.echo(f"{url}: {fp.code}")
|
||||
|
||||
In this case the callback returns the URL unchanged but also passes a
|
||||
second ``fp`` value to the callback. What's more recommended is to pass
|
||||
the information in a wrapper however:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import urllib
|
||||
|
||||
class URL(object):
|
||||
|
||||
def __init__(self, url, fp):
|
||||
self.url = url
|
||||
self.fp = fp
|
||||
|
||||
def open_url(ctx, param, value):
|
||||
if value is not None:
|
||||
return URL(value, urllib.urlopen(value))
|
||||
|
||||
@click.command()
|
||||
@click.option('--url', callback=open_url)
|
||||
def cli(url):
|
||||
if url is not None:
|
||||
click.echo(f"{url.url}: {url.fp.code}")
|
||||
|
||||
|
||||
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(f"Name: {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(f'Count: {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 three 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 last. 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.
|
||||
|
||||
.. _forwarding-unknown-options:
|
||||
|
||||
Forwarding Unknown Options
|
||||
--------------------------
|
||||
|
||||
In some situations it is interesting to be able to accept all unknown
|
||||
options for further manual processing. Click can generally do that as of
|
||||
Click 4.0, but it has some limitations that lie in the nature of the
|
||||
problem. The support for this is provided through a parser flag called
|
||||
``ignore_unknown_options`` which will instruct the parser to collect all
|
||||
unknown options and to put them to the leftover argument instead of
|
||||
triggering a parsing error.
|
||||
|
||||
This can generally be activated in two different ways:
|
||||
|
||||
1. It can be enabled on custom :class:`Command` subclasses by changing
|
||||
the :attr:`~BaseCommand.ignore_unknown_options` attribute.
|
||||
2. It can be enabled by changing the attribute of the same name on the
|
||||
context class (:attr:`Context.ignore_unknown_options`). This is best
|
||||
changed through the ``context_settings`` dictionary on the command.
|
||||
|
||||
For most situations the easiest solution is the second. Once the behavior
|
||||
is changed something needs to pick up those leftover options (which at
|
||||
this point are considered arguments). For this again you have two
|
||||
options:
|
||||
|
||||
1. You can use :func:`pass_context` to get the context passed. This will
|
||||
only work if in addition to :attr:`~Context.ignore_unknown_options`
|
||||
you also set :attr:`~Context.allow_extra_args` as otherwise the
|
||||
command will abort with an error that there are leftover arguments.
|
||||
If you go with this solution, the extra arguments will be collected in
|
||||
:attr:`Context.args`.
|
||||
2. You can attach a :func:`argument` with ``nargs`` set to `-1` which
|
||||
will eat up all leftover arguments. In this case it's recommended to
|
||||
set the `type` to :data:`UNPROCESSED` to avoid any string processing
|
||||
on those arguments as otherwise they are forced into unicode strings
|
||||
automatically which is often not what you want.
|
||||
|
||||
In the end you end up with something like this:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import sys
|
||||
from subprocess import call
|
||||
|
||||
@click.command(context_settings=dict(
|
||||
ignore_unknown_options=True,
|
||||
))
|
||||
@click.option('-v', '--verbose', is_flag=True, help='Enables verbose mode')
|
||||
@click.argument('timeit_args', nargs=-1, type=click.UNPROCESSED)
|
||||
def cli(verbose, timeit_args):
|
||||
"""A fake wrapper around Python's timeit."""
|
||||
cmdline = ['echo', 'python', '-mtimeit'] + list(timeit_args)
|
||||
if verbose:
|
||||
click.echo(f"Invoking: {' '.join(cmdline)}")
|
||||
call(cmdline)
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='cli', args=['--help'])
|
||||
println()
|
||||
invoke(cli, prog_name='cli', args=['-n', '100', 'a = 1; b = 2; a * b'])
|
||||
println()
|
||||
invoke(cli, prog_name='cli', args=['-v', 'a = 1; b = 2; a * b'])
|
||||
|
||||
As you can see the verbosity flag is handled by Click, everything else
|
||||
ends up in the `timeit_args` variable for further processing which then
|
||||
for instance, allows invoking a subprocess. There are a few things that
|
||||
are important to know about how this ignoring of unhandled flag happens:
|
||||
|
||||
* Unknown long options are generally ignored and not processed at all.
|
||||
So for instance if ``--foo=bar`` or ``--foo bar`` are passed they
|
||||
generally end up like that. Note that because the parser cannot know
|
||||
if an option will accept an argument or not, the ``bar`` part might be
|
||||
handled as an argument.
|
||||
* Unknown short options might be partially handled and reassembled if
|
||||
necessary. For instance in the above example there is an option
|
||||
called ``-v`` which enables verbose mode. If the command would be
|
||||
ignored with ``-va`` then the ``-v`` part would be handled by Click
|
||||
(as it is known) and ``-a`` would end up in the leftover parameters
|
||||
for further processing.
|
||||
* Depending on what you plan on doing you might have some success by
|
||||
disabling interspersed arguments
|
||||
(:attr:`~Context.allow_interspersed_args`) which instructs the parser
|
||||
to not allow arguments and options to be mixed. Depending on your
|
||||
situation this might improve your results.
|
||||
|
||||
Generally though the combinated handling of options and arguments from
|
||||
your own commands and commands from another application are discouraged
|
||||
and if you can avoid it, you should. It's a much better idea to have
|
||||
everything below a subcommand be forwarded to another application than to
|
||||
handle some arguments yourself.
|
||||
|
||||
|
||||
Global Context Access
|
||||
---------------------
|
||||
|
||||
.. versionadded:: 5.0
|
||||
|
||||
Starting with Click 5.0 it is possible to access the current context from
|
||||
anywhere within the same thread through the use of the
|
||||
:func:`get_current_context` function which returns it. This is primarily
|
||||
useful for accessing the context bound object as well as some flags that
|
||||
are stored on it to customize the runtime behavior. For instance the
|
||||
:func:`echo` function does this to infer the default value of the `color`
|
||||
flag.
|
||||
|
||||
Example usage::
|
||||
|
||||
def get_current_command_name():
|
||||
return click.get_current_context().info_name
|
||||
|
||||
It should be noted that this only works within the current thread. If you
|
||||
spawn additional threads then those threads will not have the ability to
|
||||
refer to the current context. If you want to give another thread the
|
||||
ability to refer to this context you need to use the context within the
|
||||
thread as a context manager::
|
||||
|
||||
def spawn_thread(ctx, func):
|
||||
def wrapper():
|
||||
with ctx:
|
||||
func()
|
||||
t = threading.Thread(target=wrapper)
|
||||
t.start()
|
||||
return t
|
||||
|
||||
Now the thread function can access the context like the main thread would
|
||||
do. However if you do use this for threading you need to be very careful
|
||||
as the vast majority of the context is not thread safe! You are only
|
||||
allowed to read from the context, but not to perform any modifications on
|
||||
it.
|
||||
|
||||
|
||||
Detecting the Source of a Parameter
|
||||
-----------------------------------
|
||||
|
||||
In some situations it's helpful to understand whether or not an option
|
||||
or parameter came from the command line, the environment, the default
|
||||
value, or :attr:`Context.default_map`. The
|
||||
:meth:`Context.get_parameter_source` method can be used to find this
|
||||
out. It will return a member of the :class:`~click.core.ParameterSource`
|
||||
enum.
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('port', nargs=1, default=8080, envvar="PORT")
|
||||
@click.pass_context
|
||||
def cli(ctx, port):
|
||||
source = ctx.get_parameter_source("port")
|
||||
click.echo(f"Port came from {source.name}")
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='cli', args=['8080'])
|
||||
println()
|
||||
invoke(cli, prog_name='cli', args=[], env={"PORT": "8080"})
|
||||
println()
|
||||
invoke(cli, prog_name='cli', args=[])
|
||||
println()
|
||||
|
||||
|
||||
Managing Resources
|
||||
------------------
|
||||
|
||||
It can be useful to open a resource in a group, to be made available to
|
||||
subcommands. Many types of resources need to be closed or otherwise
|
||||
cleaned up after use. The standard way to do this in Python is by using
|
||||
a context manager with the ``with`` statement.
|
||||
|
||||
For example, the ``Repo`` class from :doc:`complex` might actually be
|
||||
defined as a context manager:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Repo:
|
||||
def __init__(self, home=None):
|
||||
self.home = os.path.abspath(home or ".")
|
||||
self.db = None
|
||||
|
||||
def __enter__(self):
|
||||
path = os.path.join(self.home, "repo.db")
|
||||
self.db = open_database(path)
|
||||
|
||||
def __exit__(self, exc_type, exc_value, tb):
|
||||
self.db.close()
|
||||
|
||||
Ordinarily, it would be used with the ``with`` statement:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with Repo() as repo:
|
||||
repo.db.query(...)
|
||||
|
||||
However, a ``with`` block in a group would exit and close the database
|
||||
before it could be used by a subcommand.
|
||||
|
||||
Instead, use the context's :meth:`~click.Context.with_resource` method
|
||||
to enter the context manager and return the resource. When the group and
|
||||
any subcommands finish, the context's resources are cleaned up.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.group()
|
||||
@click.option("--repo-home", default=".repo")
|
||||
@click.pass_context
|
||||
def cli(ctx, repo_home):
|
||||
ctx.obj = ctx.with_resource(Repo(repo_home))
|
||||
|
||||
@cli.command()
|
||||
@click.pass_obj
|
||||
def log(obj):
|
||||
# obj is the repo opened in the cli group
|
||||
for entry in obj.db.query(...):
|
||||
click.echo(entry)
|
||||
|
||||
If the resource isn't a context manager, usually it can be wrapped in
|
||||
one using something from :mod:`contextlib`. If that's not possible, use
|
||||
the context's :meth:`~click.Context.call_on_close` method to register a
|
||||
cleanup function.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.group()
|
||||
@click.option("--name", default="repo.db")
|
||||
@click.pass_context
|
||||
def cli(ctx, repo_home):
|
||||
ctx.obj = db = open_db(repo_home)
|
||||
|
||||
@ctx.call_on_close
|
||||
def close_db():
|
||||
db.record_use()
|
||||
db.save()
|
||||
db.close()
|
209
docs/api.rst
209
docs/api.rst
|
@ -1,209 +0,0 @@
|
|||
API
|
||||
===
|
||||
|
||||
.. module:: click
|
||||
|
||||
This part of the documentation lists the full API reference of all public
|
||||
classes and functions.
|
||||
|
||||
Decorators
|
||||
----------
|
||||
|
||||
.. autofunction:: command
|
||||
|
||||
.. autofunction:: group
|
||||
|
||||
.. autofunction:: argument
|
||||
|
||||
.. autofunction:: option
|
||||
|
||||
.. autofunction:: password_option
|
||||
|
||||
.. autofunction:: confirmation_option
|
||||
|
||||
.. autofunction:: version_option
|
||||
|
||||
.. autofunction:: help_option
|
||||
|
||||
.. autofunction:: pass_context
|
||||
|
||||
.. autofunction:: pass_obj
|
||||
|
||||
.. autofunction:: make_pass_decorator
|
||||
|
||||
.. autofunction:: click.decorators.pass_meta_key
|
||||
|
||||
|
||||
Utilities
|
||||
---------
|
||||
|
||||
.. autofunction:: echo
|
||||
|
||||
.. autofunction:: echo_via_pager
|
||||
|
||||
.. autofunction:: prompt
|
||||
|
||||
.. autofunction:: confirm
|
||||
|
||||
.. autofunction:: progressbar
|
||||
|
||||
.. autofunction:: clear
|
||||
|
||||
.. autofunction:: style
|
||||
|
||||
.. autofunction:: unstyle
|
||||
|
||||
.. autofunction:: secho
|
||||
|
||||
.. autofunction:: edit
|
||||
|
||||
.. autofunction:: launch
|
||||
|
||||
.. autofunction:: getchar
|
||||
|
||||
.. autofunction:: pause
|
||||
|
||||
.. autofunction:: get_binary_stream
|
||||
|
||||
.. autofunction:: get_text_stream
|
||||
|
||||
.. autofunction:: open_file
|
||||
|
||||
.. autofunction:: get_app_dir
|
||||
|
||||
.. autofunction:: format_filename
|
||||
|
||||
Commands
|
||||
--------
|
||||
|
||||
.. autoclass:: BaseCommand
|
||||
:members:
|
||||
|
||||
.. autoclass:: Command
|
||||
:members:
|
||||
|
||||
.. autoclass:: MultiCommand
|
||||
:members:
|
||||
|
||||
.. autoclass:: Group
|
||||
:members:
|
||||
|
||||
.. autoclass:: CommandCollection
|
||||
:members:
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
.. autoclass:: Parameter
|
||||
:members:
|
||||
|
||||
.. autoclass:: Option
|
||||
|
||||
.. autoclass:: Argument
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. autoclass:: Context
|
||||
:members:
|
||||
|
||||
.. autofunction:: get_current_context
|
||||
|
||||
.. autoclass:: click.core.ParameterSource
|
||||
:members:
|
||||
:member-order: bysource
|
||||
|
||||
|
||||
Types
|
||||
-----
|
||||
|
||||
.. autodata:: STRING
|
||||
|
||||
.. autodata:: INT
|
||||
|
||||
.. autodata:: FLOAT
|
||||
|
||||
.. autodata:: BOOL
|
||||
|
||||
.. autodata:: UUID
|
||||
|
||||
.. autodata:: UNPROCESSED
|
||||
|
||||
.. autoclass:: File
|
||||
|
||||
.. autoclass:: Path
|
||||
|
||||
.. autoclass:: Choice
|
||||
|
||||
.. autoclass:: IntRange
|
||||
|
||||
.. autoclass:: FloatRange
|
||||
|
||||
.. autoclass:: DateTime
|
||||
|
||||
.. autoclass:: Tuple
|
||||
|
||||
.. autoclass:: ParamType
|
||||
:members:
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. autoexception:: ClickException
|
||||
|
||||
.. autoexception:: Abort
|
||||
|
||||
.. autoexception:: UsageError
|
||||
|
||||
.. autoexception:: BadParameter
|
||||
|
||||
.. autoexception:: FileError
|
||||
|
||||
.. autoexception:: NoSuchOption
|
||||
|
||||
.. autoexception:: BadOptionUsage
|
||||
|
||||
.. autoexception:: BadArgumentUsage
|
||||
|
||||
Formatting
|
||||
----------
|
||||
|
||||
.. autoclass:: HelpFormatter
|
||||
:members:
|
||||
|
||||
.. autofunction:: wrap_text
|
||||
|
||||
Parsing
|
||||
-------
|
||||
|
||||
.. autoclass:: OptionParser
|
||||
:members:
|
||||
|
||||
|
||||
Shell Completion
|
||||
----------------
|
||||
|
||||
See :doc:`/shell-completion` for information about enabling and
|
||||
customizing Click's shell completion system.
|
||||
|
||||
.. currentmodule:: click.shell_completion
|
||||
|
||||
.. autoclass:: CompletionItem
|
||||
|
||||
.. autoclass:: ShellComplete
|
||||
:members:
|
||||
:member-order: bysource
|
||||
|
||||
.. autofunction:: add_completion_class
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
.. currentmodule:: click.testing
|
||||
|
||||
.. autoclass:: CliRunner
|
||||
:members:
|
||||
|
||||
.. autoclass:: Result
|
||||
:members:
|
|
@ -1,269 +0,0 @@
|
|||
.. _arguments:
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
Arguments work similarly to :ref:`options <options>` but are positional.
|
||||
They also only support a subset of the features of options due to their
|
||||
syntactical nature. Click will also not attempt to document arguments for
|
||||
you and wants you to :ref:`document them manually <documenting-arguments>`
|
||||
in order to avoid ugly help pages.
|
||||
|
||||
Basic Arguments
|
||||
---------------
|
||||
|
||||
The most basic option is a simple string argument of one value. If no
|
||||
type is provided, the type of the default value is used, and if no default
|
||||
value is provided, the type is assumed to be :data:`STRING`.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('filename')
|
||||
def touch(filename):
|
||||
"""Print FILENAME."""
|
||||
click.echo(filename)
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(touch, args=['foo.txt'])
|
||||
|
||||
Variadic Arguments
|
||||
------------------
|
||||
|
||||
The second most common version is variadic arguments where a specific (or
|
||||
unlimited) number of arguments is accepted. This can be controlled with
|
||||
the ``nargs`` parameter. If it is set to ``-1``, then an unlimited number
|
||||
of arguments is accepted.
|
||||
|
||||
The value is then passed as a tuple. Note that only one argument can be
|
||||
set to ``nargs=-1``, as it will eat up all arguments.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('src', nargs=-1)
|
||||
@click.argument('dst', nargs=1)
|
||||
def copy(src, dst):
|
||||
"""Move file SRC to DST."""
|
||||
for fn in src:
|
||||
click.echo(f"move {fn} to folder {dst}")
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(copy, args=['foo.txt', 'bar.txt', 'my_folder'])
|
||||
|
||||
Note that this is not how you would write this application. The reason
|
||||
for this is that in this particular example the arguments are defined as
|
||||
strings. Filenames, however, are not strings! They might be on certain
|
||||
operating systems, but not necessarily on all. For better ways to write
|
||||
this, see the next sections.
|
||||
|
||||
.. admonition:: Note on Non-Empty Variadic Arguments
|
||||
|
||||
If you come from ``argparse``, you might be missing support for setting
|
||||
``nargs`` to ``+`` to indicate that at least one argument is required.
|
||||
|
||||
This is supported by setting ``required=True``. However, this should
|
||||
not be used if you can avoid it as we believe scripts should gracefully
|
||||
degrade into becoming noops if a variadic argument is empty. The
|
||||
reason for this is that very often, scripts are invoked with wildcard
|
||||
inputs from the command line and they should not error out if the
|
||||
wildcard is empty.
|
||||
|
||||
.. _file-args:
|
||||
|
||||
File Arguments
|
||||
--------------
|
||||
|
||||
Since all the examples have already worked with filenames, it makes sense
|
||||
to explain how to deal with files properly. Command line tools are more
|
||||
fun if they work with files the Unix way, which is to accept ``-`` as a
|
||||
special file that refers to stdin/stdout.
|
||||
|
||||
Click supports this through the :class:`click.File` type which
|
||||
intelligently handles files for you. It also deals with Unicode and bytes
|
||||
correctly for all versions of Python so your script stays very portable.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('input', type=click.File('rb'))
|
||||
@click.argument('output', type=click.File('wb'))
|
||||
def inout(input, output):
|
||||
"""Copy contents of INPUT to OUTPUT."""
|
||||
while True:
|
||||
chunk = input.read(1024)
|
||||
if not chunk:
|
||||
break
|
||||
output.write(chunk)
|
||||
|
||||
And what it does:
|
||||
|
||||
.. click:run::
|
||||
|
||||
with isolated_filesystem():
|
||||
invoke(inout, args=['-', 'hello.txt'], input=['hello'],
|
||||
terminate_input=True)
|
||||
invoke(inout, args=['hello.txt', '-'])
|
||||
|
||||
File Path Arguments
|
||||
-------------------
|
||||
|
||||
In the previous example, the files were opened immediately. But what if
|
||||
we just want the filename? The naïve way is to use the default string
|
||||
argument type. However, remember that Click is Unicode-based, so the string
|
||||
will always be a Unicode value. Unfortunately, filenames can be Unicode or
|
||||
bytes depending on which operating system is being used. As such, the type
|
||||
is insufficient.
|
||||
|
||||
Instead, you should be using the :class:`Path` type, which automatically
|
||||
handles this ambiguity. Not only will it return either bytes or Unicode
|
||||
depending on what makes more sense, but it will also be able to do some
|
||||
basic checks for you such as existence checks.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('filename', type=click.Path(exists=True))
|
||||
def touch(filename):
|
||||
"""Print FILENAME if the file exists."""
|
||||
click.echo(click.format_filename(filename))
|
||||
|
||||
And what it does:
|
||||
|
||||
.. click:run::
|
||||
|
||||
with isolated_filesystem():
|
||||
with open('hello.txt', 'w') as f:
|
||||
f.write('Hello World!\n')
|
||||
invoke(touch, args=['hello.txt'])
|
||||
println()
|
||||
invoke(touch, args=['missing.txt'])
|
||||
|
||||
|
||||
File Opening Safety
|
||||
-------------------
|
||||
|
||||
The :class:`FileType` type has one problem it needs to deal with, and that
|
||||
is to decide when to open a file. The default behavior is to be
|
||||
"intelligent" about it. What this means is that it will open stdin/stdout
|
||||
and files opened for reading immediately. This will give the user direct
|
||||
feedback when a file cannot be opened, but it will only open files
|
||||
for writing the first time an IO operation is performed by automatically
|
||||
wrapping the file in a special wrapper.
|
||||
|
||||
This behavior can be forced by passing ``lazy=True`` or ``lazy=False`` to
|
||||
the constructor. If the file is opened lazily, it will fail its first IO
|
||||
operation by raising an :exc:`FileError`.
|
||||
|
||||
Since files opened for writing will typically immediately empty the file,
|
||||
the lazy mode should only be disabled if the developer is absolutely sure
|
||||
that this is intended behavior.
|
||||
|
||||
Forcing lazy mode is also very useful to avoid resource handling
|
||||
confusion. If a file is opened in lazy mode, it will receive a
|
||||
``close_intelligently`` method that can help figure out if the file
|
||||
needs closing or not. This is not needed for parameters, but is
|
||||
necessary for manually prompting with the :func:`prompt` function as you
|
||||
do not know if a stream like stdout was opened (which was already open
|
||||
before) or a real file that needs closing.
|
||||
|
||||
Starting with Click 2.0, it is also possible to open files in atomic mode by
|
||||
passing ``atomic=True``. In atomic mode, all writes go into a separate
|
||||
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
|
||||
---------------------
|
||||
|
||||
Like options, arguments can also grab values from an environment variable.
|
||||
Unlike options, however, this is only supported for explicitly named
|
||||
environment variables.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('src', envvar='SRC', type=click.File('r'))
|
||||
def echo(src):
|
||||
"""Print value of SRC environment variable."""
|
||||
click.echo(src.read())
|
||||
|
||||
And from the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
with isolated_filesystem():
|
||||
with open('hello.txt', 'w') as f:
|
||||
f.write('Hello World!')
|
||||
invoke(echo, env={'SRC': 'hello.txt'})
|
||||
|
||||
In that case, it can also be a list of different environment variables
|
||||
where the first one is picked.
|
||||
|
||||
Generally, this feature is not recommended because it can cause the user
|
||||
a lot of confusion.
|
||||
|
||||
Option-Like Arguments
|
||||
---------------------
|
||||
|
||||
Sometimes, you want to process arguments that look like options. For
|
||||
instance, imagine you have a file named ``-foo.txt``. If you pass this as
|
||||
an argument in this manner, Click will treat it as an option.
|
||||
|
||||
To solve this, Click does what any POSIX style command line script does,
|
||||
and that is to accept the string ``--`` as a separator for options and
|
||||
arguments. After the ``--`` marker, all further parameters are accepted as
|
||||
arguments.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('files', nargs=-1, type=click.Path())
|
||||
def touch(files):
|
||||
"""Print all FILES file names."""
|
||||
for filename in files:
|
||||
click.echo(filename)
|
||||
|
||||
And from the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(touch, ['--', '-foo.txt', 'bar.txt'])
|
||||
|
||||
If you don't like the ``--`` marker, you can set ignore_unknown_options to
|
||||
True to avoid checking unknown options:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command(context_settings={"ignore_unknown_options": True})
|
||||
@click.argument('files', nargs=-1, type=click.Path())
|
||||
def touch(files):
|
||||
"""Print all FILES file names."""
|
||||
for filename in files:
|
||||
click.echo(filename)
|
||||
|
||||
And from the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(touch, ['-foo.txt', 'bar.txt'])
|
|
@ -1,4 +0,0 @@
|
|||
Changes
|
||||
=======
|
||||
|
||||
.. include:: ../CHANGES.rst
|
|
@ -1,571 +0,0 @@
|
|||
Commands and Groups
|
||||
===================
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
The most important feature of Click is the concept of arbitrarily nesting
|
||||
command line utilities. This is implemented through the :class:`Command`
|
||||
and :class:`Group` (actually :class:`MultiCommand`).
|
||||
|
||||
Callback Invocation
|
||||
-------------------
|
||||
|
||||
For a regular command, the callback is executed whenever the command runs.
|
||||
If the script is the only command, it will always fire (unless a parameter
|
||||
callback prevents it. This for instance happens if someone passes
|
||||
``--help`` to the script).
|
||||
|
||||
For groups and multi commands, the situation looks different. In this case,
|
||||
the callback fires whenever a subcommand fires (unless this behavior is
|
||||
changed). What this means in practice is that an outer command runs
|
||||
when an inner command runs:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group()
|
||||
@click.option('--debug/--no-debug', default=False)
|
||||
def cli(debug):
|
||||
click.echo(f"Debug mode is {'on' if debug else 'off'}")
|
||||
|
||||
@cli.command() # @cli, not @click!
|
||||
def sync():
|
||||
click.echo('Syncing')
|
||||
|
||||
Here is what this looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='tool.py')
|
||||
println()
|
||||
invoke(cli, prog_name='tool.py', args=['--debug', 'sync'])
|
||||
|
||||
Passing Parameters
|
||||
------------------
|
||||
|
||||
Click strictly separates parameters between commands and subcommands. What this
|
||||
means is that options and arguments for a specific command have to be specified
|
||||
*after* the command name itself, but *before* any other command names.
|
||||
|
||||
This behavior is already observable with the predefined ``--help`` option.
|
||||
Suppose we have a program called ``tool.py``, containing a subcommand called
|
||||
``sub``.
|
||||
|
||||
- ``tool.py --help`` will return the help for the whole program (listing
|
||||
subcommands).
|
||||
|
||||
- ``tool.py sub --help`` will return the help for the ``sub`` subcommand.
|
||||
|
||||
- But ``tool.py --help sub`` will treat ``--help`` as an argument for the main
|
||||
program. Click then invokes the callback for ``--help``, which prints the
|
||||
help and aborts the program before click can process the subcommand.
|
||||
|
||||
Nested Handling and Contexts
|
||||
----------------------------
|
||||
|
||||
As you can see from the earlier example, the basic command group accepts a
|
||||
debug argument which is passed to its callback, but not to the sync
|
||||
command itself. The sync command only accepts its own arguments.
|
||||
|
||||
This allows tools to act completely independent of each other, but how
|
||||
does one command talk to a nested one? The answer to this is the
|
||||
:class:`Context`.
|
||||
|
||||
Each time a command is invoked, a new context is created and linked with the
|
||||
parent context. Normally, you can't see these contexts, but they are
|
||||
there. Contexts are passed to parameter callbacks together with the
|
||||
value automatically. Commands can also ask for the context to be passed
|
||||
by marking themselves with the :func:`pass_context` decorator. In that
|
||||
case, the context is passed as first argument.
|
||||
|
||||
The context can also carry a program specified object that can be
|
||||
used for the program's purposes. What this means is that you can build a
|
||||
script like this:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group()
|
||||
@click.option('--debug/--no-debug', default=False)
|
||||
@click.pass_context
|
||||
def cli(ctx, debug):
|
||||
# ensure that ctx.obj exists and is a dict (in case `cli()` is called
|
||||
# by means other than the `if` block below)
|
||||
ctx.ensure_object(dict)
|
||||
|
||||
ctx.obj['DEBUG'] = debug
|
||||
|
||||
@cli.command()
|
||||
@click.pass_context
|
||||
def sync(ctx):
|
||||
click.echo(f"Debug is {'on' if ctx.obj['DEBUG'] else 'off'}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli(obj={})
|
||||
|
||||
If the object is provided, each context will pass the object onwards to
|
||||
its children, but at any level a context's object can be overridden. To
|
||||
reach to a parent, ``context.parent`` can be used.
|
||||
|
||||
In addition to that, instead of passing an object down, nothing stops the
|
||||
application from modifying global state. For instance, you could just flip
|
||||
a global ``DEBUG`` variable and be done with it.
|
||||
|
||||
Decorating Commands
|
||||
-------------------
|
||||
|
||||
As you have seen in the earlier example, a decorator can change how a
|
||||
command is invoked. What actually happens behind the scenes is that
|
||||
callbacks are always invoked through the :meth:`Context.invoke` method
|
||||
which automatically invokes a command correctly (by either passing the
|
||||
context or not).
|
||||
|
||||
This is very useful when you want to write custom decorators. For
|
||||
instance, a common pattern would be to configure an object representing
|
||||
state and then storing it on the context and then to use a custom
|
||||
decorator to find the most recent object of this sort and pass it as first
|
||||
argument.
|
||||
|
||||
For instance, the :func:`pass_obj` decorator can be implemented like this:
|
||||
|
||||
.. click:example::
|
||||
|
||||
from functools import update_wrapper
|
||||
|
||||
def pass_obj(f):
|
||||
@click.pass_context
|
||||
def new_func(ctx, *args, **kwargs):
|
||||
return ctx.invoke(f, ctx.obj, *args, **kwargs)
|
||||
return update_wrapper(new_func, f)
|
||||
|
||||
The :meth:`Context.invoke` command will automatically invoke the function
|
||||
in the correct way, so the function will either be called with ``f(ctx,
|
||||
obj)`` or ``f(obj)`` depending on whether or not it itself is decorated with
|
||||
:func:`pass_context`.
|
||||
|
||||
This is a very powerful concept that can be used to build very complex
|
||||
nested applications; see :ref:`complex-guide` for more information.
|
||||
|
||||
|
||||
Group Invocation Without Command
|
||||
--------------------------------
|
||||
|
||||
By default, a group or multi command is not invoked unless a subcommand is
|
||||
passed. In fact, not providing a command automatically passes ``--help``
|
||||
by default. This behavior can be changed by passing
|
||||
``invoke_without_command=True`` to a group. In that case, the callback is
|
||||
always invoked instead of showing the help page. The context object also
|
||||
includes information about whether or not the invocation would go to a
|
||||
subcommand.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group(invoke_without_command=True)
|
||||
@click.pass_context
|
||||
def cli(ctx):
|
||||
if ctx.invoked_subcommand is None:
|
||||
click.echo('I was invoked without subcommand')
|
||||
else:
|
||||
click.echo(f"I am about to invoke {ctx.invoked_subcommand}")
|
||||
|
||||
@cli.command()
|
||||
def sync():
|
||||
click.echo('The subcommand')
|
||||
|
||||
And how it works in practice:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='tool', args=[])
|
||||
invoke(cli, prog_name='tool', args=['sync'])
|
||||
|
||||
.. _custom-multi-commands:
|
||||
|
||||
Custom Multi Commands
|
||||
---------------------
|
||||
|
||||
In addition to using :func:`click.group`, you can also build your own
|
||||
custom multi commands. This is useful when you want to support commands
|
||||
being loaded lazily from plugins.
|
||||
|
||||
A custom multi command just needs to implement a list and load method:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import click
|
||||
import os
|
||||
|
||||
plugin_folder = os.path.join(os.path.dirname(__file__), 'commands')
|
||||
|
||||
class MyCLI(click.MultiCommand):
|
||||
|
||||
def list_commands(self, ctx):
|
||||
rv = []
|
||||
for filename in os.listdir(plugin_folder):
|
||||
if filename.endswith('.py') and filename != '__init__.py':
|
||||
rv.append(filename[:-3])
|
||||
rv.sort()
|
||||
return rv
|
||||
|
||||
def get_command(self, ctx, name):
|
||||
ns = {}
|
||||
fn = os.path.join(plugin_folder, name + '.py')
|
||||
with open(fn) as f:
|
||||
code = compile(f.read(), fn, 'exec')
|
||||
eval(code, ns, ns)
|
||||
return ns['cli']
|
||||
|
||||
cli = MyCLI(help='This tool\'s subcommands are loaded from a '
|
||||
'plugin folder dynamically.')
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
|
||||
These custom classes can also be used with decorators:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command(cls=MyCLI)
|
||||
def cli():
|
||||
pass
|
||||
|
||||
Merging Multi Commands
|
||||
----------------------
|
||||
|
||||
In addition to implementing custom multi commands, it can also be
|
||||
interesting to merge multiple together into one script. While this is
|
||||
generally not as recommended as it nests one below the other, the merging
|
||||
approach can be useful in some circumstances for a nicer shell experience.
|
||||
|
||||
The default implementation for such a merging system is the
|
||||
:class:`CommandCollection` class. It accepts a list of other multi
|
||||
commands and makes the commands available on the same level.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import click
|
||||
|
||||
@click.group()
|
||||
def cli1():
|
||||
pass
|
||||
|
||||
@cli1.command()
|
||||
def cmd1():
|
||||
"""Command on cli1"""
|
||||
|
||||
@click.group()
|
||||
def cli2():
|
||||
pass
|
||||
|
||||
@cli2.command()
|
||||
def cmd2():
|
||||
"""Command on cli2"""
|
||||
|
||||
cli = click.CommandCollection(sources=[cli1, cli2])
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='cli', args=['--help'])
|
||||
|
||||
In case a command exists in more than one source, the first source wins.
|
||||
|
||||
|
||||
.. _multi-command-chaining:
|
||||
|
||||
Multi Command Chaining
|
||||
----------------------
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
Sometimes it is useful to be allowed to invoke more than one subcommand in
|
||||
one go. For instance if you have installed a setuptools package before
|
||||
you might be familiar with the ``setup.py sdist bdist_wheel upload``
|
||||
command chain which invokes ``sdist`` before ``bdist_wheel`` before
|
||||
``upload``. Starting with Click 3.0 this is very simple to implement.
|
||||
All you have to do is to pass ``chain=True`` to your multicommand:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group(chain=True)
|
||||
def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command('sdist')
|
||||
def sdist():
|
||||
click.echo('sdist called')
|
||||
|
||||
|
||||
@cli.command('bdist_wheel')
|
||||
def bdist_wheel():
|
||||
click.echo('bdist_wheel called')
|
||||
|
||||
Now you can invoke it like this:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='setup.py', args=['sdist', 'bdist_wheel'])
|
||||
|
||||
When using multi command chaining you can only have one command (the last)
|
||||
use ``nargs=-1`` on an argument. It is also not possible to nest multi
|
||||
commands below chained multicommands. Other than that there are no
|
||||
restrictions on how they work. They can accept options and arguments as
|
||||
normal. The order between options and arguments is limited for chained
|
||||
commands. Currently only ``--options argument`` order is allowed.
|
||||
|
||||
Another note: the :attr:`Context.invoked_subcommand` attribute is a bit
|
||||
useless for multi commands as it will give ``'*'`` as value if more than
|
||||
one command is invoked. This is necessary because the handling of
|
||||
subcommands happens one after another so the exact subcommands that will
|
||||
be handled are not yet available when the callback fires.
|
||||
|
||||
.. note::
|
||||
|
||||
It is currently not possible for chain commands to be nested. This
|
||||
will be fixed in future versions of Click.
|
||||
|
||||
|
||||
Multi Command Pipelines
|
||||
-----------------------
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
A very common usecase of multi command chaining is to have one command
|
||||
process the result of the previous command. There are various ways in
|
||||
which this can be facilitated. The most obvious way is to store a value
|
||||
on the context object and process it from function to function. This
|
||||
works by decorating a function with :func:`pass_context` after which the
|
||||
context object is provided and a subcommand can store its data there.
|
||||
|
||||
Another way to accomplish this is to setup pipelines by returning
|
||||
processing functions. Think of it like this: when a subcommand gets
|
||||
invoked it processes all of its parameters and comes up with a plan of
|
||||
how to do its processing. At that point it then returns a processing
|
||||
function and returns.
|
||||
|
||||
Where do the returned functions go? The chained multicommand can register
|
||||
a callback with :meth:`MultiCommand.result_callback` that goes over all
|
||||
these functions and then invoke them.
|
||||
|
||||
To make this a bit more concrete consider this example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group(chain=True, invoke_without_command=True)
|
||||
@click.option('-i', '--input', type=click.File('r'))
|
||||
def cli(input):
|
||||
pass
|
||||
|
||||
@cli.result_callback()
|
||||
def process_pipeline(processors, input):
|
||||
iterator = (x.rstrip('\r\n') for x in input)
|
||||
for processor in processors:
|
||||
iterator = processor(iterator)
|
||||
for item in iterator:
|
||||
click.echo(item)
|
||||
|
||||
@cli.command('uppercase')
|
||||
def make_uppercase():
|
||||
def processor(iterator):
|
||||
for line in iterator:
|
||||
yield line.upper()
|
||||
return processor
|
||||
|
||||
@cli.command('lowercase')
|
||||
def make_lowercase():
|
||||
def processor(iterator):
|
||||
for line in iterator:
|
||||
yield line.lower()
|
||||
return processor
|
||||
|
||||
@cli.command('strip')
|
||||
def make_strip():
|
||||
def processor(iterator):
|
||||
for line in iterator:
|
||||
yield line.strip()
|
||||
return processor
|
||||
|
||||
That's a lot in one go, so let's go through it step by step.
|
||||
|
||||
1. The first thing is to make a :func:`group` that is chainable. In
|
||||
addition to that we also instruct Click to invoke even if no
|
||||
subcommand is defined. If this would not be done, then invoking an
|
||||
empty pipeline would produce the help page instead of running the
|
||||
result callbacks.
|
||||
2. The next thing we do is to register a result callback on our group.
|
||||
This callback will be invoked with an argument which is the list of
|
||||
all return values of all subcommands and then the same keyword
|
||||
parameters as our group itself. This means we can access the input
|
||||
file easily there without having to use the context object.
|
||||
3. In this result callback we create an iterator of all the lines in the
|
||||
input file and then pass this iterator through all the returned
|
||||
callbacks from all subcommands and finally we print all lines to
|
||||
stdout.
|
||||
|
||||
After that point we can register as many subcommands as we want and each
|
||||
subcommand can return a processor function to modify the stream of lines.
|
||||
|
||||
One important thing of note is that Click shuts down the context after
|
||||
each callback has been run. This means that for instance file types
|
||||
cannot be accessed in the `processor` functions as the files will already
|
||||
be closed there. This limitation is unlikely to change because it would
|
||||
make resource handling much more complicated. For such it's recommended
|
||||
to not use the file type and manually open the file through
|
||||
:func:`open_file`.
|
||||
|
||||
For a more complex example that also improves upon handling of the
|
||||
pipelines have a look at the `imagepipe multi command chaining demo
|
||||
<https://github.com/pallets/click/tree/main/examples/imagepipe>`__ in
|
||||
the Click repository. It implements a pipeline based image editing tool
|
||||
that has a nice internal structure for the pipelines.
|
||||
|
||||
|
||||
Overriding Defaults
|
||||
-------------------
|
||||
|
||||
By default, the default value for a parameter is pulled from the
|
||||
``default`` flag that is provided when it's defined, but that's not the
|
||||
only place defaults can be loaded from. The other place is the
|
||||
:attr:`Context.default_map` (a dictionary) on the context. This allows
|
||||
defaults to be loaded from a configuration file to override the regular
|
||||
defaults.
|
||||
|
||||
This is useful if you plug in some commands from another package but
|
||||
you're not satisfied with the defaults.
|
||||
|
||||
The default map can be nested arbitrarily for each subcommand:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
default_map = {
|
||||
"debug": True, # default for a top level option
|
||||
"runserver": {"port": 5000} # default for a subcommand
|
||||
}
|
||||
|
||||
The default map can be provided when the script is invoked, or
|
||||
overridden at any point by commands. For instance, a top-level command
|
||||
could load the defaults from a configuration file.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import click
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
@cli.command()
|
||||
@click.option('--port', default=8000)
|
||||
def runserver(port):
|
||||
click.echo(f"Serving on http://127.0.0.1:{port}/")
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli(default_map={
|
||||
'runserver': {
|
||||
'port': 5000
|
||||
}
|
||||
})
|
||||
|
||||
And in action:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='cli', args=['runserver'], default_map={
|
||||
'runserver': {
|
||||
'port': 5000
|
||||
}
|
||||
})
|
||||
|
||||
Context Defaults
|
||||
----------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Starting with Click 2.0 you can override defaults for contexts not just
|
||||
when calling your script, but also in the decorator that declares a
|
||||
command. For instance given the previous example which defines a custom
|
||||
``default_map`` this can also be accomplished in the decorator now.
|
||||
|
||||
This example does the same as the previous example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import click
|
||||
|
||||
CONTEXT_SETTINGS = dict(
|
||||
default_map={'runserver': {'port': 5000}}
|
||||
)
|
||||
|
||||
@click.group(context_settings=CONTEXT_SETTINGS)
|
||||
def cli():
|
||||
pass
|
||||
|
||||
@cli.command()
|
||||
@click.option('--port', default=8000)
|
||||
def runserver(port):
|
||||
click.echo(f"Serving on http://127.0.0.1:{port}/")
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
|
||||
And again the example in action:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='cli', args=['runserver'])
|
||||
|
||||
|
||||
Command Return Values
|
||||
---------------------
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
One of the new introductions in Click 3.0 is the full support for return
|
||||
values from command callbacks. This enables a whole range of features
|
||||
that were previously hard to implement.
|
||||
|
||||
In essence any command callback can now return a value. This return value
|
||||
is bubbled to certain receivers. One usecase for this has already been
|
||||
show in the example of :ref:`multi-command-chaining` where it has been
|
||||
demonstrated that chained multi commands can have callbacks that process
|
||||
all return values.
|
||||
|
||||
When working with command return values in Click, this is what you need to
|
||||
know:
|
||||
|
||||
- The return value of a command callback is generally returned from the
|
||||
:meth:`BaseCommand.invoke` method. The exception to this rule has to
|
||||
do with :class:`Group`\s:
|
||||
|
||||
* In a group the return value is generally the return value of the
|
||||
subcommand invoked. The only exception to this rule is that the
|
||||
return value is the return value of the group callback if it's
|
||||
invoked without arguments and `invoke_without_command` is enabled.
|
||||
* If a group is set up for chaining then the return value is a list
|
||||
of all subcommands' results.
|
||||
* Return values of groups can be processed through a
|
||||
:attr:`MultiCommand.result_callback`. This is invoked with the
|
||||
list of all return values in chain mode, or the single return
|
||||
value in case of non chained commands.
|
||||
|
||||
- The return value is bubbled through from the :meth:`Context.invoke`
|
||||
and :meth:`Context.forward` methods. This is useful in situations
|
||||
where you internally want to call into another command.
|
||||
|
||||
- Click does not have any hard requirements for the return values and
|
||||
does not use them itself. This allows return values to be used for
|
||||
custom decorators or workflows (like in the multi command chaining
|
||||
example).
|
||||
|
||||
- When a Click script is invoked as command line application (through
|
||||
:meth:`BaseCommand.main`) the return value is ignored unless the
|
||||
`standalone_mode` is disabled in which case it's bubbled through.
|
220
docs/complex.rst
220
docs/complex.rst
|
@ -1,220 +0,0 @@
|
|||
.. _complex-guide:
|
||||
|
||||
Complex Applications
|
||||
====================
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
Click is designed to assist with the creation of complex and simple CLI tools
|
||||
alike. However, the power of its design is the ability to arbitrarily nest
|
||||
systems together. For instance, if you have ever used Django, you will
|
||||
have realized that it provides a command line utility, but so does Celery.
|
||||
When using Celery with Django, there are two tools that need to interact with
|
||||
each other and be cross-configured.
|
||||
|
||||
In a theoretical world of two separate Click command line utilities, they
|
||||
could solve this problem by nesting one inside the other. For instance, the
|
||||
web framework could also load the commands for the message queue framework.
|
||||
|
||||
Basic Concepts
|
||||
--------------
|
||||
|
||||
To understand how this works, you need to understand two concepts: contexts
|
||||
and the calling convention.
|
||||
|
||||
Contexts
|
||||
````````
|
||||
|
||||
Whenever a Click command is executed, a :class:`Context` object is created
|
||||
which holds state for this particular invocation. It remembers parsed
|
||||
parameters, what command created it, which resources need to be cleaned up
|
||||
at the end of the function, and so forth. It can also optionally hold an
|
||||
application-defined object.
|
||||
|
||||
Context objects build a linked list until they hit the top one. Each context
|
||||
is linked to a parent context. This allows a command to work below
|
||||
another command and store its own information there without having to be
|
||||
afraid of altering up the state of the parent command.
|
||||
|
||||
Because the parent data is available, however, it is possible to navigate to
|
||||
it if needed.
|
||||
|
||||
Most of the time, you do not see the context object, but when writing more
|
||||
complex applications it comes in handy. This brings us to the next point.
|
||||
|
||||
Calling Convention
|
||||
``````````````````
|
||||
|
||||
When a Click command callback is executed, it's passed all the non-hidden
|
||||
parameters as keyword arguments. Notably absent is the context. However,
|
||||
a callback can opt into being passed to the context object by marking itself
|
||||
with :func:`pass_context`.
|
||||
|
||||
So how do you invoke a command callback if you don't know if it should
|
||||
receive the context or not? The answer is that the context itself
|
||||
provides a helper function (:meth:`Context.invoke`) which can do this for
|
||||
you. It accepts the callback as first argument and then invokes the
|
||||
function correctly.
|
||||
|
||||
Building a Git Clone
|
||||
--------------------
|
||||
|
||||
In this example, we want to build a command line tool that resembles a
|
||||
version control system. Systems like Git usually provide one
|
||||
over-arching command that already accepts some parameters and
|
||||
configuration, and then have extra subcommands that do other things.
|
||||
|
||||
The Root Command
|
||||
````````````````
|
||||
|
||||
At the top level, we need a group that can hold all our commands. In this
|
||||
case, we use the basic :func:`click.group` which allows us to register
|
||||
other Click commands below it.
|
||||
|
||||
For this command, we also want to accept some parameters that configure the
|
||||
state of our tool:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import os
|
||||
import click
|
||||
|
||||
|
||||
class Repo(object):
|
||||
def __init__(self, home=None, debug=False):
|
||||
self.home = os.path.abspath(home or '.')
|
||||
self.debug = debug
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.option('--repo-home', envvar='REPO_HOME', default='.repo')
|
||||
@click.option('--debug/--no-debug', default=False,
|
||||
envvar='REPO_DEBUG')
|
||||
@click.pass_context
|
||||
def cli(ctx, repo_home, debug):
|
||||
ctx.obj = Repo(repo_home, debug)
|
||||
|
||||
|
||||
Let's understand what this does. We create a group command which can
|
||||
have subcommands. When it is invoked, it will create an instance of a
|
||||
``Repo`` class. This holds the state for our command line tool. In this
|
||||
case, it just remembers some parameters, but at this point it could also
|
||||
start loading configuration files and so on.
|
||||
|
||||
This state object is then remembered by the context as :attr:`~Context.obj`.
|
||||
This is a special attribute where commands are supposed to remember what
|
||||
they need to pass on to their children.
|
||||
|
||||
In order for this to work, we need to mark our function with
|
||||
:func:`pass_context`, because otherwise, the context object would be
|
||||
entirely hidden from us.
|
||||
|
||||
The First Child Command
|
||||
```````````````````````
|
||||
|
||||
Let's add our first child command to it, the clone command:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@cli.command()
|
||||
@click.argument('src')
|
||||
@click.argument('dest', required=False)
|
||||
def clone(src, dest):
|
||||
pass
|
||||
|
||||
So now we have a clone command, but how do we get access to the repo? As
|
||||
you can imagine, one way is to use the :func:`pass_context` function which
|
||||
again will make our callback also get the context passed on which we
|
||||
memorized the repo. However, there is a second version of this decorator
|
||||
called :func:`pass_obj` which will just pass the stored object, (in our case
|
||||
the repo):
|
||||
|
||||
.. click:example::
|
||||
|
||||
@cli.command()
|
||||
@click.argument('src')
|
||||
@click.argument('dest', required=False)
|
||||
@click.pass_obj
|
||||
def clone(repo, src, dest):
|
||||
pass
|
||||
|
||||
Interleaved Commands
|
||||
````````````````````
|
||||
|
||||
While not relevant for the particular program we want to build, there is
|
||||
also quite good support for interleaving systems. Imagine for instance that
|
||||
there was a super cool plugin for our version control system that needed a
|
||||
lot of configuration and wanted to store its own configuration as
|
||||
:attr:`~Context.obj`. If we would then attach another command below that,
|
||||
we would all of a sudden get the plugin configuration instead of our repo
|
||||
object.
|
||||
|
||||
One obvious way to remedy this is to store a reference to the repo in the
|
||||
plugin, but then a command needs to be aware that it's attached below such a
|
||||
plugin.
|
||||
|
||||
There is a much better system that can be built by taking advantage of the
|
||||
linked nature of contexts. We know that the plugin context is linked to the
|
||||
context that created our repo. Because of that, we can start a search for
|
||||
the last level where the object stored by the context was a repo.
|
||||
|
||||
Built-in support for this is provided by the :func:`make_pass_decorator`
|
||||
factory, which will create decorators for us that find objects (it
|
||||
internally calls into :meth:`Context.find_object`). In our case, we
|
||||
know that we want to find the closest ``Repo`` object, so let's make a
|
||||
decorator for this:
|
||||
|
||||
.. click:example::
|
||||
|
||||
pass_repo = click.make_pass_decorator(Repo)
|
||||
|
||||
If we now use ``pass_repo`` instead of ``pass_obj``, we will always get a
|
||||
repo instead of something else:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@cli.command()
|
||||
@click.argument('src')
|
||||
@click.argument('dest', required=False)
|
||||
@pass_repo
|
||||
def clone(repo, src, dest):
|
||||
pass
|
||||
|
||||
Ensuring Object Creation
|
||||
````````````````````````
|
||||
|
||||
The above example only works if there was an outer command that created a
|
||||
``Repo`` object and stored it in the context. For some more advanced use
|
||||
cases, this might become a problem. The default behavior of
|
||||
:func:`make_pass_decorator` is to call :meth:`Context.find_object`
|
||||
which will find the object. If it can't find the object,
|
||||
:meth:`make_pass_decorator` will raise an error.
|
||||
The alternative behavior is to use :meth:`Context.ensure_object`
|
||||
which will find the object, and if it cannot find it, will create one and
|
||||
store it in the innermost context. This behavior can also be enabled for
|
||||
:func:`make_pass_decorator` by passing ``ensure=True``:
|
||||
|
||||
.. click:example::
|
||||
|
||||
pass_repo = click.make_pass_decorator(Repo, ensure=True)
|
||||
|
||||
In this case, the innermost context gets an object created if it is
|
||||
missing. This might replace objects being placed there earlier. In this
|
||||
case, the command stays executable, even if the outer command does not run.
|
||||
For this to work, the object type needs to have a constructor that accepts
|
||||
no arguments.
|
||||
|
||||
As such it runs standalone:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@pass_repo
|
||||
def cp(repo):
|
||||
click.echo(isinstance(repo, Repo))
|
||||
|
||||
As you can see:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cp, [])
|
59
docs/conf.py
59
docs/conf.py
|
@ -1,59 +0,0 @@
|
|||
from pallets_sphinx_themes import get_version
|
||||
from pallets_sphinx_themes import ProjectLink
|
||||
|
||||
import click._compat
|
||||
|
||||
# compat until pallets-sphinx-themes is updated
|
||||
click._compat.text_type = str
|
||||
|
||||
# Project --------------------------------------------------------------
|
||||
|
||||
project = "Click"
|
||||
copyright = "2014 Pallets"
|
||||
author = "Pallets"
|
||||
release, version = get_version("Click")
|
||||
|
||||
# General --------------------------------------------------------------
|
||||
|
||||
master_doc = "index"
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinxcontrib.log_cabinet",
|
||||
"pallets_sphinx_themes",
|
||||
"sphinx_issues",
|
||||
"sphinx_tabs.tabs",
|
||||
]
|
||||
autodoc_typehints = "description"
|
||||
intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)}
|
||||
issues_github_path = "pallets/click"
|
||||
|
||||
# HTML -----------------------------------------------------------------
|
||||
|
||||
html_theme = "click"
|
||||
html_theme_options = {"index_sidebar_logo": False}
|
||||
html_context = {
|
||||
"project_links": [
|
||||
ProjectLink("Donate", "https://palletsprojects.com/donate"),
|
||||
ProjectLink("PyPI Releases", "https://pypi.org/project/click/"),
|
||||
ProjectLink("Source Code", "https://github.com/pallets/click/"),
|
||||
ProjectLink("Issue Tracker", "https://github.com/pallets/click/issues/"),
|
||||
ProjectLink("Website", "https://palletsprojects.com/p/click"),
|
||||
ProjectLink("Twitter", "https://twitter.com/PalletsTeam"),
|
||||
ProjectLink("Chat", "https://discord.gg/pallets"),
|
||||
]
|
||||
}
|
||||
html_sidebars = {
|
||||
"index": ["project.html", "localtoc.html", "searchbox.html", "ethicalads.html"],
|
||||
"**": ["localtoc.html", "relations.html", "searchbox.html", "ethicalads.html"],
|
||||
}
|
||||
singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]}
|
||||
html_static_path = ["_static"]
|
||||
html_favicon = "_static/click-icon.png"
|
||||
html_logo = "_static/click-logo-sidebar.png"
|
||||
html_title = f"Click Documentation ({version})"
|
||||
html_show_sourcelink = False
|
||||
|
||||
# LaTeX ----------------------------------------------------------------
|
||||
|
||||
latex_documents = [(master_doc, f"Click-{version}.tex", html_title, author, "manual")]
|
|
@ -1,25 +0,0 @@
|
|||
.. _contrib:
|
||||
|
||||
=============
|
||||
click-contrib
|
||||
=============
|
||||
|
||||
As the userbase of Click grows, more and more major feature requests pop up in
|
||||
Click's bugtracker. As reasonable as it may be for those features to be bundled
|
||||
with Click instead of being a standalone project, many of those requested
|
||||
features are either highly experimental or have unproven practical use, while
|
||||
potentially being a burden to maintain.
|
||||
|
||||
This is why click-contrib_ exists. The GitHub organization is a collection of
|
||||
possibly experimental third-party packages whose featureset does not belong
|
||||
into Click, but also a playground for major features that may be added to Click
|
||||
in the future. It is also meant to coordinate and concentrate effort on writing
|
||||
third-party extensions for Click, and to ease the effort of searching for such
|
||||
extensions. In that sense it could be described as a low-maintenance
|
||||
alternative to extension repositories of other frameworks.
|
||||
|
||||
Please note that the quality and stability of those packages may be different
|
||||
than what you expect from Click itself. While published under a common
|
||||
organization, they are still projects separate from Click.
|
||||
|
||||
.. _click-contrib: https://github.com/click-contrib/
|
|
@ -1,241 +0,0 @@
|
|||
Documenting Scripts
|
||||
===================
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
Click makes it very easy to document your command line tools. First of
|
||||
all, it automatically generates help pages for you. While these are
|
||||
currently not customizable in terms of their layout, all of the text
|
||||
can be changed.
|
||||
|
||||
Help Texts
|
||||
----------
|
||||
|
||||
Commands and options accept help arguments. In the case of commands, the
|
||||
docstring of the function is automatically used if provided.
|
||||
|
||||
Simple example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--count', default=1, help='number of greetings')
|
||||
@click.argument('name')
|
||||
def hello(count, name):
|
||||
"""This script prints hello NAME COUNT times."""
|
||||
for x in range(count):
|
||||
click.echo(f"Hello {name}!")
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, args=['--help'])
|
||||
|
||||
|
||||
.. _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
|
||||
the most necessary things, and to document them in the command help text
|
||||
by referring to them by name.
|
||||
|
||||
You might prefer to reference the argument in the description:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('filename')
|
||||
def touch(filename):
|
||||
"""Print FILENAME."""
|
||||
click.echo(filename)
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(touch, args=['--help'])
|
||||
|
||||
Or you might prefer to explicitly provide a description of the argument:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.argument('filename')
|
||||
def touch(filename):
|
||||
"""Print FILENAME.
|
||||
|
||||
FILENAME is the name of the file to check.
|
||||
"""
|
||||
click.echo(filename)
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(touch, args=['--help'])
|
||||
|
||||
For more examples, see the examples in :doc:`/arguments`.
|
||||
|
||||
|
||||
Preventing Rewrapping
|
||||
---------------------
|
||||
|
||||
The default behavior of Click is to rewrap text based on the width of the
|
||||
terminal. In some circumstances, this can become a problem. The main issue
|
||||
is when showing code examples, where newlines are significant.
|
||||
|
||||
Rewrapping can be disabled on a per-paragraph basis by adding a line with
|
||||
solely the ``\b`` escape marker in it. This line will be removed from the
|
||||
help text and rewrapping will be disabled.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
def cli():
|
||||
"""First paragraph.
|
||||
|
||||
This is a very long second paragraph and as you
|
||||
can see wrapped very early in the source text
|
||||
but will be rewrapped to the terminal width in
|
||||
the final output.
|
||||
|
||||
\b
|
||||
This is
|
||||
a paragraph
|
||||
without rewrapping.
|
||||
|
||||
And this is a paragraph
|
||||
that will be rewrapped again.
|
||||
"""
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, args=['--help'])
|
||||
|
||||
.. _doc-meta-variables:
|
||||
|
||||
Truncating Help Texts
|
||||
---------------------
|
||||
|
||||
Click gets command help text from function docstrings. However if you
|
||||
already use docstrings to document function arguments you may not want
|
||||
to see :param: and :return: lines in your help text.
|
||||
|
||||
You can use the ``\f`` escape marker to have Click truncate the help text
|
||||
after the marker.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.pass_context
|
||||
def cli(ctx):
|
||||
"""First paragraph.
|
||||
|
||||
This is a very long second
|
||||
paragraph and not correctly
|
||||
wrapped but it will be rewrapped.
|
||||
\f
|
||||
|
||||
:param click.core.Context ctx: Click context.
|
||||
"""
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, args=['--help'])
|
||||
|
||||
|
||||
Meta Variables
|
||||
--------------
|
||||
|
||||
Options and parameters accept a ``metavar`` argument that can change the
|
||||
meta variable in the help page. The default version is the parameter name
|
||||
in uppercase with underscores, but can be annotated differently if
|
||||
desired. This can be customized at all levels:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command(options_metavar='<options>')
|
||||
@click.option('--count', default=1, help='number of greetings',
|
||||
metavar='<int>')
|
||||
@click.argument('name', metavar='<name>')
|
||||
def hello(count, name):
|
||||
"""This script prints hello <name> <int> times."""
|
||||
for x in range(count):
|
||||
click.echo(f"Hello {name}!")
|
||||
|
||||
Example:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, args=['--help'])
|
||||
|
||||
|
||||
Command Short Help
|
||||
------------------
|
||||
|
||||
For commands, a short help snippet is generated. By default, it's the first
|
||||
sentence of the help message of the command, unless it's too long. This can
|
||||
also be overridden:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
"""A simple command line tool."""
|
||||
|
||||
@cli.command('init', short_help='init the repo')
|
||||
def init():
|
||||
"""Initializes the repository."""
|
||||
|
||||
@cli.command('delete', short_help='delete the repo')
|
||||
def delete():
|
||||
"""Deletes the repository."""
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='repo.py')
|
||||
|
||||
|
||||
Help Parameter Customization
|
||||
----------------------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
The help parameter is implemented in Click in a very special manner.
|
||||
Unlike regular parameters it's automatically added by Click for any
|
||||
command and it performs automatic conflict resolution. By default it's
|
||||
called ``--help``, but this can be changed. If a command itself implements
|
||||
a parameter with the same name, the default help parameter stops accepting
|
||||
it. There is a context setting that can be used to override the names of
|
||||
the help parameters called :attr:`~Context.help_option_names`.
|
||||
|
||||
This example changes the default parameters to ``-h`` and ``--help``
|
||||
instead of just ``--help``:
|
||||
|
||||
.. click:example::
|
||||
|
||||
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
||||
|
||||
@click.command(context_settings=CONTEXT_SETTINGS)
|
||||
def cli():
|
||||
pass
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, ['-h'])
|
|
@ -1,73 +0,0 @@
|
|||
Exception Handling
|
||||
==================
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
Click internally uses exceptions to signal various error conditions that
|
||||
the user of the application might have caused. Primarily this is things
|
||||
like incorrect usage.
|
||||
|
||||
Where are Errors Handled?
|
||||
-------------------------
|
||||
|
||||
Click's main error handling is happening in :meth:`BaseCommand.main`. In
|
||||
there it handles all subclasses of :exc:`ClickException` as well as the
|
||||
standard :exc:`EOFError` and :exc:`KeyboardInterrupt` exceptions. The
|
||||
latter are internally translated into a :exc:`Abort`.
|
||||
|
||||
The logic applied is the following:
|
||||
|
||||
1. If an :exc:`EOFError` or :exc:`KeyboardInterrupt` happens, reraise it
|
||||
as :exc:`Abort`.
|
||||
2. If an :exc:`ClickException` is raised, invoke the
|
||||
:meth:`ClickException.show` method on it to display it and then exit
|
||||
the program with :attr:`ClickException.exit_code`.
|
||||
3. If an :exc:`Abort` exception is raised print the string ``Aborted!``
|
||||
to standard error and exit the program with exit code ``1``.
|
||||
4. if it goes through well, exit the program with exit code ``0``.
|
||||
|
||||
What if I don't want that?
|
||||
--------------------------
|
||||
|
||||
Generally you always have the option to invoke the :meth:`invoke` method
|
||||
yourself. For instance if you have a :class:`Command` you can invoke it
|
||||
manually like this::
|
||||
|
||||
ctx = command.make_context('command-name', ['args', 'go', 'here'])
|
||||
with ctx:
|
||||
result = command.invoke(ctx)
|
||||
|
||||
In this case exceptions will not be handled at all and bubbled up as you
|
||||
would expect.
|
||||
|
||||
Starting with Click 3.0 you can also use the :meth:`Command.main` method
|
||||
but disable the standalone mode which will do two things: disable
|
||||
exception handling and disable the implicit :meth:`sys.exit` at the end.
|
||||
|
||||
So you can do something like this::
|
||||
|
||||
command.main(['command-name', 'args', 'go', 'here'],
|
||||
standalone_mode=False)
|
||||
|
||||
Which Exceptions Exist?
|
||||
-----------------------
|
||||
|
||||
Click has two exception bases: :exc:`ClickException` which is raised for
|
||||
all exceptions that Click wants to signal to the user and :exc:`Abort`
|
||||
which is used to instruct Click to abort the execution.
|
||||
|
||||
A :exc:`ClickException` has a :meth:`~ClickException.show` method which
|
||||
can render an error message to stderr or the given file object. If you
|
||||
want to use the exception yourself for doing something check the API docs
|
||||
about what else they provide.
|
||||
|
||||
The following common subclasses exist:
|
||||
|
||||
* :exc:`UsageError` to inform the user that something went wrong.
|
||||
* :exc:`BadParameter` to inform the user that something went wrong with
|
||||
a specific parameter. These are often handled internally in Click and
|
||||
augmented with extra information if possible. For instance if those
|
||||
are raised from a callback Click will automatically augment it with
|
||||
the parameter name if possible.
|
||||
* :exc:`FileError` this is an error that is raised by the
|
||||
:exc:`FileType` if Click encounters issues opening the file.
|
107
docs/index.rst
107
docs/index.rst
|
@ -1,107 +0,0 @@
|
|||
.. rst-class:: hide-header
|
||||
|
||||
Welcome to Click
|
||||
================
|
||||
|
||||
.. image:: _static/click-logo.png
|
||||
:align: center
|
||||
:scale: 50%
|
||||
:target: https://palletsprojects.com/p/click/
|
||||
|
||||
Click is a Python package for creating beautiful command line interfaces
|
||||
in a composable way with as little code as necessary. It's the "Command
|
||||
Line Interface Creation Kit". It's highly configurable but comes with
|
||||
sensible defaults out of the box.
|
||||
|
||||
It aims to make the process of writing command line tools quick and fun
|
||||
while also preventing any frustration caused by the inability to implement
|
||||
an intended CLI API.
|
||||
|
||||
Click in three points:
|
||||
|
||||
- arbitrary nesting of commands
|
||||
- automatic help page generation
|
||||
- supports lazy loading of subcommands at runtime
|
||||
|
||||
What does it look like? Here is an example of a simple Click program:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
@click.option('--count', default=1, help='Number of greetings.')
|
||||
@click.option('--name', prompt='Your name',
|
||||
help='The person to greet.')
|
||||
def hello(count, name):
|
||||
"""Simple program that greets NAME for a total of COUNT times."""
|
||||
for x in range(count):
|
||||
click.echo(f"Hello {name}!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
hello()
|
||||
|
||||
And what it looks like when run:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, ['--count=3'], prog_name='python hello.py', input='John\n')
|
||||
|
||||
It automatically generates nicely formatted help pages:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, ['--help'], prog_name='python hello.py')
|
||||
|
||||
You can get the library directly from PyPI::
|
||||
|
||||
pip install click
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
This part of the documentation guides you through all of the library's
|
||||
usage patterns.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
why
|
||||
quickstart
|
||||
setuptools
|
||||
parameters
|
||||
options
|
||||
arguments
|
||||
commands
|
||||
prompts
|
||||
documentation
|
||||
complex
|
||||
advanced
|
||||
testing
|
||||
utils
|
||||
shell-completion
|
||||
exceptions
|
||||
unicode-support
|
||||
wincmd
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
If you are looking for information on a specific function, class, or
|
||||
method, this part of the documentation is for you.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
api
|
||||
|
||||
Miscellaneous Pages
|
||||
-------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
contrib
|
||||
upgrading
|
||||
license
|
||||
changes
|
|
@ -1,4 +0,0 @@
|
|||
BSD-3-Clause License
|
||||
====================
|
||||
|
||||
.. include:: ../LICENSE.rst
|
|
@ -1,36 +0,0 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
set SPHINXPROJ=Jinja
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
935
docs/options.rst
935
docs/options.rst
|
@ -1,935 +0,0 @@
|
|||
.. _options:
|
||||
|
||||
Options
|
||||
=======
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
Adding options to commands can be accomplished by the :func:`option`
|
||||
decorator. Since options can come in various different versions, there
|
||||
are a ton of parameters to configure their behavior. Options in click are
|
||||
distinct from :ref:`positional arguments <arguments>`.
|
||||
|
||||
Name Your Options
|
||||
-----------------
|
||||
|
||||
Options have a name that will be used as the Python argument name when
|
||||
calling the decorated function. This can be inferred from the option
|
||||
names or given explicitly. Names are given as position arguments to the
|
||||
decorator.
|
||||
|
||||
A name is chosen in the following order
|
||||
|
||||
1. If a name is not prefixed, it is used as the Python argument name
|
||||
and not treated as an option name on the command line.
|
||||
2. If there is at least one name prefixed with two dashes, the first
|
||||
one given is used as the name.
|
||||
3. The first name prefixed with one dash is used otherwise.
|
||||
|
||||
To get the Python argument name, the chosen name is converted to lower
|
||||
case, up to two dashes are removed as the prefix, and other dashes are
|
||||
converted to underscores.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.command()
|
||||
@click.option('-s', '--string-to-echo')
|
||||
def echo(string_to_echo):
|
||||
click.echo(string_to_echo)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.command()
|
||||
@click.option('-s', '--string-to-echo', 'string')
|
||||
def echo(string):
|
||||
click.echo(string)
|
||||
|
||||
- ``"-f", "--foo-bar"``, the name is ``foo_bar``
|
||||
- ``"-x"``, the name is ``x``
|
||||
- ``"-f", "--filename", "dest"``, the name is ``dest``
|
||||
- ``"--CamelCase"``, the name is ``camelcase``
|
||||
- ``"-f", "-fb"``, the name is ``f``
|
||||
- ``"--f", "--foo-bar"``, the name is ``f``
|
||||
- ``"---f"``, the name is ``_f``
|
||||
|
||||
Basic Value Options
|
||||
-------------------
|
||||
|
||||
The most basic option is a value option. These options accept one
|
||||
argument which is a value. If no type is provided, the type of the default
|
||||
value is used. If no default value is provided, the type is assumed to be
|
||||
:data:`STRING`. Unless a name is explicitly specified, the name of the
|
||||
parameter is the first long option defined; otherwise the first short one is
|
||||
used. By default, options are not required, however to make an option required,
|
||||
simply pass in `required=True` as an argument to the decorator.
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--n', default=1)
|
||||
def dots(n):
|
||||
click.echo('.' * n)
|
||||
|
||||
.. click:example::
|
||||
|
||||
# How to make an option required
|
||||
@click.command()
|
||||
@click.option('--n', required=True, type=int)
|
||||
def dots(n):
|
||||
click.echo('.' * n)
|
||||
|
||||
.. click:example::
|
||||
|
||||
# How to use a Python reserved word such as `from` as a parameter
|
||||
@click.command()
|
||||
@click.option('--from', '-f', 'from_')
|
||||
@click.option('--to', '-t')
|
||||
def reserved_param_name(from_, to):
|
||||
click.echo(f"from {from_} to {to}")
|
||||
|
||||
And on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(dots, args=['--n=2'])
|
||||
|
||||
In this case the option is of type :data:`INT` because the default value
|
||||
is an integer.
|
||||
|
||||
To show the default values when showing command help, use ``show_default=True``
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--n', default=1, show_default=True)
|
||||
def dots(n):
|
||||
click.echo('.' * n)
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(dots, args=['--help'])
|
||||
|
||||
For single option boolean flags, the default remains hidden if the default
|
||||
value is False.
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--n', default=1, show_default=True)
|
||||
@click.option("--gr", is_flag=True, show_default=True, default=False, help="Greet the world.")
|
||||
@click.option("--br", is_flag=True, show_default=True, default=True, help="Add a thematic break")
|
||||
def dots(n, gr, br):
|
||||
if gr:
|
||||
click.echo('Hello world!')
|
||||
click.echo('.' * n)
|
||||
if br:
|
||||
click.echo('-' * n)
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(dots, args=['--help'])
|
||||
|
||||
|
||||
Multi Value Options
|
||||
-------------------
|
||||
|
||||
Sometimes, you have options that take more than one argument. For options,
|
||||
only a fixed number of arguments is supported. This can be configured by
|
||||
the ``nargs`` parameter. The values are then stored as a tuple.
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--pos', nargs=2, type=float)
|
||||
def findme(pos):
|
||||
a, b = pos
|
||||
click.echo(f"{a} / {b}")
|
||||
|
||||
And on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(findme, args=['--pos', '2.0', '3.0'])
|
||||
|
||||
.. _tuple-type:
|
||||
|
||||
Tuples as Multi Value Options
|
||||
-----------------------------
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
As you can see that by using `nargs` set to a specific number each item in
|
||||
the resulting tuple is of the same type. This might not be what you want.
|
||||
Commonly you might want to use different types for different indexes in
|
||||
the tuple. For this you can directly specify a tuple as type:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--item', type=(str, int))
|
||||
def putitem(item):
|
||||
name, id = item
|
||||
click.echo(f"name={name} id={id}")
|
||||
|
||||
And on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(putitem, args=['--item', 'peter', '1338'])
|
||||
|
||||
By using a tuple literal as type, `nargs` gets automatically set to the
|
||||
length of the tuple and the :class:`click.Tuple` type is automatically
|
||||
used. The above example is thus equivalent to this:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--item', nargs=2, type=click.Tuple([str, int]))
|
||||
def putitem(item):
|
||||
name, id = item
|
||||
click.echo(f"name={name} id={id}")
|
||||
|
||||
.. _multiple-options:
|
||||
|
||||
Multiple Options
|
||||
----------------
|
||||
|
||||
Similarly to ``nargs``, there is also the case of wanting to support a
|
||||
parameter being provided multiple times and have all the values recorded --
|
||||
not just the last one. For instance, ``git commit -m foo -m bar`` would
|
||||
record two lines for the commit message: ``foo`` and ``bar``. This can be
|
||||
accomplished with the ``multiple`` flag:
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--message', '-m', multiple=True)
|
||||
def commit(message):
|
||||
click.echo('\n'.join(message))
|
||||
|
||||
And on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(commit, args=['-m', 'foo', '-m', 'bar'])
|
||||
|
||||
When passing a ``default`` with ``multiple=True``, the default value
|
||||
must be a list or tuple, otherwise it will be interpreted as a list of
|
||||
single characters.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.option("--format", multiple=True, default=["json"])
|
||||
|
||||
|
||||
Counting
|
||||
--------
|
||||
|
||||
In some very rare circumstances, it is interesting to use the repetition
|
||||
of options to count an integer up. This can be used for verbosity flags,
|
||||
for instance:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('-v', '--verbose', count=True)
|
||||
def log(verbose):
|
||||
click.echo(f"Verbosity: {verbose}")
|
||||
|
||||
And on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(log, args=['-vvv'])
|
||||
|
||||
Boolean Flags
|
||||
-------------
|
||||
|
||||
Boolean flags are options that can be enabled or disabled. This can be
|
||||
accomplished by defining two flags in one go separated by a slash (``/``)
|
||||
for enabling or disabling the option. (If a slash is in an option string,
|
||||
Click automatically knows that it's a boolean flag and will pass
|
||||
``is_flag=True`` implicitly.) Click always wants you to provide an enable
|
||||
and disable flag so that you can change the default later.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import sys
|
||||
|
||||
@click.command()
|
||||
@click.option('--shout/--no-shout', default=False)
|
||||
def info(shout):
|
||||
rv = sys.platform
|
||||
if shout:
|
||||
rv = rv.upper() + '!!!!111'
|
||||
click.echo(rv)
|
||||
|
||||
And on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(info, args=['--shout'])
|
||||
invoke(info, args=['--no-shout'])
|
||||
invoke(info)
|
||||
|
||||
If you really don't want an off-switch, you can just define one and
|
||||
manually inform Click that something is a flag:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import sys
|
||||
|
||||
@click.command()
|
||||
@click.option('--shout', is_flag=True)
|
||||
def info(shout):
|
||||
rv = sys.platform
|
||||
if shout:
|
||||
rv = rv.upper() + '!!!!111'
|
||||
click.echo(rv)
|
||||
|
||||
And on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(info, args=['--shout'])
|
||||
invoke(info)
|
||||
|
||||
Note that if a slash is contained in your option already (for instance, if
|
||||
you use Windows-style parameters where ``/`` is the prefix character), you
|
||||
can alternatively split the parameters through ``;`` instead:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('/debug;/no-debug')
|
||||
def log(debug):
|
||||
click.echo(f"debug={debug}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
log()
|
||||
|
||||
.. versionchanged:: 6.0
|
||||
|
||||
If you want to define an alias for the second option only, then you will
|
||||
need to use leading whitespace to disambiguate the format string:
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import sys
|
||||
|
||||
@click.command()
|
||||
@click.option('--shout/--no-shout', ' /-S', default=False)
|
||||
def info(shout):
|
||||
rv = sys.platform
|
||||
if shout:
|
||||
rv = rv.upper() + '!!!!111'
|
||||
click.echo(rv)
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(info, args=['--help'])
|
||||
|
||||
Feature Switches
|
||||
----------------
|
||||
|
||||
In addition to boolean flags, there are also feature switches. These are
|
||||
implemented by setting multiple options to the same parameter name and
|
||||
defining a flag value. Note that by providing the ``flag_value`` parameter,
|
||||
Click will implicitly set ``is_flag=True``.
|
||||
|
||||
To set a default flag, assign a value of `True` to the flag that should be
|
||||
the default.
|
||||
|
||||
.. click:example::
|
||||
|
||||
import sys
|
||||
|
||||
@click.command()
|
||||
@click.option('--upper', 'transformation', flag_value='upper',
|
||||
default=True)
|
||||
@click.option('--lower', 'transformation', flag_value='lower')
|
||||
def info(transformation):
|
||||
click.echo(getattr(sys.platform, transformation)())
|
||||
|
||||
And on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(info, args=['--upper'])
|
||||
invoke(info, args=['--lower'])
|
||||
invoke(info)
|
||||
|
||||
.. _choice-opts:
|
||||
|
||||
Choice Options
|
||||
--------------
|
||||
|
||||
Sometimes, you want to have a parameter be a choice of a list of values.
|
||||
In that case you can use :class:`Choice` type. It can be instantiated
|
||||
with a list of valid values. The originally passed choice will be returned,
|
||||
not the str passed on the command line. Token normalization functions and
|
||||
``case_sensitive=False`` can cause the two to be different but still match.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--hash-type',
|
||||
type=click.Choice(['MD5', 'SHA1'], case_sensitive=False))
|
||||
def digest(hash_type):
|
||||
click.echo(hash_type)
|
||||
|
||||
What it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(digest, args=['--hash-type=MD5'])
|
||||
println()
|
||||
invoke(digest, args=['--hash-type=md5'])
|
||||
println()
|
||||
invoke(digest, args=['--hash-type=foo'])
|
||||
println()
|
||||
invoke(digest, args=['--help'])
|
||||
|
||||
Only pass the choices as list or tuple. Other iterables (like
|
||||
generators) may lead to unexpected results.
|
||||
|
||||
Choices work with options that have ``multiple=True``. If a ``default``
|
||||
value is given with ``multiple=True``, it should be a list or tuple of
|
||||
valid choices.
|
||||
|
||||
Choices should be unique after considering the effects of
|
||||
``case_sensitive`` and any specified token normalization function.
|
||||
|
||||
.. versionchanged:: 7.1
|
||||
The resulting value from an option will always be one of the
|
||||
originally passed choices regardless of ``case_sensitive``.
|
||||
|
||||
.. _option-prompting:
|
||||
|
||||
Prompting
|
||||
---------
|
||||
|
||||
In some cases, you want parameters that can be provided from the command line,
|
||||
but if not provided, ask for user input instead. This can be implemented with
|
||||
Click by defining a prompt string.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--name', prompt=True)
|
||||
def hello(name):
|
||||
click.echo(f"Hello {name}!")
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, args=['--name=John'])
|
||||
invoke(hello, input=['John'])
|
||||
|
||||
If you are not happy with the default prompt string, you can ask for
|
||||
a different one:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--name', prompt='Your name please')
|
||||
def hello(name):
|
||||
click.echo(f"Hello {name}!")
|
||||
|
||||
What it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, input=['John'])
|
||||
|
||||
It is advised that prompt not be used in conjunction with the multiple
|
||||
flag set to True. Instead, prompt in the function interactively.
|
||||
|
||||
By default, the user will be prompted for an input if one was not passed
|
||||
through the command line. To turn this behavior off, see
|
||||
:ref:`optional-value`.
|
||||
|
||||
|
||||
Password Prompts
|
||||
----------------
|
||||
|
||||
Click also supports hidden prompts and asking for confirmation. This is
|
||||
useful for password input:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import codecs
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--password", prompt=True, hide_input=True,
|
||||
confirmation_prompt=True
|
||||
)
|
||||
def encode(password):
|
||||
click.echo(f"encoded: {codecs.encode(password, 'rot13')}")
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(encode, input=['secret', 'secret'])
|
||||
|
||||
Because this combination of parameters is quite common, this can also be
|
||||
replaced with the :func:`password_option` decorator:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.command()
|
||||
@click.password_option()
|
||||
def encrypt(password):
|
||||
click.echo(f"encoded: to {codecs.encode(password, 'rot13')}")
|
||||
|
||||
|
||||
Dynamic Defaults for Prompts
|
||||
----------------------------
|
||||
|
||||
The ``auto_envvar_prefix`` and ``default_map`` options for the context
|
||||
allow the program to read option values from the environment or a
|
||||
configuration file. However, this overrides the prompting mechanism, so
|
||||
that the user does not get the option to change the value interactively.
|
||||
|
||||
If you want to let the user configure the default value, but still be
|
||||
prompted if the option isn't specified on the command line, you can do so
|
||||
by supplying a callable as the default value. For example, to get a default
|
||||
from the environment:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import os
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--username", prompt=True,
|
||||
default=lambda: os.environ.get("USER", "")
|
||||
)
|
||||
def hello(username):
|
||||
click.echo(f"Hello, {username}!")
|
||||
|
||||
To describe what the default value will be, set it in ``show_default``.
|
||||
|
||||
.. click:example::
|
||||
|
||||
import os
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--username", prompt=True,
|
||||
default=lambda: os.environ.get("USER", ""),
|
||||
show_default="current user"
|
||||
)
|
||||
def hello(username):
|
||||
click.echo(f"Hello, {username}!")
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, args=["--help"])
|
||||
|
||||
|
||||
Callbacks and Eager Options
|
||||
---------------------------
|
||||
|
||||
Sometimes, you want a parameter to completely change the execution flow.
|
||||
For instance, this is the case when you want to have a ``--version``
|
||||
parameter that prints out the version and then exits the application.
|
||||
|
||||
Note: an actual implementation of a ``--version`` parameter that is
|
||||
reusable is available in Click as :func:`click.version_option`. The code
|
||||
here is merely an example of how to implement such a flag.
|
||||
|
||||
In such cases, you need two concepts: eager parameters and a callback. An
|
||||
eager parameter is a parameter that is handled before others, and a
|
||||
callback is what executes after the parameter is handled. The eagerness
|
||||
is necessary so that an earlier required parameter does not produce an
|
||||
error message. For instance, if ``--version`` was not eager and a
|
||||
parameter ``--foo`` was required and defined before, you would need to
|
||||
specify it for ``--version`` to work. For more information, see
|
||||
:ref:`callback-evaluation-order`.
|
||||
|
||||
A callback is a function that is invoked with three parameters: the
|
||||
current :class:`Context`, the current :class:`Parameter`, and the value.
|
||||
The context provides some useful features such as quitting the
|
||||
application and gives access to other already processed parameters.
|
||||
|
||||
Here an example for a ``--version`` flag:
|
||||
|
||||
.. click:example::
|
||||
|
||||
def print_version(ctx, param, value):
|
||||
if not value or ctx.resilient_parsing:
|
||||
return
|
||||
click.echo('Version 1.0')
|
||||
ctx.exit()
|
||||
|
||||
@click.command()
|
||||
@click.option('--version', is_flag=True, callback=print_version,
|
||||
expose_value=False, is_eager=True)
|
||||
def hello():
|
||||
click.echo('Hello World!')
|
||||
|
||||
The `expose_value` parameter prevents the pretty pointless ``version``
|
||||
parameter from being passed to the callback. If that was not specified, a
|
||||
boolean would be passed to the `hello` script. The `resilient_parsing`
|
||||
flag is applied to the context if Click wants to parse the command line
|
||||
without any destructive behavior that would change the execution flow. In
|
||||
this case, because we would exit the program, we instead do nothing.
|
||||
|
||||
What it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello)
|
||||
invoke(hello, args=['--version'])
|
||||
|
||||
.. admonition:: Callback Signature Changes
|
||||
|
||||
In Click 2.0 the signature for callbacks changed. For more
|
||||
information about these changes see :ref:`upgrade-to-2.0`.
|
||||
|
||||
Yes Parameters
|
||||
--------------
|
||||
|
||||
For dangerous operations, it's very useful to be able to ask a user for
|
||||
confirmation. This can be done by adding a boolean ``--yes`` flag and
|
||||
asking for confirmation if the user did not provide it and to fail in a
|
||||
callback:
|
||||
|
||||
.. click:example::
|
||||
|
||||
def abort_if_false(ctx, param, value):
|
||||
if not value:
|
||||
ctx.abort()
|
||||
|
||||
@click.command()
|
||||
@click.option('--yes', is_flag=True, callback=abort_if_false,
|
||||
expose_value=False,
|
||||
prompt='Are you sure you want to drop the db?')
|
||||
def dropdb():
|
||||
click.echo('Dropped all tables!')
|
||||
|
||||
And what it looks like on the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(dropdb, input=['n'])
|
||||
invoke(dropdb, args=['--yes'])
|
||||
|
||||
Because this combination of parameters is quite common, this can also be
|
||||
replaced with the :func:`confirmation_option` decorator:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.confirmation_option(prompt='Are you sure you want to drop the db?')
|
||||
def dropdb():
|
||||
click.echo('Dropped all tables!')
|
||||
|
||||
.. admonition:: Callback Signature Changes
|
||||
|
||||
In Click 2.0 the signature for callbacks changed. For more
|
||||
information about these changes see :ref:`upgrade-to-2.0`.
|
||||
|
||||
Values from Environment Variables
|
||||
---------------------------------
|
||||
|
||||
A very useful feature of Click is the ability to accept parameters from
|
||||
environment variables in addition to regular parameters. This allows
|
||||
tools to be automated much easier. For instance, you might want to pass
|
||||
a configuration file with a ``--config`` parameter but also support exporting
|
||||
a ``TOOL_CONFIG=hello.cfg`` key-value pair for a nicer development
|
||||
experience.
|
||||
|
||||
This is supported by Click in two ways. One is to automatically build
|
||||
environment variables which is supported for options only. To enable this
|
||||
feature, the ``auto_envvar_prefix`` parameter needs to be passed to the
|
||||
script that is invoked. Each command and parameter is then added as an
|
||||
uppercase underscore-separated variable. If you have a subcommand
|
||||
called ``run`` taking an option called ``reload`` and the prefix is
|
||||
``WEB``, then the variable is ``WEB_RUN_RELOAD``.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--username')
|
||||
def greet(username):
|
||||
click.echo(f'Hello {username}!')
|
||||
|
||||
if __name__ == '__main__':
|
||||
greet(auto_envvar_prefix='GREETER')
|
||||
|
||||
And from the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(greet, env={'GREETER_USERNAME': 'john'},
|
||||
auto_envvar_prefix='GREETER')
|
||||
|
||||
When using ``auto_envvar_prefix`` with command groups, the command name
|
||||
needs to be included in the environment variable, between the prefix and
|
||||
the parameter name, *i.e.* ``PREFIX_COMMAND_VARIABLE``. If you have a
|
||||
subcommand called ``run-server`` taking an option called ``host`` and
|
||||
the prefix is ``WEB``, then the variable is ``WEB_RUN_SERVER_HOST``.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group()
|
||||
@click.option('--debug/--no-debug')
|
||||
def cli(debug):
|
||||
click.echo(f"Debug mode is {'on' if debug else 'off'}")
|
||||
|
||||
@cli.command()
|
||||
@click.option('--username')
|
||||
def greet(username):
|
||||
click.echo(f"Hello {username}!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli(auto_envvar_prefix='GREETER')
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, args=['greet',],
|
||||
env={'GREETER_GREET_USERNAME': 'John', 'GREETER_DEBUG': 'false'},
|
||||
auto_envvar_prefix='GREETER')
|
||||
|
||||
|
||||
The second option is to manually pull values in from specific environment
|
||||
variables by defining the name of the environment variable on the option.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--username', envvar='USERNAME')
|
||||
def greet(username):
|
||||
click.echo(f"Hello {username}!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
greet()
|
||||
|
||||
And from the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(greet, env={'USERNAME': 'john'})
|
||||
|
||||
In that case it can also be a list of different environment variables
|
||||
where the first one is picked.
|
||||
|
||||
Multiple Values from Environment Values
|
||||
---------------------------------------
|
||||
|
||||
As options can accept multiple values, pulling in such values from
|
||||
environment variables (which are strings) is a bit more complex. The way
|
||||
Click solves this is by leaving it up to the type to customize this
|
||||
behavior. For both ``multiple`` and ``nargs`` with values other than
|
||||
``1``, Click will invoke the :meth:`ParamType.split_envvar_value` method to
|
||||
perform the splitting.
|
||||
|
||||
The default implementation for all types is to split on whitespace. The
|
||||
exceptions to this rule are the :class:`File` and :class:`Path` types
|
||||
which both split according to the operating system's path splitting rules.
|
||||
On Unix systems like Linux and OS X, the splitting happens for those on
|
||||
every colon (``:``), and for Windows, on every semicolon (``;``).
|
||||
|
||||
Example usage:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('paths', '--path', envvar='PATHS', multiple=True,
|
||||
type=click.Path())
|
||||
def perform(paths):
|
||||
for path in paths:
|
||||
click.echo(path)
|
||||
|
||||
if __name__ == '__main__':
|
||||
perform()
|
||||
|
||||
And from the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
import os
|
||||
invoke(perform, env={"PATHS": f"./foo/bar{os.path.pathsep}./test"})
|
||||
|
||||
Other Prefix Characters
|
||||
-----------------------
|
||||
|
||||
Click can deal with alternative prefix characters other than ``-`` for
|
||||
options. This is for instance useful if you want to handle slashes as
|
||||
parameters ``/`` or something similar. Note that this is strongly
|
||||
discouraged in general because Click wants developers to stay close to
|
||||
POSIX semantics. However in certain situations this can be useful:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('+w/-w')
|
||||
def chmod(w):
|
||||
click.echo(f"writable={w}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
chmod()
|
||||
|
||||
And from the command line:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(chmod, args=['+w'])
|
||||
invoke(chmod, args=['-w'])
|
||||
|
||||
Note that if you are using ``/`` as prefix character and you want to use a
|
||||
boolean flag you need to separate it with ``;`` instead of ``/``:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('/debug;/no-debug')
|
||||
def log(debug):
|
||||
click.echo(f"debug={debug}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
log()
|
||||
|
||||
.. _ranges:
|
||||
|
||||
Range Options
|
||||
-------------
|
||||
|
||||
The :class:`IntRange` type extends the :data:`INT` type to ensure the
|
||||
value is contained in the given range. The :class:`FloatRange` type does
|
||||
the same for :data:`FLOAT`.
|
||||
|
||||
If ``min`` or ``max`` is omitted, that side is *unbounded*. Any value in
|
||||
that direction is accepted. By default, both bounds are *closed*, which
|
||||
means the boundary value is included in the accepted range. ``min_open``
|
||||
and ``max_open`` can be used to exclude that boundary from the range.
|
||||
|
||||
If ``clamp`` mode is enabled, a value that is outside the range is set
|
||||
to the boundary instead of failing. For example, the range ``0, 5``
|
||||
would return ``5`` for the value ``10``, or ``0`` for the value ``-1``.
|
||||
When using :class:`FloatRange`, ``clamp`` can only be enabled if both
|
||||
bounds are *closed* (the default).
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option("--count", type=click.IntRange(0, 20, clamp=True))
|
||||
@click.option("--digit", type=click.IntRange(0, 9))
|
||||
def repeat(count, digit):
|
||||
click.echo(str(digit) * count)
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(repeat, args=['--count=100', '--digit=5'])
|
||||
invoke(repeat, args=['--count=6', '--digit=12'])
|
||||
|
||||
|
||||
Callbacks for Validation
|
||||
------------------------
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
|
||||
If you want to apply custom validation logic, you can do this in the
|
||||
parameter callbacks. These callbacks can both modify values as well as
|
||||
raise errors if the validation does not work. The callback runs after
|
||||
type conversion. It is called for all sources, including prompts.
|
||||
|
||||
In Click 1.0, you can only raise the :exc:`UsageError` but starting with
|
||||
Click 2.0, you can also raise the :exc:`BadParameter` error, which has the
|
||||
added advantage that it will automatically format the error message to
|
||||
also contain the parameter name.
|
||||
|
||||
.. click:example::
|
||||
|
||||
def validate_rolls(ctx, param, value):
|
||||
if isinstance(value, tuple):
|
||||
return value
|
||||
|
||||
try:
|
||||
rolls, _, dice = value.partition("d")
|
||||
return int(dice), int(rolls)
|
||||
except ValueError:
|
||||
raise click.BadParameter("format must be 'NdM'")
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--rolls", type=click.UNPROCESSED, callback=validate_rolls,
|
||||
default="1d6", prompt=True,
|
||||
)
|
||||
def roll(rolls):
|
||||
sides, times = rolls
|
||||
click.echo(f"Rolling a {sides}-sided dice {times} time(s)")
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(roll, args=["--rolls=42"])
|
||||
println()
|
||||
invoke(roll, args=["--rolls=2d12"])
|
||||
println()
|
||||
invoke(roll, input=["42", "2d12"])
|
||||
|
||||
|
||||
.. _optional-value:
|
||||
|
||||
Optional Value
|
||||
--------------
|
||||
|
||||
Providing the value to an option can be made optional, in which case
|
||||
providing only the option's flag without a value will either show a
|
||||
prompt or use its ``flag_value``.
|
||||
|
||||
Setting ``is_flag=False, flag_value=value`` tells Click that the option
|
||||
can still be passed a value, but if only the flag is given the
|
||||
``flag_value`` is used.
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option("--name", is_flag=False, flag_value="Flag", default="Default")
|
||||
def hello(name):
|
||||
click.echo(f"Hello, {name}!")
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, args=[])
|
||||
invoke(hello, args=["--name", "Value"])
|
||||
invoke(hello, args=["--name"])
|
||||
|
||||
If the option has ``prompt`` enabled, then setting
|
||||
``prompt_required=False`` tells Click to only show the prompt if the
|
||||
option's flag is given, instead of if the option is not provided at all.
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--name', prompt=True, prompt_required=False, default="Default")
|
||||
def hello(name):
|
||||
click.echo(f"Hello {name}!")
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello)
|
||||
invoke(hello, args=["--name", "Value"])
|
||||
invoke(hello, args=["--name"], input="Prompt")
|
||||
|
||||
If ``required=True``, then the option will still prompt if it is not
|
||||
given, but it will also prompt if only the flag is given.
|
|
@ -1,143 +0,0 @@
|
|||
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`.
|
||||
|
||||
Parameter Types
|
||||
---------------
|
||||
|
||||
Parameters can be of different types. Types can be implemented with
|
||||
different behavior and some are supported out of the box:
|
||||
|
||||
``str`` / :data:`click.STRING`:
|
||||
The default parameter type which indicates unicode strings.
|
||||
|
||||
``int`` / :data:`click.INT`:
|
||||
A parameter that only accepts integers.
|
||||
|
||||
``float`` / :data:`click.FLOAT`:
|
||||
A parameter that only accepts floating point values.
|
||||
|
||||
``bool`` / :data:`click.BOOL`:
|
||||
A parameter that accepts boolean values. This is automatically used
|
||||
for boolean flags. The string values "1", "true", "t", "yes", "y",
|
||||
and "on" convert to ``True``. "0", "false", "f", "no", "n", and
|
||||
"off" convert to ``False``.
|
||||
|
||||
:data:`click.UUID`:
|
||||
A parameter that accepts UUID values. This is not automatically
|
||||
guessed but represented as :class:`uuid.UUID`.
|
||||
|
||||
.. autoclass:: File
|
||||
:noindex:
|
||||
|
||||
.. autoclass:: Path
|
||||
:noindex:
|
||||
|
||||
.. autoclass:: Choice
|
||||
:noindex:
|
||||
|
||||
.. autoclass:: IntRange
|
||||
:noindex:
|
||||
|
||||
.. autoclass:: FloatRange
|
||||
:noindex:
|
||||
|
||||
.. 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
|
||||
-------------------------
|
||||
|
||||
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.
|
||||
|
||||
The following code implements an integer type that accepts hex and octal
|
||||
numbers in addition to normal integers, and converts them into regular
|
||||
integers.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import click
|
||||
|
||||
class BasedIntParamType(click.ParamType):
|
||||
name = "integer"
|
||||
|
||||
def convert(self, value, param, ctx):
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
|
||||
try:
|
||||
if value[:2].lower() == "0x":
|
||||
return int(value[2:], 16)
|
||||
elif value[:1] == "0":
|
||||
return int(value, 8)
|
||||
return int(value, 10)
|
||||
except ValueError:
|
||||
self.fail(f"{value!r} is not a valid integer", param, ctx)
|
||||
|
||||
BASED_INT = BasedIntParamType()
|
||||
|
||||
The :attr:`~ParamType.name` attribute is optional and is used for
|
||||
documentation. Call :meth:`~ParamType.fail` if conversion fails. The
|
||||
``param`` and ``ctx`` arguments may be ``None`` in some cases such as
|
||||
prompts.
|
||||
|
||||
Values from user input or the command line will be strings, but default
|
||||
values and Python arguments may already be the correct type. The custom
|
||||
type should check at the top if the value is already valid and pass it
|
||||
through to support those cases.
|
|
@ -1,48 +0,0 @@
|
|||
User Input Prompts
|
||||
==================
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
Click supports prompts in two different places. The first is automated
|
||||
prompts when the parameter handling happens, and the second is to ask for
|
||||
prompts at a later point independently.
|
||||
|
||||
This can be accomplished with the :func:`prompt` function, which asks for
|
||||
valid input according to a type, or the :func:`confirm` function, which asks
|
||||
for confirmation (yes/no).
|
||||
|
||||
Option Prompts
|
||||
--------------
|
||||
|
||||
Option prompts are integrated into the option interface. See
|
||||
:ref:`option-prompting` for more information. Internally, it
|
||||
automatically calls either :func:`prompt` or :func:`confirm` as necessary.
|
||||
|
||||
Input Prompts
|
||||
-------------
|
||||
|
||||
To manually ask for user input, you can use the :func:`prompt` function.
|
||||
By default, it accepts any Unicode string, but you can ask for any other
|
||||
type. For instance, you can ask for a valid integer::
|
||||
|
||||
value = click.prompt('Please enter a valid integer', type=int)
|
||||
|
||||
Additionally, the type will be determined automatically if a default value is
|
||||
provided. For instance, the following will only accept floats::
|
||||
|
||||
value = click.prompt('Please enter a number', default=42.0)
|
||||
|
||||
Confirmation Prompts
|
||||
--------------------
|
||||
|
||||
To ask if a user wants to continue with an action, the :func:`confirm`
|
||||
function comes in handy. By default, it returns the result of the prompt
|
||||
as a boolean value::
|
||||
|
||||
if click.confirm('Do you want to continue?'):
|
||||
click.echo('Well done!')
|
||||
|
||||
There is also the option to make the function automatically abort the
|
||||
execution of the program if it does not return ``True``::
|
||||
|
||||
click.confirm('Do you want to continue?', abort=True)
|
|
@ -1,299 +0,0 @@
|
|||
Quickstart
|
||||
==========
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
You can get the library directly from PyPI::
|
||||
|
||||
pip install click
|
||||
|
||||
The installation into a :ref:`virtualenv` is heavily recommended.
|
||||
|
||||
.. _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. Let's see how virtualenv
|
||||
works.
|
||||
|
||||
If you are on Mac OS X or Linux::
|
||||
|
||||
$ pip install virtualenv --user
|
||||
|
||||
One of these will probably install virtualenv on your system. Maybe it's even
|
||||
in your package manager. If you use Ubuntu, try::
|
||||
|
||||
$ sudo apt-get install python-virtualenv
|
||||
|
||||
If you are on Windows (or none of the above methods worked) you must install
|
||||
``pip`` first. For more information about this, see `installing pip`_.
|
||||
Once you have it installed, run the ``pip`` command from above, but without
|
||||
the `sudo` prefix.
|
||||
|
||||
.. _installing pip: https://pip.readthedocs.io/en/latest/installing/
|
||||
|
||||
Once you have virtualenv installed, just fire up a shell and create
|
||||
your own environment. I usually create a project folder and a `venv`
|
||||
folder within::
|
||||
|
||||
$ mkdir myproject
|
||||
$ cd myproject
|
||||
$ virtualenv venv
|
||||
New python executable in venv/bin/python
|
||||
Installing setuptools, pip............done.
|
||||
|
||||
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
|
||||
|
||||
If you are a Windows user, the following command is for you::
|
||||
|
||||
$ venv\scripts\activate
|
||||
|
||||
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 go back to the real world, 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
|
||||
-----------------------
|
||||
|
||||
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>`_
|
||||
|
||||
Basic Concepts - Creating a Command
|
||||
-----------------------------------
|
||||
|
||||
Click is based on declaring commands through decorators. Internally, there
|
||||
is a non-decorator interface for advanced use cases, but it's discouraged
|
||||
for high-level usage.
|
||||
|
||||
A function becomes a Click command line tool by decorating it through
|
||||
:func:`click.command`. At its simplest, just decorating a function
|
||||
with this decorator will make it into a callable script:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
def hello():
|
||||
click.echo('Hello World!')
|
||||
|
||||
What's happening is that the decorator converts the function into a
|
||||
:class:`Command` which then can be invoked::
|
||||
|
||||
if __name__ == '__main__':
|
||||
hello()
|
||||
|
||||
And what it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, args=[], prog_name='python hello.py')
|
||||
|
||||
And the corresponding help page:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, args=['--help'], prog_name='python hello.py')
|
||||
|
||||
Echoing
|
||||
-------
|
||||
|
||||
Why does this example use :func:`echo` instead of the regular
|
||||
:func:`print` function? The answer to this question is that Click
|
||||
attempts to support different environments consistently and to be very
|
||||
robust even when the environment is misconfigured. Click wants to be
|
||||
functional at least on a basic level even if everything is completely
|
||||
broken.
|
||||
|
||||
What this means is that the :func:`echo` function applies some error
|
||||
correction in case the terminal is misconfigured instead of dying with a
|
||||
:exc:`UnicodeError`.
|
||||
|
||||
The echo function also supports color and other styles in output. It
|
||||
will automatically remove styles if the output stream is a file. On
|
||||
Windows, colorama is automatically installed and used. See
|
||||
:ref:`ansi-colors`.
|
||||
|
||||
If you don't need this, you can also use the `print()` construct /
|
||||
function.
|
||||
|
||||
Nesting Commands
|
||||
----------------
|
||||
|
||||
Commands can be attached to other commands of type :class:`Group`. This
|
||||
allows arbitrary nesting of scripts. As an example here is a script that
|
||||
implements two commands for managing databases:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
@click.command()
|
||||
def initdb():
|
||||
click.echo('Initialized the database')
|
||||
|
||||
@click.command()
|
||||
def dropdb():
|
||||
click.echo('Dropped the database')
|
||||
|
||||
cli.add_command(initdb)
|
||||
cli.add_command(dropdb)
|
||||
|
||||
As you can see, the :func:`group` decorator works like the :func:`command`
|
||||
decorator, but creates a :class:`Group` object instead which can be given
|
||||
multiple subcommands that can be attached with :meth:`Group.add_command`.
|
||||
|
||||
For simple scripts, it's also possible to automatically attach and create a
|
||||
command by using the :meth:`Group.command` decorator instead. The above
|
||||
script can instead be written like this:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
@cli.command()
|
||||
def initdb():
|
||||
click.echo('Initialized the database')
|
||||
|
||||
@cli.command()
|
||||
def dropdb():
|
||||
click.echo('Dropped the database')
|
||||
|
||||
You would then invoke the :class:`Group` in your setuptools entry points or
|
||||
other invocations::
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
|
||||
|
||||
Registering Commands Later
|
||||
--------------------------
|
||||
|
||||
Instead of using the ``@group.command()`` decorator, commands can be
|
||||
decorated with the plain ``@click.command()`` decorator and registered
|
||||
with a group later with ``group.add_command()``. This could be used to
|
||||
split commands into multiple Python modules.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.command()
|
||||
def greet():
|
||||
click.echo("Hello, World!")
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.group()
|
||||
def group():
|
||||
pass
|
||||
|
||||
group.add_command(greet)
|
||||
|
||||
|
||||
Adding Parameters
|
||||
-----------------
|
||||
|
||||
To add parameters, use the :func:`option` and :func:`argument` decorators:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
@click.option('--count', default=1, help='number of greetings')
|
||||
@click.argument('name')
|
||||
def hello(count, name):
|
||||
for x in range(count):
|
||||
click.echo(f"Hello {name}!")
|
||||
|
||||
What it looks like:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(hello, args=['--help'], prog_name='python hello.py')
|
||||
|
||||
.. _switching-to-setuptools:
|
||||
|
||||
Switching to Setuptools
|
||||
-----------------------
|
||||
|
||||
In the code you wrote so far there is a block at the end of the file which
|
||||
looks like this: ``if __name__ == '__main__':``. This is traditionally
|
||||
how a standalone Python file looks like. With Click you can continue
|
||||
doing that, but there are better ways through setuptools.
|
||||
|
||||
There are two main (and many more) reasons for this:
|
||||
|
||||
The first one is that setuptools automatically generates executable
|
||||
wrappers for Windows so your command line utilities work on Windows too.
|
||||
|
||||
The second reason is that setuptools scripts work with virtualenv on Unix
|
||||
without the virtualenv having to be activated. This is a very useful
|
||||
concept which allows you to bundle your scripts with all requirements into
|
||||
a virtualenv.
|
||||
|
||||
Click is perfectly equipped to work with that and in fact the rest of the
|
||||
documentation will assume that you are writing applications through
|
||||
setuptools.
|
||||
|
||||
I strongly recommend to have a look at the :ref:`setuptools-integration`
|
||||
chapter before reading the rest as the examples assume that you will
|
||||
be using setuptools.
|
|
@ -1,153 +0,0 @@
|
|||
.. _setuptools-integration:
|
||||
|
||||
Setuptools Integration
|
||||
======================
|
||||
|
||||
When writing command line utilities, it's recommended to write them as
|
||||
modules that are distributed with setuptools instead of using Unix
|
||||
shebangs.
|
||||
|
||||
Why would you want to do that? There are a bunch of reasons:
|
||||
|
||||
1. One of the problems with the traditional approach is that the first
|
||||
module the Python interpreter loads has an incorrect name. This might
|
||||
sound like a small issue but it has quite significant implications.
|
||||
|
||||
The first module is not called by its actual name, but the
|
||||
interpreter renames it to ``__main__``. While that is a perfectly
|
||||
valid name it means that if another piece of code wants to import from
|
||||
that module it will trigger the import a second time under its real
|
||||
name and all of a sudden your code is imported twice.
|
||||
|
||||
2. Not on all platforms are things that easy to execute. On Linux and OS
|
||||
X you can add a comment to the beginning of the file (``#!/usr/bin/env
|
||||
python``) and your script works like an executable (assuming it has
|
||||
the executable bit set). This however does not work on Windows.
|
||||
While on Windows you can associate interpreters with file extensions
|
||||
(like having everything ending in ``.py`` execute through the Python
|
||||
interpreter) you will then run into issues if you want to use the
|
||||
script in a virtualenv.
|
||||
|
||||
In fact running a script in a virtualenv is an issue with OS X and
|
||||
Linux as well. With the traditional approach you need to have the
|
||||
whole virtualenv activated so that the correct Python interpreter is
|
||||
used. Not very user friendly.
|
||||
|
||||
3. The main trick only works if the script is a Python module. If your
|
||||
application grows too large and you want to start using a package you
|
||||
will run into issues.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
To bundle your script with setuptools, all you need is the script in a
|
||||
Python package and a ``setup.py`` file.
|
||||
|
||||
Imagine this directory structure:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
yourscript.py
|
||||
setup.py
|
||||
|
||||
Contents of ``yourscript.py``:
|
||||
|
||||
.. click:example::
|
||||
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
def cli():
|
||||
"""Example script."""
|
||||
click.echo('Hello World!')
|
||||
|
||||
Contents of ``setup.py``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='yourscript',
|
||||
version='0.1.0',
|
||||
py_modules=['yourscript'],
|
||||
install_requires=[
|
||||
'Click',
|
||||
],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'yourscript = yourscript:cli',
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
The magic is in the ``entry_points`` parameter. Below
|
||||
``console_scripts``, each line identifies one console script. The first
|
||||
part before the equals sign (``=``) is the name of the script that should
|
||||
be generated, the second part is the import path followed by a colon
|
||||
(``:``) with the Click command.
|
||||
|
||||
That's it.
|
||||
|
||||
Testing The Script
|
||||
------------------
|
||||
|
||||
To test the script, you can make a new virtualenv and then install your
|
||||
package:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ virtualenv venv
|
||||
$ . venv/bin/activate
|
||||
$ pip install --editable .
|
||||
|
||||
Afterwards, your command should be available:
|
||||
|
||||
.. click:run::
|
||||
|
||||
invoke(cli, prog_name='yourscript')
|
||||
|
||||
Scripts in Packages
|
||||
-------------------
|
||||
|
||||
If your script is growing and you want to switch over to your script being
|
||||
contained in a Python package the changes necessary are minimal. Let's
|
||||
assume your directory structure changed to this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
project/
|
||||
yourpackage/
|
||||
__init__.py
|
||||
main.py
|
||||
utils.py
|
||||
scripts/
|
||||
__init__.py
|
||||
yourscript.py
|
||||
setup.py
|
||||
|
||||
In this case instead of using ``py_modules`` in your ``setup.py`` file you
|
||||
can use ``packages`` and the automatic package finding support of
|
||||
setuptools. In addition to that it's also recommended to include other
|
||||
package data.
|
||||
|
||||
These would be the modified contents of ``setup.py``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='yourpackage',
|
||||
version='0.1.0',
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
install_requires=[
|
||||
'Click',
|
||||
],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'yourscript = yourpackage.scripts.yourscript:cli',
|
||||
],
|
||||
},
|
||||
)
|
|
@ -1,287 +0,0 @@
|
|||
.. currentmodule:: click.shell_completion
|
||||
|
||||
Shell Completion
|
||||
================
|
||||
|
||||
Click provides tab completion support for Bash (version 4.4 and up),
|
||||
Zsh, and Fish. It is possible to add support for other shells too, and
|
||||
suggestions can be customized at multiple levels.
|
||||
|
||||
Shell completion suggests command names, option names, and values for
|
||||
choice, file, and path parameter types. Options are only listed if at
|
||||
least a dash has been entered. Hidden commands and options are not
|
||||
shown.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ repo <TAB><TAB>
|
||||
clone commit copy delete setuser
|
||||
$ repo clone -<TAB><TAB>
|
||||
--deep --help --rev --shallow -r
|
||||
|
||||
|
||||
Enabling Completion
|
||||
-------------------
|
||||
|
||||
Completion is only available if a script is installed and invoked
|
||||
through an entry point, not through the ``python`` command. See
|
||||
:doc:`/setuptools`. Once the executable is installed, calling it with
|
||||
a special environment variable will put Click in completion mode.
|
||||
|
||||
In order for completion to be used, the user needs to register a special
|
||||
function with their shell. The script is different for every shell, and
|
||||
Click will output it when called with ``_{PROG_NAME}_COMPLETE`` set to
|
||||
``{shell}_source``. ``{PROG_NAME}`` is the executable name in uppercase
|
||||
with dashes replaced by underscores. The built-in shells are ``bash``,
|
||||
``zsh``, and ``fish``.
|
||||
|
||||
Provide your users with the following instructions customized to your
|
||||
program name. This uses ``foo-bar`` as an example.
|
||||
|
||||
.. tabs::
|
||||
|
||||
.. group-tab:: Bash
|
||||
|
||||
Add this to ``~/.bashrc``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
eval "$(_FOO_BAR_COMPLETE=bash_source foo-bar)"
|
||||
|
||||
.. group-tab:: Zsh
|
||||
|
||||
Add this to ``~/.zshrc``:
|
||||
|
||||
.. code-block:: zsh
|
||||
|
||||
eval "$(_FOO_BAR_COMPLETE=zsh_source foo-bar)"
|
||||
|
||||
.. group-tab:: Fish
|
||||
|
||||
Add this to ``~/.config/fish/completions/foo-bar.fish``:
|
||||
|
||||
.. code-block:: fish
|
||||
|
||||
eval (env _FOO_BAR_COMPLETE=fish_source foo-bar)
|
||||
|
||||
This is the same file used for the activation script method
|
||||
below. For Fish it's probably always easier to use that method.
|
||||
|
||||
Using ``eval`` means that the command is invoked and evaluated every
|
||||
time a shell is started, which can delay shell responsiveness. To speed
|
||||
it up, write the generated script to a file, then source that. You can
|
||||
generate the files ahead of time and distribute them with your program
|
||||
to save your users a step.
|
||||
|
||||
.. tabs::
|
||||
|
||||
.. group-tab:: Bash
|
||||
|
||||
Save the script somewhere.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
_FOO_BAR_COMPLETE=bash_source foo-bar > ~/.foo-bar-complete.bash
|
||||
|
||||
Source the file in ``~/.bashrc``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
. ~/.foo-bar-complete.bash
|
||||
|
||||
.. group-tab:: Zsh
|
||||
|
||||
Save the script somewhere.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
_FOO_BAR_COMPLETE=zsh_source foo-bar > ~/.foo-bar-complete.zsh
|
||||
|
||||
Source the file in ``~/.zshrc``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
. ~/.foo-bar-complete.zsh
|
||||
|
||||
.. group-tab:: Fish
|
||||
|
||||
Save the script to ``~/.config/fish/completions/foo-bar.fish``:
|
||||
|
||||
.. code-block:: fish
|
||||
|
||||
_FOO_BAR_COMPLETE=fish_source foo-bar > ~/.config/fish/completions/foo-bar.fish
|
||||
|
||||
After modifying the shell config, you need to start a new shell in order
|
||||
for the changes to be loaded.
|
||||
|
||||
|
||||
Custom Type Completion
|
||||
----------------------
|
||||
|
||||
When creating a custom :class:`~click.ParamType`, override its
|
||||
:meth:`~click.ParamType.shell_complete` method to provide shell
|
||||
completion for parameters with the type. The method must return a list
|
||||
of :class:`~CompletionItem` objects. Besides the value, these objects
|
||||
hold metadata that shell support might use. The built-in implementations
|
||||
use ``type`` to indicate special handling for paths, and ``help`` for
|
||||
shells that support showing a help string next to a suggestion.
|
||||
|
||||
In this example, the type will suggest environment variables that start
|
||||
with the incomplete value.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class EnvVarType(ParamType):
|
||||
name = "envvar"
|
||||
|
||||
def shell_complete(self, ctx, param, incomplete):
|
||||
return [
|
||||
CompletionItem(name)
|
||||
for name in os.environ if name.startswith(incomplete)
|
||||
]
|
||||
|
||||
@click.command()
|
||||
@click.option("--ev", type=EnvVarType())
|
||||
def cli(ev):
|
||||
click.echo(os.environ[ev])
|
||||
|
||||
|
||||
Overriding Value Completion
|
||||
---------------------------
|
||||
|
||||
Value completions for a parameter can be customized without a custom
|
||||
type by providing a ``shell_complete`` function. The function is used
|
||||
instead of any completion provided by the type. It is passed 3 keyword
|
||||
arguments:
|
||||
|
||||
- ``ctx`` - The current command context.
|
||||
- ``param`` - The current parameter requesting completion.
|
||||
- ``incomplete`` - The partial word that is being completed. May
|
||||
be an empty string if no characters have been entered yet.
|
||||
|
||||
It must return a list of :class:`CompletionItem` objects, or as a
|
||||
shortcut it can return a list of strings.
|
||||
|
||||
In this example, the command will suggest environment variables that
|
||||
start with the incomplete value.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def complete_env_vars(ctx, param, incomplete):
|
||||
return [k for k in os.environ if k.startswith(incomplete)]
|
||||
|
||||
@click.command()
|
||||
@click.argument("name", shell_complete=complete_env_vars)
|
||||
def cli(name):
|
||||
click.echo(f"Name: {name}")
|
||||
click.echo(f"Value: {os.environ[name]}")
|
||||
|
||||
|
||||
Adding Support for a Shell
|
||||
--------------------------
|
||||
|
||||
Support can be added for shells that do not come built in. Be sure to
|
||||
check PyPI to see if there's already a package that adds support for
|
||||
your shell. This topic is very technical, you'll want to look at Click's
|
||||
source to study the built-in implementations.
|
||||
|
||||
Shell support is provided by subclasses of :class:`ShellComplete`
|
||||
registered with :func:`add_completion_class`. When Click is invoked in
|
||||
completion mode, it calls :meth:`~ShellComplete.source` to output the
|
||||
completion script, or :meth:`~ShellComplete.complete` to output
|
||||
completions. The base class provides default implementations that
|
||||
require implementing some smaller parts.
|
||||
|
||||
First, you'll need to figure out how your shell's completion system
|
||||
works and write a script to integrate it with Click. It must invoke your
|
||||
program with the environment variable ``_{PROG_NAME}_COMPLETE`` set to
|
||||
``{shell}_complete`` and pass the complete args and incomplete value.
|
||||
How it passes those values, and the format of the completion response
|
||||
from Click is up to you.
|
||||
|
||||
In your subclass, set :attr:`~ShellComplete.source_template` to the
|
||||
completion script. The default implementation will perform ``%``
|
||||
formatting with the following variables:
|
||||
|
||||
- ``complete_func`` - A safe name for the completion function defined
|
||||
in the script.
|
||||
- ``complete_var`` - The environment variable name for passing the
|
||||
``{shell}_complete`` instruction.
|
||||
- ``prog_name`` - The name of the executable being completed.
|
||||
|
||||
The example code is for a made up shell "My Shell" or "mysh" for short.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from click.shell_completion import add_completion_class
|
||||
from click.shell_completion import ShellComplete
|
||||
|
||||
_mysh_source = """\
|
||||
%(complete_func)s {
|
||||
response=$(%(complete_var)s=mysh_complete %(prog_name)s)
|
||||
# parse response and set completions somehow
|
||||
}
|
||||
call-on-complete %(prog_name)s %(complete_func)s
|
||||
"""
|
||||
|
||||
@add_completion_class
|
||||
class MyshComplete(ShellComplete):
|
||||
name = "mysh"
|
||||
source_template = _mysh_source
|
||||
|
||||
Next, implement :meth:`~ShellComplete.get_completion_args`. This must
|
||||
get, parse, and return the complete args and incomplete value from the
|
||||
completion script. For example, for the Bash implementation the
|
||||
``COMP_WORDS`` env var contains the command line args as a string, and
|
||||
the ``COMP_CWORD`` env var contains the index of the incomplete arg. The
|
||||
method must return a ``(args, incomplete)`` tuple.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import os
|
||||
from click.parser import split_arg_string
|
||||
|
||||
class MyshComplete(ShellComplete):
|
||||
...
|
||||
|
||||
def get_completion_args(self):
|
||||
args = split_arg_string(os.environ["COMP_WORDS"])
|
||||
|
||||
if os.environ["COMP_PARTIAL"] == "1":
|
||||
incomplete = args.pop()
|
||||
return args, incomplete
|
||||
|
||||
return args, ""
|
||||
|
||||
Finally, implement :meth:`~ShellComplete.format_completion`. This is
|
||||
called to format each :class:`CompletionItem` into a string. For
|
||||
example, the Bash implementation returns ``f"{item.type},{item.value}``
|
||||
(it doesn't support help strings), and the Zsh implementation returns
|
||||
each part separated by a newline, replacing empty help with a ``_``
|
||||
placeholder. This format is entirely up to what you parse with your
|
||||
completion script.
|
||||
|
||||
The ``type`` value is usually ``plain``, but it can be another value
|
||||
that the completion script can switch on. For example, ``file`` or
|
||||
``dir`` can tell the shell to handle path completion, since the shell is
|
||||
better at that than Click.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyshComplete(ShellComplete):
|
||||
...
|
||||
|
||||
def format_completion(self, item):
|
||||
return f"{item.type}\t{item.value}"
|
||||
|
||||
With those three things implemented, the new shell support is ready. In
|
||||
case those weren't sufficient, there are more parts that can be
|
||||
overridden, but that probably isn't necessary.
|
||||
|
||||
The activation instructions will again depend on how your shell works.
|
||||
Use the following to generate the completion script, then load it into
|
||||
the shell somehow.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
_FOO_BAR_COMPLETE=mysh_source foo-bar
|
158
docs/testing.rst
158
docs/testing.rst
|
@ -1,158 +0,0 @@
|
|||
Testing Click Applications
|
||||
==========================
|
||||
|
||||
.. currentmodule:: click.testing
|
||||
|
||||
For basic testing, Click provides the :mod:`click.testing` module which
|
||||
provides test functionality that helps you invoke command line
|
||||
applications and check their behavior.
|
||||
|
||||
These tools should really only be used for testing as they change
|
||||
the entire interpreter state for simplicity and are not in any way
|
||||
thread-safe!
|
||||
|
||||
Basic Testing
|
||||
-------------
|
||||
|
||||
The basic functionality for testing Click applications is the
|
||||
:class:`CliRunner` which can invoke commands as command line scripts. The
|
||||
:meth:`CliRunner.invoke` method runs the command line script in isolation
|
||||
and captures the output as both bytes and binary data.
|
||||
|
||||
The return value is a :class:`Result` object, which has the captured output
|
||||
data, exit code, and optional exception attached:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: hello.py
|
||||
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
@click.argument('name')
|
||||
def hello(name):
|
||||
click.echo(f'Hello {name}!')
|
||||
|
||||
.. code-block:: python
|
||||
:caption: test_hello.py
|
||||
|
||||
from click.testing import CliRunner
|
||||
from hello import hello
|
||||
|
||||
def test_hello_world():
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(hello, ['Peter'])
|
||||
assert result.exit_code == 0
|
||||
assert result.output == 'Hello Peter!\n'
|
||||
|
||||
For subcommand testing, a subcommand name must be specified in the `args` parameter of :meth:`CliRunner.invoke` method:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: sync.py
|
||||
|
||||
import click
|
||||
|
||||
@click.group()
|
||||
@click.option('--debug/--no-debug', default=False)
|
||||
def cli(debug):
|
||||
click.echo(f"Debug mode is {'on' if debug else 'off'}")
|
||||
|
||||
@cli.command()
|
||||
def sync():
|
||||
click.echo('Syncing')
|
||||
|
||||
.. code-block:: python
|
||||
:caption: test_sync.py
|
||||
|
||||
from click.testing import CliRunner
|
||||
from sync import cli
|
||||
|
||||
def test_sync():
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ['--debug', 'sync'])
|
||||
assert result.exit_code == 0
|
||||
assert 'Debug mode is on' in result.output
|
||||
assert 'Syncing' in result.output
|
||||
|
||||
Additional keyword arguments passed to ``.invoke()`` will be used to construct the initial Context object.
|
||||
For example, if you want to run your tests against a fixed terminal width you can use the following::
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ['--debug', 'sync'], terminal_width=60)
|
||||
|
||||
File System Isolation
|
||||
---------------------
|
||||
|
||||
For basic command line tools with file system operations, the
|
||||
:meth:`CliRunner.isolated_filesystem` method is useful for setting the
|
||||
current working directory to a new, empty folder.
|
||||
|
||||
.. code-block:: python
|
||||
:caption: cat.py
|
||||
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
@click.argument('f', type=click.File())
|
||||
def cat(f):
|
||||
click.echo(f.read())
|
||||
|
||||
.. code-block:: python
|
||||
:caption: test_cat.py
|
||||
|
||||
from click.testing import CliRunner
|
||||
from cat import cat
|
||||
|
||||
def test_cat():
|
||||
runner = CliRunner()
|
||||
with runner.isolated_filesystem():
|
||||
with open('hello.txt', 'w') as f:
|
||||
f.write('Hello World!')
|
||||
|
||||
result = runner.invoke(cat, ['hello.txt'])
|
||||
assert result.exit_code == 0
|
||||
assert result.output == 'Hello World!\n'
|
||||
|
||||
Pass ``temp_dir`` to control where the temporary directory is created.
|
||||
The directory will not be removed by Click in this case. This is useful
|
||||
to integrate with a framework like Pytest that manages temporary files.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def test_keep_dir(tmp_path):
|
||||
runner = CliRunner()
|
||||
|
||||
with runner.isolated_filesystem(temp_dir=tmp_path) as td:
|
||||
...
|
||||
|
||||
|
||||
Input Streams
|
||||
-------------
|
||||
|
||||
The test wrapper can also be used to provide input data for the input
|
||||
stream (stdin). This is very useful for testing prompts, for instance:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: prompt.py
|
||||
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
@click.option('--foo', prompt=True)
|
||||
def prompt(foo):
|
||||
click.echo(f"foo={foo}")
|
||||
|
||||
.. code-block:: python
|
||||
:caption: test_prompt.py
|
||||
|
||||
from click.testing import CliRunner
|
||||
from prompt import prompt
|
||||
|
||||
def test_prompts():
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(prompt, input='wau wau\n')
|
||||
assert not result.exception
|
||||
assert result.output == 'Foo: wau wau\nfoo=wau wau\n'
|
||||
|
||||
Note that prompts will be emulated so that they write the input data to
|
||||
the output stream as well. If hidden input is expected then this
|
||||
obviously does not happen.
|
|
@ -1,112 +0,0 @@
|
|||
Unicode Support
|
||||
===============
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
Click has to take extra care to support Unicode text in different
|
||||
environments.
|
||||
|
||||
* The command line in Unix is traditionally bytes, not Unicode. While
|
||||
there are encoding hints, there are some situations where this can
|
||||
break. The most common one is SSH connections to machines with
|
||||
different locales.
|
||||
|
||||
Misconfigured environments can cause a wide range of Unicode
|
||||
problems due to the lack of support for roundtripping surrogate
|
||||
escapes. This will not be fixed in Click itself!
|
||||
|
||||
* Standard input and output is opened in text mode by default. Click
|
||||
has to reopen the stream in binary mode in certain situations.
|
||||
Because there is no standard way to do this, it might not always
|
||||
work. Primarily this can become a problem when testing command-line
|
||||
applications.
|
||||
|
||||
This is not supported::
|
||||
|
||||
sys.stdin = io.StringIO('Input here')
|
||||
sys.stdout = io.StringIO()
|
||||
|
||||
Instead you need to do this::
|
||||
|
||||
input = 'Input here'
|
||||
in_stream = io.BytesIO(input.encode('utf-8'))
|
||||
sys.stdin = io.TextIOWrapper(in_stream, encoding='utf-8')
|
||||
out_stream = io.BytesIO()
|
||||
sys.stdout = io.TextIOWrapper(out_stream, encoding='utf-8')
|
||||
|
||||
Remember in that case, you need to use ``out_stream.getvalue()``
|
||||
and not ``sys.stdout.getvalue()`` if you want to access the buffer
|
||||
contents as the wrapper will not forward that method.
|
||||
|
||||
* ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are by default
|
||||
text-based. When Click needs a binary stream, it attempts to
|
||||
discover the underlying binary stream.
|
||||
|
||||
* ``sys.argv`` is always text. This means that the native type for
|
||||
input values to the types in Click is Unicode, not bytes.
|
||||
|
||||
This causes problems if the terminal is incorrectly set and Python
|
||||
does not figure out the encoding. In that case, the Unicode string
|
||||
will contain error bytes encoded as surrogate escapes.
|
||||
|
||||
* When dealing with files, Click will always use the Unicode file
|
||||
system API by using the operating system's reported or guessed
|
||||
filesystem encoding. Surrogates are supported for filenames, so it
|
||||
should be possible to open files through the :class:`File` type even
|
||||
if the environment is misconfigured.
|
||||
|
||||
|
||||
Surrogate Handling
|
||||
------------------
|
||||
|
||||
Click does all the Unicode handling in the standard library and is
|
||||
subject to its behavior. Unicode requires extra care. The reason for
|
||||
this is that the encoding detection is done in the interpreter, and on
|
||||
Linux and certain other operating systems, its encoding handling is
|
||||
problematic.
|
||||
|
||||
The biggest source of frustration is that Click scripts invoked by init
|
||||
systems, deployment tools, or cron jobs will refuse to work unless a
|
||||
Unicode locale is exported.
|
||||
|
||||
If Click encounters such an environment it will prevent further
|
||||
execution to force you to set a locale. This is done because Click
|
||||
cannot know about the state of the system once it's invoked and restore
|
||||
the values before Python's Unicode handling kicked in.
|
||||
|
||||
If you see something like this error::
|
||||
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
RuntimeError: Click will abort further execution because Python was
|
||||
configured to use ASCII as encoding for the environment. Consult
|
||||
https://click.palletsprojects.com/unicode-support/ for mitigation
|
||||
steps.
|
||||
|
||||
You are dealing with an environment where Python thinks you are
|
||||
restricted to ASCII data. The solution to these problems is different
|
||||
depending on which locale your computer is running in.
|
||||
|
||||
For instance, if you have a German Linux machine, you can fix the
|
||||
problem by exporting the locale to ``de_DE.utf-8``::
|
||||
|
||||
export LC_ALL=de_DE.utf-8
|
||||
export LANG=de_DE.utf-8
|
||||
|
||||
If you are on a US machine, ``en_US.utf-8`` is the encoding of choice.
|
||||
On some newer Linux systems, you could also try ``C.UTF-8`` as the
|
||||
locale::
|
||||
|
||||
export LC_ALL=C.UTF-8
|
||||
export LANG=C.UTF-8
|
||||
|
||||
On some systems it was reported that ``UTF-8`` has to be written as
|
||||
``UTF8`` and vice versa. To see which locales are supported you can
|
||||
invoke ``locale -a``.
|
||||
|
||||
You need to export the values before you invoke your Python script.
|
||||
|
||||
In Python 3.7 and later you will no longer get a ``RuntimeError`` in
|
||||
many cases thanks to :pep:`538` and :pep:`540`, which changed the
|
||||
default assumption in unconfigured environments. This doesn't change the
|
||||
general issue that your locale may be misconfigured.
|
|
@ -1,131 +0,0 @@
|
|||
Upgrading To Newer Releases
|
||||
===========================
|
||||
|
||||
Click attempts the highest level of backwards compatibility but sometimes
|
||||
this is not entirely possible. In case we need to break backwards
|
||||
compatibility this document gives you information about how to upgrade or
|
||||
handle backwards compatibility properly.
|
||||
|
||||
.. _upgrade-to-7.0:
|
||||
|
||||
Upgrading to 7.0
|
||||
----------------
|
||||
|
||||
Commands that take their name from the decorated function now replace
|
||||
underscores with dashes. For example, the Python function ``run_server``
|
||||
will get the command name ``run-server`` now. There are a few options
|
||||
to address this:
|
||||
|
||||
- To continue with the new behavior, pin your dependency to
|
||||
``Click>=7`` and update any documentation to use dashes.
|
||||
- To keep existing behavior, add an explicit command name with
|
||||
underscores, like ``@click.command("run_server")``.
|
||||
- To try a name with dashes if the name with underscores was not
|
||||
found, pass a ``token_normalize_func`` to the context:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def normalize(name):
|
||||
return name.replace("_", "-")
|
||||
|
||||
@click.group(context_settings={"token_normalize_func": normalize})
|
||||
def group():
|
||||
...
|
||||
|
||||
@group.command()
|
||||
def run_server():
|
||||
...
|
||||
|
||||
|
||||
.. _upgrade-to-3.2:
|
||||
|
||||
Upgrading to 3.2
|
||||
----------------
|
||||
|
||||
Click 3.2 had to perform two changes to multi commands which were
|
||||
triggered by a change between Click 2 and Click 3 that had bigger
|
||||
consequences than anticipated.
|
||||
|
||||
Context Invokes
|
||||
```````````````
|
||||
|
||||
Click 3.2 contains a fix for the :meth:`Context.invoke` function when used
|
||||
with other commands. The original intention of this function was to
|
||||
invoke the other command as as if it came from the command line when it
|
||||
was passed a context object instead of a function. This use was only
|
||||
documented in a single place in the documentation before and there was no
|
||||
proper explanation for the method in the API documentation.
|
||||
|
||||
The core issue is that before 3.2 this call worked against intentions::
|
||||
|
||||
ctx.invoke(other_command, 'arg1', 'arg2')
|
||||
|
||||
This was never intended to work as it does not allow Click to operate on
|
||||
the parameters. Given that this pattern was never documented and ill
|
||||
intended the decision was made to change this behavior in a bugfix release
|
||||
before it spreads by accident and developers depend on it.
|
||||
|
||||
The correct invocation for the above command is the following::
|
||||
|
||||
ctx.invoke(other_command, name_of_arg1='arg1', name_of_arg2='arg2')
|
||||
|
||||
This also allowed us to fix the issue that defaults were not handled
|
||||
properly by this function.
|
||||
|
||||
Multicommand Chaining API
|
||||
`````````````````````````
|
||||
|
||||
Click 3 introduced multicommand chaining. This required a change in how
|
||||
Click internally dispatches. Unfortunately this change was not correctly
|
||||
implemented and it appeared that it was possible to provide an API that
|
||||
can inform the super command about all the subcommands that will be
|
||||
invoked.
|
||||
|
||||
This assumption however does not work with one of the API guarantees that
|
||||
have been given in the past. As such this functionality has been removed
|
||||
in 3.2 as it was already broken. Instead the accidentally broken
|
||||
functionality of the :attr:`Context.invoked_subcommand` attribute was
|
||||
restored.
|
||||
|
||||
If you do require the know which exact commands will be invoked there are
|
||||
different ways to cope with this. The first one is to let the subcommands
|
||||
all return functions and then to invoke the functions in a
|
||||
:meth:`Context.result_callback`.
|
||||
|
||||
|
||||
.. _upgrade-to-2.0:
|
||||
|
||||
Upgrading to 2.0
|
||||
----------------
|
||||
|
||||
Click 2.0 has one breaking change which is the signature for parameter
|
||||
callbacks. Before 2.0, the callback was invoked with ``(ctx, value)``
|
||||
whereas now it's ``(ctx, param, value)``. This change was necessary as it
|
||||
otherwise made reusing callbacks too complicated.
|
||||
|
||||
To ease the transition Click will still accept old callbacks. Starting
|
||||
with Click 3.0 it will start to issue a warning to stderr to encourage you
|
||||
to upgrade.
|
||||
|
||||
In case you want to support both Click 1.0 and Click 2.0, you can make a
|
||||
simple decorator that adjusts the signatures::
|
||||
|
||||
import click
|
||||
from functools import update_wrapper
|
||||
|
||||
def compatcallback(f):
|
||||
# Click 1.0 does not have a version string stored, so we need to
|
||||
# use getattr here to be safe.
|
||||
if getattr(click, '__version__', '0.0') >= '2.0':
|
||||
return f
|
||||
return update_wrapper(lambda ctx, value: f(ctx, None, value), f)
|
||||
|
||||
With that helper you can then write something like this::
|
||||
|
||||
@compatcallback
|
||||
def callback(ctx, param, value):
|
||||
return value.upper()
|
||||
|
||||
Note that because Click 1.0 did not pass a parameter, the `param` argument
|
||||
here would be `None`, so a compatibility callback could not use that
|
||||
argument.
|
408
docs/utils.rst
408
docs/utils.rst
|
@ -1,408 +0,0 @@
|
|||
Utilities
|
||||
=========
|
||||
|
||||
.. currentmodule:: click
|
||||
|
||||
Besides the functionality that Click provides to interface with argument
|
||||
parsing and handling, it also provides a bunch of addon functionality that
|
||||
is useful for writing command line utilities.
|
||||
|
||||
|
||||
Printing to Stdout
|
||||
------------------
|
||||
|
||||
The most obvious helper is the :func:`echo` function, which in many ways
|
||||
works like the Python ``print`` statement or function. The main difference is
|
||||
that it works the same in many different terminal environments.
|
||||
|
||||
Example::
|
||||
|
||||
import click
|
||||
|
||||
click.echo('Hello World!')
|
||||
|
||||
It can output both text and binary data. It will emit a trailing newline
|
||||
by default, which needs to be suppressed by passing ``nl=False``::
|
||||
|
||||
click.echo(b'\xe2\x98\x83', nl=False)
|
||||
|
||||
Last but not least :func:`echo` uses click's intelligent internal output
|
||||
streams to stdout and stderr which support unicode output on the Windows
|
||||
console. This means for as long as you are using `click.echo` you can
|
||||
output unicode characters (there are some limitations on the default font
|
||||
with regards to which characters can be displayed).
|
||||
|
||||
.. versionadded:: 6.0
|
||||
|
||||
Click emulates output streams on Windows to support unicode to the
|
||||
Windows console through separate APIs. For more information see
|
||||
:doc:`wincmd`.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
You can also easily print to standard error by passing ``err=True``::
|
||||
|
||||
click.echo('Hello World!', err=True)
|
||||
|
||||
|
||||
.. _ansi-colors:
|
||||
|
||||
ANSI Colors
|
||||
-----------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
The :func:`echo` function supports ANSI colors and styles. On Windows
|
||||
this uses `colorama`_.
|
||||
|
||||
Primarily this means that:
|
||||
|
||||
- Click's :func:`echo` function will automatically strip ANSI color codes
|
||||
if the stream is not connected to a terminal.
|
||||
- the :func:`echo` function will transparently connect to the terminal on
|
||||
Windows and translate ANSI codes to terminal API calls. This means
|
||||
that colors will work on Windows the same way they do on other
|
||||
operating systems.
|
||||
|
||||
On Windows, Click uses colorama without calling ``colorama.init()``. You
|
||||
can still call that in your code, but it's not required for Click.
|
||||
|
||||
For styling a string, the :func:`style` function can be used::
|
||||
|
||||
import click
|
||||
|
||||
click.echo(click.style('Hello World!', fg='green'))
|
||||
click.echo(click.style('Some more text', bg='blue', fg='white'))
|
||||
click.echo(click.style('ATTENTION', blink=True, bold=True))
|
||||
|
||||
The combination of :func:`echo` and :func:`style` is also available in
|
||||
a single function called :func:`secho`::
|
||||
|
||||
click.secho('Hello World!', fg='green')
|
||||
click.secho('Some more text', bg='blue', fg='white')
|
||||
click.secho('ATTENTION', blink=True, bold=True)
|
||||
|
||||
|
||||
.. _colorama: https://pypi.org/project/colorama/
|
||||
|
||||
Pager Support
|
||||
-------------
|
||||
|
||||
In some situations, you might want to show long texts on the terminal and
|
||||
let a user scroll through it. This can be achieved by using the
|
||||
:func:`echo_via_pager` function which works similarly to the :func:`echo`
|
||||
function, but always writes to stdout and, if possible, through a pager.
|
||||
|
||||
Example:
|
||||
|
||||
.. click:example::
|
||||
|
||||
@click.command()
|
||||
def less():
|
||||
click.echo_via_pager("\n".join(f"Line {idx}" for idx in range(200)))
|
||||
|
||||
If you want to use the pager for a lot of text, especially if generating everything in advance would take a lot of time, you can pass a generator (or generator function) instead of a string:
|
||||
|
||||
.. click:example::
|
||||
def _generate_output():
|
||||
for idx in range(50000):
|
||||
yield f"Line {idx}\n"
|
||||
|
||||
@click.command()
|
||||
def less():
|
||||
click.echo_via_pager(_generate_output())
|
||||
|
||||
|
||||
Screen Clearing
|
||||
---------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
To clear the terminal screen, you can use the :func:`clear` function that
|
||||
is provided starting with Click 2.0. It does what the name suggests: it
|
||||
clears the entire visible screen in a platform-agnostic way:
|
||||
|
||||
::
|
||||
|
||||
import click
|
||||
click.clear()
|
||||
|
||||
|
||||
Getting Characters from Terminal
|
||||
--------------------------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Normally, when reading input from the terminal, you would read from
|
||||
standard input. However, this is buffered input and will not show up until
|
||||
the line has been terminated. In certain circumstances, you might not want
|
||||
to do that and instead read individual characters as they are being written.
|
||||
|
||||
For this, Click provides the :func:`getchar` function which reads a single
|
||||
character from the terminal buffer and returns it as a Unicode character.
|
||||
|
||||
Note that this function will always read from the terminal, even if stdin
|
||||
is instead a pipe.
|
||||
|
||||
Example::
|
||||
|
||||
import click
|
||||
|
||||
click.echo('Continue? [yn] ', nl=False)
|
||||
c = click.getchar()
|
||||
click.echo()
|
||||
if c == 'y':
|
||||
click.echo('We will go on')
|
||||
elif c == 'n':
|
||||
click.echo('Abort!')
|
||||
else:
|
||||
click.echo('Invalid input :(')
|
||||
|
||||
Note that this reads raw input, which means that things like arrow keys
|
||||
will show up in the platform's native escape format. The only characters
|
||||
translated are ``^C`` and ``^D`` which are converted into keyboard
|
||||
interrupts and end of file exceptions respectively. This is done because
|
||||
otherwise, it's too easy to forget about that and to create scripts that
|
||||
cannot be properly exited.
|
||||
|
||||
|
||||
Waiting for Key Press
|
||||
---------------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Sometimes, it's useful to pause until the user presses any key on the
|
||||
keyboard. This is especially useful on Windows where ``cmd.exe`` will
|
||||
close the window at the end of the command execution by default, instead
|
||||
of waiting.
|
||||
|
||||
In click, this can be accomplished with the :func:`pause` function. This
|
||||
function will print a quick message to the terminal (which can be
|
||||
customized) and wait for the user to press a key. In addition to that,
|
||||
it will also become a NOP (no operation instruction) if the script is not
|
||||
run interactively.
|
||||
|
||||
Example::
|
||||
|
||||
import click
|
||||
click.pause()
|
||||
|
||||
|
||||
Launching Editors
|
||||
-----------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Click supports launching editors automatically through :func:`edit`. This
|
||||
is very useful for asking users for multi-line input. It will
|
||||
automatically open the user's defined editor or fall back to a sensible
|
||||
default. If the user closes the editor without saving, the return value
|
||||
will be ``None``, otherwise the entered text.
|
||||
|
||||
Example usage::
|
||||
|
||||
import click
|
||||
|
||||
def get_commit_message():
|
||||
MARKER = '# Everything below is ignored\n'
|
||||
message = click.edit('\n\n' + MARKER)
|
||||
if message is not None:
|
||||
return message.split(MARKER, 1)[0].rstrip('\n')
|
||||
|
||||
Alternatively, the function can also be used to launch editors for files by
|
||||
a specific filename. In this case, the return value is always `None`.
|
||||
|
||||
Example usage::
|
||||
|
||||
import click
|
||||
click.edit(filename='/etc/passwd')
|
||||
|
||||
|
||||
Launching Applications
|
||||
----------------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Click supports launching applications through :func:`launch`. This can be
|
||||
used to open the default application associated with a URL or filetype.
|
||||
This can be used to launch web browsers or picture viewers, for instance.
|
||||
In addition to this, it can also launch the file manager and automatically
|
||||
select the provided file.
|
||||
|
||||
Example usage::
|
||||
|
||||
click.launch("https://click.palletsprojects.com/")
|
||||
click.launch("/my/downloaded/file.txt", locate=True)
|
||||
|
||||
|
||||
Printing Filenames
|
||||
------------------
|
||||
|
||||
Because filenames might not be Unicode, formatting them can be a bit
|
||||
tricky.
|
||||
|
||||
The way this works with click is through the :func:`format_filename`
|
||||
function. It does a best-effort conversion of the filename to Unicode and
|
||||
will never fail. This makes it possible to use these filenames in the
|
||||
context of a full Unicode string.
|
||||
|
||||
Example::
|
||||
|
||||
click.echo(f"Path: {click.format_filename(b'foo.txt')}")
|
||||
|
||||
|
||||
Standard Streams
|
||||
----------------
|
||||
|
||||
For command line utilities, it's very important to get access to input and
|
||||
output streams reliably. Python generally provides access to these
|
||||
streams through ``sys.stdout`` and friends, but unfortunately, there are
|
||||
API differences between 2.x and 3.x, especially with regards to how these
|
||||
streams respond to Unicode and binary data.
|
||||
|
||||
Because of this, click provides the :func:`get_binary_stream` and
|
||||
:func:`get_text_stream` functions, which produce consistent results with
|
||||
different Python versions and for a wide variety of terminal configurations.
|
||||
|
||||
The end result is that these functions will always return a functional
|
||||
stream object (except in very odd cases; see :doc:`/unicode-support`).
|
||||
|
||||
Example::
|
||||
|
||||
import click
|
||||
|
||||
stdin_text = click.get_text_stream('stdin')
|
||||
stdout_binary = click.get_binary_stream('stdout')
|
||||
|
||||
.. versionadded:: 6.0
|
||||
|
||||
Click now emulates output streams on Windows to support unicode to the
|
||||
Windows console through separate APIs. For more information see
|
||||
:doc:`wincmd`.
|
||||
|
||||
|
||||
Intelligent File Opening
|
||||
------------------------
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
Starting with Click 3.0 the logic for opening files from the :class:`File`
|
||||
type is exposed through the :func:`open_file` function. It can
|
||||
intelligently open stdin/stdout as well as any other file.
|
||||
|
||||
Example::
|
||||
|
||||
import click
|
||||
|
||||
stdout = click.open_file('-', 'w')
|
||||
test_file = click.open_file('test.txt', 'w')
|
||||
|
||||
If stdin or stdout are returned, the return value is wrapped in a special
|
||||
file where the context manager will prevent the closing of the file. This
|
||||
makes the handling of standard streams transparent and you can always use
|
||||
it like this::
|
||||
|
||||
with click.open_file(filename, 'w') as f:
|
||||
f.write('Hello World!\n')
|
||||
|
||||
|
||||
Finding Application Folders
|
||||
---------------------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Very often, you want to open a configuration file that belongs to your
|
||||
application. However, different operating systems store these configuration
|
||||
files in different locations depending on their standards. Click provides
|
||||
a :func:`get_app_dir` function which returns the most appropriate location
|
||||
for per-user config files for your application depending on the OS.
|
||||
|
||||
Example usage::
|
||||
|
||||
import os
|
||||
import click
|
||||
import ConfigParser
|
||||
|
||||
APP_NAME = 'My Application'
|
||||
|
||||
def read_config():
|
||||
cfg = os.path.join(click.get_app_dir(APP_NAME), 'config.ini')
|
||||
parser = ConfigParser.RawConfigParser()
|
||||
parser.read([cfg])
|
||||
rv = {}
|
||||
for section in parser.sections():
|
||||
for key, value in parser.items(section):
|
||||
rv[f"{section}.{key}"] = value
|
||||
return rv
|
||||
|
||||
|
||||
Showing Progress Bars
|
||||
---------------------
|
||||
|
||||
Sometimes, you have command line scripts that need to process a lot of data,
|
||||
but you want to quickly show the user some progress about how long that
|
||||
will take. Click supports simple progress bar rendering for that through
|
||||
the :func:`progressbar` function.
|
||||
|
||||
.. note::
|
||||
|
||||
If you find that you have requirements beyond what Click's progress
|
||||
bar supports, try using `tqdm`_.
|
||||
|
||||
.. _tqdm: https://tqdm.github.io/
|
||||
|
||||
The basic usage is very simple: the idea is that you have an iterable that
|
||||
you want to operate on. For each item in the iterable it might take some
|
||||
time to do processing. So say you have a loop like this::
|
||||
|
||||
for user in all_the_users_to_process:
|
||||
modify_the_user(user)
|
||||
|
||||
To hook this up with an automatically updating progress bar, all you need
|
||||
to do is to change the code to this::
|
||||
|
||||
import click
|
||||
|
||||
with click.progressbar(all_the_users_to_process) as bar:
|
||||
for user in bar:
|
||||
modify_the_user(user)
|
||||
|
||||
Click will then automatically print a progress bar to the terminal and
|
||||
calculate the remaining time for you. The calculation of remaining time
|
||||
requires that the iterable has a length. If it does not have a length
|
||||
but you know the length, you can explicitly provide it::
|
||||
|
||||
with click.progressbar(all_the_users_to_process,
|
||||
length=number_of_users) as bar:
|
||||
for user in bar:
|
||||
modify_the_user(user)
|
||||
|
||||
Note that :func:`progressbar` updates the bar *after* each iteration of the
|
||||
loop. So code like this will render correctly::
|
||||
|
||||
import time
|
||||
|
||||
with click.progressbar([1, 2, 3]) as bar:
|
||||
for x in bar:
|
||||
print(f"sleep({x})...")
|
||||
time.sleep(x)
|
||||
|
||||
Another useful feature is to associate a label with the progress bar which
|
||||
will be shown preceding the progress bar::
|
||||
|
||||
with click.progressbar(all_the_users_to_process,
|
||||
label='Modifying user accounts',
|
||||
length=number_of_users) as bar:
|
||||
for user in bar:
|
||||
modify_the_user(user)
|
||||
|
||||
Sometimes, one may need to iterate over an external iterator, and advance the
|
||||
progress bar irregularly. To do so, you need to specify the length (and no
|
||||
iterable), and use the update method on the context return value instead of
|
||||
iterating directly over it::
|
||||
|
||||
with click.progressbar(length=total_size,
|
||||
label='Unzipping archive') as bar:
|
||||
for archive in zip_file:
|
||||
archive.extract()
|
||||
bar.update(archive.size)
|
146
docs/why.rst
146
docs/why.rst
|
@ -1,146 +0,0 @@
|
|||
Why Click?
|
||||
==========
|
||||
|
||||
There are so many libraries out there for writing command line utilities;
|
||||
why does Click exist?
|
||||
|
||||
This question is easy to answer: because there is not a single command
|
||||
line utility for Python out there which ticks the following boxes:
|
||||
|
||||
* Is lazily composable without restrictions.
|
||||
* Supports implementation of Unix/POSIX command line conventions.
|
||||
* Supports loading values from environment variables out of the box.
|
||||
* Support for prompting of custom values.
|
||||
* Is fully nestable and composable.
|
||||
* Supports file handling out of the box.
|
||||
* Comes with useful common helpers (getting terminal dimensions,
|
||||
ANSI colors, fetching direct keyboard input, screen clearing,
|
||||
finding config paths, launching apps and editors, etc.).
|
||||
|
||||
There are many alternatives to Click; the obvious ones are ``optparse``
|
||||
and ``argparse`` from the standard library. Have a look to see if something
|
||||
else resonates with you.
|
||||
|
||||
Click actually implements its own parsing of arguments and does not use
|
||||
``optparse`` or ``argparse`` following the ``optparse`` parsing behavior.
|
||||
The reason it's not based on ``argparse`` is that ``argparse`` does not
|
||||
allow proper nesting of commands by design and has some deficiencies when
|
||||
it comes to POSIX compliant argument handling.
|
||||
|
||||
Click is designed to be fun and customizable but not overly flexible.
|
||||
For instance, the customizability of help pages is constrained. This
|
||||
constraint is intentional because Click promises multiple Click instances
|
||||
will continue to function as intended when strung together.
|
||||
|
||||
Too much customizability would break this promise.
|
||||
|
||||
Click was written to support the `Flask <https://palletsprojects.com/p/flask/>`_
|
||||
microframework ecosystem because no tool could provide it with the
|
||||
functionality it needed.
|
||||
|
||||
To get an understanding of what Click is all about, I strongly recommend
|
||||
looking at the :ref:`complex-guide` chapter.
|
||||
|
||||
Why not Argparse?
|
||||
-----------------
|
||||
|
||||
Click is internally based on ``optparse`` instead of ``argparse``. This
|
||||
is an implementation detail that a user does not have to be concerned
|
||||
with. Click is not based on ``argparse`` because it has some behaviors that
|
||||
make handling arbitrary command line interfaces hard:
|
||||
|
||||
* ``argparse`` has built-in behavior to guess if something is an
|
||||
argument or an option. This becomes a problem when dealing with
|
||||
incomplete command lines; the behaviour becomes unpredictable
|
||||
without full knowledge of a command line. This goes against Click's
|
||||
ambitions of dispatching to subparsers.
|
||||
* ``argparse`` does not support disabling interspersed arguments. Without
|
||||
this feature, it's not possible to safely implement Click's nested
|
||||
parsing.
|
||||
|
||||
Why not Docopt etc.?
|
||||
--------------------
|
||||
|
||||
Docopt, and many tools like it, are cool in how they work, but very few of
|
||||
these tools deal with nesting of commands and composability in a way like
|
||||
Click. To the best of the developer's knowledge, Click is the first
|
||||
Python library that aims to create a level of composability of applications
|
||||
that goes beyond what the system itself supports.
|
||||
|
||||
Docopt, for instance, acts by parsing your help pages and then parsing
|
||||
according to those rules. The side effect of this is that docopt is quite
|
||||
rigid in how it handles the command line interface. The upside of docopt
|
||||
is that it gives you strong control over your help page; the downside is
|
||||
that due to this it cannot rewrap your output for the current terminal
|
||||
width, and it makes translations hard. On top of that, docopt is restricted
|
||||
to basic parsing. It does not handle argument dispatching and callback
|
||||
invocation or types. This means there is a lot of code that needs to be
|
||||
written in addition to the basic help page to handle the parsing results.
|
||||
|
||||
Most of all, however, it makes composability hard. While docopt does
|
||||
support dispatching to subcommands, it, for instance, does not directly
|
||||
support any kind of automatic subcommand enumeration based on what's
|
||||
available or it does not enforce subcommands to work in a consistent way.
|
||||
|
||||
This is fine, but it's different from how Click wants to work. Click aims
|
||||
to support fully composable command line user interfaces by doing the
|
||||
following:
|
||||
|
||||
- Click does not just parse, it also dispatches to the appropriate code.
|
||||
- Click has a strong concept of an invocation context that allows
|
||||
subcommands to respond to data from the parent command.
|
||||
- Click has strong information available for all parameters and commands,
|
||||
so it can generate unified help pages for the full CLI and
|
||||
assist the user in converting the input data as necessary.
|
||||
- Click has a strong understanding of what types are, and it can give the user
|
||||
consistent error messages if something goes wrong. A subcommand
|
||||
written by a different developer will not suddenly die with a
|
||||
different error message because it's manually handled.
|
||||
- Click has enough meta information available for its whole program
|
||||
to evolve over time and improve the user experience without
|
||||
forcing developers to adjust their programs. For instance, if Click
|
||||
decides to change how help pages are formatted, all Click programs
|
||||
will automatically benefit from this.
|
||||
|
||||
The aim of Click is to make composable systems. Whereas, the aim of docopt
|
||||
is to build the most beautiful and hand-crafted command line interfaces.
|
||||
These two goals conflict with one another in subtle ways. Click
|
||||
actively prevents people from implementing certain patterns in order to
|
||||
achieve unified command line interfaces. For instance, as a developer, you
|
||||
are given very little choice in formatting your help pages.
|
||||
|
||||
|
||||
Why Hardcoded Behaviors?
|
||||
------------------------
|
||||
|
||||
The other question is why Click goes away from optparse and hardcodes
|
||||
certain behaviors instead of staying configurable. There are multiple
|
||||
reasons for this. The biggest one is that too much configurability makes
|
||||
it hard to achieve a consistent command line experience.
|
||||
|
||||
The best example for this is optparse's ``callback`` functionality for
|
||||
accepting an arbitrary number of arguments. Due to syntactical ambiguities
|
||||
on the command line, there is no way to implement fully variadic arguments.
|
||||
There are always tradeoffs that need to be made and in case of
|
||||
``argparse`` these tradeoffs have been critical enough, that a system like
|
||||
Click cannot even be implemented on top of it.
|
||||
|
||||
In this particular case, Click attempts to stay with a handful of accepted
|
||||
paradigms for building command line interfaces that can be well documented
|
||||
and tested.
|
||||
|
||||
|
||||
Why No Auto Correction?
|
||||
-----------------------
|
||||
|
||||
The question came up why Click does not auto correct parameters given that
|
||||
even optparse and ``argparse`` support automatic expansion of long arguments.
|
||||
The reason for this is that it's a liability for backwards compatibility.
|
||||
If people start relying on automatically modified parameters and someone
|
||||
adds a new parameter in the future, the script might stop working. These
|
||||
kinds of problems are hard to find, so Click does not attempt to be magical
|
||||
about this.
|
||||
|
||||
This sort of behavior however can be implemented on a higher level to
|
||||
support things such as explicit aliases. For more information see
|
||||
:ref:`aliases`.
|
|
@ -1,64 +0,0 @@
|
|||
Windows Console Notes
|
||||
=====================
|
||||
|
||||
.. versionadded:: 6.0
|
||||
|
||||
Click emulates output streams on Windows to support unicode to the
|
||||
Windows console through separate APIs and we perform different decoding of
|
||||
parameters.
|
||||
|
||||
Here is a brief overview of how this works and what it means to you.
|
||||
|
||||
Unicode Arguments
|
||||
-----------------
|
||||
|
||||
Click internally is generally based on the concept that any argument can
|
||||
come in as either byte string or unicode string and conversion is
|
||||
performed to the type expected value as late as possible. This has some
|
||||
advantages as it allows us to accept the data in the most appropriate form
|
||||
for the operating system and Python version.
|
||||
|
||||
This caused some problems on Windows where initially the wrong encoding
|
||||
was used and garbage ended up in your input data. We not only fixed the
|
||||
encoding part, but we also now extract unicode parameters from `sys.argv`.
|
||||
|
||||
There is also another limitation with this: if `sys.argv` was modified
|
||||
prior to invoking a click handler, we have to fall back to the regular
|
||||
byte input in which case not all unicode values are available but only a
|
||||
subset of the codepage used for parameters.
|
||||
|
||||
Unicode Output and Input
|
||||
------------------------
|
||||
|
||||
Unicode output and input on Windows is implemented through the concept of
|
||||
a dispatching text stream. What this means is that when click first needs
|
||||
a text output (or input) stream on windows it goes through a few checks to
|
||||
figure out of a windows console is connected or not. If no Windows
|
||||
console is present then the text output stream is returned as such and the
|
||||
encoding for that stream is set to ``utf-8`` like on all platforms.
|
||||
|
||||
However if a console is connected the stream will instead be emulated and
|
||||
use the cmd.exe unicode APIs to output text information. In this case the
|
||||
stream will also use ``utf-16-le`` as internal encoding. However there is
|
||||
some hackery going on that the underlying raw IO buffer is still bypassing
|
||||
the unicode APIs and byte output through an indirection is still possible.
|
||||
|
||||
* This unicode support is limited to ``click.echo``, ``click.prompt`` as
|
||||
well as ``click.get_text_stream``.
|
||||
* Depending on if unicode values or byte strings are passed the control
|
||||
flow goes completely different places internally which can have some
|
||||
odd artifacts if data partially ends up being buffered. Click
|
||||
attempts to protect against that by manually always flushing but if
|
||||
you are mixing and matching different string types to ``stdout`` or
|
||||
``stderr`` you will need to manually flush.
|
||||
* The raw output stream is set to binary mode, which is a global
|
||||
operation on Windows, so ``print`` calls will be affected. Prefer
|
||||
``click.echo`` over ``print``.
|
||||
* On Windows 7 and below, there is a limitation where at most 64k
|
||||
characters can be written in one call in binary mode. In this
|
||||
situation, ``sys.stdout`` and ``sys.stderr`` are replaced with
|
||||
wrappers that work around the limitation.
|
||||
|
||||
Another important thing to note is that the Windows console's default
|
||||
fonts do not support a lot of characters which means that you are mostly
|
||||
limited to international letters but no emojis or special characters.
|
|
@ -1,12 +0,0 @@
|
|||
Click Examples
|
||||
|
||||
This folder contains various Click examples. Note that
|
||||
all of these are not runnable by themselves but should be
|
||||
installed into a virtualenv.
|
||||
|
||||
This is done this way so that scripts also properly work
|
||||
on Windows and in virtualenvs without accidentally executing
|
||||
through the wrong interpreter.
|
||||
|
||||
For more information about this see the documentation:
|
||||
https://click.palletsprojects.com/setuptools/
|
|
@ -1,17 +0,0 @@
|
|||
$ aliases_
|
||||
|
||||
aliases is a fairly advanced example that shows how
|
||||
to implement command aliases with Click. It uses a
|
||||
subclass of the default group to customize how commands
|
||||
are located.
|
||||
|
||||
It supports both aliases read from a config file as well
|
||||
as automatic abbreviations.
|
||||
|
||||
The aliases from the config are read from the aliases.ini
|
||||
file. Try `aliases st` and `aliases ci`!
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ aliases --help
|
|
@ -1,2 +0,0 @@
|
|||
[aliases]
|
||||
ci=commit
|
|
@ -1,143 +0,0 @@
|
|||
import configparser
|
||||
import os
|
||||
|
||||
import click
|
||||
|
||||
|
||||
class Config:
|
||||
"""The config in this example only holds aliases."""
|
||||
|
||||
def __init__(self):
|
||||
self.path = os.getcwd()
|
||||
self.aliases = {}
|
||||
|
||||
def add_alias(self, alias, cmd):
|
||||
self.aliases.update({alias: cmd})
|
||||
|
||||
def read_config(self, filename):
|
||||
parser = configparser.RawConfigParser()
|
||||
parser.read([filename])
|
||||
try:
|
||||
self.aliases.update(parser.items("aliases"))
|
||||
except configparser.NoSectionError:
|
||||
pass
|
||||
|
||||
def write_config(self, filename):
|
||||
parser = configparser.RawConfigParser()
|
||||
parser.add_section("aliases")
|
||||
for key, value in self.aliases.items():
|
||||
parser.set("aliases", key, value)
|
||||
with open(filename, "wb") as file:
|
||||
parser.write(file)
|
||||
|
||||
|
||||
pass_config = click.make_pass_decorator(Config, ensure=True)
|
||||
|
||||
|
||||
class AliasedGroup(click.Group):
|
||||
"""This subclass of a group supports looking up aliases in a config
|
||||
file and with a bit of magic.
|
||||
"""
|
||||
|
||||
def get_command(self, ctx, cmd_name):
|
||||
# Step one: bulitin commands as normal
|
||||
rv = click.Group.get_command(self, ctx, cmd_name)
|
||||
if rv is not None:
|
||||
return rv
|
||||
|
||||
# Step two: find the config object and ensure it's there. This
|
||||
# will create the config object is missing.
|
||||
cfg = ctx.ensure_object(Config)
|
||||
|
||||
# Step three: look up an explicit command alias in the config
|
||||
if cmd_name in cfg.aliases:
|
||||
actual_cmd = cfg.aliases[cmd_name]
|
||||
return click.Group.get_command(self, ctx, actual_cmd)
|
||||
|
||||
# Alternative option: if we did not find an explicit alias we
|
||||
# allow automatic abbreviation of the command. "status" for
|
||||
# instance will match "st". We only allow that however if
|
||||
# there is only one command.
|
||||
matches = [
|
||||
x for x in self.list_commands(ctx) if x.lower().startswith(cmd_name.lower())
|
||||
]
|
||||
if not matches:
|
||||
return None
|
||||
elif len(matches) == 1:
|
||||
return click.Group.get_command(self, ctx, matches[0])
|
||||
ctx.fail(f"Too many matches: {', '.join(sorted(matches))}")
|
||||
|
||||
def resolve_command(self, ctx, args):
|
||||
# always return the command's name, not the alias
|
||||
_, cmd, args = super().resolve_command(ctx, args)
|
||||
return cmd.name, cmd, args
|
||||
|
||||
|
||||
def read_config(ctx, param, value):
|
||||
"""Callback that is used whenever --config is passed. We use this to
|
||||
always load the correct config. This means that the config is loaded
|
||||
even if the group itself never executes so our aliases stay always
|
||||
available.
|
||||
"""
|
||||
cfg = ctx.ensure_object(Config)
|
||||
if value is None:
|
||||
value = os.path.join(os.path.dirname(__file__), "aliases.ini")
|
||||
cfg.read_config(value)
|
||||
return value
|
||||
|
||||
|
||||
@click.command(cls=AliasedGroup)
|
||||
@click.option(
|
||||
"--config",
|
||||
type=click.Path(exists=True, dir_okay=False),
|
||||
callback=read_config,
|
||||
expose_value=False,
|
||||
help="The config file to use instead of the default.",
|
||||
)
|
||||
def cli():
|
||||
"""An example application that supports aliases."""
|
||||
|
||||
|
||||
@cli.command()
|
||||
def push():
|
||||
"""Pushes changes."""
|
||||
click.echo("Push")
|
||||
|
||||
|
||||
@cli.command()
|
||||
def pull():
|
||||
"""Pulls changes."""
|
||||
click.echo("Pull")
|
||||
|
||||
|
||||
@cli.command()
|
||||
def clone():
|
||||
"""Clones a repository."""
|
||||
click.echo("Clone")
|
||||
|
||||
|
||||
@cli.command()
|
||||
def commit():
|
||||
"""Commits pending changes."""
|
||||
click.echo("Commit")
|
||||
|
||||
|
||||
@cli.command()
|
||||
@pass_config
|
||||
def status(config):
|
||||
"""Shows the status."""
|
||||
click.echo(f"Status for {config.path}")
|
||||
|
||||
|
||||
@cli.command()
|
||||
@pass_config
|
||||
@click.argument("alias_", metavar="ALIAS", type=click.STRING)
|
||||
@click.argument("cmd", type=click.STRING)
|
||||
@click.option(
|
||||
"--config_file", type=click.Path(exists=True, dir_okay=False), default="aliases.ini"
|
||||
)
|
||||
def alias(config, alias_, cmd, config_file):
|
||||
"""Adds an alias to the specified configuration file."""
|
||||
config.add_alias(alias_, cmd)
|
||||
config.write_config(config_file)
|
||||
click.echo(f"Added '{alias_}' as alias for '{cmd}'")
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-aliases",
|
||||
version="1.0",
|
||||
py_modules=["aliases"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
aliases=aliases:cli
|
||||
""",
|
||||
)
|
|
@ -1,11 +0,0 @@
|
|||
$ colors_
|
||||
|
||||
colors is a simple example that shows how you can
|
||||
colorize text.
|
||||
|
||||
Uses colorama on Windows.
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ colors
|
|
@ -1,39 +0,0 @@
|
|||
import click
|
||||
|
||||
|
||||
all_colors = (
|
||||
"black",
|
||||
"red",
|
||||
"green",
|
||||
"yellow",
|
||||
"blue",
|
||||
"magenta",
|
||||
"cyan",
|
||||
"white",
|
||||
"bright_black",
|
||||
"bright_red",
|
||||
"bright_green",
|
||||
"bright_yellow",
|
||||
"bright_blue",
|
||||
"bright_magenta",
|
||||
"bright_cyan",
|
||||
"bright_white",
|
||||
)
|
||||
|
||||
|
||||
@click.command()
|
||||
def cli():
|
||||
"""This script prints some colors. It will also automatically remove
|
||||
all ANSI styles if data is piped into a file.
|
||||
|
||||
Give it a try!
|
||||
"""
|
||||
for color in all_colors:
|
||||
click.echo(click.style(f"I am colored {color}", fg=color))
|
||||
for color in all_colors:
|
||||
click.echo(click.style(f"I am colored {color} and bold", fg=color, bold=True))
|
||||
for color in all_colors:
|
||||
click.echo(click.style(f"I am reverse colored {color}", fg=color, reverse=True))
|
||||
|
||||
click.echo(click.style("I am blinking", blink=True))
|
||||
click.echo(click.style("I am underlined", underline=True))
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-colors",
|
||||
version="1.0",
|
||||
py_modules=["colors"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
colors=colors:cli
|
||||
""",
|
||||
)
|
|
@ -1,28 +0,0 @@
|
|||
$ completion
|
||||
============
|
||||
|
||||
Demonstrates Click's shell completion support.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install --editable .
|
||||
|
||||
For Bash:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
eval "$(_COMPLETION_COMPLETE=bash_source completion)"
|
||||
|
||||
For Zsh:
|
||||
|
||||
.. code-block:: zsh
|
||||
|
||||
eval "$(_COMPLETION_COMPLETE=zsh_source completion)"
|
||||
|
||||
For Fish:
|
||||
|
||||
.. code-block:: fish
|
||||
|
||||
eval (env _COMPLETION_COMPLETE=fish_source completion)
|
||||
|
||||
Now press tab (maybe twice) after typing something to see completions.
|
|
@ -1,56 +0,0 @@
|
|||
import os
|
||||
|
||||
import click
|
||||
from click.shell_completion import CompletionItem
|
||||
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option("--dir", type=click.Path(file_okay=False))
|
||||
def ls(dir):
|
||||
click.echo("\n".join(os.listdir(dir)))
|
||||
|
||||
|
||||
def get_env_vars(ctx, param, incomplete):
|
||||
# Returning a list of values is a shortcut to returning a list of
|
||||
# CompletionItem(value).
|
||||
return [k for k in os.environ if incomplete in k]
|
||||
|
||||
|
||||
@cli.command(help="A command to print environment variables")
|
||||
@click.argument("envvar", shell_complete=get_env_vars)
|
||||
def show_env(envvar):
|
||||
click.echo(f"Environment variable: {envvar}")
|
||||
click.echo(f"Value: {os.environ[envvar]}")
|
||||
|
||||
|
||||
@cli.group(help="A group that holds a subcommand")
|
||||
def group():
|
||||
pass
|
||||
|
||||
|
||||
def list_users(ctx, param, incomplete):
|
||||
# You can generate completions with help strings by returning a list
|
||||
# of CompletionItem. You can match on whatever you want, including
|
||||
# the help.
|
||||
items = [("bob", "butcher"), ("alice", "baker"), ("jerry", "candlestick maker")]
|
||||
out = []
|
||||
|
||||
for value, help in items:
|
||||
if incomplete in value or incomplete in help:
|
||||
out.append(CompletionItem(value, help=help))
|
||||
|
||||
return out
|
||||
|
||||
|
||||
@group.command(help="Choose a user")
|
||||
@click.argument("user", shell_complete=list_users)
|
||||
def select_user(user):
|
||||
click.echo(f"Chosen user is {user}")
|
||||
|
||||
|
||||
cli.add_command(group)
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-completion",
|
||||
version="1.0",
|
||||
py_modules=["completion"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
completion=completion:cli
|
||||
""",
|
||||
)
|
|
@ -1,16 +0,0 @@
|
|||
$ complex_
|
||||
|
||||
complex is an example of building very complex cli
|
||||
applications that load subcommands dynamically from
|
||||
a plugin folder and other things.
|
||||
|
||||
All the commands are implemented as plugins in the
|
||||
`complex.commands` package. If a python module is
|
||||
placed named "cmd_foo" it will show up as "foo"
|
||||
command and the `cli` object within it will be
|
||||
loaded as nested Click command.
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ complex --help
|
|
@ -1,60 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
|
||||
CONTEXT_SETTINGS = dict(auto_envvar_prefix="COMPLEX")
|
||||
|
||||
|
||||
class Environment:
|
||||
def __init__(self):
|
||||
self.verbose = False
|
||||
self.home = os.getcwd()
|
||||
|
||||
def log(self, msg, *args):
|
||||
"""Logs a message to stderr."""
|
||||
if args:
|
||||
msg %= args
|
||||
click.echo(msg, file=sys.stderr)
|
||||
|
||||
def vlog(self, msg, *args):
|
||||
"""Logs a message to stderr only if verbose is enabled."""
|
||||
if self.verbose:
|
||||
self.log(msg, *args)
|
||||
|
||||
|
||||
pass_environment = click.make_pass_decorator(Environment, ensure=True)
|
||||
cmd_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), "commands"))
|
||||
|
||||
|
||||
class ComplexCLI(click.MultiCommand):
|
||||
def list_commands(self, ctx):
|
||||
rv = []
|
||||
for filename in os.listdir(cmd_folder):
|
||||
if filename.endswith(".py") and filename.startswith("cmd_"):
|
||||
rv.append(filename[4:-3])
|
||||
rv.sort()
|
||||
return rv
|
||||
|
||||
def get_command(self, ctx, name):
|
||||
try:
|
||||
mod = __import__(f"complex.commands.cmd_{name}", None, None, ["cli"])
|
||||
except ImportError:
|
||||
return
|
||||
return mod.cli
|
||||
|
||||
|
||||
@click.command(cls=ComplexCLI, context_settings=CONTEXT_SETTINGS)
|
||||
@click.option(
|
||||
"--home",
|
||||
type=click.Path(exists=True, file_okay=False, resolve_path=True),
|
||||
help="Changes the folder to operate on.",
|
||||
)
|
||||
@click.option("-v", "--verbose", is_flag=True, help="Enables verbose mode.")
|
||||
@pass_environment
|
||||
def cli(ctx, verbose, home):
|
||||
"""A complex command line interface."""
|
||||
ctx.verbose = verbose
|
||||
if home is not None:
|
||||
ctx.home = home
|
|
@ -1,13 +0,0 @@
|
|||
from complex.cli import pass_environment
|
||||
|
||||
import click
|
||||
|
||||
|
||||
@click.command("init", short_help="Initializes a repo.")
|
||||
@click.argument("path", required=False, type=click.Path(resolve_path=True))
|
||||
@pass_environment
|
||||
def cli(ctx, path):
|
||||
"""Initializes a repository."""
|
||||
if path is None:
|
||||
path = ctx.home
|
||||
ctx.log(f"Initialized the repository in {click.format_filename(path)}")
|
|
@ -1,11 +0,0 @@
|
|||
from complex.cli import pass_environment
|
||||
|
||||
import click
|
||||
|
||||
|
||||
@click.command("status", short_help="Shows file changes.")
|
||||
@pass_environment
|
||||
def cli(ctx):
|
||||
"""Shows file changes in the current working directory."""
|
||||
ctx.log("Changed files: none")
|
||||
ctx.vlog("bla bla bla, debug info")
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-complex",
|
||||
version="1.0",
|
||||
packages=["complex", "complex.commands"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
complex=complex.cli:cli
|
||||
""",
|
||||
)
|
1
examples/imagepipe/.gitignore
vendored
1
examples/imagepipe/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
processed-*
|
|
@ -1,13 +0,0 @@
|
|||
$ imagepipe_
|
||||
|
||||
imagepipe is an example application that implements some
|
||||
multi commands that chain image processing instructions
|
||||
together.
|
||||
|
||||
This requires pillow.
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ imagepipe open -i example01.jpg resize -w 128 display
|
||||
$ imagepipe open -i example02.jpg blur save
|
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
|
@ -1,288 +0,0 @@
|
|||
from functools import update_wrapper
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageEnhance
|
||||
from PIL import ImageFilter
|
||||
|
||||
import click
|
||||
|
||||
|
||||
@click.group(chain=True)
|
||||
def cli():
|
||||
"""This script processes a bunch of images through pillow in a unix
|
||||
pipe. One commands feeds into the next.
|
||||
|
||||
Example:
|
||||
|
||||
\b
|
||||
imagepipe open -i example01.jpg resize -w 128 display
|
||||
imagepipe open -i example02.jpg blur save
|
||||
"""
|
||||
|
||||
|
||||
@cli.result_callback()
|
||||
def process_commands(processors):
|
||||
"""This result callback is invoked with an iterable of all the chained
|
||||
subcommands. As in this example each subcommand returns a function
|
||||
we can chain them together to feed one into the other, similar to how
|
||||
a pipe on unix works.
|
||||
"""
|
||||
# Start with an empty iterable.
|
||||
stream = ()
|
||||
|
||||
# Pipe it through all stream processors.
|
||||
for processor in processors:
|
||||
stream = processor(stream)
|
||||
|
||||
# Evaluate the stream and throw away the items.
|
||||
for _ in stream:
|
||||
pass
|
||||
|
||||
|
||||
def processor(f):
|
||||
"""Helper decorator to rewrite a function so that it returns another
|
||||
function from it.
|
||||
"""
|
||||
|
||||
def new_func(*args, **kwargs):
|
||||
def processor(stream):
|
||||
return f(stream, *args, **kwargs)
|
||||
|
||||
return processor
|
||||
|
||||
return update_wrapper(new_func, f)
|
||||
|
||||
|
||||
def generator(f):
|
||||
"""Similar to the :func:`processor` but passes through old values
|
||||
unchanged and does not pass through the values as parameter.
|
||||
"""
|
||||
|
||||
@processor
|
||||
def new_func(stream, *args, **kwargs):
|
||||
yield from stream
|
||||
yield from f(*args, **kwargs)
|
||||
|
||||
return update_wrapper(new_func, f)
|
||||
|
||||
|
||||
def copy_filename(new, old):
|
||||
new.filename = old.filename
|
||||
return new
|
||||
|
||||
|
||||
@cli.command("open")
|
||||
@click.option(
|
||||
"-i",
|
||||
"--image",
|
||||
"images",
|
||||
type=click.Path(),
|
||||
multiple=True,
|
||||
help="The image file to open.",
|
||||
)
|
||||
@generator
|
||||
def open_cmd(images):
|
||||
"""Loads one or multiple images for processing. The input parameter
|
||||
can be specified multiple times to load more than one image.
|
||||
"""
|
||||
for image in images:
|
||||
try:
|
||||
click.echo(f"Opening '{image}'")
|
||||
if image == "-":
|
||||
img = Image.open(click.get_binary_stdin())
|
||||
img.filename = "-"
|
||||
else:
|
||||
img = Image.open(image)
|
||||
yield img
|
||||
except Exception as e:
|
||||
click.echo(f"Could not open image '{image}': {e}", err=True)
|
||||
|
||||
|
||||
@cli.command("save")
|
||||
@click.option(
|
||||
"--filename",
|
||||
default="processed-{:04}.png",
|
||||
type=click.Path(),
|
||||
help="The format for the filename.",
|
||||
show_default=True,
|
||||
)
|
||||
@processor
|
||||
def save_cmd(images, filename):
|
||||
"""Saves all processed images to a series of files."""
|
||||
for idx, image in enumerate(images):
|
||||
try:
|
||||
fn = filename.format(idx + 1)
|
||||
click.echo(f"Saving '{image.filename}' as '{fn}'")
|
||||
yield image.save(fn)
|
||||
except Exception as e:
|
||||
click.echo(f"Could not save image '{image.filename}': {e}", err=True)
|
||||
|
||||
|
||||
@cli.command("display")
|
||||
@processor
|
||||
def display_cmd(images):
|
||||
"""Opens all images in an image viewer."""
|
||||
for image in images:
|
||||
click.echo(f"Displaying '{image.filename}'")
|
||||
image.show()
|
||||
yield image
|
||||
|
||||
|
||||
@cli.command("resize")
|
||||
@click.option("-w", "--width", type=int, help="The new width of the image.")
|
||||
@click.option("-h", "--height", type=int, help="The new height of the image.")
|
||||
@processor
|
||||
def resize_cmd(images, width, height):
|
||||
"""Resizes an image by fitting it into the box without changing
|
||||
the aspect ratio.
|
||||
"""
|
||||
for image in images:
|
||||
w, h = (width or image.size[0], height or image.size[1])
|
||||
click.echo(f"Resizing '{image.filename}' to {w}x{h}")
|
||||
image.thumbnail((w, h))
|
||||
yield image
|
||||
|
||||
|
||||
@cli.command("crop")
|
||||
@click.option(
|
||||
"-b", "--border", type=int, help="Crop the image from all sides by this amount."
|
||||
)
|
||||
@processor
|
||||
def crop_cmd(images, border):
|
||||
"""Crops an image from all edges."""
|
||||
for image in images:
|
||||
box = [0, 0, image.size[0], image.size[1]]
|
||||
|
||||
if border is not None:
|
||||
for idx, val in enumerate(box):
|
||||
box[idx] = max(0, val - border)
|
||||
click.echo(f"Cropping '{image.filename}' by {border}px")
|
||||
yield copy_filename(image.crop(box), image)
|
||||
else:
|
||||
yield image
|
||||
|
||||
|
||||
def convert_rotation(ctx, param, value):
|
||||
if value is None:
|
||||
return
|
||||
value = value.lower()
|
||||
if value in ("90", "r", "right"):
|
||||
return (Image.ROTATE_90, 90)
|
||||
if value in ("180", "-180"):
|
||||
return (Image.ROTATE_180, 180)
|
||||
if value in ("-90", "270", "l", "left"):
|
||||
return (Image.ROTATE_270, 270)
|
||||
raise click.BadParameter(f"invalid rotation '{value}'")
|
||||
|
||||
|
||||
def convert_flip(ctx, param, value):
|
||||
if value is None:
|
||||
return
|
||||
value = value.lower()
|
||||
if value in ("lr", "leftright"):
|
||||
return (Image.FLIP_LEFT_RIGHT, "left to right")
|
||||
if value in ("tb", "topbottom", "upsidedown", "ud"):
|
||||
return (Image.FLIP_LEFT_RIGHT, "top to bottom")
|
||||
raise click.BadParameter(f"invalid flip '{value}'")
|
||||
|
||||
|
||||
@cli.command("transpose")
|
||||
@click.option(
|
||||
"-r", "--rotate", callback=convert_rotation, help="Rotates the image (in degrees)"
|
||||
)
|
||||
@click.option("-f", "--flip", callback=convert_flip, help="Flips the image [LR / TB]")
|
||||
@processor
|
||||
def transpose_cmd(images, rotate, flip):
|
||||
"""Transposes an image by either rotating or flipping it."""
|
||||
for image in images:
|
||||
if rotate is not None:
|
||||
mode, degrees = rotate
|
||||
click.echo(f"Rotate '{image.filename}' by {degrees}deg")
|
||||
image = copy_filename(image.transpose(mode), image)
|
||||
if flip is not None:
|
||||
mode, direction = flip
|
||||
click.echo(f"Flip '{image.filename}' {direction}")
|
||||
image = copy_filename(image.transpose(mode), image)
|
||||
yield image
|
||||
|
||||
|
||||
@cli.command("blur")
|
||||
@click.option("-r", "--radius", default=2, show_default=True, help="The blur radius.")
|
||||
@processor
|
||||
def blur_cmd(images, radius):
|
||||
"""Applies gaussian blur."""
|
||||
blur = ImageFilter.GaussianBlur(radius)
|
||||
for image in images:
|
||||
click.echo(f"Blurring '{image.filename}' by {radius}px")
|
||||
yield copy_filename(image.filter(blur), image)
|
||||
|
||||
|
||||
@cli.command("smoothen")
|
||||
@click.option(
|
||||
"-i",
|
||||
"--iterations",
|
||||
default=1,
|
||||
show_default=True,
|
||||
help="How many iterations of the smoothen filter to run.",
|
||||
)
|
||||
@processor
|
||||
def smoothen_cmd(images, iterations):
|
||||
"""Applies a smoothening filter."""
|
||||
for image in images:
|
||||
click.echo(
|
||||
f"Smoothening {image.filename!r} {iterations}"
|
||||
f" time{'s' if iterations != 1 else ''}"
|
||||
)
|
||||
for _ in range(iterations):
|
||||
image = copy_filename(image.filter(ImageFilter.BLUR), image)
|
||||
yield image
|
||||
|
||||
|
||||
@cli.command("emboss")
|
||||
@processor
|
||||
def emboss_cmd(images):
|
||||
"""Embosses an image."""
|
||||
for image in images:
|
||||
click.echo(f"Embossing '{image.filename}'")
|
||||
yield copy_filename(image.filter(ImageFilter.EMBOSS), image)
|
||||
|
||||
|
||||
@cli.command("sharpen")
|
||||
@click.option(
|
||||
"-f", "--factor", default=2.0, help="Sharpens the image.", show_default=True
|
||||
)
|
||||
@processor
|
||||
def sharpen_cmd(images, factor):
|
||||
"""Sharpens an image."""
|
||||
for image in images:
|
||||
click.echo(f"Sharpen '{image.filename}' by {factor}")
|
||||
enhancer = ImageEnhance.Sharpness(image)
|
||||
yield copy_filename(enhancer.enhance(max(1.0, factor)), image)
|
||||
|
||||
|
||||
@cli.command("paste")
|
||||
@click.option("-l", "--left", default=0, help="Offset from left.")
|
||||
@click.option("-r", "--right", default=0, help="Offset from right.")
|
||||
@processor
|
||||
def paste_cmd(images, left, right):
|
||||
"""Pastes the second image on the first image and leaves the rest
|
||||
unchanged.
|
||||
"""
|
||||
imageiter = iter(images)
|
||||
image = next(imageiter, None)
|
||||
to_paste = next(imageiter, None)
|
||||
|
||||
if to_paste is None:
|
||||
if image is not None:
|
||||
yield image
|
||||
return
|
||||
|
||||
click.echo(f"Paste '{to_paste.filename}' on '{image.filename}'")
|
||||
mask = None
|
||||
if to_paste.mode == "RGBA" or "transparency" in to_paste.info:
|
||||
mask = to_paste
|
||||
image.paste(to_paste, (left, right), mask)
|
||||
image.filename += f"+{to_paste.filename}"
|
||||
yield image
|
||||
|
||||
yield from imageiter
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-imagepipe",
|
||||
version="1.0",
|
||||
py_modules=["imagepipe"],
|
||||
include_package_data=True,
|
||||
install_requires=["click", "pillow"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
imagepipe=imagepipe:cli
|
||||
""",
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
$ inout_
|
||||
|
||||
inout is a simple example of an application that
|
||||
can read from files and write to files but also
|
||||
accept input from stdin or write to stdout.
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ inout input_file.txt output_file.txt
|
|
@ -1,30 +0,0 @@
|
|||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("input", type=click.File("rb"), nargs=-1)
|
||||
@click.argument("output", type=click.File("wb"))
|
||||
def cli(input, output):
|
||||
"""This script works similar to the Unix `cat` command but it writes
|
||||
into a specific file (which could be the standard output as denoted by
|
||||
the ``-`` sign).
|
||||
|
||||
\b
|
||||
Copy stdin to stdout:
|
||||
inout - -
|
||||
|
||||
\b
|
||||
Copy foo.txt and bar.txt to stdout:
|
||||
inout foo.txt bar.txt -
|
||||
|
||||
\b
|
||||
Write stdin into the file foo.txt
|
||||
inout - foo.txt
|
||||
"""
|
||||
for f in input:
|
||||
while True:
|
||||
chunk = f.read(1024)
|
||||
if not chunk:
|
||||
break
|
||||
output.write(chunk)
|
||||
output.flush()
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-inout",
|
||||
version="0.1",
|
||||
py_modules=["inout"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
inout=inout:cli
|
||||
""",
|
||||
)
|
|
@ -1,14 +0,0 @@
|
|||
$ naval_
|
||||
|
||||
naval is a simple example of an application that
|
||||
is ported from the docopt example of the same name.
|
||||
|
||||
Unlike the original this one also runs some code and
|
||||
prints messages and it's command line interface was
|
||||
changed slightly to make more sense with established
|
||||
POSIX semantics.
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ naval --help
|
|
@ -1,72 +0,0 @@
|
|||
import click
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.version_option()
|
||||
def cli():
|
||||
"""Naval Fate.
|
||||
|
||||
This is the docopt example adopted to Click but with some actual
|
||||
commands implemented and not just the empty parsing which really
|
||||
is not all that interesting.
|
||||
"""
|
||||
|
||||
|
||||
@cli.group()
|
||||
def ship():
|
||||
"""Manages ships."""
|
||||
|
||||
|
||||
@ship.command("new")
|
||||
@click.argument("name")
|
||||
def ship_new(name):
|
||||
"""Creates a new ship."""
|
||||
click.echo(f"Created ship {name}")
|
||||
|
||||
|
||||
@ship.command("move")
|
||||
@click.argument("ship")
|
||||
@click.argument("x", type=float)
|
||||
@click.argument("y", type=float)
|
||||
@click.option("--speed", metavar="KN", default=10, help="Speed in knots.")
|
||||
def ship_move(ship, x, y, speed):
|
||||
"""Moves SHIP to the new location X,Y."""
|
||||
click.echo(f"Moving ship {ship} to {x},{y} with speed {speed}")
|
||||
|
||||
|
||||
@ship.command("shoot")
|
||||
@click.argument("ship")
|
||||
@click.argument("x", type=float)
|
||||
@click.argument("y", type=float)
|
||||
def ship_shoot(ship, x, y):
|
||||
"""Makes SHIP fire to X,Y."""
|
||||
click.echo(f"Ship {ship} fires to {x},{y}")
|
||||
|
||||
|
||||
@cli.group("mine")
|
||||
def mine():
|
||||
"""Manages mines."""
|
||||
|
||||
|
||||
@mine.command("set")
|
||||
@click.argument("x", type=float)
|
||||
@click.argument("y", type=float)
|
||||
@click.option(
|
||||
"ty",
|
||||
"--moored",
|
||||
flag_value="moored",
|
||||
default=True,
|
||||
help="Moored (anchored) mine. Default.",
|
||||
)
|
||||
@click.option("ty", "--drifting", flag_value="drifting", help="Drifting mine.")
|
||||
def mine_set(x, y, ty):
|
||||
"""Sets a mine at a specific coordinate."""
|
||||
click.echo(f"Set {ty} mine at {x},{y}")
|
||||
|
||||
|
||||
@mine.command("remove")
|
||||
@click.argument("x", type=float)
|
||||
@click.argument("y", type=float)
|
||||
def mine_remove(x, y):
|
||||
"""Removes a mine at a specific coordinate."""
|
||||
click.echo(f"Removed mine at {x},{y}")
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-naval",
|
||||
version="2.0",
|
||||
py_modules=["naval"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
naval=naval:cli
|
||||
""",
|
||||
)
|
|
@ -1,9 +0,0 @@
|
|||
$ repo_
|
||||
|
||||
repo is a simple example of an application that looks
|
||||
and works similar to hg or git.
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ repo --help
|
|
@ -1,166 +0,0 @@
|
|||
import os
|
||||
import posixpath
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
|
||||
class Repo:
|
||||
def __init__(self, home):
|
||||
self.home = home
|
||||
self.config = {}
|
||||
self.verbose = False
|
||||
|
||||
def set_config(self, key, value):
|
||||
self.config[key] = value
|
||||
if self.verbose:
|
||||
click.echo(f" config[{key}] = {value}", file=sys.stderr)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Repo {self.home}>"
|
||||
|
||||
|
||||
pass_repo = click.make_pass_decorator(Repo)
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.option(
|
||||
"--repo-home",
|
||||
envvar="REPO_HOME",
|
||||
default=".repo",
|
||||
metavar="PATH",
|
||||
help="Changes the repository folder location.",
|
||||
)
|
||||
@click.option(
|
||||
"--config",
|
||||
nargs=2,
|
||||
multiple=True,
|
||||
metavar="KEY VALUE",
|
||||
help="Overrides a config key/value pair.",
|
||||
)
|
||||
@click.option("--verbose", "-v", is_flag=True, help="Enables verbose mode.")
|
||||
@click.version_option("1.0")
|
||||
@click.pass_context
|
||||
def cli(ctx, repo_home, config, verbose):
|
||||
"""Repo is a command line tool that showcases how to build complex
|
||||
command line interfaces with Click.
|
||||
|
||||
This tool is supposed to look like a distributed version control
|
||||
system to show how something like this can be structured.
|
||||
"""
|
||||
# Create a repo object and remember it as as the context object. From
|
||||
# this point onwards other commands can refer to it by using the
|
||||
# @pass_repo decorator.
|
||||
ctx.obj = Repo(os.path.abspath(repo_home))
|
||||
ctx.obj.verbose = verbose
|
||||
for key, value in config:
|
||||
ctx.obj.set_config(key, value)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument("src")
|
||||
@click.argument("dest", required=False)
|
||||
@click.option(
|
||||
"--shallow/--deep",
|
||||
default=False,
|
||||
help="Makes a checkout shallow or deep. Deep by default.",
|
||||
)
|
||||
@click.option(
|
||||
"--rev", "-r", default="HEAD", help="Clone a specific revision instead of HEAD."
|
||||
)
|
||||
@pass_repo
|
||||
def clone(repo, src, dest, shallow, rev):
|
||||
"""Clones a repository.
|
||||
|
||||
This will clone the repository at SRC into the folder DEST. If DEST
|
||||
is not provided this will automatically use the last path component
|
||||
of SRC and create that folder.
|
||||
"""
|
||||
if dest is None:
|
||||
dest = posixpath.split(src)[-1] or "."
|
||||
click.echo(f"Cloning repo {src} to {os.path.basename(dest)}")
|
||||
repo.home = dest
|
||||
if shallow:
|
||||
click.echo("Making shallow checkout")
|
||||
click.echo(f"Checking out revision {rev}")
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.confirmation_option()
|
||||
@pass_repo
|
||||
def delete(repo):
|
||||
"""Deletes a repository.
|
||||
|
||||
This will throw away the current repository.
|
||||
"""
|
||||
click.echo(f"Destroying repo {repo.home}")
|
||||
click.echo("Deleted!")
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option("--username", prompt=True, help="The developer's shown username.")
|
||||
@click.option("--email", prompt="E-Mail", help="The developer's email address")
|
||||
@click.password_option(help="The login password.")
|
||||
@pass_repo
|
||||
def setuser(repo, username, email, password):
|
||||
"""Sets the user credentials.
|
||||
|
||||
This will override the current user config.
|
||||
"""
|
||||
repo.set_config("username", username)
|
||||
repo.set_config("email", email)
|
||||
repo.set_config("password", "*" * len(password))
|
||||
click.echo("Changed credentials.")
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option(
|
||||
"--message",
|
||||
"-m",
|
||||
multiple=True,
|
||||
help="The commit message. If provided multiple times each"
|
||||
" argument gets converted into a new line.",
|
||||
)
|
||||
@click.argument("files", nargs=-1, type=click.Path())
|
||||
@pass_repo
|
||||
def commit(repo, files, message):
|
||||
"""Commits outstanding changes.
|
||||
|
||||
Commit changes to the given files into the repository. You will need to
|
||||
"repo push" to push up your changes to other repositories.
|
||||
|
||||
If a list of files is omitted, all changes reported by "repo status"
|
||||
will be committed.
|
||||
"""
|
||||
if not message:
|
||||
marker = "# Files to be committed:"
|
||||
hint = ["", "", marker, "#"]
|
||||
for file in files:
|
||||
hint.append(f"# U {file}")
|
||||
message = click.edit("\n".join(hint))
|
||||
if message is None:
|
||||
click.echo("Aborted!")
|
||||
return
|
||||
msg = message.split(marker)[0].rstrip()
|
||||
if not msg:
|
||||
click.echo("Aborted! Empty commit message")
|
||||
return
|
||||
else:
|
||||
msg = "\n".join(message)
|
||||
click.echo(f"Files to be committed: {files}")
|
||||
click.echo(f"Commit message:\n{msg}")
|
||||
|
||||
|
||||
@cli.command(short_help="Copies files.")
|
||||
@click.option(
|
||||
"--force", is_flag=True, help="forcibly copy over an existing managed file"
|
||||
)
|
||||
@click.argument("src", nargs=-1, type=click.Path())
|
||||
@click.argument("dst", type=click.Path())
|
||||
@pass_repo
|
||||
def copy(repo, src, dst, force):
|
||||
"""Copies one or multiple files to a new location. This copies all
|
||||
files from SRC to DST.
|
||||
"""
|
||||
for fn in src:
|
||||
click.echo(f"Copy from {fn} -> {dst}")
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-repo",
|
||||
version="0.1",
|
||||
py_modules=["repo"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
repo=repo:cli
|
||||
""",
|
||||
)
|
|
@ -1,9 +0,0 @@
|
|||
$ termui_
|
||||
|
||||
termui showcases the different terminal UI helpers that
|
||||
Click provides.
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ termui --help
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-termui",
|
||||
version="1.0",
|
||||
py_modules=["termui"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
termui=termui:cli
|
||||
""",
|
||||
)
|
|
@ -1,169 +0,0 @@
|
|||
import math
|
||||
import random
|
||||
import time
|
||||
|
||||
import click
|
||||
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
"""This script showcases different terminal UI helpers in Click."""
|
||||
pass
|
||||
|
||||
|
||||
@cli.command()
|
||||
def colordemo():
|
||||
"""Demonstrates ANSI color support."""
|
||||
for color in "red", "green", "blue":
|
||||
click.echo(click.style(f"I am colored {color}", fg=color))
|
||||
click.echo(click.style(f"I am background colored {color}", bg=color))
|
||||
|
||||
|
||||
@cli.command()
|
||||
def pager():
|
||||
"""Demonstrates using the pager."""
|
||||
lines = []
|
||||
for x in range(200):
|
||||
lines.append(f"{click.style(str(x), fg='green')}. Hello World!")
|
||||
click.echo_via_pager("\n".join(lines))
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option(
|
||||
"--count",
|
||||
default=8000,
|
||||
type=click.IntRange(1, 100000),
|
||||
help="The number of items to process.",
|
||||
)
|
||||
def progress(count):
|
||||
"""Demonstrates the progress bar."""
|
||||
items = range(count)
|
||||
|
||||
def process_slowly(item):
|
||||
time.sleep(0.002 * random.random())
|
||||
|
||||
def filter(items):
|
||||
for item in items:
|
||||
if random.random() > 0.3:
|
||||
yield item
|
||||
|
||||
with click.progressbar(
|
||||
items, label="Processing accounts", fill_char=click.style("#", fg="green")
|
||||
) as bar:
|
||||
for item in bar:
|
||||
process_slowly(item)
|
||||
|
||||
def show_item(item):
|
||||
if item is not None:
|
||||
return f"Item #{item}"
|
||||
|
||||
with click.progressbar(
|
||||
filter(items),
|
||||
label="Committing transaction",
|
||||
fill_char=click.style("#", fg="yellow"),
|
||||
item_show_func=show_item,
|
||||
) as bar:
|
||||
for item in bar:
|
||||
process_slowly(item)
|
||||
|
||||
with click.progressbar(
|
||||
length=count,
|
||||
label="Counting",
|
||||
bar_template="%(label)s %(bar)s | %(info)s",
|
||||
fill_char=click.style("█", fg="cyan"),
|
||||
empty_char=" ",
|
||||
) as bar:
|
||||
for item in bar:
|
||||
process_slowly(item)
|
||||
|
||||
with click.progressbar(
|
||||
length=count,
|
||||
width=0,
|
||||
show_percent=False,
|
||||
show_eta=False,
|
||||
fill_char=click.style("#", fg="magenta"),
|
||||
) as bar:
|
||||
for item in bar:
|
||||
process_slowly(item)
|
||||
|
||||
# 'Non-linear progress bar'
|
||||
steps = [math.exp(x * 1.0 / 20) - 1 for x in range(20)]
|
||||
count = int(sum(steps))
|
||||
with click.progressbar(
|
||||
length=count,
|
||||
show_percent=False,
|
||||
label="Slowing progress bar",
|
||||
fill_char=click.style("█", fg="green"),
|
||||
) as bar:
|
||||
for item in steps:
|
||||
time.sleep(item)
|
||||
bar.update(item)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument("url")
|
||||
def open(url):
|
||||
"""Opens a file or URL In the default application."""
|
||||
click.launch(url)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument("url")
|
||||
def locate(url):
|
||||
"""Opens a file or URL In the default application."""
|
||||
click.launch(url, locate=True)
|
||||
|
||||
|
||||
@cli.command()
|
||||
def edit():
|
||||
"""Opens an editor with some text in it."""
|
||||
MARKER = "# Everything below is ignored\n"
|
||||
message = click.edit(f"\n\n{MARKER}")
|
||||
if message is not None:
|
||||
msg = message.split(MARKER, 1)[0].rstrip("\n")
|
||||
if not msg:
|
||||
click.echo("Empty message!")
|
||||
else:
|
||||
click.echo(f"Message:\n{msg}")
|
||||
else:
|
||||
click.echo("You did not enter anything!")
|
||||
|
||||
|
||||
@cli.command()
|
||||
def clear():
|
||||
"""Clears the entire screen."""
|
||||
click.clear()
|
||||
|
||||
|
||||
@cli.command()
|
||||
def pause():
|
||||
"""Waits for the user to press a button."""
|
||||
click.pause()
|
||||
|
||||
|
||||
@cli.command()
|
||||
def menu():
|
||||
"""Shows a simple menu."""
|
||||
menu = "main"
|
||||
while True:
|
||||
if menu == "main":
|
||||
click.echo("Main menu:")
|
||||
click.echo(" d: debug menu")
|
||||
click.echo(" q: quit")
|
||||
char = click.getchar()
|
||||
if char == "d":
|
||||
menu = "debug"
|
||||
elif char == "q":
|
||||
menu = "quit"
|
||||
else:
|
||||
click.echo("Invalid input")
|
||||
elif menu == "debug":
|
||||
click.echo("Debug menu")
|
||||
click.echo(" b: back")
|
||||
char = click.getchar()
|
||||
if char == "b":
|
||||
menu = "main"
|
||||
else:
|
||||
click.echo("Invalid input")
|
||||
elif menu == "quit":
|
||||
return
|
|
@ -1,12 +0,0 @@
|
|||
$ validation_
|
||||
|
||||
validation is a simple example of an application that
|
||||
performs custom validation of parameters in different
|
||||
ways.
|
||||
|
||||
This example requires Click 2.0 or higher.
|
||||
|
||||
Usage:
|
||||
|
||||
$ pip install --editable .
|
||||
$ validation --help
|
|
@ -1,13 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="click-example-validation",
|
||||
version="1.0",
|
||||
py_modules=["validation"],
|
||||
include_package_data=True,
|
||||
install_requires=["click"],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
validation=validation:cli
|
||||
""",
|
||||
)
|
|
@ -1,48 +0,0 @@
|
|||
from urllib import parse as urlparse
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def validate_count(ctx, param, value):
|
||||
if value < 0 or value % 2 != 0:
|
||||
raise click.BadParameter("Should be a positive, even integer.")
|
||||
return value
|
||||
|
||||
|
||||
class URL(click.ParamType):
|
||||
name = "url"
|
||||
|
||||
def convert(self, value, param, ctx):
|
||||
if not isinstance(value, tuple):
|
||||
value = urlparse.urlparse(value)
|
||||
if value.scheme not in ("http", "https"):
|
||||
self.fail(
|
||||
f"invalid URL scheme ({value.scheme}). Only HTTP URLs are allowed",
|
||||
param,
|
||||
ctx,
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--count", default=2, callback=validate_count, help="A positive even number."
|
||||
)
|
||||
@click.option("--foo", help="A mysterious parameter.")
|
||||
@click.option("--url", help="A URL", type=URL())
|
||||
@click.version_option()
|
||||
def cli(count, foo, url):
|
||||
"""Validation.
|
||||
|
||||
This example validates parameters in different ways. It does it
|
||||
through callbacks, through a custom type as well as by validating
|
||||
manually in the function.
|
||||
"""
|
||||
if foo is not None and foo != "wat":
|
||||
raise click.BadParameter(
|
||||
'If a value is provided it needs to be the value "wat".',
|
||||
param_hint=["--foo"],
|
||||
)
|
||||
click.echo(f"count: {count}")
|
||||
click.echo(f"foo: {foo}")
|
||||
click.echo(f"url: {url!r}")
|
BIN
python-click_3.3.orig.tar.gz.delta
Normal file
BIN
python-click_3.3.orig.tar.gz.delta
Normal file
Binary file not shown.
1
python-click_3.3.orig.tar.gz.id
Normal file
1
python-click_3.3.orig.tar.gz.id
Normal file
|
@ -0,0 +1 @@
|
|||
e716ec6d0f61577fc6f8827ee2f0d7d0200b7f60
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue