Adding upstream version 0.6.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e5d20de2e1
commit
271f3e2863
20 changed files with 2544 additions and 0 deletions
18
.github/dependabot.yml
vendored
Normal file
18
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: pip
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
- dependency-name: flake8
|
||||
versions:
|
||||
- 3.9.0
|
||||
- dependency-name: pytest
|
||||
versions:
|
||||
- 6.2.2
|
||||
- dependency-name: mypy
|
||||
versions:
|
||||
- "0.800"
|
22
.github/workflows/bump.yaml
vendored
Normal file
22
.github/workflows/bump.yaml
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
name: Bump version
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
bump-version:
|
||||
if: "!startsWith(github.event.head_commit.message, 'bump:')"
|
||||
runs-on: ubuntu-latest
|
||||
name: "Bump version and create changelog with commitizen"
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
- name: Create bump and changelog
|
||||
uses: commitizen-tools/commitizen-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
33
.github/workflows/publish.yaml
vendored
Normal file
33
.github/workflows/publish.yaml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: Publish package to Pypi
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Poetry
|
||||
uses: snok/install-poetry@v1
|
||||
with:
|
||||
version: latest
|
||||
virtualenvs-in-project: true
|
||||
virtualenvs-create: true
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
poetry install
|
||||
- name: Publish
|
||||
env:
|
||||
PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||
run: |
|
||||
./scripts/publish
|
43
.github/workflows/test.yaml
vendored
Normal file
43
.github/workflows/test.yaml
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
# We should restore the cache and remove extra requirements installations after this is resolved https://github.com/actions/setup-python/issues/182
|
||||
|
||||
name: Tests
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
architecture: x64
|
||||
- name: Install Poetry
|
||||
uses: snok/install-poetry@v1
|
||||
with:
|
||||
version: latest
|
||||
virtualenvs-in-project: true
|
||||
virtualenvs-create: true
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
poetry install --no-interaction
|
||||
- name: Test and Lint
|
||||
run: |
|
||||
./scripts/test
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage.xml
|
||||
flags: unittests
|
||||
name: decli
|
||||
fail_ci_if_error: true
|
111
.gitignore
vendored
Normal file
111
.gitignore
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
# Text editors
|
||||
.vscode/
|
||||
todo
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
# ruff
|
||||
.ruff_cache
|
47
CHANGELOG.md
Normal file
47
CHANGELOG.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Change Log
|
||||
|
||||
## v0.6.2 (2024-04-28)
|
||||
|
||||
### Fix
|
||||
|
||||
- add missing build-system
|
||||
|
||||
## v0.6.1 (2023-06-03)
|
||||
|
||||
### Fix
|
||||
|
||||
- commitizen bumps version in decli/__init_.py
|
||||
|
||||
## v0.6.0 (2023-04-28)
|
||||
|
||||
### Feat
|
||||
|
||||
- add py.typed
|
||||
|
||||
### Fix
|
||||
|
||||
- improve type hints
|
||||
|
||||
## v0.5.2 (2020-07-26)
|
||||
|
||||
### Fix
|
||||
|
||||
- **application**: add required subcommand support for python 3.6
|
||||
|
||||
# 0.5.1
|
||||
|
||||
### Fixes
|
||||
|
||||
* Logger changed from DEBUG to INFO
|
||||
|
||||
# 0.5.0
|
||||
|
||||
### Features
|
||||
|
||||
* **arguments:** exclusive groups are now supported
|
||||
|
||||
# 0.4.0
|
||||
|
||||
### Features
|
||||
|
||||
* **arguments:** it is possible to group arguments now
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 Santiago
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
701
README.rst
Normal file
701
README.rst
Normal file
|
@ -0,0 +1,701 @@
|
|||
======
|
||||
Decli
|
||||
======
|
||||
|
||||
Minimal declarative cli tool.
|
||||
|
||||
.. image:: https://img.shields.io/codecov/c/github/Woile/decli.svg?style=flat-square
|
||||
:alt: Codecov
|
||||
:target: https://codecov.io/gh/Woile/decli
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/decli.svg?style=flat-square
|
||||
:alt: PyPI
|
||||
:target: https://pypi.org/project/decli/
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/decli.svg?style=flat-square
|
||||
:alt: PyPI - Python Version
|
||||
:target: https://pypi.org/project/decli/
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from decli import cli
|
||||
|
||||
data = {
|
||||
"prog": "myapp",
|
||||
"description": "Process some integers.",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "integers",
|
||||
"metavar": "N",
|
||||
"type": int,
|
||||
"nargs": "+",
|
||||
"help": "an integer for the accumulator",
|
||||
},
|
||||
{
|
||||
"name": "--sum",
|
||||
"dest": "accumulate",
|
||||
"action": "store_const",
|
||||
"const": sum,
|
||||
"default": max,
|
||||
"help": "sum the integers (default: find the max)",
|
||||
},
|
||||
],
|
||||
}
|
||||
parser = cli(data)
|
||||
parser.parse_args()
|
||||
|
||||
|
||||
::
|
||||
|
||||
>> parser.print_help()
|
||||
usage: myapp [-h] [--sum] N [N ...]
|
||||
|
||||
Process some integers.
|
||||
|
||||
positional arguments:
|
||||
N an integer for the accumulator
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--sum sum the integers (default: find the max)
|
||||
|
||||
|
||||
::
|
||||
|
||||
In [4]: args = parser.parse_args("--sum 3 2 1".split())
|
||||
|
||||
In [5]: args.accumulate(args.integers)
|
||||
Out[5]: 6
|
||||
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
|
||||
|
||||
About
|
||||
=====
|
||||
|
||||
Decli is minimal wrapper around **argparse**.
|
||||
|
||||
It's useful when writing big applications that have many arguments and subcommands, this way it'll be more clear.
|
||||
|
||||
It's a minimal library to rapidly create an interface separated from your app.
|
||||
|
||||
It's possible to use any argument from **argparse** and it works really well with it.
|
||||
|
||||
Forget about copy pasting the argparse functions, if you are lazy like me, this library should be really handy!
|
||||
|
||||
Many cases were tested, but it's possible that not everything was covered, so if you find anything, please report it.
|
||||
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
::
|
||||
|
||||
pip install -U decli
|
||||
|
||||
or alternatively:
|
||||
|
||||
::
|
||||
|
||||
poetry add decli
|
||||
|
||||
|
||||
Usage
|
||||
======
|
||||
|
||||
Main cli
|
||||
--------
|
||||
|
||||
Create the dictionary in which the cli tool is declared.
|
||||
|
||||
The same arguments argparse use are accepted, except parents, which is ignored.
|
||||
|
||||
- prog - The name of the program (default: sys.argv[0])
|
||||
- usage - The string describing the program usage (default: generated from arguments added to parser)
|
||||
- description - Text to display before the argument help (default: none)
|
||||
- epilog - Text to display after the argument help (default: none)
|
||||
- formatter_class - A class for customizing the help output
|
||||
- prefix_chars - The set of characters that prefix optional arguments (default: ‘-‘)
|
||||
- fromfile_prefix_chars - The set of characters that prefix files from which additional arguments should be read (default: None)
|
||||
- argument_default - The global default value for arguments (default: None)
|
||||
- conflict_handler - The strategy for resolving conflicting optionals (usually unnecessary)
|
||||
- add_help - Add a -h/--help option to the parser (default: True)
|
||||
- allow_abbrev - Allows long options to be abbreviated if the abbreviation is unambiguous. (default: True)
|
||||
|
||||
More info in the `argparse page <https://docs.python.org/3/library/argparse.html#argumentparser-objects>`_
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
data = {
|
||||
"prog": "myapp",
|
||||
"description": "This app does something cool",
|
||||
"epilog": "And that's it"
|
||||
}
|
||||
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
It's just a list with dictionaries. To add aliases just use a list instead of a string.
|
||||
|
||||
Accepted values:
|
||||
|
||||
|
||||
- name: - Either a name or a list of option strings, e.g. foo or -f, --foo.
|
||||
- action - The basic type of action to be taken when this argument is encountered at the command line.
|
||||
- nargs - The number of command-line arguments that should be consumed.
|
||||
- const - A constant value required by some action and nargs selections.
|
||||
- default - The value produced if the argument is absent from the command line.
|
||||
- type - The type to which the command-line argument should be converted.
|
||||
- choices - A container of the allowable values for the argument.
|
||||
- required - Whether or not the command-line option may be omitted (optionals only).
|
||||
- help - A brief description of what the argument does.
|
||||
- metavar - A name for the argument in usage messages.
|
||||
- dest - The name of the attribute to be added to the object returned by parse_args().
|
||||
|
||||
|
||||
More info about `arguments <https://docs.python.org/3/library/argparse.html#the-add-argument-method>`_
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
data = {
|
||||
"prog": "myapp",
|
||||
"description": "This app does something cool",
|
||||
"epilog": "And that's it",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--foo"
|
||||
},
|
||||
{
|
||||
"name": ["-b", "--bar"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Subcommands
|
||||
-----------
|
||||
|
||||
Just a dictionary where the most important key is **commands** which is a list of the commands.
|
||||
|
||||
|
||||
Accepted values:
|
||||
|
||||
|
||||
- title - title for the sub-parser group in help output; by default “subcommands” if description is provided, otherwise uses title for positional arguments
|
||||
- description - description for the sub-parser group in help output, by default None
|
||||
- commands - list of dicts describing the commands. Same arguments as the **main cli** are supported. And **func** which is really important.
|
||||
- prog - usage information that will be displayed with sub-command help, by default the name of the program and any positional arguments before the subparser argument
|
||||
- action - the basic type of action to be taken when this argument is encountered at the command line
|
||||
- dest - name of the attribute under which sub-command name will be stored; by default None and no value is stored
|
||||
- required - Whether or not a subcommand must be provided, by default False.
|
||||
- help - help for sub-parser group in help output, by default None
|
||||
- metavar - string presenting available sub-commands in help; by default it is None and presents sub-commands in form {cmd1, cmd2, ..}
|
||||
|
||||
|
||||
More info about `subcommands <https://docs.python.org/3/library/argparse.html#sub-commands>`_
|
||||
|
||||
Func
|
||||
~~~~
|
||||
|
||||
Usually in a sub-command it's useful to specify to which function are they pointing to. That's why each command should have this parameter.
|
||||
|
||||
|
||||
When you are building an app which does multiple things, each function should be mapped to a command this way, using the **func** argument.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from decli import cli
|
||||
|
||||
data = {
|
||||
"prog": "myapp",
|
||||
"description": "This app does something cool",
|
||||
"epilog": "And that's it",
|
||||
"subcommands": {
|
||||
"title": "main",
|
||||
"commands": [
|
||||
{
|
||||
"name": "sum",
|
||||
"help": "new project",
|
||||
"func": sum,
|
||||
"arguments": [
|
||||
{
|
||||
"name": "integers",
|
||||
"metavar": "N",
|
||||
"type": int,
|
||||
"nargs": "+",
|
||||
"help": "an integer for the accumulator",
|
||||
},
|
||||
{"name": "--name", "nargs": "?"},
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
parser = cli(data)
|
||||
args = parser.parse_args(["sum 1 2 3".split()])
|
||||
args.func(args.integers) # Runs the sum of the integers
|
||||
|
||||
Groups
|
||||
------
|
||||
|
||||
Used to group the arguments based on conceptual groups. This only affects the shown **help**, nothing else.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
data = {
|
||||
"prog": "app",
|
||||
"arguments": [
|
||||
{"name": "foo", "help": "foo help", "group": "group1"},
|
||||
{"name": "choo", "help": "choo help", "group": "group1"},
|
||||
{"name": "--bar", "help": "bar help", "group": "group2"},
|
||||
]
|
||||
}
|
||||
parser = cli(data)
|
||||
parser.print_help()
|
||||
|
||||
::
|
||||
|
||||
usage: app [-h] [--bar BAR] foo choo
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
|
||||
group1:
|
||||
foo foo help
|
||||
choo choo help
|
||||
|
||||
group2:
|
||||
--bar BAR bar help
|
||||
|
||||
|
||||
Exclusive Groups
|
||||
----------------
|
||||
|
||||
A mutually exclusive group allows to execute only one **optional** argument (starting with :code:`--`) from the group.
|
||||
If the condition is not met, it will show an error.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
data = {
|
||||
"prog": "app",
|
||||
"arguments": [
|
||||
{"name": "--foo", "help": "foo help", "exclusive_group": "group1"},
|
||||
{"name": "--choo", "help": "choo help", "exclusive_group": "group1"},
|
||||
{"name": "--bar", "help": "bar help", "exclusive_group": "group1"},
|
||||
]
|
||||
}
|
||||
parser = cli(data)
|
||||
parser.print_help()
|
||||
|
||||
::
|
||||
|
||||
usage: app [-h] [--foo FOO | --choo CHOO | --bar BAR]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--foo FOO foo help
|
||||
--choo CHOO choo help
|
||||
--bar BAR bar help
|
||||
|
||||
::
|
||||
|
||||
In [1]: parser.parse_args("--foo 1 --choo 2".split())
|
||||
|
||||
usage: app [-h] [--foo FOO | --choo CHOO | --bar BAR]
|
||||
app: error: argument --choo: not allowed with argument --foo
|
||||
|
||||
|
||||
Groups and Exclusive groups
|
||||
---------------------------
|
||||
|
||||
It is not possible to have groups inside exclusive groups with **decli**.
|
||||
|
||||
**Decli** will prevent from doing this by raising a :code:`ValueError`.
|
||||
|
||||
It is possible to accomplish it with argparse, but the help message generated will be broken and the
|
||||
exclusion won't work.
|
||||
|
||||
Parents
|
||||
-------
|
||||
|
||||
Sometimes, several cli share a common set of arguments.
|
||||
|
||||
Rather than repeating the definitions of these arguments,
|
||||
one or more parent clis with all the shared arguments can be passed
|
||||
to :code:`parents=argument` to cli.
|
||||
|
||||
More info about `parents <https://docs.python.org/3/library/argparse.html#parents>`_
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
parent_foo_data = {
|
||||
"add_help": False,
|
||||
"arguments": [{"name": "--foo-parent", "type": int}],
|
||||
}
|
||||
parent_bar_data = {
|
||||
"add_help": False,
|
||||
"arguments": [{"name": "--bar-parent", "type": int}],
|
||||
}
|
||||
parent_foo_cli = cli(parent_foo_data)
|
||||
parent_bar_cli = cli(parent_bar_data)
|
||||
|
||||
parents = [parent_foo_cli, parent_bar_cli]
|
||||
|
||||
data = {
|
||||
"prog": "app",
|
||||
"arguments": [
|
||||
{"name": "foo"}
|
||||
]
|
||||
}
|
||||
parser = cli(data, parents=parents)
|
||||
parser.print_help()
|
||||
|
||||
::
|
||||
|
||||
usage: app [-h] [--foo-parent FOO_PARENT] [--bar-parent BAR_PARENT] foo
|
||||
|
||||
positional arguments:
|
||||
foo
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--foo-parent FOO_PARENT
|
||||
--bar-parent BAR_PARENT
|
||||
|
||||
|
||||
Recipes
|
||||
=======
|
||||
|
||||
Subcommands
|
||||
-----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from decli import cli
|
||||
|
||||
data = {
|
||||
"prog": "myapp",
|
||||
"formatter_class": argparse.RawDescriptionHelpFormatter,
|
||||
"description": "The software has subcommands which you can use",
|
||||
"subcommands": {
|
||||
"title": "main",
|
||||
"description": "main commands",
|
||||
"commands": [
|
||||
{
|
||||
"name": "all",
|
||||
"help": "check every values is true",
|
||||
"func": all
|
||||
},
|
||||
{
|
||||
"name": ["s", "sum"],
|
||||
"help": "new project",
|
||||
"func": sum,
|
||||
"arguments": [
|
||||
{
|
||||
"name": "integers",
|
||||
"metavar": "N",
|
||||
"type": int,
|
||||
"nargs": "+",
|
||||
"help": "an integer for the accumulator",
|
||||
},
|
||||
{"name": "--name", "nargs": "?"},
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
parser = cli(data)
|
||||
args = parser.parse_args(["sum 1 2 3".split()])
|
||||
args.func(args.integers) # Runs the sum of the integers
|
||||
|
||||
|
||||
Minimal
|
||||
-------
|
||||
|
||||
This app does nothing, but it's the min we can have:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from decli import cli
|
||||
|
||||
parser = cli({})
|
||||
parser.print_help()
|
||||
|
||||
::
|
||||
|
||||
usage: ipython [-h]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
|
||||
|
||||
Positional arguments
|
||||
--------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from decli import cli
|
||||
|
||||
data = {
|
||||
"arguments": [
|
||||
{
|
||||
"name": "echo"
|
||||
}
|
||||
]
|
||||
}
|
||||
parser = cli(data)
|
||||
args = parser.parse_args(["foo"])
|
||||
|
||||
::
|
||||
|
||||
In [11]: print(args.echo)
|
||||
foo
|
||||
|
||||
|
||||
Positional arguments with type
|
||||
------------------------------
|
||||
|
||||
When a type is specified, the argument will be treated as that type, otherwise it'll fail.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from decli import cli
|
||||
|
||||
data = {
|
||||
"arguments": [
|
||||
{
|
||||
"name": "square",
|
||||
"type": int
|
||||
}
|
||||
]
|
||||
}
|
||||
parser = cli(data)
|
||||
args = parser.parse_args(["1"])
|
||||
|
||||
::
|
||||
|
||||
In [11]: print(args.echo)
|
||||
1
|
||||
|
||||
Optional arguments
|
||||
------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from decli import cli
|
||||
|
||||
data = {
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--verbose",
|
||||
"help": "increase output verbosity"
|
||||
}
|
||||
]
|
||||
}
|
||||
parser = cli(data)
|
||||
args = parser.parse_args(["--verbosity 1"])
|
||||
|
||||
::
|
||||
|
||||
In [11]: print(args.verbosity)
|
||||
1
|
||||
|
||||
In [15]: args = parser.parse_args([])
|
||||
|
||||
In [16]: args
|
||||
Out[16]: Namespace(verbose=None)
|
||||
|
||||
|
||||
Flags
|
||||
-----
|
||||
|
||||
Flags are a boolean only (True/False) subset of options.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from decli import cli
|
||||
|
||||
data = {
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--verbose",
|
||||
"action": "store_true", # defaults to False
|
||||
},
|
||||
{
|
||||
"name": "--noisy",
|
||||
"action": "store_false", # defaults to True
|
||||
}
|
||||
]
|
||||
}
|
||||
parser = cli(data)
|
||||
|
||||
|
||||
|
||||
|
||||
Short options
|
||||
-------------
|
||||
|
||||
Used to add short versions of the options.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
data = {
|
||||
"arguments": [
|
||||
{
|
||||
"name": ["-v", "--verbose"],
|
||||
"help": "increase output verbosity"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Grouping
|
||||
--------
|
||||
|
||||
This is only possible using **arguments**.
|
||||
|
||||
Only affect the way the help gets displayed. You might be looking for subcommands.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
data = {
|
||||
"prog": "mycli",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--save",
|
||||
"group": "main",
|
||||
"help": "This save belongs to the main group",
|
||||
},
|
||||
{
|
||||
"name": "--remove",
|
||||
"group": "main",
|
||||
"help": "This remove belongs to the main group",
|
||||
},
|
||||
],
|
||||
}
|
||||
parser = cli(data)
|
||||
parser.print_help()
|
||||
|
||||
::
|
||||
|
||||
usage: mycli [-h] [--save SAVE] [--remove REMOVE]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
|
||||
main:
|
||||
--save SAVE This save belongs to the main group
|
||||
--remove REMOVE This remove belongs to the main group
|
||||
|
||||
|
||||
Exclusive group
|
||||
---------------
|
||||
|
||||
This is only possible using **optional arguments**.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
data = {
|
||||
"prog": "mycli",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--save",
|
||||
"exclusive_group": "main",
|
||||
"help": "This save belongs to the main group",
|
||||
},
|
||||
{
|
||||
"name": "--remove",
|
||||
"exclusive_group": "main",
|
||||
"help": "This remove belongs to the main group",
|
||||
},
|
||||
],
|
||||
}
|
||||
parser = cli(data)
|
||||
parser.print_help()
|
||||
|
||||
::
|
||||
|
||||
usage: mycli [-h] [--save SAVE | --remove REMOVE]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--save SAVE This save belongs to the main group
|
||||
--remove REMOVE This remove belongs to the main group
|
||||
|
||||
|
||||
Combining Positional and Optional arguments
|
||||
-------------------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
data = {
|
||||
"arguments": [
|
||||
{
|
||||
"name": "square",
|
||||
"type": int,
|
||||
"help": "display a square of a given number"
|
||||
},
|
||||
{
|
||||
"name": ["-v", "--verbose"],
|
||||
"action": "store_true",
|
||||
"help": "increase output verbosity"
|
||||
}
|
||||
]
|
||||
}
|
||||
parser = cli(data)
|
||||
|
||||
args = parser.parse_args()
|
||||
answer = args.square**2
|
||||
if args.verbose:
|
||||
print(f"the square of {args.square} equals {answer}")
|
||||
else:
|
||||
print(answer)
|
||||
|
||||
|
||||
More Examples
|
||||
-------------
|
||||
|
||||
Many examples from `argparse documentation <https://docs.python.org/3/library/argparse.html>`_
|
||||
are covered in test/examples.py
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
1. Clone the repo
|
||||
2. Install dependencies
|
||||
|
||||
::
|
||||
|
||||
poetry install
|
||||
|
||||
3. Run tests
|
||||
|
||||
::
|
||||
|
||||
./scripts/tests
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
**PRs are welcome!**
|
5
decli/__init__.py
Normal file
5
decli/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from .application import cli
|
||||
|
||||
__version__ = "0.6.2"
|
||||
|
||||
__all__ = ("cli",)
|
171
decli/application.py
Normal file
171
decli/application.py
Normal file
|
@ -0,0 +1,171 @@
|
|||
import argparse
|
||||
import logging
|
||||
from typing import Optional, Callable, Union
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
config: dict = {}
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
def init_config():
|
||||
return {"prefix_chars": "-"}
|
||||
|
||||
|
||||
def ensure_list(name: Union[str, list]) -> list:
|
||||
if isinstance(name, str):
|
||||
name = [name]
|
||||
return name
|
||||
|
||||
|
||||
def has_many_and_is_optional(names: list) -> list:
|
||||
"""The arguments can have aliases only when they are optional.
|
||||
|
||||
If this is not the case, then it raises an error.
|
||||
"""
|
||||
prefix_chars = config["prefix_chars"]
|
||||
is_optional = all(name.startswith(tuple(prefix_chars)) for name in names)
|
||||
|
||||
if not is_optional and len(names) > 1:
|
||||
msg = (
|
||||
f"Only optional arguments (starting with {prefix_chars}) "
|
||||
"can have aliases"
|
||||
)
|
||||
raise ValueError(msg)
|
||||
return names
|
||||
|
||||
|
||||
def is_exclusive_group_or_not(arg: dict):
|
||||
if "exclusive_group" in arg and "group" in arg:
|
||||
msg = "choose group or exclusive_group not both."
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
def validate_args(args: list):
|
||||
for arg in args:
|
||||
arg["name"] = ensure_list(arg["name"])
|
||||
has_many_and_is_optional(arg["name"])
|
||||
is_exclusive_group_or_not(arg)
|
||||
yield arg
|
||||
|
||||
|
||||
def get_or_create_group(
|
||||
parser,
|
||||
groups: dict,
|
||||
title: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
):
|
||||
group_parser = groups.get(title)
|
||||
if group_parser is None:
|
||||
group_parser = parser.add_argument_group(title, description)
|
||||
groups.update({title: group_parser})
|
||||
return group_parser
|
||||
|
||||
|
||||
def get_or_create_exclusive_group(
|
||||
parser, groups: dict, title: Optional[str] = None, required=False
|
||||
):
|
||||
group_parser = groups.get(title)
|
||||
if group_parser is None:
|
||||
group_parser = parser.add_mutually_exclusive_group(required=required)
|
||||
groups.update({title: group_parser})
|
||||
|
||||
return group_parser
|
||||
|
||||
|
||||
def add_arguments(parser, args: list):
|
||||
groups: dict = {}
|
||||
exclusive_groups: dict = {}
|
||||
|
||||
for arg in validate_args(args):
|
||||
logger.debug("arg: %s", arg)
|
||||
|
||||
name: list = arg.pop("name")
|
||||
group_title: Optional[str] = arg.pop("group", None)
|
||||
exclusive_group_title: Optional[str] = arg.pop("exclusive_group", None)
|
||||
|
||||
_parser = parser
|
||||
if exclusive_group_title:
|
||||
logger.debug("Exclusive group: %s", exclusive_group_title)
|
||||
_parser = get_or_create_exclusive_group(
|
||||
parser, exclusive_groups, exclusive_group_title
|
||||
)
|
||||
elif group_title:
|
||||
logger.debug("Group: %s", group_title)
|
||||
_parser = get_or_create_group(parser, groups, group_title)
|
||||
|
||||
_parser.add_argument(*name, **arg)
|
||||
|
||||
|
||||
def add_subcommand(parser, command: dict):
|
||||
args: list = command.pop("arguments", None)
|
||||
func: Optional[Callable] = command.pop("func", None)
|
||||
|
||||
names: list = ensure_list(command.pop("name"))
|
||||
name: str = names.pop(0)
|
||||
|
||||
if names:
|
||||
command.update({"aliases": names})
|
||||
|
||||
command_parser = parser.add_parser(name, **command)
|
||||
|
||||
if func:
|
||||
command_parser.set_defaults(func=func)
|
||||
if args:
|
||||
add_arguments(command_parser, args)
|
||||
|
||||
|
||||
def add_subparser(parser, subcommand: dict):
|
||||
commands: list = subcommand.pop("commands")
|
||||
|
||||
# This design is for python 3.6 compatibility
|
||||
if "required" in subcommand:
|
||||
required = subcommand.pop("required")
|
||||
subparser = parser.add_subparsers(**subcommand)
|
||||
subparser.required = required
|
||||
else:
|
||||
subparser = parser.add_subparsers(**subcommand)
|
||||
|
||||
for command in commands:
|
||||
add_subcommand(subparser, command)
|
||||
|
||||
|
||||
def add_parser(data: dict, parser_class: Callable, parents: Optional[list]):
|
||||
if parents is None:
|
||||
parents = []
|
||||
|
||||
args: Optional[list] = data.pop("arguments", None)
|
||||
subcommands: Optional[dict] = data.pop("subcommands", None)
|
||||
|
||||
parser = parser_class(**data, parents=parents)
|
||||
|
||||
if args:
|
||||
logger.debug("Adding arguments...")
|
||||
add_arguments(parser, args)
|
||||
|
||||
if subcommands:
|
||||
logger.debug("Adding subcommands...")
|
||||
add_subparser(parser, subcommands)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def cli(
|
||||
data: dict,
|
||||
parser_class: Callable = argparse.ArgumentParser,
|
||||
parents: Optional[list] = None,
|
||||
):
|
||||
"""Create a cli application.
|
||||
|
||||
This is the entrypoint.
|
||||
"""
|
||||
global config
|
||||
config = init_config()
|
||||
data = deepcopy(data)
|
||||
|
||||
if data.get("prefix_chars"):
|
||||
config.update({"prefix_chars": data.get("prefix_chars")})
|
||||
|
||||
parser = add_parser(data, parser_class, parents)
|
||||
return parser
|
0
decli/py.typed
Normal file
0
decli/py.typed
Normal file
29
examples/demo.py
Normal file
29
examples/demo.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
"""Simple app example"""
|
||||
from decli import cli
|
||||
|
||||
data = {
|
||||
"prog": "app",
|
||||
"arguments": [
|
||||
{"name": "--install", "action": "store_true", "group": "opas"},
|
||||
{"name": "--purge", "action": "store_false", "group": "opas"},
|
||||
],
|
||||
"subcommands": {
|
||||
"title": "main",
|
||||
"commands": [
|
||||
{
|
||||
"name": "commit",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--bocha",
|
||||
"action": "store_true",
|
||||
"group": "opas",
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
parser = cli(data)
|
||||
args = parser.parse_args()
|
||||
print(args)
|
885
poetry.lock
generated
Normal file
885
poetry.lock
generated
Normal file
|
@ -0,0 +1,885 @@
|
|||
# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "appnope"
|
||||
version = "0.1.3"
|
||||
description = "Disable App Nap on macOS >= 10.9"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"},
|
||||
{file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backcall"
|
||||
version = "0.2.0"
|
||||
description = "Specifications for callback functions passed in to an API"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
|
||||
{file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "23.3.0"
|
||||
description = "The uncompromising code formatter."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"},
|
||||
{file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"},
|
||||
{file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"},
|
||||
{file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"},
|
||||
{file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"},
|
||||
{file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"},
|
||||
{file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"},
|
||||
{file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"},
|
||||
{file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"},
|
||||
{file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"},
|
||||
{file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"},
|
||||
{file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"},
|
||||
{file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"},
|
||||
{file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"},
|
||||
{file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"},
|
||||
{file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"},
|
||||
{file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"},
|
||||
{file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"},
|
||||
{file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"},
|
||||
{file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"},
|
||||
{file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"},
|
||||
{file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"},
|
||||
{file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"},
|
||||
{file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"},
|
||||
{file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8.0.0"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
packaging = ">=22.0"
|
||||
pathspec = ">=0.9.0"
|
||||
platformdirs = ">=2"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
|
||||
typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.7.4)"]
|
||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2022.12.7"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
|
||||
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.1.0"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"},
|
||||
{file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"},
|
||||
{file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"},
|
||||
{file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"},
|
||||
{file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"},
|
||||
{file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"},
|
||||
{file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.3"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
|
||||
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "codecov"
|
||||
version = "2.1.13"
|
||||
description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "codecov-2.1.13-py2.py3-none-any.whl", hash = "sha256:c2ca5e51bba9ebb43644c43d0690148a55086f7f5e6fd36170858fa4206744d5"},
|
||||
{file = "codecov-2.1.13.tar.gz", hash = "sha256:2362b685633caeaf45b9951a9b76ce359cd3581dd515b430c6c3f5dfb4d92a8c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
coverage = "*"
|
||||
requests = ">=2.7.9"
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.2.3"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "coverage-7.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-win32.whl", hash = "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91"},
|
||||
{file = "coverage-7.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-win32.whl", hash = "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925"},
|
||||
{file = "coverage-7.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-win32.whl", hash = "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1"},
|
||||
{file = "coverage-7.2.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-win32.whl", hash = "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22"},
|
||||
{file = "coverage-7.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-win32.whl", hash = "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30"},
|
||||
{file = "coverage-7.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a"},
|
||||
{file = "coverage-7.2.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0"},
|
||||
{file = "coverage-7.2.3.tar.gz", hash = "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
|
||||
|
||||
[package.extras]
|
||||
toml = ["tomli"]
|
||||
|
||||
[[package]]
|
||||
name = "decorator"
|
||||
version = "5.1.1"
|
||||
description = "Decorators for Humans"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
|
||||
{file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.1.1"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
|
||||
{file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.4"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
|
||||
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "6.6.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"},
|
||||
{file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
perf = ["ipython"]
|
||||
testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
description = "brain-dead simple config-ini parsing"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipdb"
|
||||
version = "0.13.13"
|
||||
description = "IPython-enabled pdb"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4"},
|
||||
{file = "ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
decorator = {version = "*", markers = "python_version > \"3.6\""}
|
||||
ipython = {version = ">=7.31.1", markers = "python_version > \"3.6\""}
|
||||
tomli = {version = "*", markers = "python_version > \"3.6\" and python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "ipython"
|
||||
version = "7.34.0"
|
||||
description = "IPython: Productive Interactive Computing"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ipython-7.34.0-py3-none-any.whl", hash = "sha256:c175d2440a1caff76116eb719d40538fbb316e214eda85c5515c303aacbfb23e"},
|
||||
{file = "ipython-7.34.0.tar.gz", hash = "sha256:af3bdb46aa292bce5615b1b2ebc76c2080c5f77f54bda2ec72461317273e7cd6"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
appnope = {version = "*", markers = "sys_platform == \"darwin\""}
|
||||
backcall = "*"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
decorator = "*"
|
||||
jedi = ">=0.16"
|
||||
matplotlib-inline = "*"
|
||||
pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""}
|
||||
pickleshare = "*"
|
||||
prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0"
|
||||
pygments = "*"
|
||||
setuptools = ">=18.5"
|
||||
traitlets = ">=4.2"
|
||||
|
||||
[package.extras]
|
||||
all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.17)", "pygments", "qtconsole", "requests", "testpath"]
|
||||
doc = ["Sphinx (>=1.3)"]
|
||||
kernel = ["ipykernel"]
|
||||
nbconvert = ["nbconvert"]
|
||||
nbformat = ["nbformat"]
|
||||
notebook = ["ipywidgets", "notebook"]
|
||||
parallel = ["ipyparallel"]
|
||||
qtconsole = ["qtconsole"]
|
||||
test = ["ipykernel", "nbformat", "nose (>=0.10.1)", "numpy (>=1.17)", "pygments", "requests", "testpath"]
|
||||
|
||||
[[package]]
|
||||
name = "jedi"
|
||||
version = "0.18.2"
|
||||
description = "An autocompletion tool for Python that can be used for text editors."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "jedi-0.18.2-py2.py3-none-any.whl", hash = "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e"},
|
||||
{file = "jedi-0.18.2.tar.gz", hash = "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
parso = ">=0.8.0,<0.9.0"
|
||||
|
||||
[package.extras]
|
||||
docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"]
|
||||
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
|
||||
testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib-inline"
|
||||
version = "0.1.6"
|
||||
description = "Inline Matplotlib backend for Jupyter"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"},
|
||||
{file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
traitlets = "*"
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.2.0"
|
||||
description = "Optional static typing for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "mypy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:701189408b460a2ff42b984e6bd45c3f41f0ac9f5f58b8873bbedc511900086d"},
|
||||
{file = "mypy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fe91be1c51c90e2afe6827601ca14353bbf3953f343c2129fa1e247d55fd95ba"},
|
||||
{file = "mypy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d26b513225ffd3eacece727f4387bdce6469192ef029ca9dd469940158bc89e"},
|
||||
{file = "mypy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a2d219775a120581a0ae8ca392b31f238d452729adbcb6892fa89688cb8306a"},
|
||||
{file = "mypy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:2e93a8a553e0394b26c4ca683923b85a69f7ccdc0139e6acd1354cc884fe0128"},
|
||||
{file = "mypy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3efde4af6f2d3ccf58ae825495dbb8d74abd6d176ee686ce2ab19bd025273f41"},
|
||||
{file = "mypy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:695c45cea7e8abb6f088a34a6034b1d273122e5530aeebb9c09626cea6dca4cb"},
|
||||
{file = "mypy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0e9464a0af6715852267bf29c9553e4555b61f5904a4fc538547a4d67617937"},
|
||||
{file = "mypy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8293a216e902ac12779eb7a08f2bc39ec6c878d7c6025aa59464e0c4c16f7eb9"},
|
||||
{file = "mypy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:f46af8d162f3d470d8ffc997aaf7a269996d205f9d746124a179d3abe05ac602"},
|
||||
{file = "mypy-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:031fc69c9a7e12bcc5660b74122ed84b3f1c505e762cc4296884096c6d8ee140"},
|
||||
{file = "mypy-1.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:390bc685ec209ada4e9d35068ac6988c60160b2b703072d2850457b62499e336"},
|
||||
{file = "mypy-1.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4b41412df69ec06ab141808d12e0bf2823717b1c363bd77b4c0820feaa37249e"},
|
||||
{file = "mypy-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4e4a682b3f2489d218751981639cffc4e281d548f9d517addfd5a2917ac78119"},
|
||||
{file = "mypy-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a197ad3a774f8e74f21e428f0de7f60ad26a8d23437b69638aac2764d1e06a6a"},
|
||||
{file = "mypy-1.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c9a084bce1061e55cdc0493a2ad890375af359c766b8ac311ac8120d3a472950"},
|
||||
{file = "mypy-1.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaeaa0888b7f3ccb7bcd40b50497ca30923dba14f385bde4af78fac713d6d6f6"},
|
||||
{file = "mypy-1.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bea55fc25b96c53affab852ad94bf111a3083bc1d8b0c76a61dd101d8a388cf5"},
|
||||
{file = "mypy-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:4c8d8c6b80aa4a1689f2a179d31d86ae1367ea4a12855cc13aa3ba24bb36b2d8"},
|
||||
{file = "mypy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:70894c5345bea98321a2fe84df35f43ee7bb0feec117a71420c60459fc3e1eed"},
|
||||
{file = "mypy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a99fe1768925e4a139aace8f3fb66db3576ee1c30b9c0f70f744ead7e329c9f"},
|
||||
{file = "mypy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023fe9e618182ca6317ae89833ba422c411469156b690fde6a315ad10695a521"},
|
||||
{file = "mypy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4d19f1a239d59f10fdc31263d48b7937c585810288376671eaf75380b074f238"},
|
||||
{file = "mypy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:2de7babe398cb7a85ac7f1fd5c42f396c215ab3eff731b4d761d68d0f6a80f48"},
|
||||
{file = "mypy-1.2.0-py3-none-any.whl", hash = "sha256:d8e9187bfcd5ffedbe87403195e1fc340189a68463903c39e2b63307c9fa0394"},
|
||||
{file = "mypy-1.2.0.tar.gz", hash = "sha256:f70a40410d774ae23fcb4afbbeca652905a04de7948eaf0b1789c8d1426b72d1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mypy-extensions = ">=1.0.0"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""}
|
||||
typing-extensions = ">=3.10"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
install-types = ["pip"]
|
||||
python2 = ["typed-ast (>=1.4.0,<2)"]
|
||||
reports = ["lxml"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
||||
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.1"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
|
||||
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parso"
|
||||
version = "0.8.3"
|
||||
description = "A Python Parser"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
|
||||
{file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
|
||||
testing = ["docopt", "pytest (<6.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.11.1"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"},
|
||||
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pexpect"
|
||||
version = "4.8.0"
|
||||
description = "Pexpect allows easy control of interactive console applications."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
|
||||
{file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
ptyprocess = ">=0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pickleshare"
|
||||
version = "0.7.5"
|
||||
description = "Tiny 'shelve'-like database with concurrency support"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
|
||||
{file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "3.5.0"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"},
|
||||
{file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = {version = ">=4.5", markers = "python_version < \"3.8\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.0.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "prompt-toolkit"
|
||||
version = "3.0.38"
|
||||
description = "Library for building powerful interactive command lines in Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "prompt_toolkit-3.0.38-py3-none-any.whl", hash = "sha256:45ea77a2f7c60418850331366c81cf6b5b9cf4c7fd34616f733c5427e6abbb1f"},
|
||||
{file = "prompt_toolkit-3.0.38.tar.gz", hash = "sha256:23ac5d50538a9a38c8bde05fecb47d0b403ecd0662857a86f886f798563d5b9b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
wcwidth = "*"
|
||||
|
||||
[[package]]
|
||||
name = "ptyprocess"
|
||||
version = "0.7.0"
|
||||
description = "Run a subprocess in a pseudo terminal"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
|
||||
{file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.15.1"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"},
|
||||
{file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
plugins = ["importlib-metadata"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.3.1"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"},
|
||||
{file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-cov"
|
||||
version = "4.0.0"
|
||||
description = "Pytest plugin for measuring coverage."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"},
|
||||
{file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
coverage = {version = ">=5.2.1", extras = ["toml"]}
|
||||
pytest = ">=4.6"
|
||||
|
||||
[package.extras]
|
||||
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.29.0"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "requests-2.29.0-py3-none-any.whl", hash = "sha256:e8f3c9be120d3333921d213eef078af392fba3933ab7ed2d1cba3b56f2568c3b"},
|
||||
{file = "requests-2.29.0.tar.gz", hash = "sha256:f2e34a75f4749019bb0e3effb66683630e4ffeaf75819fb51bebef1bf5aef059"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = ">=2,<4"
|
||||
idna = ">=2.5,<4"
|
||||
urllib3 = ">=1.21.1,<1.27"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.263"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.0.263-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:ee6c7a77f142c427fa73e1f5f603fc1a39413a36fe6966ed0fc55e97f6921d9c"},
|
||||
{file = "ruff-0.0.263-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:c3b7d4b365207f3e4c40d235127091478e595b31e35b6cd57d940920cdfae68b"},
|
||||
{file = "ruff-0.0.263-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebc778d95f29c9917e6e7608b2b67815707e6ab8eb5af9341617beda479c3edf"},
|
||||
{file = "ruff-0.0.263-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f75fa1632ea065b8f10678e7b6ae9873f84d5046bdf146990112751e98af42a"},
|
||||
{file = "ruff-0.0.263-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddcee0d91629a4fa4bc9faebf5b94d4615d50d1cd76d1098fa71fbe1c54f4104"},
|
||||
{file = "ruff-0.0.263-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4010b156f2e9fa6e74b5581098467f6ff68beac48945599b3a9239481e578ab4"},
|
||||
{file = "ruff-0.0.263-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15386933dd8e03aafa3186f9e996d6823105492817311338fbcb64d0ecbcd95f"},
|
||||
{file = "ruff-0.0.263-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e0b280dd246448564c892bce5607d820ad1f14944f3d535db98692e2a7ac07"},
|
||||
{file = "ruff-0.0.263-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82c41f276106017b6f075dd2f2cc68e1a0b434cc75488f816fc98bd41982628d"},
|
||||
{file = "ruff-0.0.263-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3e9fcee3f81129eabc75da005d839235e32d7d374f2d4c0db0c708dad4703d6e"},
|
||||
{file = "ruff-0.0.263-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:981e3c4d773f7ff52479c4fd74a65e408f1e13fa5f889b72214d400cd1299ce4"},
|
||||
{file = "ruff-0.0.263-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bed1d3fba306e3f7e13ce226927b84200350e25abd1e754e06ee361c6d41de15"},
|
||||
{file = "ruff-0.0.263-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7890499c2c3dcb1e60de2a8b4c5f5775b2bfcdff7d3e68e38db5cb2d65b12006"},
|
||||
{file = "ruff-0.0.263-py3-none-win32.whl", hash = "sha256:c2b79919ebd93674b93dfc2c843e264bf8e52fbe737467e9b58521775c85f4ad"},
|
||||
{file = "ruff-0.0.263-py3-none-win_amd64.whl", hash = "sha256:9af932f665e177de62e172901704257fd6e5bfabb95893867ff7382a851459d3"},
|
||||
{file = "ruff-0.0.263-py3-none-win_arm64.whl", hash = "sha256:ddf4503595b560bfa5fae92fa2e4cb09ec465ee4cf88cc248f10ad2e956deec3"},
|
||||
{file = "ruff-0.0.263.tar.gz", hash = "sha256:1008f211ad8aa1d998517ac5bf3d68fbc68ec516d1da89b6081f25ff2f30b687"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "67.7.2"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"},
|
||||
{file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "traitlets"
|
||||
version = "5.9.0"
|
||||
description = "Traitlets Python configuration system"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"},
|
||||
{file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"]
|
||||
test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"]
|
||||
|
||||
[[package]]
|
||||
name = "typed-ast"
|
||||
version = "1.5.4"
|
||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"},
|
||||
{file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"},
|
||||
{file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"},
|
||||
{file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"},
|
||||
{file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"},
|
||||
{file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"},
|
||||
{file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"},
|
||||
{file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"},
|
||||
{file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"},
|
||||
{file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"},
|
||||
{file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"},
|
||||
{file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"},
|
||||
{file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"},
|
||||
{file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"},
|
||||
{file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"},
|
||||
{file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"},
|
||||
{file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"},
|
||||
{file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"},
|
||||
{file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"},
|
||||
{file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"},
|
||||
{file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"},
|
||||
{file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"},
|
||||
{file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"},
|
||||
{file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.5.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"},
|
||||
{file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.15"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
files = [
|
||||
{file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"},
|
||||
{file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.6"
|
||||
description = "Measures the displayed width of unicode strings in a terminal"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
|
||||
{file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.15.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"},
|
||||
{file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.7"
|
||||
content-hash = "e32f0e42d2eb164ff1d7045c3832c722d85d4a25a73c9f6a3aca9edab466a38f"
|
46
pyproject.toml
Normal file
46
pyproject.toml
Normal file
|
@ -0,0 +1,46 @@
|
|||
[tool.poetry]
|
||||
name = "decli"
|
||||
version = "0.6.2"
|
||||
description = "Minimal, easy-to-use, declarative cli tool"
|
||||
authors = ["Santiago Fraire <santiwilly@gmail.com>"]
|
||||
license = "MIT"
|
||||
readme = 'README.rst'
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.7"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
ipython = "^7.16"
|
||||
ipdb = "^0.13.13"
|
||||
pytest = "^7.3.1"
|
||||
pytest-cov = "^4.0.0"
|
||||
black = "^23.3.0"
|
||||
mypy = "^1.2.0"
|
||||
codecov = "^2.1.13"
|
||||
ruff = "^0.0.263"
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 88
|
||||
ignore = [
|
||||
"E501",
|
||||
"D1",
|
||||
"D415",
|
||||
]
|
||||
|
||||
[tool.ruff.isort]
|
||||
known-first-party = ["decli", "tests"]
|
||||
|
||||
[tool.commitizen]
|
||||
name = "cz_conventional_commits"
|
||||
tag_format = "v$version"
|
||||
version_type = "pep440"
|
||||
version_provider = "poetry"
|
||||
update_changelog_on_bump = true
|
||||
major_version_zero = true
|
||||
version_files = [
|
||||
"decli/__init__.py:__version__",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
4
scripts/format
Executable file
4
scripts/format
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
ruff decli tests --fix
|
||||
black decli/ tests/
|
3
scripts/publish
Executable file
3
scripts/publish
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
poetry publish --build -u "$PYPI_USERNAME" -p "$PYPI_PASSWORD"
|
10
scripts/test
Executable file
10
scripts/test
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
pr() {
|
||||
poetry run python -m "$@"
|
||||
}
|
||||
|
||||
pr pytest --cov-report term-missing --cov-report=xml:coverage.xml --cov=decli "${1:-tests}"
|
||||
pr black decli tests --check
|
||||
pr ruff decli/ tests/
|
||||
pr mypy decli/ tests/
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
197
tests/examples.py
Normal file
197
tests/examples.py
Normal file
|
@ -0,0 +1,197 @@
|
|||
import argparse
|
||||
import textwrap
|
||||
from decli import cli
|
||||
|
||||
|
||||
def main_example():
|
||||
"""https://docs.python.org/3/library/argparse.html#example"""
|
||||
data = {
|
||||
"description": "Process some integers.",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "integers",
|
||||
"metavar": "N",
|
||||
"type": int,
|
||||
"nargs": "+",
|
||||
"help": "an integer for the accumulator",
|
||||
},
|
||||
{
|
||||
"name": "--sum",
|
||||
"dest": "accumulate",
|
||||
"action": "store_const",
|
||||
"const": sum,
|
||||
"default": max,
|
||||
"help": "sum the integers (default: find the max)",
|
||||
},
|
||||
],
|
||||
}
|
||||
parser = cli(data)
|
||||
return parser
|
||||
|
||||
|
||||
def complete_example():
|
||||
data = {
|
||||
"prog": "cz",
|
||||
"formatter_class": argparse.RawDescriptionHelpFormatter,
|
||||
"description": "The software does this and that",
|
||||
"epilog": "This is the epilooogpoe ",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--debug",
|
||||
"action": "store_true",
|
||||
"default": False,
|
||||
"help": "use debug mode",
|
||||
},
|
||||
{
|
||||
"name": ["-v", "--version"],
|
||||
"action": "store_true",
|
||||
"default": False,
|
||||
"help": "get the installed version",
|
||||
"group": "ops",
|
||||
},
|
||||
{"name": "--save", "group": "ops"},
|
||||
],
|
||||
"subcommands": {
|
||||
"title": "main",
|
||||
"description": "main commands",
|
||||
"commands": [
|
||||
{
|
||||
"name": "all",
|
||||
"help": "check every values is true",
|
||||
"func": all,
|
||||
},
|
||||
{
|
||||
"name": ["sum", "s"],
|
||||
"help": "new project",
|
||||
"func": sum,
|
||||
"arguments": [
|
||||
{
|
||||
"name": "integers",
|
||||
"metavar": "N",
|
||||
"type": int,
|
||||
"nargs": "+",
|
||||
"help": "an integer for the accumulator",
|
||||
},
|
||||
{"name": "--name", "nargs": "?"},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
parser = cli(data)
|
||||
return parser
|
||||
|
||||
|
||||
def name_or_flags():
|
||||
"""https://docs.python.org/3/library/argparse.html#name-or-flags"""
|
||||
data = {
|
||||
"prog": "sti",
|
||||
"arguments": [{"name": ["-f", "--foo"]}, {"name": "bar"}],
|
||||
}
|
||||
return data
|
||||
|
||||
|
||||
def compose_clis_using_parents():
|
||||
"""
|
||||
Sometimes, several cli share a common set of arguments.
|
||||
Rather than repeating the definitions of these arguments,
|
||||
one or more parent clis with all the shared arguments can be passed
|
||||
to parents= argument to cli.
|
||||
|
||||
https://docs.python.org/3/library/argparse.html#parents
|
||||
"""
|
||||
parent_foo_data = {
|
||||
"add_help": False,
|
||||
"arguments": [{"name": "--foo-parent", "type": int}],
|
||||
}
|
||||
parent_bar_data = {
|
||||
"add_help": False,
|
||||
"arguments": [{"name": "--bar-parent", "type": int}],
|
||||
}
|
||||
parent_foo_cli = cli(parent_foo_data)
|
||||
parent_bar_cli = cli(parent_bar_data)
|
||||
|
||||
parents = [parent_foo_cli, parent_bar_cli]
|
||||
return parents
|
||||
|
||||
|
||||
def using_formatter_class():
|
||||
"""https://docs.python.org/3/library/argparse.html#formatter-class"""
|
||||
data = {
|
||||
"prog": "PROG",
|
||||
"formatter_class": argparse.RawDescriptionHelpFormatter,
|
||||
"description": textwrap.dedent(
|
||||
"""\
|
||||
Please do not mess up this text!
|
||||
--------------------------------
|
||||
I have indented it
|
||||
exactly the way
|
||||
I want it
|
||||
"""
|
||||
),
|
||||
}
|
||||
return data
|
||||
|
||||
|
||||
def prefix_chars():
|
||||
data = {
|
||||
"prog": "PROG",
|
||||
"prefix_chars": "+",
|
||||
"arguments": [{"name": ["+f", "++foo"]}, {"name": "++bar"}],
|
||||
}
|
||||
return data
|
||||
|
||||
|
||||
def grouping_arguments():
|
||||
data = {
|
||||
"prog": "mycli",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--new",
|
||||
"help": "This does not belong to a group but its a long help",
|
||||
},
|
||||
{
|
||||
"name": "--init",
|
||||
"help": "This does not belong to a group but its a long help",
|
||||
},
|
||||
{
|
||||
"name": "--run",
|
||||
"group": "app",
|
||||
"help": "This does not belong to a group",
|
||||
},
|
||||
{
|
||||
"name": "--build",
|
||||
"group": "app",
|
||||
"help": "This does not belong to a group",
|
||||
},
|
||||
{
|
||||
"name": ["--install", "--add"],
|
||||
"group": "package",
|
||||
"metavar": "package_name",
|
||||
"nargs": "+",
|
||||
"help": "This belongs to a group",
|
||||
},
|
||||
{
|
||||
"name": "--remove",
|
||||
"group": "package",
|
||||
"help": "This belongs to a group",
|
||||
},
|
||||
{
|
||||
"name": "--why",
|
||||
"group": "package",
|
||||
"help": "This belongs to a group",
|
||||
},
|
||||
],
|
||||
}
|
||||
return data
|
||||
|
||||
|
||||
def exclusive_group():
|
||||
data = {
|
||||
"prog": "app",
|
||||
"arguments": [
|
||||
{"name": "--install", "exclusive_group": "ops"},
|
||||
{"name": "--purge", "exclusive_group": "ops"},
|
||||
],
|
||||
}
|
||||
return data
|
198
tests/test_decli.py
Normal file
198
tests/test_decli.py
Normal file
|
@ -0,0 +1,198 @@
|
|||
"""Most of argparse examples rebuilt with climp."""
|
||||
import pytest
|
||||
import argparse
|
||||
from . import examples
|
||||
from decli import cli
|
||||
import unittest
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def test_main_example_ok(self):
|
||||
parser = examples.main_example()
|
||||
args = parser.parse_args("1 2 3 4".split())
|
||||
|
||||
assert args.accumulate(args.integers) == 4
|
||||
|
||||
def test_main_example_sums_ok(self):
|
||||
parser = examples.main_example()
|
||||
args = parser.parse_args("1 2 3 4 --sum".split())
|
||||
|
||||
assert args.accumulate(args.integers) == 10
|
||||
|
||||
def test_main_example_fails(self):
|
||||
parser = examples.main_example()
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
args = parser.parse_args("a b c".split())
|
||||
args.accumulate(args.integers)
|
||||
|
||||
def test_complete_example(self):
|
||||
parser = examples.complete_example()
|
||||
args = parser.parse_args("sum 1 2 3".split())
|
||||
|
||||
assert args.func(args.integers) == 6
|
||||
|
||||
def test_compose_clis_using_parents(self):
|
||||
data = {"prog": "daddy", "arguments": [{"name": "something"}]}
|
||||
parents = examples.compose_clis_using_parents()
|
||||
parser = cli(data, parents=parents)
|
||||
args = parser.parse_args(["--foo-parent", "2", "XXX"])
|
||||
|
||||
assert args.something == "XXX"
|
||||
assert args.foo_parent == 2
|
||||
|
||||
def test_compose_clis_using_parents_and_arguments(self):
|
||||
data = {"prog": "daddy", "arguments": [{"name": "--something"}]}
|
||||
parents = examples.compose_clis_using_parents()
|
||||
parser = cli(data, parents=parents)
|
||||
args = parser.parse_args(["--something", "XXX"])
|
||||
|
||||
assert args.something == "XXX"
|
||||
|
||||
def test_prefix_chars(self):
|
||||
data = examples.prefix_chars()
|
||||
parser = cli(data)
|
||||
args = parser.parse_args("+f X ++bar Y".split())
|
||||
|
||||
assert args.foo == "X"
|
||||
assert args.bar == "Y"
|
||||
|
||||
def test_name_or_flags(self):
|
||||
data = examples.name_or_flags()
|
||||
parser = cli(data)
|
||||
|
||||
args = parser.parse_args(["HELLO"])
|
||||
assert args.bar == "HELLO"
|
||||
|
||||
args = parser.parse_args(["BAR", "--foo", "FOO"])
|
||||
assert args.bar == "BAR"
|
||||
assert args.foo == "FOO"
|
||||
|
||||
def test_name_or_flags_fail(self):
|
||||
data = examples.name_or_flags()
|
||||
parser = cli(data)
|
||||
with pytest.raises(SystemExit):
|
||||
parser.parse_args(["--foo", "FOO"])
|
||||
|
||||
def test_cli_no_args(self):
|
||||
data = {"prog": "daddy", "description": "helloo"}
|
||||
parser = cli(data)
|
||||
args = parser.parse_args([])
|
||||
|
||||
assert args.__dict__ == {}
|
||||
|
||||
def test_groups(self):
|
||||
data = examples.grouping_arguments()
|
||||
parser = cli(data)
|
||||
help_result = parser.format_help()
|
||||
|
||||
assert "app" in help_result
|
||||
assert "package" in help_result
|
||||
|
||||
def test_not_optional_arg_name_validation_fails(self):
|
||||
data = {"arguments": [{"name": ["f", "foo"]}]}
|
||||
with pytest.raises(ValueError):
|
||||
cli(data)
|
||||
|
||||
def test_exclusive_group_ok(self):
|
||||
data = {
|
||||
"prog": "app",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--install",
|
||||
"action": "store_true",
|
||||
"exclusive_group": "ops",
|
||||
},
|
||||
{
|
||||
"name": "--purge",
|
||||
"action": "store_true",
|
||||
"exclusive_group": "ops",
|
||||
},
|
||||
],
|
||||
}
|
||||
parser = cli(data)
|
||||
args = parser.parse_args(["--install"])
|
||||
assert args.install is True
|
||||
assert args.purge is False
|
||||
|
||||
def test_exclusive_group_fails_when_same_group_called(self):
|
||||
data = {
|
||||
"prog": "app",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--install",
|
||||
"action": "store_true",
|
||||
"exclusive_group": "opas",
|
||||
},
|
||||
{
|
||||
"name": "--purge",
|
||||
"action": "store_true",
|
||||
"exclusive_group": "opas",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
parser = cli(data)
|
||||
with pytest.raises(SystemExit):
|
||||
parser.parse_args("--install --purge".split())
|
||||
|
||||
def test_exclusive_group_and_group_together_fail(self):
|
||||
"""
|
||||
Note:
|
||||
|
||||
Exclusive group requires at least one arg before adding groups
|
||||
"""
|
||||
data = {
|
||||
"prog": "app",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "--install",
|
||||
"action": "store_true",
|
||||
"exclusive_group": "ops",
|
||||
"group": "cmd",
|
||||
},
|
||||
{
|
||||
"name": "--purge",
|
||||
"action": "store_true",
|
||||
"exclusive_group": "ops",
|
||||
"group": "cmd",
|
||||
},
|
||||
{"name": "--fear", "exclusive_group": "ops"},
|
||||
],
|
||||
}
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
cli(data)
|
||||
|
||||
def test_subcommand_required(self):
|
||||
data = {
|
||||
"prog": "cz",
|
||||
"description": (
|
||||
"Commitizen is a cli tool to generate conventional commits.\n"
|
||||
"For more information about the topic go to "
|
||||
"https://conventionalcommits.org/"
|
||||
),
|
||||
"formatter_class": argparse.RawDescriptionHelpFormatter,
|
||||
"arguments": [
|
||||
{"name": "--debug", "action": "store_true", "help": "use debug mode"},
|
||||
{
|
||||
"name": ["-n", "--name"],
|
||||
"help": "use the given commitizen (default: cz_conventional_commits)",
|
||||
},
|
||||
],
|
||||
"subcommands": {
|
||||
"title": "commands",
|
||||
"required": True,
|
||||
"commands": [
|
||||
{
|
||||
"name": ["init"],
|
||||
"help": "init commitizen configuration",
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
parser = cli(data)
|
||||
args = parser.parse_args(["-n", "cz_jira", "init"])
|
||||
assert args.debug is False
|
||||
assert args.name == "cz_jira"
|
Loading…
Add table
Add a link
Reference in a new issue