├── .gitignore ├── setup.cfg ├── .travis.yml ├── LICENCE ├── pyproject.toml ├── flake8_print.py ├── README.md ├── test_linter.py └── poetry.lock /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pyc 3 | dist 4 | .mypy_cache -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [aliases] 2 | test=pytest 3 | 4 | [flake8] 5 | max-line-length = 120 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.7" 4 | - "3.8" 5 | - "3.9" 6 | - "3.10" 7 | 8 | env: 9 | matrix: 10 | - FLAKE8_VERSION="" 11 | - FLAKE8_VERSION="3.0" 12 | 13 | install: 14 | - pip install poetry 15 | - poetry install 16 | - if [[ -n "$FLAKE8_VERSION" ]]; then poetry run pip install flake8=="$FLAKE8_VERSION"; fi 17 | script: 18 | - poetry run pytest 19 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Joseph Kahn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["poetry-core>=1.0"] 3 | build-backend = "poetry.core.masonry.api" 4 | 5 | [tool.poetry] 6 | name = "flake8-print" 7 | version = "5.0.0" 8 | description = "print statement checker plugin for flake8" 9 | readme = "README.md" 10 | 11 | license = "MIT" 12 | 13 | authors = [ 14 | "Joseph Kahn " 15 | ] 16 | 17 | repository = "https://github.com/jbkahn/flake8-print" 18 | homepage = "https://github.com/jbkahn/flake8-print" 19 | keywords = [ 20 | "flake8", 21 | "plugin", 22 | "linting", 23 | "print", 24 | "code quality" 25 | ] 26 | 27 | classifiers = [ 28 | 'Development Status :: 3 - Alpha', 29 | 'Environment :: Console', 30 | 'Framework :: Flake8', 31 | 'Intended Audience :: Developers', 32 | 'License :: OSI Approved :: MIT License', 33 | 'Operating System :: OS Independent', 34 | 'Programming Language :: Python', 35 | 'Programming Language :: Python :: 2', 36 | 'Programming Language :: Python :: 3', 37 | 'Topic :: Software Development :: Libraries :: Python Modules', 38 | 'Topic :: Software Development :: Quality Assurance', 39 | ] 40 | 41 | 42 | include = ["pyproject.toml", "flake8_print.py", "LICENCE"] 43 | 44 | [tool.poetry.plugins."flake8.extension"] 45 | T20 = "flake8_print:PrintChecker" 46 | 47 | [tool.poetry.dependencies] 48 | python = ">=3.7" 49 | "flake8" = ">=3.0" 50 | pycodestyle = "*" 51 | 52 | [tool.poetry.dev-dependencies] 53 | black = { version = "^22.3.0" } 54 | pytest = "*" 55 | 56 | [tool.black] 57 | line-length = 120 58 | target-version = ['py36', 'py37', 'py38', 'py39'] 59 | include = '\.pyi?$' 60 | exclude = ''' 61 | /( 62 | \.git 63 | | \.hg 64 | | \.mypy_cache 65 | | \.tox 66 | | \.venv 67 | | venv 68 | | _build 69 | | buck-out 70 | | build 71 | | dist 72 | )/ 73 | ''' 74 | skip-numeric-underscore-normalization = true 75 | -------------------------------------------------------------------------------- /flake8_print.py: -------------------------------------------------------------------------------- 1 | """Extension for flake8 that finds usage of print.""" 2 | import pycodestyle 3 | import ast 4 | 5 | try: 6 | from flake8.engine import pep8 as stdin_utils 7 | except ImportError: 8 | from flake8 import utils as stdin_utils 9 | 10 | __version__ = "5.0.0" 11 | 12 | PRINT_FUNCTION_NAME = "print" 13 | PPRINT_FUNCTION_NAME = "pprint" 14 | PRINT_FUNCTION_NAMES = [PRINT_FUNCTION_NAME, PPRINT_FUNCTION_NAME] 15 | 16 | VIOLATIONS = { 17 | "found": {"print": "T201 print found.", "pprint": "T203 pprint found."}, 18 | "declared": {"print": "T202 Python 2.x reserved word print used.", "pprint": "T204 pprint declared"}, 19 | } 20 | 21 | 22 | class PrintFinder(ast.NodeVisitor): 23 | def __init__(self, *args, **kwargs): 24 | super(PrintFinder, self).__init__(*args, **kwargs) 25 | self.prints_used = {} 26 | self.prints_redefined = {} 27 | 28 | def visit_Call(self, node): 29 | is_print_function = getattr(node.func, "id", None) in PRINT_FUNCTION_NAMES 30 | is_print_function_attribute = ( 31 | getattr(getattr(node.func, "value", None), "id", None) in PRINT_FUNCTION_NAMES 32 | and getattr(node.func, "attr", None) in PRINT_FUNCTION_NAMES 33 | ) 34 | if is_print_function: 35 | self.prints_used[(node.lineno, node.col_offset)] = VIOLATIONS["found"][node.func.id] 36 | elif is_print_function_attribute: 37 | self.prints_used[(node.lineno, node.col_offset)] = VIOLATIONS["found"][node.func.attr] 38 | self.generic_visit(node) 39 | 40 | def visit_FunctionDef(self, node): 41 | if node.name in PRINT_FUNCTION_NAMES: 42 | self.prints_redefined[(node.lineno, node.col_offset)] = VIOLATIONS["declared"][node.name] 43 | 44 | for arg in node.args.args: 45 | if arg.arg in PRINT_FUNCTION_NAMES: 46 | self.prints_redefined[(node.lineno, node.col_offset)] = VIOLATIONS["declared"][arg.arg] 47 | 48 | for arg in node.args.kwonlyargs: 49 | if arg.arg in PRINT_FUNCTION_NAMES: 50 | self.prints_redefined[(node.lineno, node.col_offset)] = VIOLATIONS["declared"][arg.arg] 51 | self.generic_visit(node) 52 | 53 | def visit_Name(self, node): 54 | if node.id == PRINT_FUNCTION_NAME: 55 | self.prints_redefined[(node.lineno, node.col_offset)] = VIOLATIONS["declared"][node.id] 56 | self.generic_visit(node) 57 | 58 | 59 | class PrintChecker(object): 60 | options = None 61 | name = "flake8-print" 62 | version = __version__ 63 | 64 | def __init__(self, tree, filename): 65 | self.tree = tree 66 | self.filename = filename 67 | self.lines = None 68 | 69 | def load_file(self): 70 | if self.filename in ("stdin", "-", None): 71 | self.filename = "stdin" 72 | self.lines = stdin_utils.stdin_get_value().splitlines(True) 73 | else: 74 | self.lines = pycodestyle.readlines(self.filename) 75 | 76 | if not self.tree: 77 | self.tree = ast.parse("".join(self.lines)) 78 | 79 | def run(self): 80 | if not self.tree or not self.lines: 81 | self.load_file() 82 | 83 | parser = PrintFinder() 84 | parser.visit(self.tree) 85 | error_dicts = (parser.prints_used, parser.prints_redefined) 86 | errors_seen = set() 87 | 88 | for index, error_dict in enumerate(error_dicts): 89 | for error, message in error_dict.items(): 90 | if error in errors_seen: 91 | continue 92 | 93 | errors_seen.add(error) 94 | 95 | yield (error[0], error[1], message, PrintChecker) 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Flake8 print plugin 2 | =================== 3 | 4 | Check for Print statements in python files. 5 | 6 | This module provides a plugin for ``flake8``, the Python code checker. 7 | 8 | 9 | Installation 10 | ------------ 11 | 12 | You can install or upgrade ``flake8-print`` with these commands:: 13 | 14 | $ pip install flake8-print 15 | $ pip install --upgrade flake8-print 16 | 17 | 18 | Plugin for Flake8 19 | ----------------- 20 | 21 | When both ``flake8 2.4.1`` and ``flake8-print`` are installed, the plugin is 22 | available in ``flake8``:: 23 | 24 | $ flake8 --version 25 | 2.4.1 (pep8: 1.5.7, flake8-print: 2.0.0, mccabe: 0.3.1, pyflakes: 0.8.1) 26 | 27 | Flake8 allows disabling some tests based on the folder: 28 | 29 | ``` 30 | [flake8] 31 | per-file-ignores = 32 | scripts/*: T20 33 | cli.py: T20 34 | ``` 35 | 36 | Error codes 37 | ----------- 38 | 39 | | Error Code | Description | 40 | | ----------- | ------------------------------------ | 41 | | T201 | print found | 42 | | T203 | pprint found | 43 | | T204 | pprint declared | 44 | 45 | 46 | Changes 47 | ------- 48 | 49 | ##### 5.0.0 - 2022-04-30 50 | 51 | * Move namespace from T0* to T2* to avoid collision with other library using same error code. 52 | * Remove python 2 specific code paths, error messages and six usage. 53 | 54 | ##### 4.0.1 - 2022-04-30 55 | 56 | * Fixing bug with noqa detection by removing manual detection and relying on flake8 itself. 57 | 58 | ##### 4.0.0 - 2020-11-29 59 | 60 | * Opted back into using Poetry now that the existing issues have been fixed. 61 | * Python 2.7 support was now officially dropped. 62 | 63 | ##### 3.1.4 - 2019-1-11 64 | 65 | * Fix bug introduced in 3.1.3 66 | * Support for `nopep8` comments 67 | 68 | ##### 3.1.3 - 2019-31-10 69 | 70 | * Swapped back from poetry to setup.py :(....python ecosystem issues.... 71 | * single function refactor code 72 | 73 | ##### 3.1.1 - 2019-03-12 74 | 75 | * Fix reading from stdin when it is closed (requires flake8 > 2.1). 76 | * Add error codes to ReadMe. 77 | * Swapped to poetry from setup.py 78 | * Ran black on the repository 79 | 80 | ##### 3.1.0 - 2018-02-11 81 | * Add a framework classifier for use in pypi.org 82 | * Fix entry_point in setup.py leaving it off by default again. 83 | 84 | ##### 3.0.1 - 2017-11-06 85 | * Fix conflict in setup.py leaving it off by default again. 86 | * Fix bug in name code. 87 | 88 | ##### 3.0.0 - 2017-11-05 89 | * Remove some of the python 2/3 message differentiation. 90 | * Use an AST rather than a logical line checker with a regex. 91 | * pprint support. 92 | * Loss of multiline noqa support, until there is a way to use both the AST and have flake8 provide the noqa lines. 93 | 94 | 95 | ##### 2.0.2 - 2016-02-29 96 | * Fix ReadMe for pipy 97 | * Refactor, DRY it up. 98 | * Update python 2 vs python 3 print statement styles. 99 | 100 | ##### 2.0.1 - 2015-11-21 101 | * Add back the decorator to fix the `flake8 --version` call. 102 | 103 | ##### 2.0 - 2015-11-10 104 | * Support noqa at end of multiline print statement 105 | * Performance improvements 106 | * Removed PrintStatementChecker class and other functions 107 | * Added T101 for 'Python 2.x reserved word print used.' 108 | * Added testing for Python 3.3 and 3.5, and different flake8 versions 109 | 110 | ##### 1.6.1 - 2015-05-22 111 | * Fix bug introduced in 1.6. 112 | 113 | ##### 1.6 - 2015-05-18 114 | * Added proper support for python3 and testing for python 2.6, 2.7 and 3.4 115 | 116 | ##### 1.5 - 2014-11-04 117 | * Added python2.6 support. Thanks @zoidbergwill 118 | 119 | ##### 1.4 - 2014-10-06 120 | * Apped noqa support 121 | 122 | ##### 1.3 - 2014-09-27 123 | * Dropped noqa support 124 | * Support for multiline comments and less false positives 125 | 126 | ##### 1.2 - 2014-06-30 127 | * Does not catch the word print in single line strings 128 | * Does not catch inline comments with print in it 129 | * Added tests 130 | 131 | ##### 1.1 - 2014-06-30 132 | * First release 133 | 134 | ##### 1.0 - 2014-06-30 135 | * Whoops 136 | -------------------------------------------------------------------------------- /test_linter.py: -------------------------------------------------------------------------------- 1 | import pycodestyle 2 | 3 | from textwrap import dedent 4 | 5 | from flake8_print import PrintChecker 6 | 7 | 8 | class CaptureReport(pycodestyle.BaseReport): 9 | """Collect the results of the checks.""" 10 | 11 | def __init__(self, options): 12 | self._results = [] 13 | super(CaptureReport, self).__init__(options) 14 | 15 | def error(self, line_number, offset, text, check): 16 | """Store each error.""" 17 | code = super(CaptureReport, self).error(line_number, offset, text, check) 18 | if code: 19 | record = {"line": line_number, "col": offset, "message": "{0} {1}".format(code, text[5:])} 20 | self._results.append(record) 21 | return code 22 | 23 | 24 | class PrintTestStyleGuide(pycodestyle.StyleGuide): 25 | 26 | logical_checks = [] 27 | physical_checks = [] 28 | ast_checks = [("print_usage", PrintChecker, ["tree", "filename", "lines"])] 29 | max_line_length = None 30 | hang_closing = False 31 | verbose = False 32 | benchmark_keys = {"files": 0, "physical lines": 0, "logical lines": 0} 33 | max_doc_length = None 34 | indent_size = 4 35 | 36 | 37 | _print_test_style = PrintTestStyleGuide() 38 | 39 | 40 | def check_code_for_print_statements(code): 41 | """Process code using pycodestyle Checker and return all errors.""" 42 | from tempfile import NamedTemporaryFile 43 | 44 | test_file = NamedTemporaryFile(delete=False) 45 | test_file.write(code.encode()) 46 | test_file.flush() 47 | report = CaptureReport(options=_print_test_style) 48 | lines = [line + "\n" for line in code.split("\n")] 49 | checker = pycodestyle.Checker(filename=test_file.name, lines=lines, options=_print_test_style, report=report) 50 | 51 | checker.check_all() 52 | return report._results 53 | 54 | 55 | T201 = "T201 print found." 56 | T203 = "T203 pprint found." 57 | T202 = "T202 Python 2.x reserved word print used." 58 | T204 = "T204 pprint declared." 59 | 60 | 61 | class TestGenericCases(object): 62 | def test_catches_multiline_print(self): 63 | result = check_code_for_print_statements( 64 | dedent( 65 | """ 66 | print("a" 67 | "b") 68 | """ 69 | ) 70 | ) 71 | assert result == [{"col": 0, "line": 2, "message": T201}] 72 | 73 | def test_catches_simple_print_python3(self): 74 | result = check_code_for_print_statements("print(4)") 75 | assert result == [{"col": 0, "line": 1, "message": T201}] 76 | 77 | def test_catches_pprint(self): 78 | result = check_code_for_print_statements("pprint(4)") 79 | assert result == [{"col": 0, "line": 1, "message": T203}] 80 | 81 | def test_catches_print_multiline(self): 82 | result = check_code_for_print_statements("print(0\n)") 83 | assert result == [{"col": 0, "line": 1, "message": T201}] 84 | 85 | def test_catches_empty_print(self): 86 | result = check_code_for_print_statements("print(\n)") 87 | assert result == [{"col": 0, "line": 1, "message": T201}] 88 | 89 | def test_catches_print_invocation_in_lambda(self): 90 | result = check_code_for_print_statements("x = lambda a: print(a)") 91 | assert result == [{"col": 14, "line": 1, "message": T201}] 92 | 93 | 94 | class TestComments(object): 95 | def test_print_in_inline_comment_is_not_a_false_positive(self): 96 | result = check_code_for_print_statements("# what should I print ?") 97 | assert result == list() 98 | 99 | def test_print_same_line_as_comment(self): 100 | result = check_code_for_print_statements("print(5) # what should I do with 5 ?") 101 | assert result == [{"col": 0, "line": 1, "message": T201}] 102 | 103 | 104 | class TestSingleQuotes(object): 105 | def test_print_in_one_single_quote_single_line_string_not_false_positive(self): 106 | result = check_code_for_print_statements("a('print the things', 25)") 107 | assert result == list() 108 | 109 | def test_print_in_three_single_quote_single_line_string_not_false_positive(self): 110 | result = check_code_for_print_statements("a('''print the things''', 25)") 111 | assert result == list() 112 | 113 | 114 | class TestDoubleQuotes(object): 115 | def test_print_in_one_double_quote_single_line_string_not_false_positive(self): 116 | result = check_code_for_print_statements('a("print the things", 25)') 117 | assert result == list() 118 | 119 | def test_print_in_three_double_quote_single_line_string_not_false_positive(self): 120 | result = check_code_for_print_statements('a("""print the things""", 25)') 121 | assert result == list() 122 | 123 | 124 | class TestMultilineFalsePositive(object): 125 | def test_print_in_one_double_quote_single_line_string_not_false_positive(self): 126 | result = check_code_for_print_statements('hello="""there is a \nprint on\n the next line"""') 127 | assert result == list() 128 | 129 | def test_print_in_three_double_quote_single_line_string_not_false_positive(self): 130 | result = check_code_for_print_statements('a("""print the things""", 25)') 131 | assert result == list() 132 | 133 | 134 | class TestNameFalsePositive(object): 135 | def test_print_in_name(self): 136 | result = check_code_for_print_statements("def print_foo(): pass") 137 | assert result == [] 138 | result = check_code_for_print_statements("def foo_print(): pass") 139 | assert result == [] 140 | result = check_code_for_print_statements("foo_print = 1") 141 | assert result == [] 142 | result = check_code_for_print_statements("print_foo = 1") 143 | assert result == [] 144 | 145 | def test_redefine_print_function(self): 146 | result = check_code_for_print_statements("def print(): pass") 147 | assert result == [{"col": 0, "line": 1, "message": T202}] 148 | 149 | def test_print_arg(self): 150 | result = check_code_for_print_statements("def foo(print): pass") 151 | assert result == [{"col": 0, "line": 1, "message": T202}] 152 | 153 | result = check_code_for_print_statements("def foo(*, print=3): pass") 154 | assert result == [{"col": 0, "line": 1, "message": T202}] 155 | 156 | result = check_code_for_print_statements("def foo(print=3): pass") 157 | assert result == [{"col": 0, "line": 1, "message": T202}] 158 | 159 | def test_print_assignment(self): 160 | result = check_code_for_print_statements("print=1") 161 | assert result == [{"col": 0, "line": 1, "message": T202}] 162 | 163 | def test_print_assignment_value(self): 164 | result = check_code_for_print_statements("x = print") 165 | assert result == [{"col": 4, "line": 1, "message": T202}] 166 | 167 | def test_print_assignment_value_else(self): 168 | result = check_code_for_print_statements("x = print if True else 1") 169 | assert result == [{"col": 4, "line": 1, "message": T202}] 170 | result = check_code_for_print_statements("x = 1 if True else print") 171 | assert result == [{"col": 19, "line": 1, "message": T202}] 172 | 173 | def test_print_assignment_value_or(self): 174 | result = check_code_for_print_statements("x = print or 1") 175 | assert result == [{"col": 4, "line": 1, "message": T202}] 176 | result = check_code_for_print_statements("x = 1 or print") 177 | assert result == [{"col": 9, "line": 1, "message": T202}] 178 | 179 | def test_print_in_lambda(self): 180 | result = check_code_for_print_statements("x = lambda a: print") 181 | assert result == [{"col": 14, "line": 1, "message": T202}] 182 | 183 | 184 | class TestPprintCases(object): 185 | def test_pprint_module_ignored(self): 186 | result = check_code_for_print_statements("import pprint;") 187 | assert result == list() 188 | 189 | def test_pprint_function_ignored(self): 190 | result = check_code_for_print_statements("import pprint; pprint.pprint;") 191 | assert result == list() 192 | 193 | def test_pprint_function_call_detected(self): 194 | result = check_code_for_print_statements('import pprint; pprint.pprint("foo");') 195 | assert result == [{"col": 15, "line": 1, "message": T203}] 196 | 197 | def test_pprint_standalone_function_call_detected(self): 198 | result = check_code_for_print_statements('from pprint import pprint; pprint("foo");') 199 | assert result == [{"col": 27, "line": 1, "message": T203}] 200 | 201 | def test_pprint_function_call_with_complex_data(self): 202 | result = check_code_for_print_statements('import pprint; pprint.pprint({"foo": "print"});') 203 | assert result == [{"col": 15, "line": 1, "message": T203}] 204 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "atomicwrites" 3 | version = "1.4.0" 4 | description = "Atomic file writes." 5 | category = "dev" 6 | optional = false 7 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 8 | 9 | [[package]] 10 | name = "attrs" 11 | version = "21.4.0" 12 | description = "Classes Without Boilerplate" 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 16 | 17 | [package.extras] 18 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] 19 | docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] 20 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] 21 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] 22 | 23 | [[package]] 24 | name = "black" 25 | version = "22.3.0" 26 | description = "The uncompromising code formatter." 27 | category = "dev" 28 | optional = false 29 | python-versions = ">=3.6.2" 30 | 31 | [package.dependencies] 32 | click = ">=8.0.0" 33 | mypy-extensions = ">=0.4.3" 34 | pathspec = ">=0.9.0" 35 | platformdirs = ">=2" 36 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 37 | typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} 38 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 39 | 40 | [package.extras] 41 | colorama = ["colorama (>=0.4.3)"] 42 | d = ["aiohttp (>=3.7.4)"] 43 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 44 | uvloop = ["uvloop (>=0.15.2)"] 45 | 46 | [[package]] 47 | name = "click" 48 | version = "8.1.3" 49 | description = "Composable command line interface toolkit" 50 | category = "dev" 51 | optional = false 52 | python-versions = ">=3.7" 53 | 54 | [package.dependencies] 55 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 56 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 57 | 58 | [[package]] 59 | name = "colorama" 60 | version = "0.4.4" 61 | description = "Cross-platform colored terminal text." 62 | category = "dev" 63 | optional = false 64 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 65 | 66 | [[package]] 67 | name = "flake8" 68 | version = "4.0.1" 69 | description = "the modular source code checker: pep8 pyflakes and co" 70 | category = "main" 71 | optional = false 72 | python-versions = ">=3.6" 73 | 74 | [package.dependencies] 75 | importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""} 76 | mccabe = ">=0.6.0,<0.7.0" 77 | pycodestyle = ">=2.8.0,<2.9.0" 78 | pyflakes = ">=2.4.0,<2.5.0" 79 | 80 | [[package]] 81 | name = "importlib-metadata" 82 | version = "4.2.0" 83 | description = "Read metadata from Python packages" 84 | category = "main" 85 | optional = false 86 | python-versions = ">=3.6" 87 | 88 | [package.dependencies] 89 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} 90 | zipp = ">=0.5" 91 | 92 | [package.extras] 93 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] 94 | testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] 95 | 96 | [[package]] 97 | name = "iniconfig" 98 | version = "1.1.1" 99 | description = "iniconfig: brain-dead simple config-ini parsing" 100 | category = "dev" 101 | optional = false 102 | python-versions = "*" 103 | 104 | [[package]] 105 | name = "mccabe" 106 | version = "0.6.1" 107 | description = "McCabe checker, plugin for flake8" 108 | category = "main" 109 | optional = false 110 | python-versions = "*" 111 | 112 | [[package]] 113 | name = "mypy-extensions" 114 | version = "0.4.3" 115 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 116 | category = "dev" 117 | optional = false 118 | python-versions = "*" 119 | 120 | [[package]] 121 | name = "packaging" 122 | version = "21.3" 123 | description = "Core utilities for Python packages" 124 | category = "dev" 125 | optional = false 126 | python-versions = ">=3.6" 127 | 128 | [package.dependencies] 129 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" 130 | 131 | [[package]] 132 | name = "pathspec" 133 | version = "0.9.0" 134 | description = "Utility library for gitignore style pattern matching of file paths." 135 | category = "dev" 136 | optional = false 137 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 138 | 139 | [[package]] 140 | name = "platformdirs" 141 | version = "2.5.2" 142 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 143 | category = "dev" 144 | optional = false 145 | python-versions = ">=3.7" 146 | 147 | [package.extras] 148 | docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] 149 | test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] 150 | 151 | [[package]] 152 | name = "pluggy" 153 | version = "1.0.0" 154 | description = "plugin and hook calling mechanisms for python" 155 | category = "dev" 156 | optional = false 157 | python-versions = ">=3.6" 158 | 159 | [package.dependencies] 160 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 161 | 162 | [package.extras] 163 | dev = ["pre-commit", "tox"] 164 | testing = ["pytest", "pytest-benchmark"] 165 | 166 | [[package]] 167 | name = "py" 168 | version = "1.11.0" 169 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 170 | category = "dev" 171 | optional = false 172 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 173 | 174 | [[package]] 175 | name = "pycodestyle" 176 | version = "2.8.0" 177 | description = "Python style guide checker" 178 | category = "main" 179 | optional = false 180 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 181 | 182 | [[package]] 183 | name = "pyflakes" 184 | version = "2.4.0" 185 | description = "passive checker of Python programs" 186 | category = "main" 187 | optional = false 188 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 189 | 190 | [[package]] 191 | name = "pyparsing" 192 | version = "3.0.8" 193 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 194 | category = "dev" 195 | optional = false 196 | python-versions = ">=3.6.8" 197 | 198 | [package.extras] 199 | diagrams = ["railroad-diagrams", "jinja2"] 200 | 201 | [[package]] 202 | name = "pytest" 203 | version = "7.1.2" 204 | description = "pytest: simple powerful testing with Python" 205 | category = "dev" 206 | optional = false 207 | python-versions = ">=3.7" 208 | 209 | [package.dependencies] 210 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 211 | attrs = ">=19.2.0" 212 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 213 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 214 | iniconfig = "*" 215 | packaging = "*" 216 | pluggy = ">=0.12,<2.0" 217 | py = ">=1.8.2" 218 | tomli = ">=1.0.0" 219 | 220 | [package.extras] 221 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 222 | 223 | [[package]] 224 | name = "tomli" 225 | version = "2.0.1" 226 | description = "A lil' TOML parser" 227 | category = "dev" 228 | optional = false 229 | python-versions = ">=3.7" 230 | 231 | [[package]] 232 | name = "typed-ast" 233 | version = "1.5.3" 234 | description = "a fork of Python 2 and 3 ast modules with type comment support" 235 | category = "dev" 236 | optional = false 237 | python-versions = ">=3.6" 238 | 239 | [[package]] 240 | name = "typing-extensions" 241 | version = "4.2.0" 242 | description = "Backported and Experimental Type Hints for Python 3.7+" 243 | category = "main" 244 | optional = false 245 | python-versions = ">=3.7" 246 | 247 | [[package]] 248 | name = "zipp" 249 | version = "3.8.0" 250 | description = "Backport of pathlib-compatible object wrapper for zip files" 251 | category = "main" 252 | optional = false 253 | python-versions = ">=3.7" 254 | 255 | [package.extras] 256 | docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] 257 | testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] 258 | 259 | [metadata] 260 | lock-version = "1.1" 261 | python-versions = ">=3.7" 262 | content-hash = "ad4dc8113cc28c9e84d1e5cc868cf0ed3bd91ba8dde7748de7155ea4b651e1ba" 263 | 264 | [metadata.files] 265 | atomicwrites = [ 266 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 267 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 268 | ] 269 | attrs = [ 270 | {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, 271 | {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, 272 | ] 273 | black = [ 274 | {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, 275 | {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, 276 | {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"}, 277 | {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"}, 278 | {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"}, 279 | {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"}, 280 | {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"}, 281 | {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"}, 282 | {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"}, 283 | {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"}, 284 | {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"}, 285 | {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"}, 286 | {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"}, 287 | {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"}, 288 | {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"}, 289 | {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"}, 290 | {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"}, 291 | {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"}, 292 | {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"}, 293 | {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"}, 294 | {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"}, 295 | {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, 296 | {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, 297 | ] 298 | click = [ 299 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 300 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 301 | ] 302 | colorama = [ 303 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 304 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 305 | ] 306 | flake8 = [ 307 | {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, 308 | {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, 309 | ] 310 | importlib-metadata = [ 311 | {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, 312 | {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, 313 | ] 314 | iniconfig = [ 315 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 316 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 317 | ] 318 | mccabe = [ 319 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 320 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 321 | ] 322 | mypy-extensions = [ 323 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 324 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 325 | ] 326 | packaging = [ 327 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, 328 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, 329 | ] 330 | pathspec = [ 331 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 332 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 333 | ] 334 | platformdirs = [ 335 | {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, 336 | {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, 337 | ] 338 | pluggy = [ 339 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 340 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 341 | ] 342 | py = [ 343 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 344 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 345 | ] 346 | pycodestyle = [ 347 | {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, 348 | {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, 349 | ] 350 | pyflakes = [ 351 | {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, 352 | {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, 353 | ] 354 | pyparsing = [ 355 | {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, 356 | {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, 357 | ] 358 | pytest = [ 359 | {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, 360 | {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, 361 | ] 362 | tomli = [ 363 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 364 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 365 | ] 366 | typed-ast = [ 367 | {file = "typed_ast-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ad3b48cf2b487be140072fb86feff36801487d4abb7382bb1929aaac80638ea"}, 368 | {file = "typed_ast-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:542cd732351ba8235f20faa0fc7398946fe1a57f2cdb289e5497e1e7f48cfedb"}, 369 | {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc2c11ae59003d4a26dda637222d9ae924387f96acae9492df663843aefad55"}, 370 | {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd5df1313915dbd70eaaa88c19030b441742e8b05e6103c631c83b75e0435ccc"}, 371 | {file = "typed_ast-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:e34f9b9e61333ecb0f7d79c21c28aa5cd63bec15cb7e1310d7d3da6ce886bc9b"}, 372 | {file = "typed_ast-1.5.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f818c5b81966d4728fec14caa338e30a70dfc3da577984d38f97816c4b3071ec"}, 373 | {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3042bfc9ca118712c9809201f55355479cfcdc17449f9f8db5e744e9625c6805"}, 374 | {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4fff9fdcce59dc61ec1b317bdb319f8f4e6b69ebbe61193ae0a60c5f9333dc49"}, 375 | {file = "typed_ast-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8e0b8528838ffd426fea8d18bde4c73bcb4167218998cc8b9ee0a0f2bfe678a6"}, 376 | {file = "typed_ast-1.5.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ef1d96ad05a291f5c36895d86d1375c0ee70595b90f6bb5f5fdbee749b146db"}, 377 | {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed44e81517364cb5ba367e4f68fca01fba42a7a4690d40c07886586ac267d9b9"}, 378 | {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f60d9de0d087454c91b3999a296d0c4558c1666771e3460621875021bf899af9"}, 379 | {file = "typed_ast-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9e237e74fd321a55c90eee9bc5d44be976979ad38a29bbd734148295c1ce7617"}, 380 | {file = "typed_ast-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee852185964744987609b40aee1d2eb81502ae63ee8eef614558f96a56c1902d"}, 381 | {file = "typed_ast-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27e46cdd01d6c3a0dd8f728b6a938a6751f7bd324817501c15fb056307f918c6"}, 382 | {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d64dabc6336ddc10373922a146fa2256043b3b43e61f28961caec2a5207c56d5"}, 383 | {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8cdf91b0c466a6c43f36c1964772918a2c04cfa83df8001ff32a89e357f8eb06"}, 384 | {file = "typed_ast-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:9cc9e1457e1feb06b075c8ef8aeb046a28ec351b1958b42c7c31c989c841403a"}, 385 | {file = "typed_ast-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e20d196815eeffb3d76b75223e8ffed124e65ee62097e4e73afb5fec6b993e7a"}, 386 | {file = "typed_ast-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:37e5349d1d5de2f4763d534ccb26809d1c24b180a477659a12c4bde9dd677d74"}, 387 | {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f1a27592fac87daa4e3f16538713d705599b0a27dfe25518b80b6b017f0a6d"}, 388 | {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8831479695eadc8b5ffed06fdfb3e424adc37962a75925668deeb503f446c0a3"}, 389 | {file = "typed_ast-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:20d5118e494478ef2d3a2702d964dae830aedd7b4d3b626d003eea526be18718"}, 390 | {file = "typed_ast-1.5.3.tar.gz", hash = "sha256:27f25232e2dd0edfe1f019d6bfaaf11e86e657d9bdb7b0956db95f560cceb2b3"}, 391 | ] 392 | typing-extensions = [ 393 | {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, 394 | {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, 395 | ] 396 | zipp = [ 397 | {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, 398 | {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, 399 | ] 400 | --------------------------------------------------------------------------------