Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Release v0.30.0 #190

Merged
merged 14 commits into from
Oct 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ on: # yamllint disable-line rule:truthy
push:
branches:
- master
- 'release/**'
pull_request:
branches:
- master
- 'release/**'

jobs:
tox:
Expand All @@ -19,10 +21,11 @@ jobs:
- '3.9'
- '3.10'
- '3.11'
- 'pypy-3.8'
- '3.12'
- 'pypy-3.9'
- 'pypy-3.10'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## Ignored stuff

# temp files
*.swo
*.swp
*$
*.pyc
*.pyo
Expand Down
13 changes: 9 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,30 @@ repos:
name: isort

- repo: https://github.com/psf/black
rev: 22.12.0
rev: 23.9.1
hooks:
- id: black
language_version: python3

- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
rev: 6.1.0
hooks:
- id: flake8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
hooks:
- id: mypy

- repo: https://github.com/PyCQA/bandit
rev: 1.7.4
rev: 1.7.5
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]
additional_dependencies: ["bandit[toml]"]

- repo: https://github.com/adrienverge/yamllint.git
rev: v1.29.0
rev: v1.32.0
hooks:
- id: yamllint
files: \.(yaml|yml)$
Expand Down
File renamed without changes.
84 changes: 79 additions & 5 deletions CHANGES → CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,79 @@
Changelog
~~~~~~~~~

Version 0.30.0
--------------

Backwards incompatible changes:

- Removed previously deprecated features (#184 → #188):

- argument help string in annotations — reserved for type hints;
- `argh.SUPPORTS_ALIASES`;
- `argh.safe_input()`;
- previously renamed arguments for `add_commands()`: `namespace`,
`namespace_kwargs`, `title`, `description`, `help`;
- `pre_call` argument in `dispatch()`. The basic usage remains simple but
more granular functions are now available for more control.

Instead of this::

argh.dispatch(..., pre_call=pre_call_hook)

please use this::

func, ns = argh.parse_and_resolve(...)
pre_call_hook(ns)
argh.run_endpoint_function(func, ns, ...)

- A new policy for mapping function arguments to CLI arguments is used by
default (see :class:`argh.assembling.NameMappingPolicy`).
In case you need to retain the CLI mapping but cannot modify the function
signature to use kwonly args for options, consider using this::

set_default_command(
func, name_mapping_policy=NameMappingPolicy.BY_NAME_IF_HAS_DEFAULT
)

- The name mapping policy `BY_NAME_IF_HAS_DEFAULT` slightly deviates from the
old behaviour. Kwonly arguments without default values used to be marked as
required options (``--foo FOO``), now they are treated as positionals
(``foo``). Please consider the new default policy (`BY_NAME_IF_KWONLY`) for
a better treatment of kwonly.

Deprecated:

- The `@expects_obj` decorator. Rationale: it used to support the old,
"un-pythonic" style of usage, which essentially lies outside the scope of
Argh. If you are not using the mapping of function arguments onto CLI, then
you aren't reducing the amount of code compared to vanilla Argparse.

- The `add_help_command` argument in `dispatch()`.
Rationale: it doesn't add much to user experience; it's not much harder to
type ``--help`` than it is to type ``help``; moreover, the option can be
added anywhere, unlike its positional counterpart.

Enhancements:

- Added support for Python 3.12.
- Added type annotations to existing Argh code (#185 → #189).
- The `dispatch()` function has been refactored, so in case you need finer
control over the process, two new, more granular functions can be used:

- `endpoint_function, namespace = argh.parse_and_resolve(...)`
- `argh.run_endpoint_function(endpoint_function, namespace, ...)`

Please note that the names may change in the upcoming versions.

- Configurable name mapping policy has been introduced for function argument
to CLI argument translation (#191 → #199):

- `BY_NAME_IF_KWONLY` (default and recommended).
- `BY_NAME_IF_HAS_DEFAULT` (close to pre-v.0.30 behaviour);

Please check API docs on :class:`argh.assembling.NameMappingPolicy` for
details.

Version 0.29.4
--------------

Expand All @@ -19,9 +92,10 @@ Version 0.29.0

Backwards incompatible changes:

- Wrapped exceptions now cause ``dispatching.dispatch()`` to raise ``SystemExit(1)``
instead of returning without error. For most users, this means failed commands
will now exit with a failure status instead of a success. (#161)
- Wrapped exceptions now cause ``dispatching.dispatch()`` to raise
``SystemExit(1)`` instead of returning without error. For most users, this
means failed commands will now exit with a failure status instead of a
success. (#161)

Deprecated:

Expand All @@ -34,8 +108,8 @@ Deprecated:

Enhancements:

- Can control exit status (see Backwards Incompatible Changes above) when raising
``CommandError`` using the ``code`` keyword arg.
- Can control exit status (see Backwards Incompatible Changes above) when
raising ``CommandError`` using the ``code`` keyword arg.

Bugs fixed:

Expand Down
41 changes: 19 additions & 22 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,18 @@ In a nutshell
Nested commands are a piece of cake, no messing with subparsers (though
they are of course used under the hood);

:Term-Friendly:
Command output is processed with respect to stream encoding;

:Unobtrusive:
`Argh` can dispatch a subset of pure-`argparse` code, and pure-`argparse`
code can update and dispatch a parser assembled with `Argh`;

:DRY:
The amount of boilerplate code is minimal; among other things, `Argh` will:
Don't Repeat Yourself. The amount of boilerplate code is minimal.
Among other things, `Argh` will:

* infer command name from function name;
* infer arguments from function signature;
* infer argument type from the default value;
* infer argument action from the default value (for booleans);
* add an alias root command ``help`` for the ``--help`` argument.

:NIH free:
`Argh` supports *completion*, *progress bars* and everything else by being
Expand Down Expand Up @@ -107,8 +104,8 @@ A very simple application with one command:

import argh

def main():
return 'Hello world'
def main() -> str:
return "Hello world"

argh.dispatch_command(main)

Expand Down Expand Up @@ -148,9 +145,9 @@ A potentially modular application with more control over the process:
"Returns given word as is."
return text

def greet(name, greeting='Hello'):
def greet(name: str, greeting: str = "Hello") -> str:
"Greets the user with given name. The greeting is customizable."
return f'{greeting}, {name}!'
return f"{greeting}, {name}!"

# assembling:

Expand All @@ -159,7 +156,7 @@ A potentially modular application with more control over the process:

# dispatching:

if __name__ == '__main__':
if __name__ == "__main__":
parser.dispatch()

.. code-block:: bash
Expand All @@ -173,7 +170,7 @@ A potentially modular application with more control over the process:
Here's the auto-generated help for this application (note how the docstrings
are reused)::

$ ./app.py help
$ ./app.py --help

usage: app.py {echo,greet} ...

Expand All @@ -184,7 +181,7 @@ are reused)::
...and for a specific command (an ordinary function signature is converted
to CLI arguments)::

$ ./app.py help greet
$ ./app.py --help greet

usage: app.py greet [-g GREETING] name

Expand All @@ -203,26 +200,26 @@ enough; in these cases the powerful API of `argparse` is also available:

.. code-block:: python

@arg('text', default='hello world', nargs='+', help='The message')
def echo(text):
@arg("text", default="hello world", nargs="+", help="The message")
def echo(text: str) -> None:
print text

The approaches can be safely combined even up to this level:

.. code-block:: python

# adding help to `foo` which is in the function signature:
@arg('foo', help='blah')
@arg("foo", help="blah")
# these are not in the signature so they go to **kwargs:
@arg('baz')
@arg('-q', '--quux')
@arg("baz")
@arg("-q", "--quux")
# the function itself:
def cmd(foo, bar=1, *args, **kwargs):
def cmd(foo: str, bar: int = 1, *args, **kwargs) -> Iterator[str]:
yield foo
yield bar
yield ', '.join(args)
yield kwargs['baz']
yield kwargs['quux']
yield ", ".join(args)
yield kwargs["baz"]
yield kwargs["quux"]

Links
-----
Expand All @@ -245,7 +242,7 @@ Author

Developed by Andrey Mikhaylenko since 2010.

See file `AUTHORS` for a list of contributors to this library.
See file `AUTHORS.rst` for a list of contributors to this library.

Support
-------
Expand Down
2 changes: 1 addition & 1 deletion docs/source/changes.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
.. include:: ../../CHANGES
.. include:: ../../CHANGES.rst
2 changes: 2 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@
}

nitpicky = True

autodoc_typehints = "both"
2 changes: 1 addition & 1 deletion docs/source/contributors.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
.. include:: ../../AUTHORS
.. include:: ../../AUTHORS.rst
6 changes: 3 additions & 3 deletions docs/source/cookbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ Use `nargs` from argparse by amending the function signature with the

.. code-block:: python

@argh.arg('-p', '--patterns', nargs='*')
def cmd(patterns=None):
distros = ('abc', 'xyz')
@argh.arg("-p", "--patterns", nargs="*")
def cmd(patterns: list[str] | None = None) -> list:
distros = ("abc", "xyz")
return [d for d in distros if not patterns
or any(p in d for p in patterns)]

Expand Down
3 changes: 2 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Dependencies
------------

The `argh` library is supported (and tested unless otherwise specified)
on the following versions of Python: 3.8, 3.9, 3.10, 3.11.
on the following versions of Python: 3.8, 3.9, 3.10, 3.11, 3.12.

If you need support for ancient Pythons, please use the following versions
of Argh (the numeric puns were semi-intentional):
Expand All @@ -26,6 +26,7 @@ Details
tutorial
reference
cookbook
the_story
similar
projects
subparsers
Expand Down
3 changes: 0 additions & 3 deletions docs/source/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ API Reference
.. automodule:: argh.exceptions
:members:

.. automodule:: argh.io
:members:

.. automodule:: argh.utils
:members:

Expand Down
14 changes: 12 additions & 2 deletions docs/source/similar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ supports Python3. Not every "yes" in this table would count as pro.
* opster_ and finaloption_ support nested commands but are based on the
outdated `optparse` library and therefore reimplement some features available
in `argparse`. They also introduce decorators that don't just decorate
functions but change their behaviour, which is bad practice.
functions but change their behaviour, which is a questionable practice.
* simpleopt_ has an odd API and is rather a simple replacement for standard
libraries than an extension.
* opterator_ is based on the outdated `optparse` and does not support nested
Expand All @@ -36,11 +36,20 @@ supports Python3. Not every "yes" in this table would count as pro.
worth migrating but it is surely very flexible and easy to use.
* baker_
* plumbum_
* docopt_
* docopt_ takes an inverted approach: you write the usage docs, it generates a
parser. Then you need to wire the parsing results into you code manually.
* aaargh_
* cliff_
* cement_
* autocommand_
* click_ is a rather popular library, a bit younger than Argh. The authors of
both libraries even gave lightning talks on a PyCon within a few minutes :)
Although I expected it to kill Argh because it comes with Flask, in fact
it takes an approach so different from Argh that they can coexist.
Like Opster, Click's decorator replaces the underlying function (a
questionable practice); it does not derive the CLI arguments from the
function signature but entirely relies on additional decorators, while Argh
strives for the opposite.

.. _argdeclare: http://code.activestate.com/recipes/576935-argdeclare-declarative-interface-to-argparse/
.. _argparse-cli: http://code.google.com/p/argparse-cli/
Expand All @@ -59,3 +68,4 @@ supports Python3. Not every "yes" in this table would count as pro.
.. _cliff: http://pypi.python.org/pypi/cliff
.. _cement: http://builtoncement.com/2.0/
.. _autocommand: https://pypi.python.org/pypi/autocommand/
.. _click: https://click.palletsprojects.com
Loading
Loading