summaryrefslogtreecommitdiff
path: root/venv/Lib/site-packages/pylint
diff options
context:
space:
mode:
Diffstat (limited to 'venv/Lib/site-packages/pylint')
-rw-r--r--venv/Lib/site-packages/pylint/__init__.py43
-rw-r--r--venv/Lib/site-packages/pylint/__main__.py7
-rw-r--r--venv/Lib/site-packages/pylint/__pkginfo__.py85
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/__init__.cpython-37.pycbin1084 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/__main__.cpython-37.pycbin210 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/__pkginfo__.cpython-37.pycbin2632 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/config.cpython-37.pycbin25815 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/constants.cpython-37.pycbin1018 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/epylint.cpython-37.pycbin4958 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/exceptions.cpython-37.pycbin1361 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/graph.cpython-37.pycbin5211 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/interfaces.cpython-37.pycbin3665 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/lint.cpython-37.pycbin45362 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/__pycache__/testutils.cpython-37.pycbin9521 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__init__.py64
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/__init__.cpython-37.pycbin1580 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/async.cpython-37.pycbin2722 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/base.cpython-37.pycbin61785 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/base_checker.cpython-37.pycbin6481 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/classes.cpython-37.pycbin44537 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/design_analysis.cpython-37.pycbin11667 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/exceptions.cpython-37.pycbin15668 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/format.cpython-37.pycbin31580 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/imports.cpython-37.pycbin25427 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/logging.cpython-37.pycbin10919 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/misc.cpython-37.pycbin4597 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/newstyle.cpython-37.pycbin2422 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/python3.cpython-37.pycbin34941 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/raw_metrics.cpython-37.pycbin3254 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/refactoring.cpython-37.pycbin45321 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/similar.cpython-37.pycbin12304 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/spelling.cpython-37.pycbin9755 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/stdlib.cpython-37.pycbin12738 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/strings.cpython-37.pycbin17427 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/typecheck.cpython-37.pycbin40274 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/utils.cpython-37.pycbin31460 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/__pycache__/variables.cpython-37.pycbin44587 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/checkers/async.py89
-rw-r--r--venv/Lib/site-packages/pylint/checkers/base.py2333
-rw-r--r--venv/Lib/site-packages/pylint/checkers/base_checker.py187
-rw-r--r--venv/Lib/site-packages/pylint/checkers/classes.py1844
-rw-r--r--venv/Lib/site-packages/pylint/checkers/design_analysis.py496
-rw-r--r--venv/Lib/site-packages/pylint/checkers/exceptions.py546
-rw-r--r--venv/Lib/site-packages/pylint/checkers/format.py1332
-rw-r--r--venv/Lib/site-packages/pylint/checkers/imports.py981
-rw-r--r--venv/Lib/site-packages/pylint/checkers/logging.py384
-rw-r--r--venv/Lib/site-packages/pylint/checkers/misc.py171
-rw-r--r--venv/Lib/site-packages/pylint/checkers/newstyle.py127
-rw-r--r--venv/Lib/site-packages/pylint/checkers/python3.py1398
-rw-r--r--venv/Lib/site-packages/pylint/checkers/raw_metrics.py119
-rw-r--r--venv/Lib/site-packages/pylint/checkers/refactoring.py1510
-rw-r--r--venv/Lib/site-packages/pylint/checkers/similar.py452
-rw-r--r--venv/Lib/site-packages/pylint/checkers/spelling.py411
-rw-r--r--venv/Lib/site-packages/pylint/checkers/stdlib.py452
-rw-r--r--venv/Lib/site-packages/pylint/checkers/strings.py755
-rw-r--r--venv/Lib/site-packages/pylint/checkers/typecheck.py1770
-rw-r--r--venv/Lib/site-packages/pylint/checkers/utils.py1253
-rw-r--r--venv/Lib/site-packages/pylint/checkers/variables.py1987
-rw-r--r--venv/Lib/site-packages/pylint/config.py913
-rw-r--r--venv/Lib/site-packages/pylint/constants.py43
-rw-r--r--venv/Lib/site-packages/pylint/epylint.py197
-rw-r--r--venv/Lib/site-packages/pylint/exceptions.py29
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__init__.py0
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/__init__.cpython-37.pycbin181 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/_check_docs_utils.cpython-37.pycbin18819 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/bad_builtin.cpython-37.pycbin1967 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/broad_try_clause.cpython-37.pycbin1702 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/check_docs.cpython-37.pycbin685 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/check_elif.cpython-37.pycbin2647 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/comparetozero.cpython-37.pycbin1959 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/docparams.cpython-37.pycbin14746 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/docstyle.cpython-37.pycbin2503 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/emptystring.cpython-37.pycbin2035 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/mccabe.cpython-37.pycbin5579 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/overlapping_exceptions.cpython-37.pycbin2604 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/__pycache__/redefined_variable_type.cpython-37.pycbin3248 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/extensions/_check_docs_utils.py792
-rw-r--r--venv/Lib/site-packages/pylint/extensions/bad_builtin.py69
-rw-r--r--venv/Lib/site-packages/pylint/extensions/broad_try_clause.py59
-rw-r--r--venv/Lib/site-packages/pylint/extensions/check_docs.py23
-rw-r--r--venv/Lib/site-packages/pylint/extensions/check_elif.py77
-rw-r--r--venv/Lib/site-packages/pylint/extensions/comparetozero.py74
-rw-r--r--venv/Lib/site-packages/pylint/extensions/docparams.py536
-rw-r--r--venv/Lib/site-packages/pylint/extensions/docstyle.py89
-rw-r--r--venv/Lib/site-packages/pylint/extensions/emptystring.py74
-rw-r--r--venv/Lib/site-packages/pylint/extensions/mccabe.py196
-rw-r--r--venv/Lib/site-packages/pylint/extensions/overlapping_exceptions.py88
-rw-r--r--venv/Lib/site-packages/pylint/extensions/redefined_variable_type.py116
-rw-r--r--venv/Lib/site-packages/pylint/graph.py197
-rw-r--r--venv/Lib/site-packages/pylint/interfaces.py102
-rw-r--r--venv/Lib/site-packages/pylint/lint.py1817
-rw-r--r--venv/Lib/site-packages/pylint/message/__init__.py54
-rw-r--r--venv/Lib/site-packages/pylint/message/__pycache__/__init__.cpython-37.pycbin664 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/message/__pycache__/message.cpython-37.pycbin1225 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/message/__pycache__/message_definition.cpython-37.pycbin2982 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/message/__pycache__/message_definition_store.cpython-37.pycbin4075 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/message/__pycache__/message_handler_mix_in.cpython-37.pycbin11049 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/message/__pycache__/message_id_store.cpython-37.pycbin4925 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/message/message.py53
-rw-r--r--venv/Lib/site-packages/pylint/message/message_definition.py84
-rw-r--r--venv/Lib/site-packages/pylint/message/message_definition_store.py90
-rw-r--r--venv/Lib/site-packages/pylint/message/message_handler_mix_in.py393
-rw-r--r--venv/Lib/site-packages/pylint/message/message_id_store.py128
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__init__.py8
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/__init__.cpython-37.pycbin241 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/diadefslib.cpython-37.pycbin7621 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/diagrams.cpython-37.pycbin8716 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/inspector.cpython-37.pycbin10187 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/main.cpython-37.pycbin4522 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/utils.cpython-37.pycbin5787 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/vcgutils.cpython-37.pycbin4697 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/__pycache__/writer.cpython-37.pycbin7286 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/diadefslib.py238
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/diagrams.py268
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/inspector.py357
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/main.py214
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/utils.py220
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/vcgutils.py229
-rw-r--r--venv/Lib/site-packages/pylint/pyreverse/writer.py213
-rw-r--r--venv/Lib/site-packages/pylint/reporters/__init__.py34
-rw-r--r--venv/Lib/site-packages/pylint/reporters/__pycache__/__init__.cpython-37.pycbin823 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/__pycache__/base_reporter.cpython-37.pycbin2767 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/__pycache__/collecting_reporter.cpython-37.pycbin817 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/__pycache__/json_reporter.cpython-37.pycbin2003 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/__pycache__/reports_handler_mix_in.cpython-37.pycbin3028 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/__pycache__/text.cpython-37.pycbin7263 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/base_reporter.py66
-rw-r--r--venv/Lib/site-packages/pylint/reporters/collecting_reporter.py21
-rw-r--r--venv/Lib/site-packages/pylint/reporters/json_reporter.py58
-rw-r--r--venv/Lib/site-packages/pylint/reporters/reports_handler_mix_in.py79
-rw-r--r--venv/Lib/site-packages/pylint/reporters/text.py247
-rw-r--r--venv/Lib/site-packages/pylint/reporters/ureports/__init__.py96
-rw-r--r--venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/__init__.cpython-37.pycbin3065 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/nodes.cpython-37.pycbin6062 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/text_writer.cpython-37.pycbin3673 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/reporters/ureports/nodes.py188
-rw-r--r--venv/Lib/site-packages/pylint/reporters/ureports/text_writer.py94
-rw-r--r--venv/Lib/site-packages/pylint/testutils.py298
-rw-r--r--venv/Lib/site-packages/pylint/utils/__init__.py64
-rw-r--r--venv/Lib/site-packages/pylint/utils/__pycache__/__init__.cpython-37.pycbin869 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/utils/__pycache__/ast_walker.cpython-37.pycbin2078 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/utils/__pycache__/file_state.cpython-37.pycbin3852 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/utils/__pycache__/utils.cpython-37.pycbin10339 -> 0 bytes
-rw-r--r--venv/Lib/site-packages/pylint/utils/ast_walker.py79
-rw-r--r--venv/Lib/site-packages/pylint/utils/file_state.py138
-rw-r--r--venv/Lib/site-packages/pylint/utils/utils.py371
146 files changed, 0 insertions, 28669 deletions
diff --git a/venv/Lib/site-packages/pylint/__init__.py b/venv/Lib/site-packages/pylint/__init__.py
deleted file mode 100644
index 8980938..0000000
--- a/venv/Lib/site-packages/pylint/__init__.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (c) 2008, 2012 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2014, 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import sys
-
-from pylint.__pkginfo__ import version as __version__
-from pylint.checkers.similar import Run as SimilarRun
-from pylint.epylint import Run as EpylintRun
-from pylint.lint import Run as PylintRun
-from pylint.pyreverse.main import Run as PyreverseRun
-
-
-def run_pylint():
- """run pylint"""
-
- try:
- PylintRun(sys.argv[1:])
- except KeyboardInterrupt:
- sys.exit(1)
-
-
-def run_epylint():
- """run pylint"""
-
- EpylintRun()
-
-
-def run_pyreverse():
- """run pyreverse"""
-
- PyreverseRun(sys.argv[1:])
-
-
-def run_symilar():
- """run symilar"""
-
- SimilarRun(sys.argv[1:])
diff --git a/venv/Lib/site-packages/pylint/__main__.py b/venv/Lib/site-packages/pylint/__main__.py
deleted file mode 100644
index e12309b..0000000
--- a/venv/Lib/site-packages/pylint/__main__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-#!/usr/bin/env python
-import pylint
-
-pylint.run_pylint()
diff --git a/venv/Lib/site-packages/pylint/__pkginfo__.py b/venv/Lib/site-packages/pylint/__pkginfo__.py
deleted file mode 100644
index 68702f4..0000000
--- a/venv/Lib/site-packages/pylint/__pkginfo__.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (c) 2006-2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2010 Julien Jehannet <julien.jehannet@logilab.fr>
-# Copyright (c) 2013-2014 Google, Inc.
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Ricardo Gemignani <ricardo.gemignani@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2016 Florian Bruhin <git@the-compiler.org>
-# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2017-2018 Hugo <hugovk@users.noreply.github.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Ashley Whetter <ashley@awhetter.co.uk>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-# pylint: disable=redefined-builtin,invalid-name
-"""pylint packaging information"""
-
-from os.path import join
-
-# For an official release, use dev_version = None
-numversion = (2, 4, 4)
-dev_version = None
-
-version = ".".join(str(num) for num in numversion)
-if dev_version is not None:
- version += "-dev" + str(dev_version)
-
-install_requires = ["astroid>=2.3.0,<2.4", "isort>=4.2.5,<5", "mccabe>=0.6,<0.7"]
-
-dependency_links = [] # type: ignore
-
-extras_require = {}
-extras_require[':sys_platform=="win32"'] = ["colorama"]
-
-license = "GPL"
-description = "python code static checker"
-web = "https://github.com/PyCQA/pylint"
-mailinglist = "mailto:code-quality@python.org"
-author = "Python Code Quality Authority"
-author_email = "code-quality@python.org"
-
-classifiers = [
- "Development Status :: 6 - Mature",
- "Environment :: Console",
- "Intended Audience :: Developers",
- "License :: OSI Approved :: GNU General Public License (GPL)",
- "Operating System :: OS Independent",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.5",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: Implementation :: CPython",
- "Programming Language :: Python :: Implementation :: PyPy",
- "Topic :: Software Development :: Debuggers",
- "Topic :: Software Development :: Quality Assurance",
- "Topic :: Software Development :: Testing",
-]
-
-
-long_desc = """\
- Pylint is a Python source code analyzer which looks for programming
- errors, helps enforcing a coding standard and sniffs for some code
- smells (as defined in Martin Fowler's Refactoring book)
- .
- Pylint can be seen as another PyChecker since nearly all tests you
- can do with PyChecker can also be done with Pylint. However, Pylint
- offers some more features, like checking length of lines of code,
- checking if variable names are well-formed according to your coding
- standard, or checking if declared interfaces are truly implemented,
- and much more.
- .
- Additionally, it is possible to write plugins to add your own checks.
- .
- Pylint is shipped with "pyreverse" (UML diagram generator)
- and "symilar" (an independent similarities checker)."""
-
-scripts = [
- join("bin", filename) for filename in ("pylint", "symilar", "epylint", "pyreverse")
-]
diff --git a/venv/Lib/site-packages/pylint/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 4a5176d..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/__main__.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/__main__.cpython-37.pyc
deleted file mode 100644
index 06de374..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/__main__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/__pkginfo__.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/__pkginfo__.cpython-37.pyc
deleted file mode 100644
index 41da823..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/__pkginfo__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/config.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/config.cpython-37.pyc
deleted file mode 100644
index 0d3fde9..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/config.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/constants.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/constants.cpython-37.pyc
deleted file mode 100644
index 1d96028..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/constants.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/epylint.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/epylint.cpython-37.pyc
deleted file mode 100644
index 1b8630e..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/epylint.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/exceptions.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/exceptions.cpython-37.pyc
deleted file mode 100644
index 9766c27..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/exceptions.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/graph.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/graph.cpython-37.pyc
deleted file mode 100644
index 3a0dd39..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/graph.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/interfaces.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/interfaces.cpython-37.pyc
deleted file mode 100644
index 53b4224..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/interfaces.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/lint.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/lint.cpython-37.pyc
deleted file mode 100644
index ed84248..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/lint.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/__pycache__/testutils.cpython-37.pyc b/venv/Lib/site-packages/pylint/__pycache__/testutils.cpython-37.pyc
deleted file mode 100644
index 8db991c..0000000
--- a/venv/Lib/site-packages/pylint/__pycache__/testutils.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__init__.py b/venv/Lib/site-packages/pylint/checkers/__init__.py
deleted file mode 100644
index 9c6306f..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__init__.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2013-2014 Google, Inc.
-# Copyright (c) 2013 buck@yelp.com <buck@yelp.com>
-# Copyright (c) 2014-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2017-2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""utilities methods and classes for checkers
-
-Base id of standard checkers (used in msg and report ids):
-01: base
-02: classes
-03: format
-04: import
-05: misc
-06: variables
-07: exceptions
-08: similar
-09: design_analysis
-10: newstyle
-11: typecheck
-12: logging
-13: string_format
-14: string_constant
-15: stdlib
-16: python3
-17: refactoring
-18-50: not yet used: reserved for future internal checkers.
-51-99: perhaps used: reserved for external checkers
-
-The raw_metrics checker has no number associated since it doesn't emit any
-messages nor reports. XXX not true, emit a 07 report !
-
-"""
-
-from pylint.checkers.base_checker import BaseChecker, BaseTokenChecker
-from pylint.utils import register_plugins
-
-
-def table_lines_from_stats(stats, _, columns):
- """get values listed in <columns> from <stats> and <old_stats>,
- and return a formated list of values, designed to be given to a
- ureport.Table object
- """
- lines = []
- for m_type in columns:
- new = stats[m_type]
- new = "%.3f" % new if isinstance(new, float) else str(new)
- lines += (m_type.replace("_", " "), new, "NC", "NC")
- return lines
-
-
-def initialize(linter):
- """initialize linter with checkers in this package """
- register_plugins(linter, __path__[0])
-
-
-__all__ = ("BaseChecker", "BaseTokenChecker", "initialize")
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 3782086..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/async.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/async.cpython-37.pyc
deleted file mode 100644
index ea14658..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/async.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/base.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/base.cpython-37.pyc
deleted file mode 100644
index aaa3e51..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/base.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/base_checker.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/base_checker.cpython-37.pyc
deleted file mode 100644
index e4f8221..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/base_checker.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/classes.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/classes.cpython-37.pyc
deleted file mode 100644
index d0f58b4..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/classes.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/design_analysis.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/design_analysis.cpython-37.pyc
deleted file mode 100644
index 647b5aa..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/design_analysis.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/exceptions.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/exceptions.cpython-37.pyc
deleted file mode 100644
index 5371c29..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/exceptions.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/format.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/format.cpython-37.pyc
deleted file mode 100644
index 8a6a0c0..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/format.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/imports.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/imports.cpython-37.pyc
deleted file mode 100644
index f8b924d..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/imports.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/logging.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/logging.cpython-37.pyc
deleted file mode 100644
index 90cc06e..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/logging.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/misc.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/misc.cpython-37.pyc
deleted file mode 100644
index 9f449d4..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/misc.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/newstyle.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/newstyle.cpython-37.pyc
deleted file mode 100644
index e409591..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/newstyle.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/python3.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/python3.cpython-37.pyc
deleted file mode 100644
index b405dd3..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/python3.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/raw_metrics.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/raw_metrics.cpython-37.pyc
deleted file mode 100644
index fdf16f6..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/raw_metrics.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/refactoring.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/refactoring.cpython-37.pyc
deleted file mode 100644
index f65c6b5..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/refactoring.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/similar.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/similar.cpython-37.pyc
deleted file mode 100644
index 09b77e5..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/similar.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/spelling.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/spelling.cpython-37.pyc
deleted file mode 100644
index dbf748c..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/spelling.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/stdlib.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/stdlib.cpython-37.pyc
deleted file mode 100644
index 97576df..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/stdlib.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/strings.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/strings.cpython-37.pyc
deleted file mode 100644
index 0aab77c..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/strings.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/typecheck.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/typecheck.cpython-37.pyc
deleted file mode 100644
index cc0c9b4..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/typecheck.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/utils.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/utils.cpython-37.pyc
deleted file mode 100644
index 90e8ff1..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/utils.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/__pycache__/variables.cpython-37.pyc b/venv/Lib/site-packages/pylint/checkers/__pycache__/variables.cpython-37.pyc
deleted file mode 100644
index 943ffbd..0000000
--- a/venv/Lib/site-packages/pylint/checkers/__pycache__/variables.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/checkers/async.py b/venv/Lib/site-packages/pylint/checkers/async.py
deleted file mode 100644
index c33071e..0000000
--- a/venv/Lib/site-packages/pylint/checkers/async.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2017 Derek Gustafson <degustaf@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Checker for anything related to the async protocol (PEP 492)."""
-
-import sys
-
-import astroid
-from astroid import bases, exceptions
-
-from pylint import checkers, interfaces, utils
-from pylint.checkers import utils as checker_utils
-from pylint.checkers.utils import decorated_with
-
-
-class AsyncChecker(checkers.BaseChecker):
- __implements__ = interfaces.IAstroidChecker
- name = "async"
- msgs = {
- "E1700": (
- "Yield inside async function",
- "yield-inside-async-function",
- "Used when an `yield` or `yield from` statement is "
- "found inside an async function.",
- {"minversion": (3, 5)},
- ),
- "E1701": (
- "Async context manager '%s' doesn't implement __aenter__ and __aexit__.",
- "not-async-context-manager",
- "Used when an async context manager is used with an object "
- "that does not implement the async context management protocol.",
- {"minversion": (3, 5)},
- ),
- }
-
- def open(self):
- self._ignore_mixin_members = utils.get_global_option(
- self, "ignore-mixin-members"
- )
- self._async_generators = ["contextlib.asynccontextmanager"]
-
- @checker_utils.check_messages("yield-inside-async-function")
- def visit_asyncfunctiondef(self, node):
- for child in node.nodes_of_class(astroid.Yield):
- if child.scope() is node and (
- sys.version_info[:2] == (3, 5) or isinstance(child, astroid.YieldFrom)
- ):
- self.add_message("yield-inside-async-function", node=child)
-
- @checker_utils.check_messages("not-async-context-manager")
- def visit_asyncwith(self, node):
- for ctx_mgr, _ in node.items:
- inferred = checker_utils.safe_infer(ctx_mgr)
- if inferred is None or inferred is astroid.Uninferable:
- continue
-
- if isinstance(inferred, bases.AsyncGenerator):
- # Check if we are dealing with a function decorated
- # with contextlib.asynccontextmanager.
- if decorated_with(inferred.parent, self._async_generators):
- continue
- else:
- try:
- inferred.getattr("__aenter__")
- inferred.getattr("__aexit__")
- except exceptions.NotFoundError:
- if isinstance(inferred, astroid.Instance):
- # If we do not know the bases of this class,
- # just skip it.
- if not checker_utils.has_known_bases(inferred):
- continue
- # Just ignore mixin classes.
- if self._ignore_mixin_members:
- if inferred.name[-5:].lower() == "mixin":
- continue
- else:
- continue
-
- self.add_message(
- "not-async-context-manager", node=node, args=(inferred.name,)
- )
-
-
-def register(linter):
- """required method to auto register this checker"""
- linter.register_checker(AsyncChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/base.py b/venv/Lib/site-packages/pylint/checkers/base.py
deleted file mode 100644
index c94676e..0000000
--- a/venv/Lib/site-packages/pylint/checkers/base.py
+++ /dev/null
@@ -1,2333 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2016 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2010 Daniel Harding <dharding@gmail.com>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Nick Bastin <nick.bastin@gmail.com>
-# Copyright (c) 2015 Michael Kefeder <oss@multiwave.ch>
-# Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
-# Copyright (c) 2015 Stephane Wirtel <stephane@wirtel.be>
-# Copyright (c) 2015 Cosmin Poieana <cmin@ropython.org>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Radu Ciorba <radu@devrandom.ro>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016, 2018 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2016-2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-# Copyright (c) 2016 Elias Dorneles <eliasdorneles@gmail.com>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2016 Yannack <yannack@users.noreply.github.com>
-# Copyright (c) 2016 Alex Jurkiewicz <alex@jurkiewi.cz>
-# Copyright (c) 2017 Jacques Kvam <jwkvam@gmail.com>
-# Copyright (c) 2017 ttenhoeve-aa <ttenhoeve@appannie.com>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-# Copyright (c) 2018 Steven M. Vascellaro <svascellaro@gmail.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Chris Lamb <chris@chris-lamb.co.uk>
-# Copyright (c) 2018 glmdgrielson <32415403+glmdgrielson@users.noreply.github.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""basic checker for Python code"""
-
-import builtins
-import collections
-import itertools
-import re
-import sys
-from typing import Pattern
-
-import astroid
-import astroid.bases
-import astroid.scoped_nodes
-from astroid.arguments import CallSite
-
-import pylint.utils as lint_utils
-from pylint import checkers, exceptions, interfaces
-from pylint.checkers import utils
-from pylint.checkers.utils import is_property_setter_or_deleter
-from pylint.reporters.ureports import nodes as reporter_nodes
-
-
-class NamingStyle:
- # It may seem counterintuitive that single naming style
- # has multiple "accepted" forms of regular expressions,
- # but we need to special-case stuff like dunder names
- # in method names.
- CLASS_NAME_RGX = None # type: Pattern[str]
- MOD_NAME_RGX = None # type: Pattern[str]
- CONST_NAME_RGX = None # type: Pattern[str]
- COMP_VAR_RGX = None # type: Pattern[str]
- DEFAULT_NAME_RGX = None # type: Pattern[str]
- CLASS_ATTRIBUTE_RGX = None # type: Pattern[str]
-
- @classmethod
- def get_regex(cls, name_type):
- return {
- "module": cls.MOD_NAME_RGX,
- "const": cls.CONST_NAME_RGX,
- "class": cls.CLASS_NAME_RGX,
- "function": cls.DEFAULT_NAME_RGX,
- "method": cls.DEFAULT_NAME_RGX,
- "attr": cls.DEFAULT_NAME_RGX,
- "argument": cls.DEFAULT_NAME_RGX,
- "variable": cls.DEFAULT_NAME_RGX,
- "class_attribute": cls.CLASS_ATTRIBUTE_RGX,
- "inlinevar": cls.COMP_VAR_RGX,
- }[name_type]
-
-
-class SnakeCaseStyle(NamingStyle):
- """Regex rules for snake_case naming style."""
-
- CLASS_NAME_RGX = re.compile("[a-z_][a-z0-9_]+$")
- MOD_NAME_RGX = re.compile("([a-z_][a-z0-9_]*)$")
- CONST_NAME_RGX = re.compile("(([a-z_][a-z0-9_]*)|(__.*__))$")
- COMP_VAR_RGX = re.compile("[a-z_][a-z0-9_]*$")
- DEFAULT_NAME_RGX = re.compile(
- "(([a-z_][a-z0-9_]{2,})|(_[a-z0-9_]*)|(__[a-z][a-z0-9_]+__))$"
- )
- CLASS_ATTRIBUTE_RGX = re.compile(r"(([a-z_][a-z0-9_]{2,}|(__.*__)))$")
-
-
-class CamelCaseStyle(NamingStyle):
- """Regex rules for camelCase naming style."""
-
- CLASS_NAME_RGX = re.compile("[a-z_][a-zA-Z0-9]+$")
- MOD_NAME_RGX = re.compile("([a-z_][a-zA-Z0-9]*)$")
- CONST_NAME_RGX = re.compile("(([a-z_][A-Za-z0-9]*)|(__.*__))$")
- COMP_VAR_RGX = re.compile("[a-z_][A-Za-z0-9]*$")
- DEFAULT_NAME_RGX = re.compile("(([a-z_][a-zA-Z0-9]{2,})|(__[a-z][a-zA-Z0-9_]+__))$")
- CLASS_ATTRIBUTE_RGX = re.compile(r"([a-z_][A-Za-z0-9]{2,}|(__.*__))$")
-
-
-class PascalCaseStyle(NamingStyle):
- """Regex rules for PascalCase naming style."""
-
- CLASS_NAME_RGX = re.compile("[A-Z_][a-zA-Z0-9]+$")
- MOD_NAME_RGX = re.compile("[A-Z_][a-zA-Z0-9]+$")
- CONST_NAME_RGX = re.compile("(([A-Z_][A-Za-z0-9]*)|(__.*__))$")
- COMP_VAR_RGX = re.compile("[A-Z_][a-zA-Z0-9]+$")
- DEFAULT_NAME_RGX = re.compile("[A-Z_][a-zA-Z0-9]{2,}$|(__[a-z][a-zA-Z0-9_]+__)$")
- CLASS_ATTRIBUTE_RGX = re.compile("[A-Z_][a-zA-Z0-9]{2,}$")
-
-
-class UpperCaseStyle(NamingStyle):
- """Regex rules for UPPER_CASE naming style."""
-
- CLASS_NAME_RGX = re.compile("[A-Z_][A-Z0-9_]+$")
- MOD_NAME_RGX = re.compile("[A-Z_][A-Z0-9_]+$")
- CONST_NAME_RGX = re.compile("(([A-Z_][A-Z0-9_]*)|(__.*__))$")
- COMP_VAR_RGX = re.compile("[A-Z_][A-Z0-9_]+$")
- DEFAULT_NAME_RGX = re.compile("([A-Z_][A-Z0-9_]{2,})|(__[a-z][a-zA-Z0-9_]+__)$")
- CLASS_ATTRIBUTE_RGX = re.compile("[A-Z_][A-Z0-9_]{2,}$")
-
-
-class AnyStyle(NamingStyle):
- @classmethod
- def get_regex(cls, name_type):
- return re.compile(".*")
-
-
-NAMING_STYLES = {
- "snake_case": SnakeCaseStyle,
- "camelCase": CamelCaseStyle,
- "PascalCase": PascalCaseStyle,
- "UPPER_CASE": UpperCaseStyle,
- "any": AnyStyle,
-}
-
-# do not require a doc string on private/system methods
-NO_REQUIRED_DOC_RGX = re.compile("^_")
-REVERSED_PROTOCOL_METHOD = "__reversed__"
-SEQUENCE_PROTOCOL_METHODS = ("__getitem__", "__len__")
-REVERSED_METHODS = (SEQUENCE_PROTOCOL_METHODS, (REVERSED_PROTOCOL_METHOD,))
-TYPECHECK_COMPARISON_OPERATORS = frozenset(("is", "is not", "==", "!=", "in", "not in"))
-LITERAL_NODE_TYPES = (astroid.Const, astroid.Dict, astroid.List, astroid.Set)
-UNITTEST_CASE = "unittest.case"
-BUILTINS = builtins.__name__
-TYPE_QNAME = "%s.type" % BUILTINS
-ABC_METACLASSES = {"_py_abc.ABCMeta", "abc.ABCMeta"} # Python 3.7+,
-
-# Name categories that are always consistent with all naming conventions.
-EXEMPT_NAME_CATEGORIES = {"exempt", "ignore"}
-
-# A mapping from builtin-qname -> symbol, to be used when generating messages
-# about dangerous default values as arguments
-DEFAULT_ARGUMENT_SYMBOLS = dict(
- zip(
- [".".join([BUILTINS, x]) for x in ("set", "dict", "list")],
- ["set()", "{}", "[]"],
- )
-)
-REVERSED_COMPS = {"<": ">", "<=": ">=", ">": "<", ">=": "<="}
-COMPARISON_OPERATORS = frozenset(("==", "!=", "<", ">", "<=", ">="))
-# List of methods which can be redefined
-REDEFINABLE_METHODS = frozenset(("__module__",))
-TYPING_FORWARD_REF_QNAME = "typing.ForwardRef"
-
-
-def _redefines_import(node):
- """ Detect that the given node (AssignName) is inside an
- exception handler and redefines an import from the tryexcept body.
- Returns True if the node redefines an import, False otherwise.
- """
- current = node
- while current and not isinstance(current.parent, astroid.ExceptHandler):
- current = current.parent
- if not current or not utils.error_of_type(current.parent, ImportError):
- return False
- try_block = current.parent.parent
- for import_node in try_block.nodes_of_class((astroid.ImportFrom, astroid.Import)):
- for name, alias in import_node.names:
- if alias:
- if alias == node.name:
- return True
- elif name == node.name:
- return True
- return False
-
-
-def in_loop(node):
- """return True if the node is inside a kind of for loop"""
- parent = node.parent
- while parent is not None:
- if isinstance(
- parent,
- (
- astroid.For,
- astroid.ListComp,
- astroid.SetComp,
- astroid.DictComp,
- astroid.GeneratorExp,
- ),
- ):
- return True
- parent = parent.parent
- return False
-
-
-def in_nested_list(nested_list, obj):
- """return true if the object is an element of <nested_list> or of a nested
- list
- """
- for elmt in nested_list:
- if isinstance(elmt, (list, tuple)):
- if in_nested_list(elmt, obj):
- return True
- elif elmt == obj:
- return True
- return False
-
-
-def _get_break_loop_node(break_node):
- """
- Returns the loop node that holds the break node in arguments.
-
- Args:
- break_node (astroid.Break): the break node of interest.
-
- Returns:
- astroid.For or astroid.While: the loop node holding the break node.
- """
- loop_nodes = (astroid.For, astroid.While)
- parent = break_node.parent
- while not isinstance(parent, loop_nodes) or break_node in getattr(
- parent, "orelse", []
- ):
- break_node = parent
- parent = parent.parent
- if parent is None:
- break
- return parent
-
-
-def _loop_exits_early(loop):
- """
- Returns true if a loop may ends up in a break statement.
-
- Args:
- loop (astroid.For, astroid.While): the loop node inspected.
-
- Returns:
- bool: True if the loop may ends up in a break statement, False otherwise.
- """
- loop_nodes = (astroid.For, astroid.While)
- definition_nodes = (astroid.FunctionDef, astroid.ClassDef)
- inner_loop_nodes = [
- _node
- for _node in loop.nodes_of_class(loop_nodes, skip_klass=definition_nodes)
- if _node != loop
- ]
- return any(
- _node
- for _node in loop.nodes_of_class(astroid.Break, skip_klass=definition_nodes)
- if _get_break_loop_node(_node) not in inner_loop_nodes
- )
-
-
-def _is_multi_naming_match(match, node_type, confidence):
- return (
- match is not None
- and match.lastgroup is not None
- and match.lastgroup not in EXEMPT_NAME_CATEGORIES
- and (node_type != "method" or confidence != interfaces.INFERENCE_FAILURE)
- )
-
-
-BUILTIN_PROPERTY = "builtins.property"
-
-
-def _get_properties(config):
- """Returns a tuple of property classes and names.
-
- Property classes are fully qualified, such as 'abc.abstractproperty' and
- property names are the actual names, such as 'abstract_property'.
- """
- property_classes = {BUILTIN_PROPERTY}
- property_names = set() # Not returning 'property', it has its own check.
- if config is not None:
- property_classes.update(config.property_classes)
- property_names.update(
- (prop.rsplit(".", 1)[-1] for prop in config.property_classes)
- )
- return property_classes, property_names
-
-
-def _determine_function_name_type(node, config=None):
- """Determine the name type whose regex the a function's name should match.
-
- :param node: A function node.
- :type node: astroid.node_classes.NodeNG
- :param config: Configuration from which to pull additional property classes.
- :type config: :class:`optparse.Values`
-
- :returns: One of ('function', 'method', 'attr')
- :rtype: str
- """
- property_classes, property_names = _get_properties(config)
- if not node.is_method():
- return "function"
-
- if is_property_setter_or_deleter(node):
- # If the function is decorated using the prop_method.{setter,getter}
- # form, treat it like an attribute as well.
- return "attr"
-
- if node.decorators:
- decorators = node.decorators.nodes
- else:
- decorators = []
- for decorator in decorators:
- # If the function is a property (decorated with @property
- # or @abc.abstractproperty), the name type is 'attr'.
- if isinstance(decorator, astroid.Name) or (
- isinstance(decorator, astroid.Attribute)
- and decorator.attrname in property_names
- ):
- inferred = utils.safe_infer(decorator)
- if inferred and inferred.qname() in property_classes:
- return "attr"
- return "method"
-
-
-def _has_abstract_methods(node):
- """
- Determine if the given `node` has abstract methods.
-
- The methods should be made abstract by decorating them
- with `abc` decorators.
- """
- return len(utils.unimplemented_abstract_methods(node)) > 0
-
-
-def report_by_type_stats(sect, stats, _):
- """make a report of
-
- * percentage of different types documented
- * percentage of different types with a bad name
- """
- # percentage of different types documented and/or with a bad name
- nice_stats = {}
- for node_type in ("module", "class", "method", "function"):
- try:
- total = stats[node_type]
- except KeyError:
- raise exceptions.EmptyReportError()
- nice_stats[node_type] = {}
- if total != 0:
- try:
- documented = total - stats["undocumented_" + node_type]
- percent = (documented * 100.0) / total
- nice_stats[node_type]["percent_documented"] = "%.2f" % percent
- except KeyError:
- nice_stats[node_type]["percent_documented"] = "NC"
- try:
- percent = (stats["badname_" + node_type] * 100.0) / total
- nice_stats[node_type]["percent_badname"] = "%.2f" % percent
- except KeyError:
- nice_stats[node_type]["percent_badname"] = "NC"
- lines = ("type", "number", "old number", "difference", "%documented", "%badname")
- for node_type in ("module", "class", "method", "function"):
- new = stats[node_type]
- lines += (
- node_type,
- str(new),
- "NC",
- "NC",
- nice_stats[node_type].get("percent_documented", "0"),
- nice_stats[node_type].get("percent_badname", "0"),
- )
- sect.append(reporter_nodes.Table(children=lines, cols=6, rheaders=1))
-
-
-def redefined_by_decorator(node):
- """return True if the object is a method redefined via decorator.
-
- For example:
- @property
- def x(self): return self._x
- @x.setter
- def x(self, value): self._x = value
- """
- if node.decorators:
- for decorator in node.decorators.nodes:
- if (
- isinstance(decorator, astroid.Attribute)
- and getattr(decorator.expr, "name", None) == node.name
- ):
- return True
- return False
-
-
-class _BasicChecker(checkers.BaseChecker):
- __implements__ = interfaces.IAstroidChecker
- name = "basic"
-
-
-class BasicErrorChecker(_BasicChecker):
- msgs = {
- "E0100": (
- "__init__ method is a generator",
- "init-is-generator",
- "Used when the special class method __init__ is turned into a "
- "generator by a yield in its body.",
- ),
- "E0101": (
- "Explicit return in __init__",
- "return-in-init",
- "Used when the special class method __init__ has an explicit "
- "return value.",
- ),
- "E0102": (
- "%s already defined line %s",
- "function-redefined",
- "Used when a function / class / method is redefined.",
- ),
- "E0103": (
- "%r not properly in loop",
- "not-in-loop",
- "Used when break or continue keywords are used outside a loop.",
- ),
- "E0104": (
- "Return outside function",
- "return-outside-function",
- 'Used when a "return" statement is found outside a function or method.',
- ),
- "E0105": (
- "Yield outside function",
- "yield-outside-function",
- 'Used when a "yield" statement is found outside a function or method.',
- ),
- "E0106": (
- "Return with argument inside generator",
- "return-arg-in-generator",
- 'Used when a "return" statement with an argument is found '
- "outside in a generator function or method (e.g. with some "
- '"yield" statements).',
- {"maxversion": (3, 3)},
- ),
- "E0107": (
- "Use of the non-existent %s operator",
- "nonexistent-operator",
- "Used when you attempt to use the C-style pre-increment or "
- "pre-decrement operator -- and ++, which doesn't exist in Python.",
- ),
- "E0108": (
- "Duplicate argument name %s in function definition",
- "duplicate-argument-name",
- "Duplicate argument names in function definitions are syntax errors.",
- ),
- "E0110": (
- "Abstract class %r with abstract methods instantiated",
- "abstract-class-instantiated",
- "Used when an abstract class with `abc.ABCMeta` as metaclass "
- "has abstract methods and is instantiated.",
- ),
- "W0120": (
- "Else clause on loop without a break statement",
- "useless-else-on-loop",
- "Loops should only have an else clause if they can exit early "
- "with a break statement, otherwise the statements under else "
- "should be on the same scope as the loop itself.",
- ),
- "E0112": (
- "More than one starred expression in assignment",
- "too-many-star-expressions",
- "Emitted when there are more than one starred "
- "expressions (`*x`) in an assignment. This is a SyntaxError.",
- ),
- "E0113": (
- "Starred assignment target must be in a list or tuple",
- "invalid-star-assignment-target",
- "Emitted when a star expression is used as a starred assignment target.",
- ),
- "E0114": (
- "Can use starred expression only in assignment target",
- "star-needs-assignment-target",
- "Emitted when a star expression is not used in an assignment target.",
- ),
- "E0115": (
- "Name %r is nonlocal and global",
- "nonlocal-and-global",
- "Emitted when a name is both nonlocal and global.",
- ),
- "E0116": (
- "'continue' not supported inside 'finally' clause",
- "continue-in-finally",
- "Emitted when the `continue` keyword is found "
- "inside a finally clause, which is a SyntaxError.",
- ),
- "E0117": (
- "nonlocal name %s found without binding",
- "nonlocal-without-binding",
- "Emitted when a nonlocal variable does not have an attached "
- "name somewhere in the parent scopes",
- ),
- "E0118": (
- "Name %r is used prior to global declaration",
- "used-prior-global-declaration",
- "Emitted when a name is used prior a global declaration, "
- "which results in an error since Python 3.6.",
- {"minversion": (3, 6)},
- ),
- }
-
- @utils.check_messages("function-redefined")
- def visit_classdef(self, node):
- self._check_redefinition("class", node)
-
- def _too_many_starred_for_tuple(self, assign_tuple):
- starred_count = 0
- for elem in assign_tuple.itered():
- if isinstance(elem, astroid.Tuple):
- return self._too_many_starred_for_tuple(elem)
- if isinstance(elem, astroid.Starred):
- starred_count += 1
- return starred_count > 1
-
- @utils.check_messages("too-many-star-expressions", "invalid-star-assignment-target")
- def visit_assign(self, node):
- # Check *a, *b = ...
- assign_target = node.targets[0]
- # Check *a = b
- if isinstance(node.targets[0], astroid.Starred):
- self.add_message("invalid-star-assignment-target", node=node)
-
- if not isinstance(assign_target, astroid.Tuple):
- return
- if self._too_many_starred_for_tuple(assign_target):
- self.add_message("too-many-star-expressions", node=node)
-
- @utils.check_messages("star-needs-assignment-target")
- def visit_starred(self, node):
- """Check that a Starred expression is used in an assignment target."""
- if isinstance(node.parent, astroid.Call):
- # f(*args) is converted to Call(args=[Starred]), so ignore
- # them for this check.
- return
- if isinstance(
- node.parent, (astroid.List, astroid.Tuple, astroid.Set, astroid.Dict)
- ):
- # PEP 448 unpacking.
- return
-
- stmt = node.statement()
- if not isinstance(stmt, astroid.Assign):
- return
-
- if stmt.value is node or stmt.value.parent_of(node):
- self.add_message("star-needs-assignment-target", node=node)
-
- @utils.check_messages(
- "init-is-generator",
- "return-in-init",
- "function-redefined",
- "return-arg-in-generator",
- "duplicate-argument-name",
- "nonlocal-and-global",
- "used-prior-global-declaration",
- )
- def visit_functiondef(self, node):
- self._check_nonlocal_and_global(node)
- self._check_name_used_prior_global(node)
- if not redefined_by_decorator(
- node
- ) and not utils.is_registered_in_singledispatch_function(node):
- self._check_redefinition(node.is_method() and "method" or "function", node)
- # checks for max returns, branch, return in __init__
- returns = node.nodes_of_class(
- astroid.Return, skip_klass=(astroid.FunctionDef, astroid.ClassDef)
- )
- if node.is_method() and node.name == "__init__":
- if node.is_generator():
- self.add_message("init-is-generator", node=node)
- else:
- values = [r.value for r in returns]
- # Are we returning anything but None from constructors
- if any(v for v in values if not utils.is_none(v)):
- self.add_message("return-in-init", node=node)
- # Check for duplicate names by clustering args with same name for detailed report
- arg_clusters = collections.defaultdict(list)
- arguments = filter(None, [node.args.args, node.args.kwonlyargs])
-
- for arg in itertools.chain.from_iterable(arguments):
- arg_clusters[arg.name].append(arg)
-
- # provide detailed report about each repeated argument
- for argument_duplicates in arg_clusters.values():
- if len(argument_duplicates) != 1:
- for argument in argument_duplicates:
- self.add_message(
- "duplicate-argument-name",
- line=argument.lineno,
- node=argument,
- args=(argument.name,),
- )
-
- visit_asyncfunctiondef = visit_functiondef
-
- def _check_name_used_prior_global(self, node):
-
- scope_globals = {
- name: child
- for child in node.nodes_of_class(astroid.Global)
- for name in child.names
- if child.scope() is node
- }
-
- if not scope_globals:
- return
-
- for node_name in node.nodes_of_class(astroid.Name):
- if node_name.scope() is not node:
- continue
-
- name = node_name.name
- corresponding_global = scope_globals.get(name)
- if not corresponding_global:
- continue
-
- global_lineno = corresponding_global.fromlineno
- if global_lineno and global_lineno > node_name.fromlineno:
- self.add_message(
- "used-prior-global-declaration", node=node_name, args=(name,)
- )
-
- def _check_nonlocal_and_global(self, node):
- """Check that a name is both nonlocal and global."""
-
- def same_scope(current):
- return current.scope() is node
-
- from_iter = itertools.chain.from_iterable
- nonlocals = set(
- from_iter(
- child.names
- for child in node.nodes_of_class(astroid.Nonlocal)
- if same_scope(child)
- )
- )
-
- if not nonlocals:
- return
-
- global_vars = set(
- from_iter(
- child.names
- for child in node.nodes_of_class(astroid.Global)
- if same_scope(child)
- )
- )
- for name in nonlocals.intersection(global_vars):
- self.add_message("nonlocal-and-global", args=(name,), node=node)
-
- @utils.check_messages("return-outside-function")
- def visit_return(self, node):
- if not isinstance(node.frame(), astroid.FunctionDef):
- self.add_message("return-outside-function", node=node)
-
- @utils.check_messages("yield-outside-function")
- def visit_yield(self, node):
- self._check_yield_outside_func(node)
-
- @utils.check_messages("yield-outside-function")
- def visit_yieldfrom(self, node):
- self._check_yield_outside_func(node)
-
- @utils.check_messages("not-in-loop", "continue-in-finally")
- def visit_continue(self, node):
- self._check_in_loop(node, "continue")
-
- @utils.check_messages("not-in-loop")
- def visit_break(self, node):
- self._check_in_loop(node, "break")
-
- @utils.check_messages("useless-else-on-loop")
- def visit_for(self, node):
- self._check_else_on_loop(node)
-
- @utils.check_messages("useless-else-on-loop")
- def visit_while(self, node):
- self._check_else_on_loop(node)
-
- @utils.check_messages("nonexistent-operator")
- def visit_unaryop(self, node):
- """check use of the non-existent ++ and -- operator operator"""
- if (
- (node.op in "+-")
- and isinstance(node.operand, astroid.UnaryOp)
- and (node.operand.op == node.op)
- ):
- self.add_message("nonexistent-operator", node=node, args=node.op * 2)
-
- def _check_nonlocal_without_binding(self, node, name):
- current_scope = node.scope()
- while True:
- if current_scope.parent is None:
- break
-
- if not isinstance(current_scope, (astroid.ClassDef, astroid.FunctionDef)):
- self.add_message("nonlocal-without-binding", args=(name,), node=node)
- return
-
- if name not in current_scope.locals:
- current_scope = current_scope.parent.scope()
- continue
-
- # Okay, found it.
- return
-
- if not isinstance(current_scope, astroid.FunctionDef):
- self.add_message("nonlocal-without-binding", args=(name,), node=node)
-
- @utils.check_messages("nonlocal-without-binding")
- def visit_nonlocal(self, node):
- for name in node.names:
- self._check_nonlocal_without_binding(node, name)
-
- @utils.check_messages("abstract-class-instantiated")
- def visit_call(self, node):
- """ Check instantiating abstract class with
- abc.ABCMeta as metaclass.
- """
- try:
- for inferred in node.func.infer():
- self._check_inferred_class_is_abstract(inferred, node)
- except astroid.InferenceError:
- return
-
- def _check_inferred_class_is_abstract(self, inferred, node):
- if not isinstance(inferred, astroid.ClassDef):
- return
-
- klass = utils.node_frame_class(node)
- if klass is inferred:
- # Don't emit the warning if the class is instantiated
- # in its own body or if the call is not an instance
- # creation. If the class is instantiated into its own
- # body, we're expecting that it knows what it is doing.
- return
-
- # __init__ was called
- abstract_methods = _has_abstract_methods(inferred)
-
- if not abstract_methods:
- return
-
- metaclass = inferred.metaclass()
-
- if metaclass is None:
- # Python 3.4 has `abc.ABC`, which won't be detected
- # by ClassNode.metaclass()
- for ancestor in inferred.ancestors():
- if ancestor.qname() == "abc.ABC":
- self.add_message(
- "abstract-class-instantiated", args=(inferred.name,), node=node
- )
- break
-
- return
-
- if metaclass.qname() in ABC_METACLASSES:
- self.add_message(
- "abstract-class-instantiated", args=(inferred.name,), node=node
- )
-
- def _check_yield_outside_func(self, node):
- if not isinstance(node.frame(), (astroid.FunctionDef, astroid.Lambda)):
- self.add_message("yield-outside-function", node=node)
-
- def _check_else_on_loop(self, node):
- """Check that any loop with an else clause has a break statement."""
- if node.orelse and not _loop_exits_early(node):
- self.add_message(
- "useless-else-on-loop",
- node=node,
- # This is not optimal, but the line previous
- # to the first statement in the else clause
- # will usually be the one that contains the else:.
- line=node.orelse[0].lineno - 1,
- )
-
- def _check_in_loop(self, node, node_name):
- """check that a node is inside a for or while loop"""
- _node = node.parent
- while _node:
- if isinstance(_node, (astroid.For, astroid.While)):
- if node not in _node.orelse:
- return
-
- if isinstance(_node, (astroid.ClassDef, astroid.FunctionDef)):
- break
- if (
- isinstance(_node, astroid.TryFinally)
- and node in _node.finalbody
- and isinstance(node, astroid.Continue)
- ):
- self.add_message("continue-in-finally", node=node)
-
- _node = _node.parent
-
- self.add_message("not-in-loop", node=node, args=node_name)
-
- def _check_redefinition(self, redeftype, node):
- """check for redefinition of a function / method / class name"""
- parent_frame = node.parent.frame()
-
- # Ignore function stubs created for type information
- redefinitions = parent_frame.locals[node.name]
- defined_self = next(
- (local for local in redefinitions if not utils.is_overload_stub(local)),
- node,
- )
- if defined_self is not node and not astroid.are_exclusive(node, defined_self):
-
- # Additional checks for methods which are not considered
- # redefined, since they are already part of the base API.
- if (
- isinstance(parent_frame, astroid.ClassDef)
- and node.name in REDEFINABLE_METHODS
- ):
- return
-
- if utils.is_overload_stub(node):
- return
-
- # Check if we have forward references for this node.
- try:
- redefinition_index = redefinitions.index(node)
- except ValueError:
- pass
- else:
- for redefinition in redefinitions[:redefinition_index]:
- inferred = utils.safe_infer(redefinition)
- if (
- inferred
- and isinstance(inferred, astroid.Instance)
- and inferred.qname() == TYPING_FORWARD_REF_QNAME
- ):
- return
-
- dummy_variables_rgx = lint_utils.get_global_option(
- self, "dummy-variables-rgx", default=None
- )
- if dummy_variables_rgx and dummy_variables_rgx.match(node.name):
- return
- self.add_message(
- "function-redefined",
- node=node,
- args=(redeftype, defined_self.fromlineno),
- )
-
-
-class BasicChecker(_BasicChecker):
- """checks for :
- * doc strings
- * number of arguments, local variables, branches, returns and statements in
- functions, methods
- * required module attributes
- * dangerous default values as arguments
- * redefinition of function / method / class
- * uses of the global statement
- """
-
- __implements__ = interfaces.IAstroidChecker
-
- name = "basic"
- msgs = {
- "W0101": (
- "Unreachable code",
- "unreachable",
- 'Used when there is some code behind a "return" or "raise" '
- "statement, which will never be accessed.",
- ),
- "W0102": (
- "Dangerous default value %s as argument",
- "dangerous-default-value",
- "Used when a mutable value as list or dictionary is detected in "
- "a default value for an argument.",
- ),
- "W0104": (
- "Statement seems to have no effect",
- "pointless-statement",
- "Used when a statement doesn't have (or at least seems to) any effect.",
- ),
- "W0105": (
- "String statement has no effect",
- "pointless-string-statement",
- "Used when a string is used as a statement (which of course "
- "has no effect). This is a particular case of W0104 with its "
- "own message so you can easily disable it if you're using "
- "those strings as documentation, instead of comments.",
- ),
- "W0106": (
- 'Expression "%s" is assigned to nothing',
- "expression-not-assigned",
- "Used when an expression that is not a function call is assigned "
- "to nothing. Probably something else was intended.",
- ),
- "W0108": (
- "Lambda may not be necessary",
- "unnecessary-lambda",
- "Used when the body of a lambda expression is a function call "
- "on the same argument list as the lambda itself; such lambda "
- "expressions are in all but a few cases replaceable with the "
- "function being called in the body of the lambda.",
- ),
- "W0109": (
- "Duplicate key %r in dictionary",
- "duplicate-key",
- "Used when a dictionary expression binds the same key multiple times.",
- ),
- "W0122": (
- "Use of exec",
- "exec-used",
- 'Used when you use the "exec" statement (function for Python '
- "3), to discourage its usage. That doesn't "
- "mean you cannot use it !",
- ),
- "W0123": (
- "Use of eval",
- "eval-used",
- 'Used when you use the "eval" function, to discourage its '
- "usage. Consider using `ast.literal_eval` for safely evaluating "
- "strings containing Python expressions "
- "from untrusted sources. ",
- ),
- "W0150": (
- "%s statement in finally block may swallow exception",
- "lost-exception",
- "Used when a break or a return statement is found inside the "
- "finally clause of a try...finally block: the exceptions raised "
- "in the try clause will be silently swallowed instead of being "
- "re-raised.",
- ),
- "W0199": (
- "Assert called on a 2-item-tuple. Did you mean 'assert x,y'?",
- "assert-on-tuple",
- "A call of assert on a tuple will always evaluate to true if "
- "the tuple is not empty, and will always evaluate to false if "
- "it is.",
- ),
- "W0124": (
- 'Following "as" with another context manager looks like a tuple.',
- "confusing-with-statement",
- "Emitted when a `with` statement component returns multiple values "
- "and uses name binding with `as` only for a part of those values, "
- "as in with ctx() as a, b. This can be misleading, since it's not "
- "clear if the context manager returns a tuple or if the node without "
- "a name binding is another context manager.",
- ),
- "W0125": (
- "Using a conditional statement with a constant value",
- "using-constant-test",
- "Emitted when a conditional statement (If or ternary if) "
- "uses a constant value for its test. This might not be what "
- "the user intended to do.",
- ),
- "W0126": (
- "Using a conditional statement with potentially wrong function or method call due to missing parentheses",
- "missing-parentheses-for-call-in-test",
- "Emitted when a conditional statement (If or ternary if) "
- "seems to wrongly call a function due to missing parentheses",
- ),
- "W0127": (
- "Assigning the same variable %r to itself",
- "self-assigning-variable",
- "Emitted when we detect that a variable is assigned to itself",
- ),
- "W0128": (
- "Redeclared variable %r in assignment",
- "redeclared-assigned-name",
- "Emitted when we detect that a variable was redeclared in the same assignment.",
- ),
- "E0111": (
- "The first reversed() argument is not a sequence",
- "bad-reversed-sequence",
- "Used when the first argument to reversed() builtin "
- "isn't a sequence (does not implement __reversed__, "
- "nor __getitem__ and __len__",
- ),
- "E0119": (
- "format function is not called on str",
- "misplaced-format-function",
- "Emitted when format function is not called on str object. "
- 'e.g doing print("value: {}").format(123) instead of '
- 'print("value: {}".format(123)). This might not be what the user '
- "intended to do.",
- ),
- }
-
- reports = (("RP0101", "Statistics by type", report_by_type_stats),)
-
- def __init__(self, linter):
- _BasicChecker.__init__(self, linter)
- self.stats = None
- self._tryfinallys = None
-
- def open(self):
- """initialize visit variables and statistics
- """
- self._tryfinallys = []
- self.stats = self.linter.add_stats(module=0, function=0, method=0, class_=0)
-
- @utils.check_messages("using-constant-test", "missing-parentheses-for-call-in-test")
- def visit_if(self, node):
- self._check_using_constant_test(node, node.test)
-
- @utils.check_messages("using-constant-test", "missing-parentheses-for-call-in-test")
- def visit_ifexp(self, node):
- self._check_using_constant_test(node, node.test)
-
- @utils.check_messages("using-constant-test", "missing-parentheses-for-call-in-test")
- def visit_comprehension(self, node):
- if node.ifs:
- for if_test in node.ifs:
- self._check_using_constant_test(node, if_test)
-
- def _check_using_constant_test(self, node, test):
- const_nodes = (
- astroid.Module,
- astroid.scoped_nodes.GeneratorExp,
- astroid.Lambda,
- astroid.FunctionDef,
- astroid.ClassDef,
- astroid.bases.Generator,
- astroid.UnboundMethod,
- astroid.BoundMethod,
- astroid.Module,
- )
- structs = (astroid.Dict, astroid.Tuple, astroid.Set)
-
- # These nodes are excepted, since they are not constant
- # values, requiring a computation to happen.
- except_nodes = (
- astroid.Call,
- astroid.BinOp,
- astroid.BoolOp,
- astroid.UnaryOp,
- astroid.Subscript,
- )
- inferred = None
- emit = isinstance(test, (astroid.Const,) + structs + const_nodes)
- if not isinstance(test, except_nodes):
- inferred = utils.safe_infer(test)
-
- if emit:
- self.add_message("using-constant-test", node=node)
- elif isinstance(inferred, const_nodes):
- # If the constant node is a FunctionDef or Lambda then
- #  it may be a illicit function call due to missing parentheses
- call_inferred = None
- if isinstance(inferred, astroid.FunctionDef):
- call_inferred = inferred.infer_call_result()
- elif isinstance(inferred, astroid.Lambda):
- call_inferred = inferred.infer_call_result(node)
- if call_inferred:
- try:
- for inf_call in call_inferred:
- if inf_call != astroid.Uninferable:
- self.add_message(
- "missing-parentheses-for-call-in-test", node=node
- )
- break
- except astroid.InferenceError:
- pass
- self.add_message("using-constant-test", node=node)
-
- def visit_module(self, _):
- """check module name, docstring and required arguments
- """
- self.stats["module"] += 1
-
- def visit_classdef(self, node): # pylint: disable=unused-argument
- """check module name, docstring and redefinition
- increment branch counter
- """
- self.stats["class"] += 1
-
- @utils.check_messages(
- "pointless-statement", "pointless-string-statement", "expression-not-assigned"
- )
- def visit_expr(self, node):
- """Check for various kind of statements without effect"""
- expr = node.value
- if isinstance(expr, astroid.Const) and isinstance(expr.value, str):
- # treat string statement in a separated message
- # Handle PEP-257 attribute docstrings.
- # An attribute docstring is defined as being a string right after
- # an assignment at the module level, class level or __init__ level.
- scope = expr.scope()
- if isinstance(
- scope, (astroid.ClassDef, astroid.Module, astroid.FunctionDef)
- ):
- if isinstance(scope, astroid.FunctionDef) and scope.name != "__init__":
- pass
- else:
- sibling = expr.previous_sibling()
- if (
- sibling is not None
- and sibling.scope() is scope
- and isinstance(sibling, (astroid.Assign, astroid.AnnAssign))
- ):
- return
- self.add_message("pointless-string-statement", node=node)
- return
-
- # Ignore if this is :
- # * a direct function call
- # * the unique child of a try/except body
- # * a yield statement
- # * an ellipsis (which can be used on Python 3 instead of pass)
- # warn W0106 if we have any underlying function call (we can't predict
- # side effects), else pointless-statement
- if (
- isinstance(
- expr, (astroid.Yield, astroid.Await, astroid.Ellipsis, astroid.Call)
- )
- or (
- isinstance(node.parent, astroid.TryExcept)
- and node.parent.body == [node]
- )
- or (isinstance(expr, astroid.Const) and expr.value is Ellipsis)
- ):
- return
- if any(expr.nodes_of_class(astroid.Call)):
- self.add_message(
- "expression-not-assigned", node=node, args=expr.as_string()
- )
- else:
- self.add_message("pointless-statement", node=node)
-
- @staticmethod
- def _filter_vararg(node, call_args):
- # Return the arguments for the given call which are
- # not passed as vararg.
- for arg in call_args:
- if isinstance(arg, astroid.Starred):
- if (
- isinstance(arg.value, astroid.Name)
- and arg.value.name != node.args.vararg
- ):
- yield arg
- else:
- yield arg
-
- @staticmethod
- def _has_variadic_argument(args, variadic_name):
- if not args:
- return True
- for arg in args:
- if isinstance(arg.value, astroid.Name):
- if arg.value.name != variadic_name:
- return True
- else:
- return True
- return False
-
- @utils.check_messages("unnecessary-lambda")
- def visit_lambda(self, node):
- """check whether or not the lambda is suspicious
- """
- # if the body of the lambda is a call expression with the same
- # argument list as the lambda itself, then the lambda is
- # possibly unnecessary and at least suspicious.
- if node.args.defaults:
- # If the arguments of the lambda include defaults, then a
- # judgment cannot be made because there is no way to check
- # that the defaults defined by the lambda are the same as
- # the defaults defined by the function called in the body
- # of the lambda.
- return
- call = node.body
- if not isinstance(call, astroid.Call):
- # The body of the lambda must be a function call expression
- # for the lambda to be unnecessary.
- return
- if isinstance(node.body.func, astroid.Attribute) and isinstance(
- node.body.func.expr, astroid.Call
- ):
- # Chained call, the intermediate call might
- # return something else (but we don't check that, yet).
- return
-
- call_site = CallSite.from_call(call)
- ordinary_args = list(node.args.args)
- new_call_args = list(self._filter_vararg(node, call.args))
- if node.args.kwarg:
- if self._has_variadic_argument(call.kwargs, node.args.kwarg):
- return
-
- if node.args.vararg:
- if self._has_variadic_argument(call.starargs, node.args.vararg):
- return
- elif call.starargs:
- return
-
- if call.keywords:
- # Look for additional keyword arguments that are not part
- # of the lambda's signature
- lambda_kwargs = {keyword.name for keyword in node.args.defaults}
- if len(lambda_kwargs) != len(call_site.keyword_arguments):
- # Different lengths, so probably not identical
- return
- if set(call_site.keyword_arguments).difference(lambda_kwargs):
- return
-
- # The "ordinary" arguments must be in a correspondence such that:
- # ordinary_args[i].name == call.args[i].name.
- if len(ordinary_args) != len(new_call_args):
- return
- for arg, passed_arg in zip(ordinary_args, new_call_args):
- if not isinstance(passed_arg, astroid.Name):
- return
- if arg.name != passed_arg.name:
- return
-
- self.add_message("unnecessary-lambda", line=node.fromlineno, node=node)
-
- @utils.check_messages("dangerous-default-value")
- def visit_functiondef(self, node):
- """check function name, docstring, arguments, redefinition,
- variable names, max locals
- """
- self.stats["method" if node.is_method() else "function"] += 1
- self._check_dangerous_default(node)
-
- visit_asyncfunctiondef = visit_functiondef
-
- def _check_dangerous_default(self, node):
- # check for dangerous default values as arguments
- is_iterable = lambda n: isinstance(n, (astroid.List, astroid.Set, astroid.Dict))
- for default in node.args.defaults:
- try:
- value = next(default.infer())
- except astroid.InferenceError:
- continue
-
- if (
- isinstance(value, astroid.Instance)
- and value.qname() in DEFAULT_ARGUMENT_SYMBOLS
- ):
-
- if value is default:
- msg = DEFAULT_ARGUMENT_SYMBOLS[value.qname()]
- elif isinstance(value, astroid.Instance) or is_iterable(value):
- # We are here in the following situation(s):
- # * a dict/set/list/tuple call which wasn't inferred
- # to a syntax node ({}, () etc.). This can happen
- # when the arguments are invalid or unknown to
- # the inference.
- # * a variable from somewhere else, which turns out to be a list
- # or a dict.
- if is_iterable(default):
- msg = value.pytype()
- elif isinstance(default, astroid.Call):
- msg = "%s() (%s)" % (value.name, value.qname())
- else:
- msg = "%s (%s)" % (default.as_string(), value.qname())
- else:
- # this argument is a name
- msg = "%s (%s)" % (
- default.as_string(),
- DEFAULT_ARGUMENT_SYMBOLS[value.qname()],
- )
- self.add_message("dangerous-default-value", node=node, args=(msg,))
-
- @utils.check_messages("unreachable", "lost-exception")
- def visit_return(self, node):
- """1 - check is the node has a right sibling (if so, that's some
- unreachable code)
- 2 - check is the node is inside the finally clause of a try...finally
- block
- """
- self._check_unreachable(node)
- # Is it inside final body of a try...finally bloc ?
- self._check_not_in_finally(node, "return", (astroid.FunctionDef,))
-
- @utils.check_messages("unreachable")
- def visit_continue(self, node):
- """check is the node has a right sibling (if so, that's some unreachable
- code)
- """
- self._check_unreachable(node)
-
- @utils.check_messages("unreachable", "lost-exception")
- def visit_break(self, node):
- """1 - check is the node has a right sibling (if so, that's some
- unreachable code)
- 2 - check is the node is inside the finally clause of a try...finally
- block
- """
- # 1 - Is it right sibling ?
- self._check_unreachable(node)
- # 2 - Is it inside final body of a try...finally bloc ?
- self._check_not_in_finally(node, "break", (astroid.For, astroid.While))
-
- @utils.check_messages("unreachable")
- def visit_raise(self, node):
- """check if the node has a right sibling (if so, that's some unreachable
- code)
- """
- self._check_unreachable(node)
-
- @utils.check_messages("exec-used")
- def visit_exec(self, node):
- """just print a warning on exec statements"""
- self.add_message("exec-used", node=node)
-
- def _check_misplaced_format_function(self, call_node):
- if not isinstance(call_node.func, astroid.Attribute):
- return
- if call_node.func.attrname != "format":
- return
-
- expr = utils.safe_infer(call_node.func.expr)
- if expr is astroid.Uninferable:
- return
- if not expr:
- # we are doubtful on inferred type of node, so here just check if format
- # was called on print()
- call_expr = call_node.func.expr
- if not isinstance(call_expr, astroid.Call):
- return
- if (
- isinstance(call_expr.func, astroid.Name)
- and call_expr.func.name == "print"
- ):
- self.add_message("misplaced-format-function", node=call_node)
-
- @utils.check_messages(
- "eval-used", "exec-used", "bad-reversed-sequence", "misplaced-format-function"
- )
- def visit_call(self, node):
- """visit a Call node -> check if this is not a blacklisted builtin
- call and check for * or ** use
- """
- self._check_misplaced_format_function(node)
- if isinstance(node.func, astroid.Name):
- name = node.func.name
- # ignore the name if it's not a builtin (i.e. not defined in the
- # locals nor globals scope)
- if not (name in node.frame() or name in node.root()):
- if name == "exec":
- self.add_message("exec-used", node=node)
- elif name == "reversed":
- self._check_reversed(node)
- elif name == "eval":
- self.add_message("eval-used", node=node)
-
- @utils.check_messages("assert-on-tuple")
- def visit_assert(self, node):
- """check the use of an assert statement on a tuple."""
- if (
- node.fail is None
- and isinstance(node.test, astroid.Tuple)
- and len(node.test.elts) == 2
- ):
- self.add_message("assert-on-tuple", node=node)
-
- @utils.check_messages("duplicate-key")
- def visit_dict(self, node):
- """check duplicate key in dictionary"""
- keys = set()
- for k, _ in node.items:
- if isinstance(k, astroid.Const):
- key = k.value
- if key in keys:
- self.add_message("duplicate-key", node=node, args=key)
- keys.add(key)
-
- def visit_tryfinally(self, node):
- """update try...finally flag"""
- self._tryfinallys.append(node)
-
- def leave_tryfinally(self, node): # pylint: disable=unused-argument
- """update try...finally flag"""
- self._tryfinallys.pop()
-
- def _check_unreachable(self, node):
- """check unreachable code"""
- unreach_stmt = node.next_sibling()
- if unreach_stmt is not None:
- self.add_message("unreachable", node=unreach_stmt)
-
- def _check_not_in_finally(self, node, node_name, breaker_classes=()):
- """check that a node is not inside a finally clause of a
- try...finally statement.
- If we found before a try...finally bloc a parent which its type is
- in breaker_classes, we skip the whole check."""
- # if self._tryfinallys is empty, we're not an in try...finally block
- if not self._tryfinallys:
- return
- # the node could be a grand-grand...-children of the try...finally
- _parent = node.parent
- _node = node
- while _parent and not isinstance(_parent, breaker_classes):
- if hasattr(_parent, "finalbody") and _node in _parent.finalbody:
- self.add_message("lost-exception", node=node, args=node_name)
- return
- _node = _parent
- _parent = _node.parent
-
- def _check_reversed(self, node):
- """ check that the argument to `reversed` is a sequence """
- try:
- argument = utils.safe_infer(utils.get_argument_from_call(node, position=0))
- except utils.NoSuchArgumentError:
- pass
- else:
- if argument is astroid.Uninferable:
- return
- if argument is None:
- # Nothing was inferred.
- # Try to see if we have iter().
- if isinstance(node.args[0], astroid.Call):
- try:
- func = next(node.args[0].func.infer())
- except astroid.InferenceError:
- return
- if getattr(
- func, "name", None
- ) == "iter" and utils.is_builtin_object(func):
- self.add_message("bad-reversed-sequence", node=node)
- return
-
- if isinstance(argument, (astroid.List, astroid.Tuple)):
- return
-
- if isinstance(argument, astroid.Instance):
- if argument._proxied.name == "dict" and utils.is_builtin_object(
- argument._proxied
- ):
- self.add_message("bad-reversed-sequence", node=node)
- return
- if any(
- ancestor.name == "dict" and utils.is_builtin_object(ancestor)
- for ancestor in argument._proxied.ancestors()
- ):
- # Mappings aren't accepted by reversed(), unless
- # they provide explicitly a __reversed__ method.
- try:
- argument.locals[REVERSED_PROTOCOL_METHOD]
- except KeyError:
- self.add_message("bad-reversed-sequence", node=node)
- return
-
- if hasattr(argument, "getattr"):
- # everything else is not a proper sequence for reversed()
- for methods in REVERSED_METHODS:
- for meth in methods:
- try:
- argument.getattr(meth)
- except astroid.NotFoundError:
- break
- else:
- break
- else:
- self.add_message("bad-reversed-sequence", node=node)
- else:
- self.add_message("bad-reversed-sequence", node=node)
-
- @utils.check_messages("confusing-with-statement")
- def visit_with(self, node):
- # a "with" statement with multiple managers coresponds
- # to one AST "With" node with multiple items
- pairs = node.items
- if pairs:
- for prev_pair, pair in zip(pairs, pairs[1:]):
- if isinstance(prev_pair[1], astroid.AssignName) and (
- pair[1] is None and not isinstance(pair[0], astroid.Call)
- ):
- # Don't emit a message if the second is a function call
- # there's no way that can be mistaken for a name assignment.
- # If the line number doesn't match
- # we assume it's a nested "with".
- self.add_message("confusing-with-statement", node=node)
-
- def _check_self_assigning_variable(self, node):
- # Detect assigning to the same variable.
-
- scope = node.scope()
- scope_locals = scope.locals
-
- rhs_names = []
- targets = node.targets
- if isinstance(targets[0], astroid.Tuple):
- if len(targets) != 1:
- # A complex assignment, so bail out early.
- return
- targets = targets[0].elts
-
- if isinstance(node.value, astroid.Name):
- if len(targets) != 1:
- return
- rhs_names = [node.value]
- elif isinstance(node.value, astroid.Tuple):
- rhs_count = len(node.value.elts)
- if len(targets) != rhs_count or rhs_count == 1:
- return
- rhs_names = node.value.elts
-
- for target, lhs_name in zip(targets, rhs_names):
- if not isinstance(lhs_name, astroid.Name):
- continue
- if not isinstance(target, astroid.AssignName):
- continue
- if isinstance(scope, astroid.ClassDef) and target.name in scope_locals:
- # Check that the scope is different than a class level, which is usually
- # a pattern to expose module level attributes as class level ones.
- continue
- if target.name == lhs_name.name:
- self.add_message(
- "self-assigning-variable", args=(target.name,), node=target
- )
-
- def _check_redeclared_assign_name(self, targets):
- for target in targets:
- if not isinstance(target, astroid.Tuple):
- continue
-
- found_names = []
- for element in target.elts:
- if isinstance(element, astroid.Tuple):
- self._check_redeclared_assign_name([element])
- elif isinstance(element, astroid.AssignName) and element.name != "_":
- found_names.append(element.name)
-
- names = collections.Counter(found_names)
- for name, count in names.most_common():
- if count > 1:
- self.add_message(
- "redeclared-assigned-name", args=(name,), node=target
- )
-
- @utils.check_messages("self-assigning-variable", "redeclared-assigned-name")
- def visit_assign(self, node):
- self._check_self_assigning_variable(node)
- self._check_redeclared_assign_name(node.targets)
-
- @utils.check_messages("redeclared-assigned-name")
- def visit_for(self, node):
- self._check_redeclared_assign_name([node.target])
-
-
-KNOWN_NAME_TYPES = {
- "module",
- "const",
- "class",
- "function",
- "method",
- "attr",
- "argument",
- "variable",
- "class_attribute",
- "inlinevar",
-}
-
-
-HUMAN_READABLE_TYPES = {
- "module": "module",
- "const": "constant",
- "class": "class",
- "function": "function",
- "method": "method",
- "attr": "attribute",
- "argument": "argument",
- "variable": "variable",
- "class_attribute": "class attribute",
- "inlinevar": "inline iteration",
-}
-
-DEFAULT_NAMING_STYLES = {
- "module": "snake_case",
- "const": "UPPER_CASE",
- "class": "PascalCase",
- "function": "snake_case",
- "method": "snake_case",
- "attr": "snake_case",
- "argument": "snake_case",
- "variable": "snake_case",
- "class_attribute": "any",
- "inlinevar": "any",
-}
-
-
-def _create_naming_options():
- name_options = []
- for name_type in sorted(KNOWN_NAME_TYPES):
- human_readable_name = HUMAN_READABLE_TYPES[name_type]
- default_style = DEFAULT_NAMING_STYLES[name_type]
- name_type = name_type.replace("_", "-")
- name_options.append(
- (
- "%s-naming-style" % (name_type,),
- {
- "default": default_style,
- "type": "choice",
- "choices": list(NAMING_STYLES.keys()),
- "metavar": "<style>",
- "help": "Naming style matching correct %s names."
- % (human_readable_name,),
- },
- )
- )
- name_options.append(
- (
- "%s-rgx" % (name_type,),
- {
- "default": None,
- "type": "regexp",
- "metavar": "<regexp>",
- "help": "Regular expression matching correct %s names. Overrides %s-naming-style."
- % (human_readable_name, name_type),
- },
- )
- )
- return tuple(name_options)
-
-
-class NameChecker(_BasicChecker):
-
- msgs = {
- "C0102": (
- 'Black listed name "%s"',
- "blacklisted-name",
- "Used when the name is listed in the black list (unauthorized names).",
- ),
- "C0103": (
- '%s name "%s" doesn\'t conform to %s',
- "invalid-name",
- "Used when the name doesn't conform to naming rules "
- "associated to its type (constant, variable, class...).",
- ),
- "W0111": (
- "Name %s will become a keyword in Python %s",
- "assign-to-new-keyword",
- "Used when assignment will become invalid in future "
- "Python release due to introducing new keyword.",
- ),
- }
-
- options = (
- (
- "good-names",
- {
- "default": ("i", "j", "k", "ex", "Run", "_"),
- "type": "csv",
- "metavar": "<names>",
- "help": "Good variable names which should always be accepted,"
- " separated by a comma.",
- },
- ),
- (
- "bad-names",
- {
- "default": ("foo", "bar", "baz", "toto", "tutu", "tata"),
- "type": "csv",
- "metavar": "<names>",
- "help": "Bad variable names which should always be refused, "
- "separated by a comma.",
- },
- ),
- (
- "name-group",
- {
- "default": (),
- "type": "csv",
- "metavar": "<name1:name2>",
- "help": (
- "Colon-delimited sets of names that determine each"
- " other's naming style when the name regexes"
- " allow several styles."
- ),
- },
- ),
- (
- "include-naming-hint",
- {
- "default": False,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "Include a hint for the correct naming format with invalid-name.",
- },
- ),
- (
- "property-classes",
- {
- "default": ("abc.abstractproperty",),
- "type": "csv",
- "metavar": "<decorator names>",
- "help": "List of decorators that produce properties, such as "
- "abc.abstractproperty. Add to this list to register "
- "other decorators that produce valid properties. "
- "These decorators are taken in consideration only for invalid-name.",
- },
- ),
- ) + _create_naming_options()
-
- KEYWORD_ONSET = {(3, 7): {"async", "await"}}
-
- def __init__(self, linter):
- _BasicChecker.__init__(self, linter)
- self._name_category = {}
- self._name_group = {}
- self._bad_names = {}
- self._name_regexps = {}
- self._name_hints = {}
-
- def open(self):
- self.stats = self.linter.add_stats(
- badname_module=0,
- badname_class=0,
- badname_function=0,
- badname_method=0,
- badname_attr=0,
- badname_const=0,
- badname_variable=0,
- badname_inlinevar=0,
- badname_argument=0,
- badname_class_attribute=0,
- )
- for group in self.config.name_group:
- for name_type in group.split(":"):
- self._name_group[name_type] = "group_%s" % (group,)
-
- regexps, hints = self._create_naming_rules()
- self._name_regexps = regexps
- self._name_hints = hints
-
- def _create_naming_rules(self):
- regexps = {}
- hints = {}
-
- for name_type in KNOWN_NAME_TYPES:
- naming_style_option_name = "%s_naming_style" % (name_type,)
- naming_style_name = getattr(self.config, naming_style_option_name)
-
- regexps[name_type] = NAMING_STYLES[naming_style_name].get_regex(name_type)
-
- custom_regex_setting_name = "%s_rgx" % (name_type,)
- custom_regex = getattr(self.config, custom_regex_setting_name, None)
- if custom_regex is not None:
- regexps[name_type] = custom_regex
-
- if custom_regex is not None:
- hints[name_type] = "%r pattern" % custom_regex.pattern
- else:
- hints[name_type] = "%s naming style" % naming_style_name
-
- return regexps, hints
-
- @utils.check_messages("blacklisted-name", "invalid-name")
- def visit_module(self, node):
- self._check_name("module", node.name.split(".")[-1], node)
- self._bad_names = {}
-
- def leave_module(self, node): # pylint: disable=unused-argument
- for all_groups in self._bad_names.values():
- if len(all_groups) < 2:
- continue
- groups = collections.defaultdict(list)
- min_warnings = sys.maxsize
- for group in all_groups.values():
- groups[len(group)].append(group)
- min_warnings = min(len(group), min_warnings)
- if len(groups[min_warnings]) > 1:
- by_line = sorted(
- groups[min_warnings],
- key=lambda group: min(warning[0].lineno for warning in group),
- )
- warnings = itertools.chain(*by_line[1:])
- else:
- warnings = groups[min_warnings][0]
- for args in warnings:
- self._raise_name_warning(*args)
-
- @utils.check_messages("blacklisted-name", "invalid-name", "assign-to-new-keyword")
- def visit_classdef(self, node):
- self._check_assign_to_new_keyword_violation(node.name, node)
- self._check_name("class", node.name, node)
- for attr, anodes in node.instance_attrs.items():
- if not any(node.instance_attr_ancestors(attr)):
- self._check_name("attr", attr, anodes[0])
-
- @utils.check_messages("blacklisted-name", "invalid-name", "assign-to-new-keyword")
- def visit_functiondef(self, node):
- # Do not emit any warnings if the method is just an implementation
- # of a base class method.
- self._check_assign_to_new_keyword_violation(node.name, node)
- confidence = interfaces.HIGH
- if node.is_method():
- if utils.overrides_a_method(node.parent.frame(), node.name):
- return
- confidence = (
- interfaces.INFERENCE
- if utils.has_known_bases(node.parent.frame())
- else interfaces.INFERENCE_FAILURE
- )
-
- self._check_name(
- _determine_function_name_type(node, config=self.config),
- node.name,
- node,
- confidence,
- )
- # Check argument names
- args = node.args.args
- if args is not None:
- self._recursive_check_names(args, node)
-
- visit_asyncfunctiondef = visit_functiondef
-
- @utils.check_messages("blacklisted-name", "invalid-name")
- def visit_global(self, node):
- for name in node.names:
- self._check_name("const", name, node)
-
- @utils.check_messages("blacklisted-name", "invalid-name", "assign-to-new-keyword")
- def visit_assignname(self, node):
- """check module level assigned names"""
- self._check_assign_to_new_keyword_violation(node.name, node)
- frame = node.frame()
- assign_type = node.assign_type()
- if isinstance(assign_type, astroid.Comprehension):
- self._check_name("inlinevar", node.name, node)
- elif isinstance(frame, astroid.Module):
- if isinstance(assign_type, astroid.Assign) and not in_loop(assign_type):
- if isinstance(utils.safe_infer(assign_type.value), astroid.ClassDef):
- self._check_name("class", node.name, node)
- else:
- if not _redefines_import(node):
- # Don't emit if the name redefines an import
- # in an ImportError except handler.
- self._check_name("const", node.name, node)
- elif isinstance(assign_type, astroid.ExceptHandler):
- self._check_name("variable", node.name, node)
- elif isinstance(frame, astroid.FunctionDef):
- # global introduced variable aren't in the function locals
- if node.name in frame and node.name not in frame.argnames():
- if not _redefines_import(node):
- self._check_name("variable", node.name, node)
- elif isinstance(frame, astroid.ClassDef):
- if not list(frame.local_attr_ancestors(node.name)):
- self._check_name("class_attribute", node.name, node)
-
- def _recursive_check_names(self, args, node):
- """check names in a possibly recursive list <arg>"""
- for arg in args:
- if isinstance(arg, astroid.AssignName):
- self._check_name("argument", arg.name, node)
- else:
- self._recursive_check_names(arg.elts, node)
-
- def _find_name_group(self, node_type):
- return self._name_group.get(node_type, node_type)
-
- def _raise_name_warning(self, node, node_type, name, confidence):
- type_label = HUMAN_READABLE_TYPES[node_type]
- hint = self._name_hints[node_type]
- if self.config.include_naming_hint:
- hint += " (%r pattern)" % self._name_regexps[node_type].pattern
- args = (type_label.capitalize(), name, hint)
-
- self.add_message("invalid-name", node=node, args=args, confidence=confidence)
- self.stats["badname_" + node_type] += 1
-
- def _check_name(self, node_type, name, node, confidence=interfaces.HIGH):
- """check for a name using the type's regexp"""
-
- def _should_exempt_from_invalid_name(node):
- if node_type == "variable":
- inferred = utils.safe_infer(node)
- if isinstance(inferred, astroid.ClassDef):
- return True
- return False
-
- if utils.is_inside_except(node):
- clobbering, _ = utils.clobber_in_except(node)
- if clobbering:
- return
- if name in self.config.good_names:
- return
- if name in self.config.bad_names:
- self.stats["badname_" + node_type] += 1
- self.add_message("blacklisted-name", node=node, args=name)
- return
- regexp = self._name_regexps[node_type]
- match = regexp.match(name)
-
- if _is_multi_naming_match(match, node_type, confidence):
- name_group = self._find_name_group(node_type)
- bad_name_group = self._bad_names.setdefault(name_group, {})
- warnings = bad_name_group.setdefault(match.lastgroup, [])
- warnings.append((node, node_type, name, confidence))
-
- if match is None and not _should_exempt_from_invalid_name(node):
- self._raise_name_warning(node, node_type, name, confidence)
-
- def _check_assign_to_new_keyword_violation(self, name, node):
- keyword_first_version = self._name_became_keyword_in_version(
- name, self.KEYWORD_ONSET
- )
- if keyword_first_version is not None:
- self.add_message(
- "assign-to-new-keyword",
- node=node,
- args=(name, keyword_first_version),
- confidence=interfaces.HIGH,
- )
-
- @staticmethod
- def _name_became_keyword_in_version(name, rules):
- for version, keywords in rules.items():
- if name in keywords and sys.version_info < version:
- return ".".join(map(str, version))
- return None
-
-
-class DocStringChecker(_BasicChecker):
- msgs = {
- "C0112": (
- "Empty %s docstring",
- "empty-docstring",
- "Used when a module, function, class or method has an empty "
- "docstring (it would be too easy ;).",
- {"old_names": [("W0132", "old-empty-docstring")]},
- ),
- "C0114": (
- "Missing module docstring",
- "missing-module-docstring",
- "Used when a module has no docstring."
- "Empty modules do not require a docstring.",
- {"old_names": [("C0111", "missing-docstring")]},
- ),
- "C0115": (
- "Missing class docstring",
- "missing-class-docstring",
- "Used when a class has no docstring."
- "Even an empty class must have a docstring.",
- {"old_names": [("C0111", "missing-docstring")]},
- ),
- "C0116": (
- "Missing function or method docstring",
- "missing-function-docstring",
- "Used when a function or method has no docstring."
- "Some special methods like __init__ do not require a "
- "docstring.",
- {"old_names": [("C0111", "missing-docstring")]},
- ),
- }
- options = (
- (
- "no-docstring-rgx",
- {
- "default": NO_REQUIRED_DOC_RGX,
- "type": "regexp",
- "metavar": "<regexp>",
- "help": "Regular expression which should only match "
- "function or class names that do not require a "
- "docstring.",
- },
- ),
- (
- "docstring-min-length",
- {
- "default": -1,
- "type": "int",
- "metavar": "<int>",
- "help": (
- "Minimum line length for functions/classes that"
- " require docstrings, shorter ones are exempt."
- ),
- },
- ),
- )
-
- def open(self):
- self.stats = self.linter.add_stats(
- undocumented_module=0,
- undocumented_function=0,
- undocumented_method=0,
- undocumented_class=0,
- )
-
- @utils.check_messages("missing-docstring", "empty-docstring")
- def visit_module(self, node):
- self._check_docstring("module", node)
-
- @utils.check_messages("missing-docstring", "empty-docstring")
- def visit_classdef(self, node):
- if self.config.no_docstring_rgx.match(node.name) is None:
- self._check_docstring("class", node)
-
- @utils.check_messages("missing-docstring", "empty-docstring")
- def visit_functiondef(self, node):
- if self.config.no_docstring_rgx.match(node.name) is None:
- ftype = "method" if node.is_method() else "function"
- if is_property_setter_or_deleter(node):
- return
-
- if isinstance(node.parent.frame(), astroid.ClassDef):
- overridden = False
- confidence = (
- interfaces.INFERENCE
- if utils.has_known_bases(node.parent.frame())
- else interfaces.INFERENCE_FAILURE
- )
- # check if node is from a method overridden by its ancestor
- for ancestor in node.parent.frame().ancestors():
- if node.name in ancestor and isinstance(
- ancestor[node.name], astroid.FunctionDef
- ):
- overridden = True
- break
- self._check_docstring(
- ftype, node, report_missing=not overridden, confidence=confidence
- )
- elif isinstance(node.parent.frame(), astroid.Module):
- self._check_docstring(ftype, node)
- else:
- return
-
- visit_asyncfunctiondef = visit_functiondef
-
- def _check_docstring(
- self, node_type, node, report_missing=True, confidence=interfaces.HIGH
- ):
- """check the node has a non empty docstring"""
- docstring = node.doc
- if docstring is None:
- if not report_missing:
- return
- lines = utils.get_node_last_lineno(node) - node.lineno
-
- if node_type == "module" and not lines:
- # If the module has no body, there's no reason
- # to require a docstring.
- return
- max_lines = self.config.docstring_min_length
-
- if node_type != "module" and max_lines > -1 and lines < max_lines:
- return
- self.stats["undocumented_" + node_type] += 1
- if (
- node.body
- and isinstance(node.body[0], astroid.Expr)
- and isinstance(node.body[0].value, astroid.Call)
- ):
- # Most likely a string with a format call. Let's see.
- func = utils.safe_infer(node.body[0].value.func)
- if isinstance(func, astroid.BoundMethod) and isinstance(
- func.bound, astroid.Instance
- ):
- # Strings.
- if func.bound.name == "str":
- return
- if func.bound.name in ("str", "unicode", "bytes"):
- return
- if node_type == "module":
- message = "missing-module-docstring"
- elif node_type == "class":
- message = "missing-class-docstring"
- else:
- message = "missing-function-docstring"
- self.add_message(message, node=node, confidence=confidence)
- elif not docstring.strip():
- self.stats["undocumented_" + node_type] += 1
- self.add_message(
- "empty-docstring", node=node, args=(node_type,), confidence=confidence
- )
-
-
-class PassChecker(_BasicChecker):
- """check if the pass statement is really necessary"""
-
- msgs = {
- "W0107": (
- "Unnecessary pass statement",
- "unnecessary-pass",
- 'Used when a "pass" statement that can be avoided is encountered.',
- )
- }
-
- @utils.check_messages("unnecessary-pass")
- def visit_pass(self, node):
- if len(node.parent.child_sequence(node)) > 1 or (
- isinstance(node.parent, (astroid.ClassDef, astroid.FunctionDef))
- and (node.parent.doc is not None)
- ):
- self.add_message("unnecessary-pass", node=node)
-
-
-def _is_one_arg_pos_call(call):
- """Is this a call with exactly 1 argument,
- where that argument is positional?
- """
- return isinstance(call, astroid.Call) and len(call.args) == 1 and not call.keywords
-
-
-class ComparisonChecker(_BasicChecker):
- """Checks for comparisons
-
- - singleton comparison: 'expr == True', 'expr == False' and 'expr == None'
- - yoda condition: 'const "comp" right' where comp can be '==', '!=', '<',
- '<=', '>' or '>=', and right can be a variable, an attribute, a method or
- a function
- """
-
- msgs = {
- "C0121": (
- "Comparison to %s should be %s",
- "singleton-comparison",
- "Used when an expression is compared to singleton "
- "values like True, False or None.",
- ),
- "C0122": (
- "Comparison should be %s",
- "misplaced-comparison-constant",
- "Used when the constant is placed on the left side "
- "of a comparison. It is usually clearer in intent to "
- "place it in the right hand side of the comparison.",
- ),
- "C0123": (
- "Using type() instead of isinstance() for a typecheck.",
- "unidiomatic-typecheck",
- "The idiomatic way to perform an explicit typecheck in "
- "Python is to use isinstance(x, Y) rather than "
- "type(x) == Y, type(x) is Y. Though there are unusual "
- "situations where these give different results.",
- {"old_names": [("W0154", "old-unidiomatic-typecheck")]},
- ),
- "R0123": (
- "Comparison to literal",
- "literal-comparison",
- "Used when comparing an object to a literal, which is usually "
- "what you do not want to do, since you can compare to a different "
- "literal than what was expected altogether.",
- ),
- "R0124": (
- "Redundant comparison - %s",
- "comparison-with-itself",
- "Used when something is compared against itself.",
- ),
- "W0143": (
- "Comparing against a callable, did you omit the parenthesis?",
- "comparison-with-callable",
- "This message is emitted when pylint detects that a comparison with a "
- "callable was made, which might suggest that some parenthesis were omitted, "
- "resulting in potential unwanted behaviour.",
- ),
- }
-
- def _check_singleton_comparison(self, singleton, root_node, negative_check=False):
- if singleton.value is True:
- if not negative_check:
- suggestion = "just 'expr'"
- else:
- suggestion = "just 'not expr'"
- self.add_message(
- "singleton-comparison", node=root_node, args=(True, suggestion)
- )
- elif singleton.value is False:
- if not negative_check:
- suggestion = "'not expr'"
- else:
- suggestion = "'expr'"
- self.add_message(
- "singleton-comparison", node=root_node, args=(False, suggestion)
- )
- elif singleton.value is None:
- if not negative_check:
- suggestion = "'expr is None'"
- else:
- suggestion = "'expr is not None'"
- self.add_message(
- "singleton-comparison", node=root_node, args=(None, suggestion)
- )
-
- def _check_literal_comparison(self, literal, node):
- """Check if we compare to a literal, which is usually what we do not want to do."""
- nodes = (astroid.List, astroid.Tuple, astroid.Dict, astroid.Set)
- is_other_literal = isinstance(literal, nodes)
- is_const = False
- if isinstance(literal, astroid.Const):
- if isinstance(literal.value, bool) or literal.value is None:
- # Not interested in this values.
- return
- is_const = isinstance(literal.value, (bytes, str, int, float))
-
- if is_const or is_other_literal:
- self.add_message("literal-comparison", node=node)
-
- def _check_misplaced_constant(self, node, left, right, operator):
- if isinstance(right, astroid.Const):
- return
- operator = REVERSED_COMPS.get(operator, operator)
- suggestion = "%s %s %r" % (right.as_string(), operator, left.value)
- self.add_message("misplaced-comparison-constant", node=node, args=(suggestion,))
-
- def _check_logical_tautology(self, node):
- """Check if identifier is compared against itself.
- :param node: Compare node
- :type node: astroid.node_classes.Compare
- :Example:
- val = 786
- if val == val: # [comparison-with-itself]
- pass
- """
- left_operand = node.left
- right_operand = node.ops[0][1]
- operator = node.ops[0][0]
- if isinstance(left_operand, astroid.Const) and isinstance(
- right_operand, astroid.Const
- ):
- left_operand = left_operand.value
- right_operand = right_operand.value
- elif isinstance(left_operand, astroid.Name) and isinstance(
- right_operand, astroid.Name
- ):
- left_operand = left_operand.name
- right_operand = right_operand.name
-
- if left_operand == right_operand:
- suggestion = "%s %s %s" % (left_operand, operator, right_operand)
- self.add_message("comparison-with-itself", node=node, args=(suggestion,))
-
- def _check_callable_comparison(self, node):
- operator = node.ops[0][0]
- if operator not in COMPARISON_OPERATORS:
- return
-
- bare_callables = (astroid.FunctionDef, astroid.BoundMethod)
- left_operand, right_operand = node.left, node.ops[0][1]
- # this message should be emitted only when there is comparison of bare callable
- # with non bare callable.
- if (
- sum(
- 1
- for operand in (left_operand, right_operand)
- if isinstance(utils.safe_infer(operand), bare_callables)
- )
- == 1
- ):
- self.add_message("comparison-with-callable", node=node)
-
- @utils.check_messages(
- "singleton-comparison",
- "misplaced-comparison-constant",
- "unidiomatic-typecheck",
- "literal-comparison",
- "comparison-with-itself",
- "comparison-with-callable",
- )
- def visit_compare(self, node):
- self._check_callable_comparison(node)
- self._check_logical_tautology(node)
- self._check_unidiomatic_typecheck(node)
- # NOTE: this checker only works with binary comparisons like 'x == 42'
- # but not 'x == y == 42'
- if len(node.ops) != 1:
- return
-
- left = node.left
- operator, right = node.ops[0]
- if operator in COMPARISON_OPERATORS and isinstance(left, astroid.Const):
- self._check_misplaced_constant(node, left, right, operator)
-
- if operator == "==":
- if isinstance(left, astroid.Const):
- self._check_singleton_comparison(left, node)
- elif isinstance(right, astroid.Const):
- self._check_singleton_comparison(right, node)
- if operator == "!=":
- if isinstance(right, astroid.Const):
- self._check_singleton_comparison(right, node, negative_check=True)
- if operator in ("is", "is not"):
- self._check_literal_comparison(right, node)
-
- def _check_unidiomatic_typecheck(self, node):
- operator, right = node.ops[0]
- if operator in TYPECHECK_COMPARISON_OPERATORS:
- left = node.left
- if _is_one_arg_pos_call(left):
- self._check_type_x_is_y(node, left, operator, right)
-
- def _check_type_x_is_y(self, node, left, operator, right):
- """Check for expressions like type(x) == Y."""
- left_func = utils.safe_infer(left.func)
- if not (
- isinstance(left_func, astroid.ClassDef) and left_func.qname() == TYPE_QNAME
- ):
- return
-
- if operator in ("is", "is not") and _is_one_arg_pos_call(right):
- right_func = utils.safe_infer(right.func)
- if (
- isinstance(right_func, astroid.ClassDef)
- and right_func.qname() == TYPE_QNAME
- ):
- # type(x) == type(a)
- right_arg = utils.safe_infer(right.args[0])
- if not isinstance(right_arg, LITERAL_NODE_TYPES):
- # not e.g. type(x) == type([])
- return
- self.add_message("unidiomatic-typecheck", node=node)
-
-
-def register(linter):
- """required method to auto register this checker"""
- linter.register_checker(BasicErrorChecker(linter))
- linter.register_checker(BasicChecker(linter))
- linter.register_checker(NameChecker(linter))
- linter.register_checker(DocStringChecker(linter))
- linter.register_checker(PassChecker(linter))
- linter.register_checker(ComparisonChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/base_checker.py b/venv/Lib/site-packages/pylint/checkers/base_checker.py
deleted file mode 100644
index f2ae4e5..0000000
--- a/venv/Lib/site-packages/pylint/checkers/base_checker.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2013-2014 Google, Inc.
-# Copyright (c) 2013 buck@yelp.com <buck@yelp.com>
-# Copyright (c) 2014-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2017-2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-from inspect import cleandoc
-from typing import Any
-
-from pylint.config import OptionsProviderMixIn
-from pylint.constants import _MSG_ORDER, WarningScope
-from pylint.exceptions import InvalidMessageError
-from pylint.interfaces import UNDEFINED, IRawChecker, ITokenChecker, implements
-from pylint.message.message_definition import MessageDefinition
-from pylint.utils import get_rst_section, get_rst_title
-
-
-class BaseChecker(OptionsProviderMixIn):
-
- # checker name (you may reuse an existing one)
- name = None # type: str
- # options level (0 will be displaying in --help, 1 in --long-help)
- level = 1
- # ordered list of options to control the checker behaviour
- options = () # type: Any
- # messages issued by this checker
- msgs = {} # type: Any
- # reports issued by this checker
- reports = () # type: Any
- # mark this checker as enabled or not.
- enabled = True
-
- def __init__(self, linter=None):
- """checker instances should have the linter as argument
-
- :param ILinter linter: is an object implementing ILinter."""
- if self.name is not None:
- self.name = self.name.lower()
- OptionsProviderMixIn.__init__(self)
- self.linter = linter
-
- def __gt__(self, other):
- """Permit to sort a list of Checker by name."""
- return "{}{}".format(self.name, self.msgs).__gt__(
- "{}{}".format(other.name, other.msgs)
- )
-
- def __repr__(self):
- status = "Checker" if self.enabled else "Disabled checker"
- return "{} '{}' (responsible for '{}')".format(
- status, self.name, "', '".join(self.msgs.keys())
- )
-
- def __str__(self):
- """This might be incomplete because multiple class inheriting BaseChecker
- can have the same name. Cf MessageHandlerMixIn.get_full_documentation()"""
- return self.get_full_documentation(
- msgs=self.msgs, options=self.options_and_values(), reports=self.reports
- )
-
- def get_full_documentation(self, msgs, options, reports, doc=None, module=None):
- result = ""
- checker_title = "%s checker" % (self.name.replace("_", " ").title())
- if module:
- # Provide anchor to link against
- result += ".. _%s:\n\n" % module
- result += "%s\n" % get_rst_title(checker_title, "~")
- if module:
- result += "This checker is provided by ``%s``.\n" % module
- result += "Verbatim name of the checker is ``%s``.\n\n" % self.name
- if doc:
- # Provide anchor to link against
- result += get_rst_title("{} Documentation".format(checker_title), "^")
- result += "%s\n\n" % cleandoc(doc)
- # options might be an empty generator and not be False when casted to boolean
- options = list(options)
- if options:
- result += get_rst_title("{} Options".format(checker_title), "^")
- result += "%s\n" % get_rst_section(None, options)
- if msgs:
- result += get_rst_title("{} Messages".format(checker_title), "^")
- for msgid, msg in sorted(
- msgs.items(), key=lambda kv: (_MSG_ORDER.index(kv[0][0]), kv[1])
- ):
- msg = self.create_message_definition_from_tuple(msgid, msg)
- result += "%s\n" % msg.format_help(checkerref=False)
- result += "\n"
- if reports:
- result += get_rst_title("{} Reports".format(checker_title), "^")
- for report in reports:
- result += ":%s: %s\n" % report[:2]
- result += "\n"
- result += "\n"
- return result
-
- def add_message(
- self, msgid, line=None, node=None, args=None, confidence=None, col_offset=None
- ):
- if not confidence:
- confidence = UNDEFINED
- self.linter.add_message(msgid, line, node, args, confidence, col_offset)
-
- def check_consistency(self):
- """Check the consistency of msgid.
-
- msg ids for a checker should be a string of len 4, where the two first
- characters are the checker id and the two last the msg id in this
- checker.
-
- :raises InvalidMessageError: If the checker id in the messages are not
- always the same. """
- checker_id = None
- existing_ids = []
- for message in self.messages:
- if checker_id is not None and checker_id != message.msgid[1:3]:
- error_msg = "Inconsistent checker part in message id "
- error_msg += "'{}' (expected 'x{checker_id}xx' ".format(
- message.msgid, checker_id=checker_id
- )
- error_msg += "because we already had {existing_ids}).".format(
- existing_ids=existing_ids
- )
- raise InvalidMessageError(error_msg)
- checker_id = message.msgid[1:3]
- existing_ids.append(message.msgid)
-
- def create_message_definition_from_tuple(self, msgid, msg_tuple):
- if implements(self, (IRawChecker, ITokenChecker)):
- default_scope = WarningScope.LINE
- else:
- default_scope = WarningScope.NODE
- options = {}
- if len(msg_tuple) > 3:
- (msg, symbol, descr, options) = msg_tuple
- elif len(msg_tuple) > 2:
- (msg, symbol, descr) = msg_tuple
- else:
- error_msg = """Messages should have a msgid and a symbol. Something like this :
-
-"W1234": (
- "message",
- "message-symbol",
- "Message description with detail.",
- ...
-),
-"""
- raise InvalidMessageError(error_msg)
- options.setdefault("scope", default_scope)
- return MessageDefinition(self, msgid, msg, descr, symbol, **options)
-
- @property
- def messages(self) -> list:
- return [
- self.create_message_definition_from_tuple(msgid, msg_tuple)
- for msgid, msg_tuple in sorted(self.msgs.items())
- ]
-
- # dummy methods implementing the IChecker interface
-
- def get_message_definition(self, msgid):
- for message_definition in self.messages:
- if message_definition.msgid == msgid:
- return message_definition
- error_msg = "MessageDefinition for '{}' does not exists. ".format(msgid)
- error_msg += "Choose from {}.".format([m.msgid for m in self.messages])
- raise InvalidMessageError(error_msg)
-
- def open(self):
- """called before visiting project (i.e set of modules)"""
-
- def close(self):
- """called after visiting project (i.e set of modules)"""
-
-
-class BaseTokenChecker(BaseChecker):
- """Base class for checkers that want to have access to the token stream."""
-
- def process_tokens(self, tokens):
- """Should be overridden by subclasses."""
- raise NotImplementedError()
diff --git a/venv/Lib/site-packages/pylint/checkers/classes.py b/venv/Lib/site-packages/pylint/checkers/classes.py
deleted file mode 100644
index 9f5d099..0000000
--- a/venv/Lib/site-packages/pylint/checkers/classes.py
+++ /dev/null
@@ -1,1844 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2016 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2010 Maarten ter Huurne <maarten@treewalker.org>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com>
-# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2014 David Pursehouse <david.pursehouse@gmail.com>
-# Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016-2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2016 Anthony Foglia <afoglia@users.noreply.github.com>
-# Copyright (c) 2016 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2018 Ben Green <benhgreen@icloud.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""classes checker for Python code
-"""
-import collections
-from itertools import chain, zip_longest
-
-import astroid
-from astroid import decorators, objects
-from astroid.bases import BUILTINS, Generator
-from astroid.exceptions import DuplicateBasesError, InconsistentMroError
-from astroid.scoped_nodes import function_to_method
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import (
- PYMETHODS,
- SPECIAL_METHODS_PARAMS,
- check_messages,
- class_is_abstract,
- decorated_with,
- decorated_with_property,
- has_known_bases,
- is_attr_private,
- is_attr_protected,
- is_builtin_object,
- is_comprehension,
- is_iterable,
- is_property_setter,
- is_property_setter_or_deleter,
- is_protocol_class,
- node_frame_class,
- overrides_a_method,
- safe_infer,
- unimplemented_abstract_methods,
-)
-from pylint.interfaces import IAstroidChecker
-from pylint.utils import get_global_option
-
-NEXT_METHOD = "__next__"
-INVALID_BASE_CLASSES = {"bool", "range", "slice", "memoryview"}
-BUILTIN_DECORATORS = {"builtins.property", "builtins.classmethod"}
-
-# Dealing with useless override detection, with regard
-# to parameters vs arguments
-
-_CallSignature = collections.namedtuple(
- "_CallSignature", "args kws starred_args starred_kws"
-)
-_ParameterSignature = collections.namedtuple(
- "_ParameterSignature", "args kwonlyargs varargs kwargs"
-)
-
-
-def _signature_from_call(call):
- kws = {}
- args = []
- starred_kws = []
- starred_args = []
- for keyword in call.keywords or []:
- arg, value = keyword.arg, keyword.value
- if arg is None and isinstance(value, astroid.Name):
- # Starred node and we are interested only in names,
- # otherwise some transformation might occur for the parameter.
- starred_kws.append(value.name)
- elif isinstance(value, astroid.Name):
- kws[arg] = value.name
- else:
- kws[arg] = None
-
- for arg in call.args:
- if isinstance(arg, astroid.Starred) and isinstance(arg.value, astroid.Name):
- # Positional variadic and a name, otherwise some transformation
- # might have occurred.
- starred_args.append(arg.value.name)
- elif isinstance(arg, astroid.Name):
- args.append(arg.name)
- else:
- args.append(None)
-
- return _CallSignature(args, kws, starred_args, starred_kws)
-
-
-def _signature_from_arguments(arguments):
- kwarg = arguments.kwarg
- vararg = arguments.vararg
- args = [arg.name for arg in arguments.args if arg.name != "self"]
- kwonlyargs = [arg.name for arg in arguments.kwonlyargs]
- return _ParameterSignature(args, kwonlyargs, vararg, kwarg)
-
-
-def _definition_equivalent_to_call(definition, call):
- """Check if a definition signature is equivalent to a call."""
- if definition.kwargs:
- same_kw_variadics = definition.kwargs in call.starred_kws
- else:
- same_kw_variadics = not call.starred_kws
- if definition.varargs:
- same_args_variadics = definition.varargs in call.starred_args
- else:
- same_args_variadics = not call.starred_args
- same_kwonlyargs = all(kw in call.kws for kw in definition.kwonlyargs)
- same_args = definition.args == call.args
-
- no_additional_kwarg_arguments = True
- if call.kws:
- for keyword in call.kws:
- is_arg = keyword in call.args
- is_kwonly = keyword in definition.kwonlyargs
- if not is_arg and not is_kwonly:
- # Maybe this argument goes into **kwargs,
- # or it is an extraneous argument.
- # In any case, the signature is different than
- # the call site, which stops our search.
- no_additional_kwarg_arguments = False
- break
-
- return all(
- (
- same_args,
- same_kwonlyargs,
- same_args_variadics,
- same_kw_variadics,
- no_additional_kwarg_arguments,
- )
- )
-
-
-# Deal with parameters overridding in two methods.
-
-
-def _positional_parameters(method):
- positional = method.args.args
- if method.type in ("classmethod", "method"):
- positional = positional[1:]
- return positional
-
-
-def _get_node_type(node, potential_types):
- """
- Return the type of the node if it exists in potential_types.
-
- Args:
- node (astroid.node): node to get the type of.
- potential_types (tuple): potential types of the node.
-
- Returns:
- type: type of the node or None.
- """
- for potential_type in potential_types:
- if isinstance(node, potential_type):
- return potential_type
- return None
-
-
-def _check_arg_equality(node_a, node_b, attr_name):
- """
- Check equality of nodes based on the comparison of their attributes named attr_name.
-
- Args:
- node_a (astroid.node): first node to compare.
- node_b (astroid.node): second node to compare.
- attr_name (str): name of the nodes attribute to use for comparison.
-
- Returns:
- bool: True if node_a.attr_name == node_b.attr_name, False otherwise.
- """
- return getattr(node_a, attr_name) == getattr(node_b, attr_name)
-
-
-def _has_different_parameters_default_value(original, overridden):
- """
- Check if original and overridden methods arguments have different default values
-
- Return True if one of the overridden arguments has a default
- value different from the default value of the original argument
- If one of the method doesn't have argument (.args is None)
- return False
- """
- if original.args is None or overridden.args is None:
- return False
-
- all_args = chain(original.args, original.kwonlyargs)
- original_param_names = [param.name for param in all_args]
- default_missing = object()
- for param_name in original_param_names:
- try:
- original_default = original.default_value(param_name)
- except astroid.exceptions.NoDefault:
- original_default = default_missing
- try:
- overridden_default = overridden.default_value(param_name)
- except astroid.exceptions.NoDefault:
- overridden_default = default_missing
-
- default_list = [
- arg == default_missing for arg in (original_default, overridden_default)
- ]
- if any(default_list) and not all(default_list):
- # Only one arg has no default value
- return True
-
- astroid_type_compared_attr = {
- astroid.Const: "value",
- astroid.ClassDef: "name",
- astroid.Tuple: "elts",
- astroid.List: "elts",
- }
- handled_types = tuple(
- astroid_type for astroid_type in astroid_type_compared_attr
- )
- original_type = _get_node_type(original_default, handled_types)
- if original_type:
- #  We handle only astroid types that are inside the dict astroid_type_compared_attr
- if not isinstance(overridden_default, original_type):
- #  Two args with same name but different types
- return True
- if not _check_arg_equality(
- original_default,
- overridden_default,
- astroid_type_compared_attr[original_type],
- ):
- # Two args with same type but different values
- return True
- return False
-
-
-def _has_different_parameters(original, overridden, dummy_parameter_regex):
- zipped = zip_longest(original, overridden)
- for original_param, overridden_param in zipped:
- params = (original_param, overridden_param)
- if not all(params):
- return True
-
- names = [param.name for param in params]
- if any(map(dummy_parameter_regex.match, names)):
- continue
- if original_param.name != overridden_param.name:
- return True
- return False
-
-
-def _different_parameters(original, overridden, dummy_parameter_regex):
- """Determine if the two methods have different parameters
-
- They are considered to have different parameters if:
-
- * they have different positional parameters, including different names
-
- * one of the methods is having variadics, while the other is not
-
- * they have different keyword only parameters.
-
- """
- original_parameters = _positional_parameters(original)
- overridden_parameters = _positional_parameters(overridden)
-
- different_positional = _has_different_parameters(
- original_parameters, overridden_parameters, dummy_parameter_regex
- )
- different_kwonly = _has_different_parameters(
- original.args.kwonlyargs, overridden.args.kwonlyargs, dummy_parameter_regex
- )
- if original.name in PYMETHODS:
- # Ignore the difference for special methods. If the parameter
- # numbers are different, then that is going to be caught by
- # unexpected-special-method-signature.
- # If the names are different, it doesn't matter, since they can't
- # be used as keyword arguments anyway.
- different_positional = different_kwonly = False
-
- # Both or none should have extra variadics, otherwise the method
- # loses or gains capabilities that are not reflected into the parent method,
- # leading to potential inconsistencies in the code.
- different_kwarg = (
- sum(1 for param in (original.args.kwarg, overridden.args.kwarg) if not param)
- == 1
- )
- different_vararg = (
- sum(1 for param in (original.args.vararg, overridden.args.vararg) if not param)
- == 1
- )
-
- return any(
- (different_positional, different_kwarg, different_vararg, different_kwonly)
- )
-
-
-def _is_invalid_base_class(cls):
- return cls.name in INVALID_BASE_CLASSES and is_builtin_object(cls)
-
-
-def _has_data_descriptor(cls, attr):
- attributes = cls.getattr(attr)
- for attribute in attributes:
- try:
- for inferred in attribute.infer():
- if isinstance(inferred, astroid.Instance):
- try:
- inferred.getattr("__get__")
- inferred.getattr("__set__")
- except astroid.NotFoundError:
- continue
- else:
- return True
- except astroid.InferenceError:
- # Can't infer, avoid emitting a false positive in this case.
- return True
- return False
-
-
-def _called_in_methods(func, klass, methods):
- """ Check if the func was called in any of the given methods,
- belonging to the *klass*. Returns True if so, False otherwise.
- """
- if not isinstance(func, astroid.FunctionDef):
- return False
- for method in methods:
- try:
- inferred = klass.getattr(method)
- except astroid.NotFoundError:
- continue
- for infer_method in inferred:
- for call in infer_method.nodes_of_class(astroid.Call):
- try:
- bound = next(call.func.infer())
- except (astroid.InferenceError, StopIteration):
- continue
- if not isinstance(bound, astroid.BoundMethod):
- continue
- func_obj = bound._proxied
- if isinstance(func_obj, astroid.UnboundMethod):
- func_obj = func_obj._proxied
- if func_obj.name == func.name:
- return True
- return False
-
-
-def _is_attribute_property(name, klass):
- """ Check if the given attribute *name* is a property
- in the given *klass*.
-
- It will look for `property` calls or for functions
- with the given name, decorated by `property` or `property`
- subclasses.
- Returns ``True`` if the name is a property in the given klass,
- ``False`` otherwise.
- """
-
- try:
- attributes = klass.getattr(name)
- except astroid.NotFoundError:
- return False
- property_name = "{}.property".format(BUILTINS)
- for attr in attributes:
- if attr is astroid.Uninferable:
- continue
- try:
- inferred = next(attr.infer())
- except astroid.InferenceError:
- continue
- if isinstance(inferred, astroid.FunctionDef) and decorated_with_property(
- inferred
- ):
- return True
- if inferred.pytype() == property_name:
- return True
- return False
-
-
-def _has_bare_super_call(fundef_node):
- for call in fundef_node.nodes_of_class(astroid.Call):
- func = call.func
- if isinstance(func, astroid.Name) and func.name == "super" and not call.args:
- return True
- return False
-
-
-def _safe_infer_call_result(node, caller, context=None):
- """
- Safely infer the return value of a function.
-
- Returns None if inference failed or if there is some ambiguity (more than
- one node has been inferred). Otherwise returns inferred value.
- """
- try:
- inferit = node.infer_call_result(caller, context=context)
- value = next(inferit)
- except astroid.InferenceError:
- return None # inference failed
- except StopIteration:
- return None # no values inferred
- try:
- next(inferit)
- return None # there is ambiguity on the inferred node
- except astroid.InferenceError:
- return None # there is some kind of ambiguity
- except StopIteration:
- return value
-
-
-def _has_same_layout_slots(slots, assigned_value):
- inferred = next(assigned_value.infer())
- if isinstance(inferred, astroid.ClassDef):
- other_slots = inferred.slots()
- if all(
- first_slot and second_slot and first_slot.value == second_slot.value
- for (first_slot, second_slot) in zip_longest(slots, other_slots)
- ):
- return True
- return False
-
-
-MSGS = {
- "F0202": (
- "Unable to check methods signature (%s / %s)",
- "method-check-failed",
- "Used when Pylint has been unable to check methods signature "
- "compatibility for an unexpected reason. Please report this kind "
- "if you don't make sense of it.",
- ),
- "E0202": (
- "An attribute defined in %s line %s hides this method",
- "method-hidden",
- "Used when a class defines a method which is hidden by an "
- "instance attribute from an ancestor class or set by some "
- "client code.",
- ),
- "E0203": (
- "Access to member %r before its definition line %s",
- "access-member-before-definition",
- "Used when an instance member is accessed before it's actually assigned.",
- ),
- "W0201": (
- "Attribute %r defined outside __init__",
- "attribute-defined-outside-init",
- "Used when an instance attribute is defined outside the __init__ method.",
- ),
- "W0212": (
- "Access to a protected member %s of a client class", # E0214
- "protected-access",
- "Used when a protected member (i.e. class member with a name "
- "beginning with an underscore) is access outside the class or a "
- "descendant of the class where it's defined.",
- ),
- "E0211": (
- "Method has no argument",
- "no-method-argument",
- "Used when a method which should have the bound instance as "
- "first argument has no argument defined.",
- ),
- "E0213": (
- 'Method should have "self" as first argument',
- "no-self-argument",
- 'Used when a method has an attribute different the "self" as '
- "first argument. This is considered as an error since this is "
- "a so common convention that you shouldn't break it!",
- ),
- "C0202": (
- "Class method %s should have %s as first argument",
- "bad-classmethod-argument",
- "Used when a class method has a first argument named differently "
- "than the value specified in valid-classmethod-first-arg option "
- '(default to "cls"), recommended to easily differentiate them '
- "from regular instance methods.",
- ),
- "C0203": (
- "Metaclass method %s should have %s as first argument",
- "bad-mcs-method-argument",
- "Used when a metaclass method has a first argument named "
- "differently than the value specified in valid-classmethod-first"
- '-arg option (default to "cls"), recommended to easily '
- "differentiate them from regular instance methods.",
- ),
- "C0204": (
- "Metaclass class method %s should have %s as first argument",
- "bad-mcs-classmethod-argument",
- "Used when a metaclass class method has a first argument named "
- "differently than the value specified in valid-metaclass-"
- 'classmethod-first-arg option (default to "mcs"), recommended to '
- "easily differentiate them from regular instance methods.",
- ),
- "W0211": (
- "Static method with %r as first argument",
- "bad-staticmethod-argument",
- 'Used when a static method has "self" or a value specified in '
- "valid-classmethod-first-arg option or "
- "valid-metaclass-classmethod-first-arg option as first argument.",
- ),
- "R0201": (
- "Method could be a function",
- "no-self-use",
- "Used when a method doesn't use its bound instance, and so could "
- "be written as a function.",
- ),
- "W0221": (
- "Parameters differ from %s %r method",
- "arguments-differ",
- "Used when a method has a different number of arguments than in "
- "the implemented interface or in an overridden method.",
- ),
- "W0222": (
- "Signature differs from %s %r method",
- "signature-differs",
- "Used when a method signature is different than in the "
- "implemented interface or in an overridden method.",
- ),
- "W0223": (
- "Method %r is abstract in class %r but is not overridden",
- "abstract-method",
- "Used when an abstract method (i.e. raise NotImplementedError) is "
- "not overridden in concrete class.",
- ),
- "W0231": (
- "__init__ method from base class %r is not called",
- "super-init-not-called",
- "Used when an ancestor class method has an __init__ method "
- "which is not called by a derived class.",
- ),
- "W0232": (
- "Class has no __init__ method",
- "no-init",
- "Used when a class has no __init__ method, neither its parent classes.",
- ),
- "W0233": (
- "__init__ method from a non direct base class %r is called",
- "non-parent-init-called",
- "Used when an __init__ method is called on a class which is not "
- "in the direct ancestors for the analysed class.",
- ),
- "W0235": (
- "Useless super delegation in method %r",
- "useless-super-delegation",
- "Used whenever we can detect that an overridden method is useless, "
- "relying on super() delegation to do the same thing as another method "
- "from the MRO.",
- ),
- "W0236": (
- "Method %r was expected to be %r, found it instead as %r",
- "invalid-overridden-method",
- "Used when we detect that a method was overridden as a property "
- "or the other way around, which could result in potential bugs at "
- "runtime.",
- ),
- "E0236": (
- "Invalid object %r in __slots__, must contain only non empty strings",
- "invalid-slots-object",
- "Used when an invalid (non-string) object occurs in __slots__.",
- ),
- "E0237": (
- "Assigning to attribute %r not defined in class slots",
- "assigning-non-slot",
- "Used when assigning to an attribute not defined in the class slots.",
- ),
- "E0238": (
- "Invalid __slots__ object",
- "invalid-slots",
- "Used when an invalid __slots__ is found in class. "
- "Only a string, an iterable or a sequence is permitted.",
- ),
- "E0239": (
- "Inheriting %r, which is not a class.",
- "inherit-non-class",
- "Used when a class inherits from something which is not a class.",
- ),
- "E0240": (
- "Inconsistent method resolution order for class %r",
- "inconsistent-mro",
- "Used when a class has an inconsistent method resolution order.",
- ),
- "E0241": (
- "Duplicate bases for class %r",
- "duplicate-bases",
- "Used when a class has duplicate bases.",
- ),
- "E0242": (
- "Value %r in slots conflicts with class variable",
- "class-variable-slots-conflict",
- "Used when a value in __slots__ conflicts with a class variable, property or method.",
- ),
- "R0202": (
- "Consider using a decorator instead of calling classmethod",
- "no-classmethod-decorator",
- "Used when a class method is defined without using the decorator syntax.",
- ),
- "R0203": (
- "Consider using a decorator instead of calling staticmethod",
- "no-staticmethod-decorator",
- "Used when a static method is defined without using the decorator syntax.",
- ),
- "C0205": (
- "Class __slots__ should be a non-string iterable",
- "single-string-used-for-slots",
- "Used when a class __slots__ is a simple string, rather than an iterable.",
- ),
- "R0205": (
- "Class %r inherits from object, can be safely removed from bases in python3",
- "useless-object-inheritance",
- "Used when a class inherit from object, which under python3 is implicit, "
- "hence can be safely removed from bases.",
- ),
- "R0206": (
- "Cannot have defined parameters for properties",
- "property-with-parameters",
- "Used when we detect that a property also has parameters, which are useless, "
- "given that properties cannot be called with additional arguments.",
- ),
-}
-
-
-class ScopeAccessMap:
- """Store the accessed variables per scope."""
-
- def __init__(self):
- self._scopes = collections.defaultdict(lambda: collections.defaultdict(list))
-
- def set_accessed(self, node):
- """Set the given node as accessed."""
-
- frame = node_frame_class(node)
- if frame is None:
- # The node does not live in a class.
- return
- self._scopes[frame][node.attrname].append(node)
-
- def accessed(self, scope):
- """Get the accessed variables for the given scope."""
- return self._scopes.get(scope, {})
-
-
-class ClassChecker(BaseChecker):
- """checks for :
- * methods without self as first argument
- * overridden methods signature
- * access only to existent members via self
- * attributes not defined in the __init__ method
- * unreachable code
- """
-
- __implements__ = (IAstroidChecker,)
-
- # configuration section name
- name = "classes"
- # messages
- msgs = MSGS
- priority = -2
- # configuration options
- options = (
- (
- "defining-attr-methods",
- {
- "default": ("__init__", "__new__", "setUp", "__post_init__"),
- "type": "csv",
- "metavar": "<method names>",
- "help": "List of method names used to declare (i.e. assign) \
-instance attributes.",
- },
- ),
- (
- "valid-classmethod-first-arg",
- {
- "default": ("cls",),
- "type": "csv",
- "metavar": "<argument names>",
- "help": "List of valid names for the first argument in \
-a class method.",
- },
- ),
- (
- "valid-metaclass-classmethod-first-arg",
- {
- "default": ("cls",),
- "type": "csv",
- "metavar": "<argument names>",
- "help": "List of valid names for the first argument in \
-a metaclass class method.",
- },
- ),
- (
- "exclude-protected",
- {
- "default": (
- # namedtuple public API.
- "_asdict",
- "_fields",
- "_replace",
- "_source",
- "_make",
- ),
- "type": "csv",
- "metavar": "<protected access exclusions>",
- "help": (
- "List of member names, which should be excluded "
- "from the protected access warning."
- ),
- },
- ),
- )
-
- def __init__(self, linter=None):
- BaseChecker.__init__(self, linter)
- self._accessed = ScopeAccessMap()
- self._first_attrs = []
- self._meth_could_be_func = None
-
- @decorators.cachedproperty
- def _dummy_rgx(self):
- return get_global_option(self, "dummy-variables-rgx", default=None)
-
- @decorators.cachedproperty
- def _ignore_mixin(self):
- return get_global_option(self, "ignore-mixin-members", default=True)
-
- @check_messages(
- "abstract-method",
- "no-init",
- "invalid-slots",
- "single-string-used-for-slots",
- "invalid-slots-object",
- "class-variable-slots-conflict",
- "inherit-non-class",
- "useless-object-inheritance",
- "inconsistent-mro",
- "duplicate-bases",
- )
- def visit_classdef(self, node):
- """init visit variable _accessed
- """
- self._check_bases_classes(node)
- # if not an exception or a metaclass
- if node.type == "class" and has_known_bases(node):
- try:
- node.local_attr("__init__")
- except astroid.NotFoundError:
- self.add_message("no-init", args=node, node=node)
- self._check_slots(node)
- self._check_proper_bases(node)
- self._check_consistent_mro(node)
-
- def _check_consistent_mro(self, node):
- """Detect that a class has a consistent mro or duplicate bases."""
- try:
- node.mro()
- except InconsistentMroError:
- self.add_message("inconsistent-mro", args=node.name, node=node)
- except DuplicateBasesError:
- self.add_message("duplicate-bases", args=node.name, node=node)
- except NotImplementedError:
- # Old style class, there's no mro so don't do anything.
- pass
-
- def _check_proper_bases(self, node):
- """
- Detect that a class inherits something which is not
- a class or a type.
- """
- for base in node.bases:
- ancestor = safe_infer(base)
- if ancestor in (astroid.Uninferable, None):
- continue
- if isinstance(ancestor, astroid.Instance) and ancestor.is_subtype_of(
- "%s.type" % (BUILTINS,)
- ):
- continue
-
- if not isinstance(ancestor, astroid.ClassDef) or _is_invalid_base_class(
- ancestor
- ):
- self.add_message("inherit-non-class", args=base.as_string(), node=node)
-
- if ancestor.name == object.__name__:
- self.add_message(
- "useless-object-inheritance", args=node.name, node=node
- )
-
- def leave_classdef(self, cnode):
- """close a class node:
- check that instance attributes are defined in __init__ and check
- access to existent members
- """
- # check access to existent members on non metaclass classes
- if self._ignore_mixin and cnode.name[-5:].lower() == "mixin":
- # We are in a mixin class. No need to try to figure out if
- # something is missing, since it is most likely that it will
- # miss.
- return
-
- accessed = self._accessed.accessed(cnode)
- if cnode.type != "metaclass":
- self._check_accessed_members(cnode, accessed)
- # checks attributes are defined in an allowed method such as __init__
- if not self.linter.is_message_enabled("attribute-defined-outside-init"):
- return
- defining_methods = self.config.defining_attr_methods
- current_module = cnode.root()
- for attr, nodes in cnode.instance_attrs.items():
- # Exclude `__dict__` as it is already defined.
- if attr == "__dict__":
- continue
-
- # Skip nodes which are not in the current module and it may screw up
- # the output, while it's not worth it
- nodes = [
- n
- for n in nodes
- if not isinstance(n.statement(), (astroid.Delete, astroid.AugAssign))
- and n.root() is current_module
- ]
- if not nodes:
- continue # error detected by typechecking
-
- # Check if any method attr is defined in is a defining method
- # or if we have the attribute defined in a setter.
- frames = (node.frame() for node in nodes)
- if any(
- frame.name in defining_methods or is_property_setter(frame)
- for frame in frames
- ):
- continue
-
- # check attribute is defined in a parent's __init__
- for parent in cnode.instance_attr_ancestors(attr):
- attr_defined = False
- # check if any parent method attr is defined in is a defining method
- for node in parent.instance_attrs[attr]:
- if node.frame().name in defining_methods:
- attr_defined = True
- if attr_defined:
- # we're done :)
- break
- else:
- # check attribute is defined as a class attribute
- try:
- cnode.local_attr(attr)
- except astroid.NotFoundError:
- for node in nodes:
- if node.frame().name not in defining_methods:
- # If the attribute was set by a call in any
- # of the defining methods, then don't emit
- # the warning.
- if _called_in_methods(
- node.frame(), cnode, defining_methods
- ):
- continue
- self.add_message(
- "attribute-defined-outside-init", args=attr, node=node
- )
-
- def visit_functiondef(self, node):
- """check method arguments, overriding"""
- # ignore actual functions
- if not node.is_method():
- return
-
- self._check_useless_super_delegation(node)
- self._check_property_with_parameters(node)
-
- klass = node.parent.frame()
- self._meth_could_be_func = True
- # check first argument is self if this is actually a method
- self._check_first_arg_for_type(node, klass.type == "metaclass")
- if node.name == "__init__":
- self._check_init(node)
- return
- # check signature if the method overloads inherited method
- for overridden in klass.local_attr_ancestors(node.name):
- # get astroid for the searched method
- try:
- parent_function = overridden[node.name]
- except KeyError:
- # we have found the method but it's not in the local
- # dictionary.
- # This may happen with astroid build from living objects
- continue
- if not isinstance(parent_function, astroid.FunctionDef):
- continue
- self._check_signature(node, parent_function, "overridden", klass)
- self._check_invalid_overridden_method(node, parent_function)
- break
-
- if node.decorators:
- for decorator in node.decorators.nodes:
- if isinstance(decorator, astroid.Attribute) and decorator.attrname in (
- "getter",
- "setter",
- "deleter",
- ):
- # attribute affectation will call this method, not hiding it
- return
- if isinstance(decorator, astroid.Name):
- if decorator.name == "property":
- # attribute affectation will either call a setter or raise
- # an attribute error, anyway not hiding the function
- return
-
- # Infer the decorator and see if it returns something useful
- inferred = safe_infer(decorator)
- if not inferred:
- return
- if isinstance(inferred, astroid.FunctionDef):
- # Okay, it's a decorator, let's see what it can infer.
- try:
- inferred = next(inferred.infer_call_result(inferred))
- except astroid.InferenceError:
- return
- try:
- if (
- isinstance(inferred, (astroid.Instance, astroid.ClassDef))
- and inferred.getattr("__get__")
- and inferred.getattr("__set__")
- ):
- return
- except astroid.AttributeInferenceError:
- pass
-
- # check if the method is hidden by an attribute
- try:
- overridden = klass.instance_attr(node.name)[0]
- overridden_frame = overridden.frame()
- if (
- isinstance(overridden_frame, astroid.FunctionDef)
- and overridden_frame.type == "method"
- ):
- overridden_frame = overridden_frame.parent.frame()
- if isinstance(overridden_frame, astroid.ClassDef) and klass.is_subtype_of(
- overridden_frame.qname()
- ):
- args = (overridden.root().name, overridden.fromlineno)
- self.add_message("method-hidden", args=args, node=node)
- except astroid.NotFoundError:
- pass
-
- visit_asyncfunctiondef = visit_functiondef
-
- def _check_useless_super_delegation(self, function):
- """Check if the given function node is an useless method override
-
- We consider it *useless* if it uses the super() builtin, but having
- nothing additional whatsoever than not implementing the method at all.
- If the method uses super() to delegate an operation to the rest of the MRO,
- and if the method called is the same as the current one, the arguments
- passed to super() are the same as the parameters that were passed to
- this method, then the method could be removed altogether, by letting
- other implementation to take precedence.
- """
-
- if (
- not function.is_method()
- # With decorators is a change of use
- or function.decorators
- ):
- return
-
- body = function.body
- if len(body) != 1:
- # Multiple statements, which means this overridden method
- # could do multiple things we are not aware of.
- return
-
- statement = body[0]
- if not isinstance(statement, (astroid.Expr, astroid.Return)):
- # Doing something else than what we are interested into.
- return
-
- call = statement.value
- if (
- not isinstance(call, astroid.Call)
- # Not a super() attribute access.
- or not isinstance(call.func, astroid.Attribute)
- ):
- return
-
- # Should be a super call.
- try:
- super_call = next(call.func.expr.infer())
- except astroid.InferenceError:
- return
- else:
- if not isinstance(super_call, objects.Super):
- return
-
- # The name should be the same.
- if call.func.attrname != function.name:
- return
-
- # Should be a super call with the MRO pointer being the
- # current class and the type being the current instance.
- current_scope = function.parent.scope()
- if (
- super_call.mro_pointer != current_scope
- or not isinstance(super_call.type, astroid.Instance)
- or super_call.type.name != current_scope.name
- ):
- return
-
- #  Check values of default args
- klass = function.parent.frame()
- meth_node = None
- for overridden in klass.local_attr_ancestors(function.name):
- # get astroid for the searched method
- try:
- meth_node = overridden[function.name]
- except KeyError:
- # we have found the method but it's not in the local
- # dictionary.
- # This may happen with astroid build from living objects
- continue
- if (
- not isinstance(meth_node, astroid.FunctionDef)
- # If the method have an ancestor which is not a
- # function then it is legitimate to redefine it
- or _has_different_parameters_default_value(
- meth_node.args, function.args
- )
- ):
- return
- break
-
- # Detect if the parameters are the same as the call's arguments.
- params = _signature_from_arguments(function.args)
- args = _signature_from_call(call)
-
- if meth_node is not None:
-
- def form_annotations(annotations):
- return [
- annotation.as_string() for annotation in filter(None, annotations)
- ]
-
- called_annotations = form_annotations(function.args.annotations)
- overridden_annotations = form_annotations(meth_node.args.annotations)
- if called_annotations and overridden_annotations:
- if called_annotations != overridden_annotations:
- return
-
- if _definition_equivalent_to_call(params, args):
- self.add_message(
- "useless-super-delegation", node=function, args=(function.name,)
- )
-
- def _check_property_with_parameters(self, node):
- if node.args.args and len(node.args.args) > 1 and decorated_with_property(node):
- self.add_message("property-with-parameters", node=node)
-
- def _check_invalid_overridden_method(self, function_node, parent_function_node):
- parent_is_property = decorated_with_property(
- parent_function_node
- ) or is_property_setter_or_deleter(parent_function_node)
- current_is_property = decorated_with_property(
- function_node
- ) or is_property_setter_or_deleter(function_node)
- if parent_is_property and not current_is_property:
- self.add_message(
- "invalid-overridden-method",
- args=(function_node.name, "property", function_node.type),
- node=function_node,
- )
- elif not parent_is_property and current_is_property:
- self.add_message(
- "invalid-overridden-method",
- args=(function_node.name, "method", "property"),
- node=function_node,
- )
-
- def _check_slots(self, node):
- if "__slots__" not in node.locals:
- return
- for slots in node.igetattr("__slots__"):
- # check if __slots__ is a valid type
- if slots is astroid.Uninferable:
- continue
- if not is_iterable(slots) and not is_comprehension(slots):
- self.add_message("invalid-slots", node=node)
- continue
-
- if isinstance(slots, astroid.Const):
- # a string, ignore the following checks
- self.add_message("single-string-used-for-slots", node=node)
- continue
- if not hasattr(slots, "itered"):
- # we can't obtain the values, maybe a .deque?
- continue
-
- if isinstance(slots, astroid.Dict):
- values = [item[0] for item in slots.items]
- else:
- values = slots.itered()
- if values is astroid.Uninferable:
- return
- for elt in values:
- try:
- self._check_slots_elt(elt, node)
- except astroid.InferenceError:
- continue
-
- def _check_slots_elt(self, elt, node):
- for inferred in elt.infer():
- if inferred is astroid.Uninferable:
- continue
- if not isinstance(inferred, astroid.Const) or not isinstance(
- inferred.value, str
- ):
- self.add_message(
- "invalid-slots-object", args=inferred.as_string(), node=elt
- )
- continue
- if not inferred.value:
- self.add_message(
- "invalid-slots-object", args=inferred.as_string(), node=elt
- )
-
- # Check if we have a conflict with a class variable.
- class_variable = node.locals.get(inferred.value)
- if class_variable:
- # Skip annotated assignments which don't conflict at all with slots.
- if len(class_variable) == 1:
- parent = class_variable[0].parent
- if isinstance(parent, astroid.AnnAssign) and parent.value is None:
- return
- self.add_message(
- "class-variable-slots-conflict", args=(inferred.value,), node=elt
- )
-
- def leave_functiondef(self, node):
- """on method node, check if this method couldn't be a function
-
- ignore class, static and abstract methods, initializer,
- methods overridden from a parent class.
- """
- if node.is_method():
- if node.args.args is not None:
- self._first_attrs.pop()
- if not self.linter.is_message_enabled("no-self-use"):
- return
- class_node = node.parent.frame()
- if (
- self._meth_could_be_func
- and node.type == "method"
- and node.name not in PYMETHODS
- and not (
- node.is_abstract()
- or overrides_a_method(class_node, node.name)
- or decorated_with_property(node)
- or _has_bare_super_call(node)
- or is_protocol_class(class_node)
- )
- ):
- self.add_message("no-self-use", node=node)
-
- def visit_attribute(self, node):
- """check if the getattr is an access to a class member
- if so, register it. Also check for access to protected
- class member from outside its class (but ignore __special__
- methods)
- """
- # Check self
- if self._uses_mandatory_method_param(node):
- self._accessed.set_accessed(node)
- return
- if not self.linter.is_message_enabled("protected-access"):
- return
-
- self._check_protected_attribute_access(node)
-
- def visit_assignattr(self, node):
- if isinstance(
- node.assign_type(), astroid.AugAssign
- ) and self._uses_mandatory_method_param(node):
- self._accessed.set_accessed(node)
- self._check_in_slots(node)
-
- def _check_in_slots(self, node):
- """ Check that the given AssignAttr node
- is defined in the class slots.
- """
- inferred = safe_infer(node.expr)
- if not isinstance(inferred, astroid.Instance):
- return
-
- klass = inferred._proxied
- if not has_known_bases(klass):
- return
- if "__slots__" not in klass.locals or not klass.newstyle:
- return
-
- slots = klass.slots()
- if slots is None:
- return
- # If any ancestor doesn't use slots, the slots
- # defined for this class are superfluous.
- if any(
- "__slots__" not in ancestor.locals and ancestor.name != "object"
- for ancestor in klass.ancestors()
- ):
- return
-
- if not any(slot.value == node.attrname for slot in slots):
- # If we have a '__dict__' in slots, then
- # assigning any name is valid.
- if not any(slot.value == "__dict__" for slot in slots):
- if _is_attribute_property(node.attrname, klass):
- # Properties circumvent the slots mechanism,
- # so we should not emit a warning for them.
- return
- if node.attrname in klass.locals and _has_data_descriptor(
- klass, node.attrname
- ):
- # Descriptors circumvent the slots mechanism as well.
- return
- if node.attrname == "__class__" and _has_same_layout_slots(
- slots, node.parent.value
- ):
- return
- self.add_message("assigning-non-slot", args=(node.attrname,), node=node)
-
- @check_messages(
- "protected-access", "no-classmethod-decorator", "no-staticmethod-decorator"
- )
- def visit_assign(self, assign_node):
- self._check_classmethod_declaration(assign_node)
- node = assign_node.targets[0]
- if not isinstance(node, astroid.AssignAttr):
- return
-
- if self._uses_mandatory_method_param(node):
- return
- self._check_protected_attribute_access(node)
-
- def _check_classmethod_declaration(self, node):
- """Checks for uses of classmethod() or staticmethod()
-
- When a @classmethod or @staticmethod decorator should be used instead.
- A message will be emitted only if the assignment is at a class scope
- and only if the classmethod's argument belongs to the class where it
- is defined.
- `node` is an assign node.
- """
- if not isinstance(node.value, astroid.Call):
- return
-
- # check the function called is "classmethod" or "staticmethod"
- func = node.value.func
- if not isinstance(func, astroid.Name) or func.name not in (
- "classmethod",
- "staticmethod",
- ):
- return
-
- msg = (
- "no-classmethod-decorator"
- if func.name == "classmethod"
- else "no-staticmethod-decorator"
- )
- # assignment must be at a class scope
- parent_class = node.scope()
- if not isinstance(parent_class, astroid.ClassDef):
- return
-
- # Check if the arg passed to classmethod is a class member
- classmeth_arg = node.value.args[0]
- if not isinstance(classmeth_arg, astroid.Name):
- return
-
- method_name = classmeth_arg.name
- if any(method_name == member.name for member in parent_class.mymethods()):
- self.add_message(msg, node=node.targets[0])
-
- def _check_protected_attribute_access(self, node):
- """Given an attribute access node (set or get), check if attribute
- access is legitimate. Call _check_first_attr with node before calling
- this method. Valid cases are:
- * self._attr in a method or cls._attr in a classmethod. Checked by
- _check_first_attr.
- * Klass._attr inside "Klass" class.
- * Klass2._attr inside "Klass" class when Klass2 is a base class of
- Klass.
- """
- attrname = node.attrname
-
- if (
- is_attr_protected(attrname)
- and attrname not in self.config.exclude_protected
- ):
-
- klass = node_frame_class(node)
-
- # In classes, check we are not getting a parent method
- # through the class object or through super
- callee = node.expr.as_string()
-
- # We are not in a class, no remaining valid case
- if klass is None:
- self.add_message("protected-access", node=node, args=attrname)
- return
-
- # If the expression begins with a call to super, that's ok.
- if (
- isinstance(node.expr, astroid.Call)
- and isinstance(node.expr.func, astroid.Name)
- and node.expr.func.name == "super"
- ):
- return
-
- # If the expression begins with a call to type(self), that's ok.
- if self._is_type_self_call(node.expr):
- return
-
- # We are in a class, one remaining valid cases, Klass._attr inside
- # Klass
- if not (callee == klass.name or callee in klass.basenames):
- # Detect property assignments in the body of the class.
- # This is acceptable:
- #
- # class A:
- # b = property(lambda: self._b)
-
- stmt = node.parent.statement()
- if (
- isinstance(stmt, astroid.Assign)
- and len(stmt.targets) == 1
- and isinstance(stmt.targets[0], astroid.AssignName)
- ):
- name = stmt.targets[0].name
- if _is_attribute_property(name, klass):
- return
-
- #  A licit use of protected member is inside a special method
- if not attrname.startswith(
- "__"
- ) and self._is_called_inside_special_method(node):
- return
-
- self.add_message("protected-access", node=node, args=attrname)
-
- @staticmethod
- def _is_called_inside_special_method(node: astroid.node_classes.NodeNG) -> bool:
- """
- Returns true if the node is located inside a special (aka dunder) method
- """
- try:
- frame_name = node.frame().name
- except AttributeError:
- return False
- return frame_name and frame_name in PYMETHODS
-
- def _is_type_self_call(self, expr):
- return (
- isinstance(expr, astroid.Call)
- and isinstance(expr.func, astroid.Name)
- and expr.func.name == "type"
- and len(expr.args) == 1
- and self._is_mandatory_method_param(expr.args[0])
- )
-
- def visit_name(self, node):
- """check if the name handle an access to a class member
- if so, register it
- """
- if self._first_attrs and (
- node.name == self._first_attrs[-1] or not self._first_attrs[-1]
- ):
- self._meth_could_be_func = False
-
- def _check_accessed_members(self, node, accessed):
- """check that accessed members are defined"""
- excs = ("AttributeError", "Exception", "BaseException")
- for attr, nodes in accessed.items():
- try:
- # is it a class attribute ?
- node.local_attr(attr)
- # yes, stop here
- continue
- except astroid.NotFoundError:
- pass
- # is it an instance attribute of a parent class ?
- try:
- next(node.instance_attr_ancestors(attr))
- # yes, stop here
- continue
- except StopIteration:
- pass
- # is it an instance attribute ?
- try:
- defstmts = node.instance_attr(attr)
- except astroid.NotFoundError:
- pass
- else:
- # filter out augment assignment nodes
- defstmts = [stmt for stmt in defstmts if stmt not in nodes]
- if not defstmts:
- # only augment assignment for this node, no-member should be
- # triggered by the typecheck checker
- continue
- # filter defstmts to only pick the first one when there are
- # several assignments in the same scope
- scope = defstmts[0].scope()
- defstmts = [
- stmt
- for i, stmt in enumerate(defstmts)
- if i == 0 or stmt.scope() is not scope
- ]
- # if there are still more than one, don't attempt to be smarter
- # than we can be
- if len(defstmts) == 1:
- defstmt = defstmts[0]
- # check that if the node is accessed in the same method as
- # it's defined, it's accessed after the initial assignment
- frame = defstmt.frame()
- lno = defstmt.fromlineno
- for _node in nodes:
- if (
- _node.frame() is frame
- and _node.fromlineno < lno
- and not astroid.are_exclusive(
- _node.statement(), defstmt, excs
- )
- ):
- self.add_message(
- "access-member-before-definition",
- node=_node,
- args=(attr, lno),
- )
-
- def _check_first_arg_for_type(self, node, metaclass=0):
- """check the name of first argument, expect:
-
- * 'self' for a regular method
- * 'cls' for a class method or a metaclass regular method (actually
- valid-classmethod-first-arg value)
- * 'mcs' for a metaclass class method (actually
- valid-metaclass-classmethod-first-arg)
- * not one of the above for a static method
- """
- # don't care about functions with unknown argument (builtins)
- if node.args.args is None:
- return
- if node.args.args:
- first_arg = node.argnames()[0]
- elif node.args.posonlyargs:
- first_arg = node.args.posonlyargs[0].name
- else:
- first_arg = None
- self._first_attrs.append(first_arg)
- first = self._first_attrs[-1]
- # static method
- if node.type == "staticmethod":
- if (
- first_arg == "self"
- or first_arg in self.config.valid_classmethod_first_arg
- or first_arg in self.config.valid_metaclass_classmethod_first_arg
- ):
- self.add_message("bad-staticmethod-argument", args=first, node=node)
- return
- self._first_attrs[-1] = None
- # class / regular method with no args
- elif not node.args.args and not node.args.posonlyargs:
- self.add_message("no-method-argument", node=node)
- # metaclass
- elif metaclass:
- # metaclass __new__ or classmethod
- if node.type == "classmethod":
- self._check_first_arg_config(
- first,
- self.config.valid_metaclass_classmethod_first_arg,
- node,
- "bad-mcs-classmethod-argument",
- node.name,
- )
- # metaclass regular method
- else:
- self._check_first_arg_config(
- first,
- self.config.valid_classmethod_first_arg,
- node,
- "bad-mcs-method-argument",
- node.name,
- )
- # regular class
- else:
- # class method
- if node.type == "classmethod" or node.name == "__class_getitem__":
- self._check_first_arg_config(
- first,
- self.config.valid_classmethod_first_arg,
- node,
- "bad-classmethod-argument",
- node.name,
- )
- # regular method without self as argument
- elif first != "self":
- self.add_message("no-self-argument", node=node)
-
- def _check_first_arg_config(self, first, config, node, message, method_name):
- if first not in config:
- if len(config) == 1:
- valid = repr(config[0])
- else:
- valid = ", ".join(repr(v) for v in config[:-1])
- valid = "%s or %r" % (valid, config[-1])
- self.add_message(message, args=(method_name, valid), node=node)
-
- def _check_bases_classes(self, node):
- """check that the given class node implements abstract methods from
- base classes
- """
-
- def is_abstract(method):
- return method.is_abstract(pass_is_abstract=False)
-
- # check if this class abstract
- if class_is_abstract(node):
- return
-
- methods = sorted(
- unimplemented_abstract_methods(node, is_abstract).items(),
- key=lambda item: item[0],
- )
- for name, method in methods:
- owner = method.parent.frame()
- if owner is node:
- continue
- # owner is not this class, it must be a parent class
- # check that the ancestor's method is not abstract
- if name in node.locals:
- # it is redefined as an attribute or with a descriptor
- continue
- self.add_message("abstract-method", node=node, args=(name, owner.name))
-
- def _check_init(self, node):
- """check that the __init__ method call super or ancestors'__init__
- method (unless it is used for type hinting with `typing.overload`)
- """
- if not self.linter.is_message_enabled(
- "super-init-not-called"
- ) and not self.linter.is_message_enabled("non-parent-init-called"):
- return
- klass_node = node.parent.frame()
- to_call = _ancestors_to_call(klass_node)
- not_called_yet = dict(to_call)
- for stmt in node.nodes_of_class(astroid.Call):
- expr = stmt.func
- if not isinstance(expr, astroid.Attribute) or expr.attrname != "__init__":
- continue
- # skip the test if using super
- if (
- isinstance(expr.expr, astroid.Call)
- and isinstance(expr.expr.func, astroid.Name)
- and expr.expr.func.name == "super"
- ):
- return
- try:
- for klass in expr.expr.infer():
- if klass is astroid.Uninferable:
- continue
- # The inferred klass can be super(), which was
- # assigned to a variable and the `__init__`
- # was called later.
- #
- # base = super()
- # base.__init__(...)
-
- if (
- isinstance(klass, astroid.Instance)
- and isinstance(klass._proxied, astroid.ClassDef)
- and is_builtin_object(klass._proxied)
- and klass._proxied.name == "super"
- ):
- return
- if isinstance(klass, objects.Super):
- return
- try:
- del not_called_yet[klass]
- except KeyError:
- if klass not in to_call:
- self.add_message(
- "non-parent-init-called", node=expr, args=klass.name
- )
- except astroid.InferenceError:
- continue
- for klass, method in not_called_yet.items():
- if decorated_with(node, ["typing.overload"]):
- continue
- cls = node_frame_class(method)
- if klass.name == "object" or (cls and cls.name == "object"):
- continue
- self.add_message("super-init-not-called", args=klass.name, node=node)
-
- def _check_signature(self, method1, refmethod, class_type, cls):
- """check that the signature of the two given methods match
- """
- if not (
- isinstance(method1, astroid.FunctionDef)
- and isinstance(refmethod, astroid.FunctionDef)
- ):
- self.add_message(
- "method-check-failed", args=(method1, refmethod), node=method1
- )
- return
-
- instance = cls.instantiate_class()
- method1 = function_to_method(method1, instance)
- refmethod = function_to_method(refmethod, instance)
-
- # Don't care about functions with unknown argument (builtins).
- if method1.args.args is None or refmethod.args.args is None:
- return
-
- # Ignore private to class methods.
- if is_attr_private(method1.name):
- return
- # Ignore setters, they have an implicit extra argument,
- # which shouldn't be taken in consideration.
- if is_property_setter(method1):
- return
-
- if _different_parameters(
- refmethod, method1, dummy_parameter_regex=self._dummy_rgx
- ):
- self.add_message(
- "arguments-differ", args=(class_type, method1.name), node=method1
- )
- elif len(method1.args.defaults) < len(refmethod.args.defaults):
- self.add_message(
- "signature-differs", args=(class_type, method1.name), node=method1
- )
-
- def _uses_mandatory_method_param(self, node):
- """Check that attribute lookup name use first attribute variable name
-
- Name is `self` for method, `cls` for classmethod and `mcs` for metaclass.
- """
- return self._is_mandatory_method_param(node.expr)
-
- def _is_mandatory_method_param(self, node):
- """Check if astroid.Name corresponds to first attribute variable name
-
- Name is `self` for method, `cls` for classmethod and `mcs` for metaclass.
- """
- return (
- self._first_attrs
- and isinstance(node, astroid.Name)
- and node.name == self._first_attrs[-1]
- )
-
-
-class SpecialMethodsChecker(BaseChecker):
- """Checker which verifies that special methods
- are implemented correctly.
- """
-
- __implements__ = (IAstroidChecker,)
- name = "classes"
- msgs = {
- "E0301": (
- "__iter__ returns non-iterator",
- "non-iterator-returned",
- "Used when an __iter__ method returns something which is not an "
- "iterable (i.e. has no `%s` method)" % NEXT_METHOD,
- {
- "old_names": [
- ("W0234", "old-non-iterator-returned-1"),
- ("E0234", "old-non-iterator-returned-2"),
- ]
- },
- ),
- "E0302": (
- "The special method %r expects %s param(s), %d %s given",
- "unexpected-special-method-signature",
- "Emitted when a special method was defined with an "
- "invalid number of parameters. If it has too few or "
- "too many, it might not work at all.",
- {"old_names": [("E0235", "bad-context-manager")]},
- ),
- "E0303": (
- "__len__ does not return non-negative integer",
- "invalid-length-returned",
- "Used when a __len__ method returns something which is not a "
- "non-negative integer",
- {},
- ),
- }
- priority = -2
-
- @check_messages(
- "unexpected-special-method-signature",
- "non-iterator-returned",
- "invalid-length-returned",
- )
- def visit_functiondef(self, node):
- if not node.is_method():
- return
- if node.name == "__iter__":
- self._check_iter(node)
- if node.name == "__len__":
- self._check_len(node)
- if node.name in PYMETHODS:
- self._check_unexpected_method_signature(node)
-
- visit_asyncfunctiondef = visit_functiondef
-
- def _check_unexpected_method_signature(self, node):
- expected_params = SPECIAL_METHODS_PARAMS[node.name]
-
- if expected_params is None:
- # This can support a variable number of parameters.
- return
- if not node.args.args and not node.args.vararg:
- # Method has no parameter, will be caught
- # by no-method-argument.
- return
-
- if decorated_with(node, [BUILTINS + ".staticmethod"]):
- # We expect to not take in consideration self.
- all_args = node.args.args
- else:
- all_args = node.args.args[1:]
- mandatory = len(all_args) - len(node.args.defaults)
- optional = len(node.args.defaults)
- current_params = mandatory + optional
-
- if isinstance(expected_params, tuple):
- # The expected number of parameters can be any value from this
- # tuple, although the user should implement the method
- # to take all of them in consideration.
- emit = mandatory not in expected_params
- expected_params = "between %d or %d" % expected_params
- else:
- # If the number of mandatory parameters doesn't
- # suffice, the expected parameters for this
- # function will be deduced from the optional
- # parameters.
- rest = expected_params - mandatory
- if rest == 0:
- emit = False
- elif rest < 0:
- emit = True
- elif rest > 0:
- emit = not ((optional - rest) >= 0 or node.args.vararg)
-
- if emit:
- verb = "was" if current_params <= 1 else "were"
- self.add_message(
- "unexpected-special-method-signature",
- args=(node.name, expected_params, current_params, verb),
- node=node,
- )
-
- @staticmethod
- def _is_iterator(node):
- if node is astroid.Uninferable:
- # Just ignore Uninferable objects.
- return True
- if isinstance(node, Generator):
- # Generators can be itered.
- return True
-
- if isinstance(node, astroid.Instance):
- try:
- node.local_attr(NEXT_METHOD)
- return True
- except astroid.NotFoundError:
- pass
- elif isinstance(node, astroid.ClassDef):
- metaclass = node.metaclass()
- if metaclass and isinstance(metaclass, astroid.ClassDef):
- try:
- metaclass.local_attr(NEXT_METHOD)
- return True
- except astroid.NotFoundError:
- pass
- return False
-
- def _check_iter(self, node):
- inferred = _safe_infer_call_result(node, node)
- if inferred is not None:
- if not self._is_iterator(inferred):
- self.add_message("non-iterator-returned", node=node)
-
- def _check_len(self, node):
- inferred = _safe_infer_call_result(node, node)
- if not inferred or inferred is astroid.Uninferable:
- return
-
- if (
- isinstance(inferred, astroid.Instance)
- and inferred.name == "int"
- and not isinstance(inferred, astroid.Const)
- ):
- # Assume it's good enough, since the int() call might wrap
- # something that's uninferable for us
- return
-
- if not isinstance(inferred, astroid.Const):
- self.add_message("invalid-length-returned", node=node)
- return
-
- value = inferred.value
- if not isinstance(value, int) or value < 0:
- self.add_message("invalid-length-returned", node=node)
-
-
-def _ancestors_to_call(klass_node, method="__init__"):
- """return a dictionary where keys are the list of base classes providing
- the queried method, and so that should/may be called from the method node
- """
- to_call = {}
- for base_node in klass_node.ancestors(recurs=False):
- try:
- to_call[base_node] = next(base_node.igetattr(method))
- except astroid.InferenceError:
- continue
- return to_call
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(ClassChecker(linter))
- linter.register_checker(SpecialMethodsChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/design_analysis.py b/venv/Lib/site-packages/pylint/checkers/design_analysis.py
deleted file mode 100644
index 50d8eaa..0000000
--- a/venv/Lib/site-packages/pylint/checkers/design_analysis.py
+++ /dev/null
@@ -1,496 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006, 2009-2010, 2012-2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012, 2014 Google, Inc.
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2017 ahirnish <ahirnish@gmail.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 Mark Miller <725mrm@gmail.com>
-# Copyright (c) 2018 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-# Copyright (c) 2018 Jakub Wilk <jwilk@jwilk.net>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""check for signs of poor design"""
-
-import re
-from collections import defaultdict
-
-import astroid
-from astroid import BoolOp, If, decorators
-
-from pylint import utils
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker
-
-MSGS = {
- "R0901": (
- "Too many ancestors (%s/%s)",
- "too-many-ancestors",
- "Used when class has too many parent classes, try to reduce "
- "this to get a simpler (and so easier to use) class.",
- ),
- "R0902": (
- "Too many instance attributes (%s/%s)",
- "too-many-instance-attributes",
- "Used when class has too many instance attributes, try to reduce "
- "this to get a simpler (and so easier to use) class.",
- ),
- "R0903": (
- "Too few public methods (%s/%s)",
- "too-few-public-methods",
- "Used when class has too few public methods, so be sure it's "
- "really worth it.",
- ),
- "R0904": (
- "Too many public methods (%s/%s)",
- "too-many-public-methods",
- "Used when class has too many public methods, try to reduce "
- "this to get a simpler (and so easier to use) class.",
- ),
- "R0911": (
- "Too many return statements (%s/%s)",
- "too-many-return-statements",
- "Used when a function or method has too many return statement, "
- "making it hard to follow.",
- ),
- "R0912": (
- "Too many branches (%s/%s)",
- "too-many-branches",
- "Used when a function or method has too many branches, "
- "making it hard to follow.",
- ),
- "R0913": (
- "Too many arguments (%s/%s)",
- "too-many-arguments",
- "Used when a function or method takes too many arguments.",
- ),
- "R0914": (
- "Too many local variables (%s/%s)",
- "too-many-locals",
- "Used when a function or method has too many local variables.",
- ),
- "R0915": (
- "Too many statements (%s/%s)",
- "too-many-statements",
- "Used when a function or method has too many statements. You "
- "should then split it in smaller functions / methods.",
- ),
- "R0916": (
- "Too many boolean expressions in if statement (%s/%s)",
- "too-many-boolean-expressions",
- "Used when an if statement contains too many boolean expressions.",
- ),
-}
-SPECIAL_OBJ = re.compile("^_{2}[a-z]+_{2}$")
-DATACLASSES_DECORATORS = frozenset({"dataclass", "attrs"})
-DATACLASS_IMPORT = "dataclasses"
-TYPING_NAMEDTUPLE = "typing.NamedTuple"
-
-
-def _is_exempt_from_public_methods(node: astroid.ClassDef) -> bool:
- """Check if a class is exempt from too-few-public-methods"""
-
- # If it's a typing.Namedtuple or an Enum
- for ancestor in node.ancestors():
- if ancestor.name == "Enum" and ancestor.root().name == "enum":
- return True
- if ancestor.qname() == TYPING_NAMEDTUPLE:
- return True
-
- # Or if it's a dataclass
- if not node.decorators:
- return False
-
- root_locals = set(node.root().locals)
- for decorator in node.decorators.nodes:
- if isinstance(decorator, astroid.Call):
- decorator = decorator.func
- if not isinstance(decorator, (astroid.Name, astroid.Attribute)):
- continue
- if isinstance(decorator, astroid.Name):
- name = decorator.name
- else:
- name = decorator.attrname
- if name in DATACLASSES_DECORATORS and (
- root_locals.intersection(DATACLASSES_DECORATORS)
- or DATACLASS_IMPORT in root_locals
- ):
- return True
- return False
-
-
-def _count_boolean_expressions(bool_op):
- """Counts the number of boolean expressions in BoolOp `bool_op` (recursive)
-
- example: a and (b or c or (d and e)) ==> 5 boolean expressions
- """
- nb_bool_expr = 0
- for bool_expr in bool_op.get_children():
- if isinstance(bool_expr, BoolOp):
- nb_bool_expr += _count_boolean_expressions(bool_expr)
- else:
- nb_bool_expr += 1
- return nb_bool_expr
-
-
-def _count_methods_in_class(node):
- all_methods = sum(1 for method in node.methods() if not method.name.startswith("_"))
- # Special methods count towards the number of public methods,
- # but don't count towards there being too many methods.
- for method in node.mymethods():
- if SPECIAL_OBJ.search(method.name) and method.name != "__init__":
- all_methods += 1
- return all_methods
-
-
-class MisdesignChecker(BaseChecker):
- """checks for sign of poor/misdesign:
- * number of methods, attributes, local variables...
- * size, complexity of functions, methods
- """
-
- __implements__ = (IAstroidChecker,)
-
- # configuration section name
- name = "design"
- # messages
- msgs = MSGS
- priority = -2
- # configuration options
- options = (
- (
- "max-args",
- {
- "default": 5,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of arguments for function / method.",
- },
- ),
- (
- "max-locals",
- {
- "default": 15,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of locals for function / method body.",
- },
- ),
- (
- "max-returns",
- {
- "default": 6,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of return / yield for function / "
- "method body.",
- },
- ),
- (
- "max-branches",
- {
- "default": 12,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of branch for function / method body.",
- },
- ),
- (
- "max-statements",
- {
- "default": 50,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of statements in function / method " "body.",
- },
- ),
- (
- "max-parents",
- {
- "default": 7,
- "type": "int",
- "metavar": "<num>",
- "help": "Maximum number of parents for a class (see R0901).",
- },
- ),
- (
- "max-attributes",
- {
- "default": 7,
- "type": "int",
- "metavar": "<num>",
- "help": "Maximum number of attributes for a class \
-(see R0902).",
- },
- ),
- (
- "min-public-methods",
- {
- "default": 2,
- "type": "int",
- "metavar": "<num>",
- "help": "Minimum number of public methods for a class \
-(see R0903).",
- },
- ),
- (
- "max-public-methods",
- {
- "default": 20,
- "type": "int",
- "metavar": "<num>",
- "help": "Maximum number of public methods for a class \
-(see R0904).",
- },
- ),
- (
- "max-bool-expr",
- {
- "default": 5,
- "type": "int",
- "metavar": "<num>",
- "help": "Maximum number of boolean expressions in an if "
- "statement (see R0916).",
- },
- ),
- )
-
- def __init__(self, linter=None):
- BaseChecker.__init__(self, linter)
- self.stats = None
- self._returns = None
- self._branches = None
- self._stmts = None
-
- def open(self):
- """initialize visit variables"""
- self.stats = self.linter.add_stats()
- self._returns = []
- self._branches = defaultdict(int)
- self._stmts = []
-
- def _inc_all_stmts(self, amount):
- for i in range(len(self._stmts)):
- self._stmts[i] += amount
-
- @decorators.cachedproperty
- def _ignored_argument_names(self):
- return utils.get_global_option(self, "ignored-argument-names", default=None)
-
- @check_messages(
- "too-many-ancestors",
- "too-many-instance-attributes",
- "too-few-public-methods",
- "too-many-public-methods",
- )
- def visit_classdef(self, node):
- """check size of inheritance hierarchy and number of instance attributes
- """
- nb_parents = len(list(node.ancestors()))
- if nb_parents > self.config.max_parents:
- self.add_message(
- "too-many-ancestors",
- node=node,
- args=(nb_parents, self.config.max_parents),
- )
-
- if len(node.instance_attrs) > self.config.max_attributes:
- self.add_message(
- "too-many-instance-attributes",
- node=node,
- args=(len(node.instance_attrs), self.config.max_attributes),
- )
-
- @check_messages("too-few-public-methods", "too-many-public-methods")
- def leave_classdef(self, node):
- """check number of public methods"""
- my_methods = sum(
- 1 for method in node.mymethods() if not method.name.startswith("_")
- )
-
- # Does the class contain less than n public methods ?
- # This checks only the methods defined in the current class,
- # since the user might not have control over the classes
- # from the ancestors. It avoids some false positives
- # for classes such as unittest.TestCase, which provides
- # a lot of assert methods. It doesn't make sense to warn
- # when the user subclasses TestCase to add his own tests.
- if my_methods > self.config.max_public_methods:
- self.add_message(
- "too-many-public-methods",
- node=node,
- args=(my_methods, self.config.max_public_methods),
- )
-
- # Stop here for exception, metaclass, interface classes and other
- # classes for which we don't need to count the methods.
- if node.type != "class" or _is_exempt_from_public_methods(node):
- return
-
- # Does the class contain more than n public methods ?
- # This checks all the methods defined by ancestors and
- # by the current class.
- all_methods = _count_methods_in_class(node)
- if all_methods < self.config.min_public_methods:
- self.add_message(
- "too-few-public-methods",
- node=node,
- args=(all_methods, self.config.min_public_methods),
- )
-
- @check_messages(
- "too-many-return-statements",
- "too-many-branches",
- "too-many-arguments",
- "too-many-locals",
- "too-many-statements",
- "keyword-arg-before-vararg",
- )
- def visit_functiondef(self, node):
- """check function name, docstring, arguments, redefinition,
- variable names, max locals
- """
- # init branch and returns counters
- self._returns.append(0)
- # check number of arguments
- args = node.args.args
- ignored_argument_names = self._ignored_argument_names
- if args is not None:
- ignored_args_num = 0
- if ignored_argument_names:
- ignored_args_num = sum(
- 1 for arg in args if ignored_argument_names.match(arg.name)
- )
-
- argnum = len(args) - ignored_args_num
- if argnum > self.config.max_args:
- self.add_message(
- "too-many-arguments",
- node=node,
- args=(len(args), self.config.max_args),
- )
- else:
- ignored_args_num = 0
- # check number of local variables
- locnum = len(node.locals) - ignored_args_num
- if locnum > self.config.max_locals:
- self.add_message(
- "too-many-locals", node=node, args=(locnum, self.config.max_locals)
- )
- # init new statements counter
- self._stmts.append(1)
-
- visit_asyncfunctiondef = visit_functiondef
-
- @check_messages(
- "too-many-return-statements",
- "too-many-branches",
- "too-many-arguments",
- "too-many-locals",
- "too-many-statements",
- )
- def leave_functiondef(self, node):
- """most of the work is done here on close:
- checks for max returns, branch, return in __init__
- """
- returns = self._returns.pop()
- if returns > self.config.max_returns:
- self.add_message(
- "too-many-return-statements",
- node=node,
- args=(returns, self.config.max_returns),
- )
- branches = self._branches[node]
- if branches > self.config.max_branches:
- self.add_message(
- "too-many-branches",
- node=node,
- args=(branches, self.config.max_branches),
- )
- # check number of statements
- stmts = self._stmts.pop()
- if stmts > self.config.max_statements:
- self.add_message(
- "too-many-statements",
- node=node,
- args=(stmts, self.config.max_statements),
- )
-
- leave_asyncfunctiondef = leave_functiondef
-
- def visit_return(self, _):
- """count number of returns"""
- if not self._returns:
- return # return outside function, reported by the base checker
- self._returns[-1] += 1
-
- def visit_default(self, node):
- """default visit method -> increments the statements counter if
- necessary
- """
- if node.is_statement:
- self._inc_all_stmts(1)
-
- def visit_tryexcept(self, node):
- """increments the branches counter"""
- branches = len(node.handlers)
- if node.orelse:
- branches += 1
- self._inc_branch(node, branches)
- self._inc_all_stmts(branches)
-
- def visit_tryfinally(self, node):
- """increments the branches counter"""
- self._inc_branch(node, 2)
- self._inc_all_stmts(2)
-
- @check_messages("too-many-boolean-expressions")
- def visit_if(self, node):
- """increments the branches counter and checks boolean expressions"""
- self._check_boolean_expressions(node)
- branches = 1
- # don't double count If nodes coming from some 'elif'
- if node.orelse and (len(node.orelse) > 1 or not isinstance(node.orelse[0], If)):
- branches += 1
- self._inc_branch(node, branches)
- self._inc_all_stmts(branches)
-
- def _check_boolean_expressions(self, node):
- """Go through "if" node `node` and counts its boolean expressions
-
- if the "if" node test is a BoolOp node
- """
- condition = node.test
- if not isinstance(condition, BoolOp):
- return
- nb_bool_expr = _count_boolean_expressions(condition)
- if nb_bool_expr > self.config.max_bool_expr:
- self.add_message(
- "too-many-boolean-expressions",
- node=condition,
- args=(nb_bool_expr, self.config.max_bool_expr),
- )
-
- def visit_while(self, node):
- """increments the branches counter"""
- branches = 1
- if node.orelse:
- branches += 1
- self._inc_branch(node, branches)
-
- visit_for = visit_while
-
- def _inc_branch(self, node, branchesnum=1):
- """increments the branches counter"""
- self._branches[node.scope()] += branchesnum
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(MisdesignChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/exceptions.py b/venv/Lib/site-packages/pylint/checkers/exceptions.py
deleted file mode 100644
index 360e1d1..0000000
--- a/venv/Lib/site-packages/pylint/checkers/exceptions.py
+++ /dev/null
@@ -1,546 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2011-2014 Google, Inc.
-# Copyright (c) 2012 Tim Hatch <tim@timhatch.com>
-# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Rene Zhang <rz99@cornell.edu>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Steven Myint <hg@stevenmyint.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Erik <erik.eriksson@yahoo.com>
-# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2017 Martin von Gagern <gagern@google.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Checks for various exception related errors."""
-import builtins
-import inspect
-import typing
-
-import astroid
-from astroid.node_classes import NodeNG
-
-from pylint import checkers, interfaces
-from pylint.checkers import utils
-
-
-def _builtin_exceptions():
- def predicate(obj):
- return isinstance(obj, type) and issubclass(obj, BaseException)
-
- members = inspect.getmembers(builtins, predicate)
- return {exc.__name__ for (_, exc) in members}
-
-
-def _annotated_unpack_infer(stmt, context=None):
- """
- Recursively generate nodes inferred by the given statement.
- If the inferred value is a list or a tuple, recurse on the elements.
- Returns an iterator which yields tuples in the format
- ('original node', 'inferred node').
- """
- if isinstance(stmt, (astroid.List, astroid.Tuple)):
- for elt in stmt.elts:
- inferred = utils.safe_infer(elt)
- if inferred and inferred is not astroid.Uninferable:
- yield elt, inferred
- return
- for inferred in stmt.infer(context):
- if inferred is astroid.Uninferable:
- continue
- yield stmt, inferred
-
-
-def _is_raising(body: typing.List) -> bool:
- """Return true if the given statement node raise an exception"""
- for node in body:
- if isinstance(node, astroid.Raise):
- return True
- return False
-
-
-OVERGENERAL_EXCEPTIONS = ("BaseException", "Exception")
-BUILTINS_NAME = builtins.__name__
-
-MSGS = {
- "E0701": (
- "Bad except clauses order (%s)",
- "bad-except-order",
- "Used when except clauses are not in the correct order (from the "
- "more specific to the more generic). If you don't fix the order, "
- "some exceptions may not be caught by the most specific handler.",
- ),
- "E0702": (
- "Raising %s while only classes or instances are allowed",
- "raising-bad-type",
- "Used when something which is neither a class, an instance or a "
- "string is raised (i.e. a `TypeError` will be raised).",
- ),
- "E0703": (
- "Exception context set to something which is not an exception, nor None",
- "bad-exception-context",
- 'Used when using the syntax "raise ... from ...", '
- "where the exception context is not an exception, "
- "nor None.",
- ),
- "E0704": (
- "The raise statement is not inside an except clause",
- "misplaced-bare-raise",
- "Used when a bare raise is not used inside an except clause. "
- "This generates an error, since there are no active exceptions "
- "to be reraised. An exception to this rule is represented by "
- "a bare raise inside a finally clause, which might work, as long "
- "as an exception is raised inside the try block, but it is "
- "nevertheless a code smell that must not be relied upon.",
- ),
- "E0710": (
- "Raising a new style class which doesn't inherit from BaseException",
- "raising-non-exception",
- "Used when a new style class which doesn't inherit from "
- "BaseException is raised.",
- ),
- "E0711": (
- "NotImplemented raised - should raise NotImplementedError",
- "notimplemented-raised",
- "Used when NotImplemented is raised instead of NotImplementedError",
- ),
- "E0712": (
- "Catching an exception which doesn't inherit from Exception: %s",
- "catching-non-exception",
- "Used when a class which doesn't inherit from "
- "Exception is used as an exception in an except clause.",
- ),
- "W0702": (
- "No exception type(s) specified",
- "bare-except",
- "Used when an except clause doesn't specify exceptions type to catch.",
- ),
- "W0703": (
- "Catching too general exception %s",
- "broad-except",
- "Used when an except catches a too general exception, "
- "possibly burying unrelated errors.",
- ),
- "W0705": (
- "Catching previously caught exception type %s",
- "duplicate-except",
- "Used when an except catches a type that was already caught by "
- "a previous handler.",
- ),
- "W0706": (
- "The except handler raises immediately",
- "try-except-raise",
- "Used when an except handler uses raise as its first or only "
- "operator. This is useless because it raises back the exception "
- "immediately. Remove the raise operator or the entire "
- "try-except-raise block!",
- ),
- "W0711": (
- 'Exception to catch is the result of a binary "%s" operation',
- "binary-op-exception",
- "Used when the exception to catch is of the form "
- '"except A or B:". If intending to catch multiple, '
- 'rewrite as "except (A, B):"',
- ),
- "W0715": (
- "Exception arguments suggest string formatting might be intended",
- "raising-format-tuple",
- "Used when passing multiple arguments to an exception "
- "constructor, the first of them a string literal containing what "
- "appears to be placeholders intended for formatting",
- ),
- "W0716": (
- "Invalid exception operation. %s",
- "wrong-exception-operation",
- "Used when an operation is done against an exception, but the operation "
- "is not valid for the exception in question. Usually emitted when having "
- "binary operations between exceptions in except handlers.",
- ),
-}
-
-
-class BaseVisitor:
- """Base class for visitors defined in this module."""
-
- def __init__(self, checker, node):
- self._checker = checker
- self._node = node
-
- def visit(self, node):
- name = node.__class__.__name__.lower()
- dispatch_meth = getattr(self, "visit_" + name, None)
- if dispatch_meth:
- dispatch_meth(node)
- else:
- self.visit_default(node)
-
- def visit_default(self, node): # pylint: disable=unused-argument
- """Default implementation for all the nodes."""
-
-
-class ExceptionRaiseRefVisitor(BaseVisitor):
- """Visit references (anything that is not an AST leaf)."""
-
- def visit_name(self, name):
- if name.name == "NotImplemented":
- self._checker.add_message("notimplemented-raised", node=self._node)
-
- def visit_call(self, call):
- if isinstance(call.func, astroid.Name):
- self.visit_name(call.func)
- if (
- len(call.args) > 1
- and isinstance(call.args[0], astroid.Const)
- and isinstance(call.args[0].value, str)
- ):
- msg = call.args[0].value
- if "%" in msg or ("{" in msg and "}" in msg):
- self._checker.add_message("raising-format-tuple", node=self._node)
-
-
-class ExceptionRaiseLeafVisitor(BaseVisitor):
- """Visitor for handling leaf kinds of a raise value."""
-
- def visit_const(self, const):
- if not isinstance(const.value, str):
- # raising-string will be emitted from python3 porting checker.
- self._checker.add_message(
- "raising-bad-type", node=self._node, args=const.value.__class__.__name__
- )
-
- def visit_instance(self, instance):
- # pylint: disable=protected-access
- cls = instance._proxied
- self.visit_classdef(cls)
-
- # Exception instances have a particular class type
- visit_exceptioninstance = visit_instance
-
- def visit_classdef(self, cls):
- if not utils.inherit_from_std_ex(cls) and utils.has_known_bases(cls):
- if cls.newstyle:
- self._checker.add_message("raising-non-exception", node=self._node)
-
- def visit_tuple(self, _):
- self._checker.add_message("raising-bad-type", node=self._node, args="tuple")
-
- def visit_default(self, node):
- name = getattr(node, "name", node.__class__.__name__)
- self._checker.add_message("raising-bad-type", node=self._node, args=name)
-
-
-class ExceptionsChecker(checkers.BaseChecker):
- """Exception related checks."""
-
- __implements__ = interfaces.IAstroidChecker
-
- name = "exceptions"
- msgs = MSGS
- priority = -4
- options = (
- (
- "overgeneral-exceptions",
- {
- "default": OVERGENERAL_EXCEPTIONS,
- "type": "csv",
- "metavar": "<comma-separated class names>",
- "help": "Exceptions that will emit a warning "
- 'when being caught. Defaults to "%s".'
- % (", ".join(OVERGENERAL_EXCEPTIONS),),
- },
- ),
- )
-
- def open(self):
- self._builtin_exceptions = _builtin_exceptions()
- super(ExceptionsChecker, self).open()
-
- @utils.check_messages(
- "misplaced-bare-raise",
- "raising-bad-type",
- "raising-non-exception",
- "notimplemented-raised",
- "bad-exception-context",
- "raising-format-tuple",
- )
- def visit_raise(self, node):
- if node.exc is None:
- self._check_misplaced_bare_raise(node)
- return
-
- if node.cause:
- self._check_bad_exception_context(node)
-
- expr = node.exc
- ExceptionRaiseRefVisitor(self, node).visit(expr)
-
- try:
- inferred_value = expr.inferred()[-1]
- except astroid.InferenceError:
- pass
- else:
- if inferred_value:
- ExceptionRaiseLeafVisitor(self, node).visit(inferred_value)
-
- def _check_misplaced_bare_raise(self, node):
- # Filter out if it's present in __exit__.
- scope = node.scope()
- if (
- isinstance(scope, astroid.FunctionDef)
- and scope.is_method()
- and scope.name == "__exit__"
- ):
- return
-
- current = node
- # Stop when a new scope is generated or when the raise
- # statement is found inside a TryFinally.
- ignores = (astroid.ExceptHandler, astroid.FunctionDef)
- while current and not isinstance(current.parent, ignores):
- current = current.parent
-
- expected = (astroid.ExceptHandler,)
- if not current or not isinstance(current.parent, expected):
- self.add_message("misplaced-bare-raise", node=node)
-
- def _check_bad_exception_context(self, node):
- """Verify that the exception context is properly set.
-
- An exception context can be only `None` or an exception.
- """
- cause = utils.safe_infer(node.cause)
- if cause in (astroid.Uninferable, None):
- return
-
- if isinstance(cause, astroid.Const):
- if cause.value is not None:
- self.add_message("bad-exception-context", node=node)
- elif not isinstance(cause, astroid.ClassDef) and not utils.inherit_from_std_ex(
- cause
- ):
- self.add_message("bad-exception-context", node=node)
-
- def _check_catching_non_exception(self, handler, exc, part):
- if isinstance(exc, astroid.Tuple):
- # Check if it is a tuple of exceptions.
- inferred = [utils.safe_infer(elt) for elt in exc.elts]
- if any(node is astroid.Uninferable for node in inferred):
- # Don't emit if we don't know every component.
- return
- if all(
- node
- and (utils.inherit_from_std_ex(node) or not utils.has_known_bases(node))
- for node in inferred
- ):
- return
-
- if not isinstance(exc, astroid.ClassDef):
- # Don't emit the warning if the inferred stmt
- # is None, but the exception handler is something else,
- # maybe it was redefined.
- if isinstance(exc, astroid.Const) and exc.value is None:
- if (
- isinstance(handler.type, astroid.Const)
- and handler.type.value is None
- ) or handler.type.parent_of(exc):
- # If the exception handler catches None or
- # the exception component, which is None, is
- # defined by the entire exception handler, then
- # emit a warning.
- self.add_message(
- "catching-non-exception",
- node=handler.type,
- args=(part.as_string(),),
- )
- else:
- self.add_message(
- "catching-non-exception",
- node=handler.type,
- args=(part.as_string(),),
- )
- return
-
- if (
- not utils.inherit_from_std_ex(exc)
- and exc.name not in self._builtin_exceptions
- ):
- if utils.has_known_bases(exc):
- self.add_message(
- "catching-non-exception", node=handler.type, args=(exc.name,)
- )
-
- def _check_try_except_raise(self, node):
- def gather_exceptions_from_handler(
- handler
- ) -> typing.Optional[typing.List[NodeNG]]:
- exceptions = [] # type: typing.List[NodeNG]
- if handler.type:
- exceptions_in_handler = utils.safe_infer(handler.type)
- if isinstance(exceptions_in_handler, astroid.Tuple):
- exceptions = list(
- {
- exception
- for exception in exceptions_in_handler.elts
- if isinstance(exception, astroid.Name)
- }
- )
- elif exceptions_in_handler:
- exceptions = [exceptions_in_handler]
- else:
- # Break when we cannot infer anything reliably.
- return None
- return exceptions
-
- bare_raise = False
- handler_having_bare_raise = None
- excs_in_bare_handler = []
- for handler in node.handlers:
- if bare_raise:
- # check that subsequent handler is not parent of handler which had bare raise.
- # since utils.safe_infer can fail for bare except, check it before.
- # also break early if bare except is followed by bare except.
-
- excs_in_current_handler = gather_exceptions_from_handler(handler)
-
- if not excs_in_current_handler:
- bare_raise = False
- break
- if excs_in_bare_handler is None:
- # It can be `None` when the inference failed
- break
-
- for exc_in_current_handler in excs_in_current_handler:
- inferred_current = utils.safe_infer(exc_in_current_handler)
- if any(
- utils.is_subclass_of(
- utils.safe_infer(exc_in_bare_handler), inferred_current
- )
- for exc_in_bare_handler in excs_in_bare_handler
- ):
- bare_raise = False
- break
-
- # `raise` as the first operator inside the except handler
- if _is_raising([handler.body[0]]):
- # flags when there is a bare raise
- if handler.body[0].exc is None:
- bare_raise = True
- handler_having_bare_raise = handler
- excs_in_bare_handler = gather_exceptions_from_handler(handler)
- else:
- if bare_raise:
- self.add_message("try-except-raise", node=handler_having_bare_raise)
-
- @utils.check_messages("wrong-exception-operation")
- def visit_binop(self, node):
- if isinstance(node.parent, astroid.ExceptHandler):
- # except (V | A)
- suggestion = "Did you mean '(%s, %s)' instead?" % (
- node.left.as_string(),
- node.right.as_string(),
- )
- self.add_message("wrong-exception-operation", node=node, args=(suggestion,))
-
- @utils.check_messages("wrong-exception-operation")
- def visit_compare(self, node):
- if isinstance(node.parent, astroid.ExceptHandler):
- # except (V < A)
- suggestion = "Did you mean '(%s, %s)' instead?" % (
- node.left.as_string(),
- ", ".join(operand.as_string() for _, operand in node.ops),
- )
- self.add_message("wrong-exception-operation", node=node, args=(suggestion,))
-
- @utils.check_messages(
- "bare-except",
- "broad-except",
- "try-except-raise",
- "binary-op-exception",
- "bad-except-order",
- "catching-non-exception",
- "duplicate-except",
- )
- def visit_tryexcept(self, node):
- """check for empty except"""
- self._check_try_except_raise(node)
- exceptions_classes = []
- nb_handlers = len(node.handlers)
- for index, handler in enumerate(node.handlers):
- if handler.type is None:
- if not _is_raising(handler.body):
- self.add_message("bare-except", node=handler)
-
- # check if an "except:" is followed by some other
- # except
- if index < (nb_handlers - 1):
- msg = "empty except clause should always appear last"
- self.add_message("bad-except-order", node=node, args=msg)
-
- elif isinstance(handler.type, astroid.BoolOp):
- self.add_message(
- "binary-op-exception", node=handler, args=handler.type.op
- )
- else:
- try:
- excs = list(_annotated_unpack_infer(handler.type))
- except astroid.InferenceError:
- continue
-
- for part, exc in excs:
- if exc is astroid.Uninferable:
- continue
- if isinstance(exc, astroid.Instance) and utils.inherit_from_std_ex(
- exc
- ):
- # pylint: disable=protected-access
- exc = exc._proxied
-
- self._check_catching_non_exception(handler, exc, part)
-
- if not isinstance(exc, astroid.ClassDef):
- continue
-
- exc_ancestors = [
- anc
- for anc in exc.ancestors()
- if isinstance(anc, astroid.ClassDef)
- ]
-
- for previous_exc in exceptions_classes:
- if previous_exc in exc_ancestors:
- msg = "%s is an ancestor class of %s" % (
- previous_exc.name,
- exc.name,
- )
- self.add_message(
- "bad-except-order", node=handler.type, args=msg
- )
- if (
- exc.name in self.config.overgeneral_exceptions
- and exc.root().name == utils.EXCEPTIONS_MODULE
- and not _is_raising(handler.body)
- ):
- self.add_message(
- "broad-except", args=exc.name, node=handler.type
- )
-
- if exc in exceptions_classes:
- self.add_message(
- "duplicate-except", args=exc.name, node=handler.type
- )
-
- exceptions_classes += [exc for _, exc in excs]
-
-
-def register(linter):
- """required method to auto register this checker"""
- linter.register_checker(ExceptionsChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/format.py b/venv/Lib/site-packages/pylint/checkers/format.py
deleted file mode 100644
index c4cad31..0000000
--- a/venv/Lib/site-packages/pylint/checkers/format.py
+++ /dev/null
@@ -1,1332 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012-2015 Google, Inc.
-# Copyright (c) 2013 moxian <aleftmail@inbox.ru>
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 frost-nzcr4 <frost.nzcr4@jagmort.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Mike Frysinger <vapier@gentoo.org>
-# Copyright (c) 2015 Fabio Natali <me@fabionatali.com>
-# Copyright (c) 2015 Harut <yes@harutune.name>
-# Copyright (c) 2015 Mihai Balint <balint.mihai@gmail.com>
-# Copyright (c) 2015 Pavel Roskin <proski@gnu.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Petr Pulc <petrpulc@gmail.com>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2017-2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Krzysztof Czapla <k.czapla68@gmail.com>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2017 James M. Allen <james.m.allen@gmail.com>
-# Copyright (c) 2017 vinnyrose <vinnyrose@users.noreply.github.com>
-# Copyright (c) 2018 Bryce Guinta <bryce.guinta@protonmail.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2018 Fureigh <rhys.fureigh@gsa.gov>
-# Copyright (c) 2018 Pierre Sassoulas <pierre.sassoulas@wisebim.fr>
-# Copyright (c) 2018 Andreas Freimuth <andreas.freimuth@united-bits.de>
-# Copyright (c) 2018 Jakub Wilk <jwilk@jwilk.net>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Python code format's checker.
-
-By default try to follow Guido's style guide :
-
-https://www.python.org/doc/essays/styleguide/
-
-Some parts of the process_token method is based from The Tab Nanny std module.
-"""
-
-import keyword
-import tokenize
-from functools import reduce # pylint: disable=redefined-builtin
-
-from astroid import nodes
-
-from pylint.checkers import BaseTokenChecker
-from pylint.checkers.utils import check_messages
-from pylint.constants import OPTION_RGX, WarningScope
-from pylint.interfaces import IAstroidChecker, IRawChecker, ITokenChecker
-
-_ASYNC_TOKEN = "async"
-_CONTINUATION_BLOCK_OPENERS = [
- "elif",
- "except",
- "for",
- "if",
- "while",
- "def",
- "class",
- "with",
-]
-_KEYWORD_TOKENS = [
- "assert",
- "del",
- "elif",
- "except",
- "for",
- "if",
- "in",
- "not",
- "raise",
- "return",
- "while",
- "yield",
- "with",
-]
-
-_SPACED_OPERATORS = [
- "==",
- "<",
- ">",
- "!=",
- "<>",
- "<=",
- ">=",
- "+=",
- "-=",
- "*=",
- "**=",
- "/=",
- "//=",
- "&=",
- "|=",
- "^=",
- "%=",
- ">>=",
- "<<=",
-]
-_OPENING_BRACKETS = ["(", "[", "{"]
-_CLOSING_BRACKETS = [")", "]", "}"]
-_TAB_LENGTH = 8
-
-_EOL = frozenset([tokenize.NEWLINE, tokenize.NL, tokenize.COMMENT])
-_JUNK_TOKENS = (tokenize.COMMENT, tokenize.NL)
-
-# Whitespace checking policy constants
-_MUST = 0
-_MUST_NOT = 1
-_IGNORE = 2
-
-# Whitespace checking config constants
-_DICT_SEPARATOR = "dict-separator"
-_TRAILING_COMMA = "trailing-comma"
-_EMPTY_LINE = "empty-line"
-_NO_SPACE_CHECK_CHOICES = [_TRAILING_COMMA, _DICT_SEPARATOR, _EMPTY_LINE]
-_DEFAULT_NO_SPACE_CHECK_CHOICES = [_TRAILING_COMMA, _DICT_SEPARATOR]
-
-MSGS = {
- "C0301": (
- "Line too long (%s/%s)",
- "line-too-long",
- "Used when a line is longer than a given number of characters.",
- ),
- "C0302": (
- "Too many lines in module (%s/%s)", # was W0302
- "too-many-lines",
- "Used when a module has too many lines, reducing its readability.",
- ),
- "C0303": (
- "Trailing whitespace",
- "trailing-whitespace",
- "Used when there is whitespace between the end of a line and the newline.",
- ),
- "C0304": (
- "Final newline missing",
- "missing-final-newline",
- "Used when the last line in a file is missing a newline.",
- ),
- "C0305": (
- "Trailing newlines",
- "trailing-newlines",
- "Used when there are trailing blank lines in a file.",
- ),
- "W0311": (
- "Bad indentation. Found %s %s, expected %s",
- "bad-indentation",
- "Used when an unexpected number of indentation's tabulations or "
- "spaces has been found.",
- ),
- "C0330": ("Wrong %s indentation%s%s.\n%s%s", "bad-continuation", "TODO"),
- "W0312": (
- "Found indentation with %ss instead of %ss",
- "mixed-indentation",
- "Used when there are some mixed tabs and spaces in a module.",
- ),
- "W0301": (
- "Unnecessary semicolon", # was W0106
- "unnecessary-semicolon",
- 'Used when a statement is ended by a semi-colon (";"), which '
- "isn't necessary (that's python, not C ;).",
- ),
- "C0321": (
- "More than one statement on a single line",
- "multiple-statements",
- "Used when more than on statement are found on the same line.",
- {"scope": WarningScope.NODE},
- ),
- "C0325": (
- "Unnecessary parens after %r keyword",
- "superfluous-parens",
- "Used when a single item in parentheses follows an if, for, or "
- "other keyword.",
- ),
- "C0326": (
- "%s space %s %s %s\n%s",
- "bad-whitespace",
- (
- "Used when a wrong number of spaces is used around an operator, "
- "bracket or block opener."
- ),
- {
- "old_names": [
- ("C0323", "no-space-after-operator"),
- ("C0324", "no-space-after-comma"),
- ("C0322", "no-space-before-operator"),
- ]
- },
- ),
- "C0327": (
- "Mixed line endings LF and CRLF",
- "mixed-line-endings",
- "Used when there are mixed (LF and CRLF) newline signs in a file.",
- ),
- "C0328": (
- "Unexpected line ending format. There is '%s' while it should be '%s'.",
- "unexpected-line-ending-format",
- "Used when there is different newline than expected.",
- ),
-}
-
-
-def _underline_token(token):
- length = token[3][1] - token[2][1]
- offset = token[2][1]
- referenced_line = token[4]
- # If the referenced line does not end with a newline char, fix it
- if referenced_line[-1] != "\n":
- referenced_line += "\n"
- return referenced_line + (" " * offset) + ("^" * length)
-
-
-def _column_distance(token1, token2):
- if token1 == token2:
- return 0
- if token2[3] < token1[3]:
- token1, token2 = token2, token1
- if token1[3][0] != token2[2][0]:
- return None
- return token2[2][1] - token1[3][1]
-
-
-def _last_token_on_line_is(tokens, line_end, token):
- return (
- line_end > 0
- and tokens.token(line_end - 1) == token
- or line_end > 1
- and tokens.token(line_end - 2) == token
- and tokens.type(line_end - 1) == tokenize.COMMENT
- )
-
-
-def _token_followed_by_eol(tokens, position):
- return (
- tokens.type(position + 1) == tokenize.NL
- or tokens.type(position + 1) == tokenize.COMMENT
- and tokens.type(position + 2) == tokenize.NL
- )
-
-
-def _get_indent_string(line):
- """Return the indention string of the given line."""
- result = ""
- for char in line:
- if char in " \t":
- result += char
- else:
- break
- return result
-
-
-def _get_indent_length(line):
- """Return the length of the indentation on the given token's line."""
- result = 0
- for char in line:
- if char == " ":
- result += 1
- elif char == "\t":
- result += _TAB_LENGTH
- else:
- break
- return result
-
-
-def _get_indent_hint_line(bar_positions, bad_position):
- """Return a line with |s for each of the positions in the given lists."""
- if not bar_positions:
- return "", ""
-
- bar_positions = [_get_indent_length(indent) for indent in bar_positions]
- bad_position = _get_indent_length(bad_position)
- delta_message = ""
- markers = [(pos, "|") for pos in bar_positions]
- if len(markers) == 1:
- # if we have only one marker we'll provide an extra hint on how to fix
- expected_position = markers[0][0]
- delta = abs(expected_position - bad_position)
- direction = "add" if expected_position > bad_position else "remove"
- delta_message = _CONTINUATION_HINT_MESSAGE % (
- direction,
- delta,
- "s" if delta > 1 else "",
- )
- markers.append((bad_position, "^"))
- markers.sort()
- line = [" "] * (markers[-1][0] + 1)
- for position, marker in markers:
- line[position] = marker
- return "".join(line), delta_message
-
-
-class _ContinuedIndent:
- __slots__ = (
- "valid_outdent_strings",
- "valid_continuation_strings",
- "context_type",
- "token",
- "position",
- )
-
- def __init__(
- self,
- context_type,
- token,
- position,
- valid_outdent_strings,
- valid_continuation_strings,
- ):
- self.valid_outdent_strings = valid_outdent_strings
- self.valid_continuation_strings = valid_continuation_strings
- self.context_type = context_type
- self.position = position
- self.token = token
-
-
-# The contexts for hanging indents.
-# A hanging indented dictionary value after :
-HANGING_DICT_VALUE = "dict-value"
-# Hanging indentation in an expression.
-HANGING = "hanging"
-# Hanging indentation in a block header.
-HANGING_BLOCK = "hanging-block"
-# Continued indentation inside an expression.
-CONTINUED = "continued"
-# Continued indentation in a block header.
-CONTINUED_BLOCK = "continued-block"
-
-SINGLE_LINE = "single"
-WITH_BODY = "multi"
-
-_CONTINUATION_MSG_PARTS = {
- HANGING_DICT_VALUE: ("hanging", " in dict value"),
- HANGING: ("hanging", ""),
- HANGING_BLOCK: ("hanging", " before block"),
- CONTINUED: ("continued", ""),
- CONTINUED_BLOCK: ("continued", " before block"),
-}
-
-_CONTINUATION_HINT_MESSAGE = " (%s %d space%s)" # Ex: (remove 2 spaces)
-
-
-def _Indentations(*args):
- """Valid indentation strings for a continued line."""
- return {a: None for a in args}
-
-
-def _BeforeBlockIndentations(single, with_body):
- """Valid alternative indentation strings for continued lines before blocks.
-
- :param int single: Valid indentation string for statements on a single logical line.
- :param int with_body: Valid indentation string for statements on several lines.
-
- :returns: A dictionary mapping indent offsets to a string representing
- whether the indent if for a line or block.
- :rtype: dict
- """
- return {single: SINGLE_LINE, with_body: WITH_BODY}
-
-
-class TokenWrapper:
- """A wrapper for readable access to token information."""
-
- def __init__(self, tokens):
- self._tokens = tokens
-
- def token(self, idx):
- return self._tokens[idx][1]
-
- def type(self, idx):
- return self._tokens[idx][0]
-
- def start_line(self, idx):
- return self._tokens[idx][2][0]
-
- def start_col(self, idx):
- return self._tokens[idx][2][1]
-
- def line(self, idx):
- return self._tokens[idx][4]
-
- def line_indent(self, idx):
- """Get the string of TABs and Spaces used for indentation of the line of this token"""
- return _get_indent_string(self.line(idx))
-
- def token_indent(self, idx):
- """Get an indentation string for hanging indentation, consisting of the line-indent plus
- a number of spaces to fill up to the column of this token.
-
- e.g. the token indent for foo
- in "<TAB><TAB>print(foo)"
- is "<TAB><TAB> "
- """
- line_indent = self.line_indent(idx)
- return line_indent + " " * (self.start_col(idx) - len(line_indent))
-
-
-class ContinuedLineState:
- """Tracker for continued indentation inside a logical line."""
-
- def __init__(self, tokens, config):
- self._line_start = -1
- self._cont_stack = []
- self._is_block_opener = False
- self.retained_warnings = []
- self._config = config
- self._tokens = TokenWrapper(tokens)
-
- @property
- def has_content(self):
- return bool(self._cont_stack)
-
- @property
- def _block_indent_string(self):
- return self._config.indent_string.replace("\\t", "\t")
-
- @property
- def _continuation_string(self):
- return self._block_indent_string[0] * self._config.indent_after_paren
-
- @property
- def _continuation_size(self):
- return self._config.indent_after_paren
-
- def handle_line_start(self, pos):
- """Record the first non-junk token at the start of a line."""
- if self._line_start > -1:
- return
-
- check_token_position = pos
- if self._tokens.token(pos) == _ASYNC_TOKEN:
- check_token_position += 1
- self._is_block_opener = (
- self._tokens.token(check_token_position) in _CONTINUATION_BLOCK_OPENERS
- )
- self._line_start = pos
-
- def next_physical_line(self):
- """Prepares the tracker for a new physical line (NL)."""
- self._line_start = -1
- self._is_block_opener = False
-
- def next_logical_line(self):
- """Prepares the tracker for a new logical line (NEWLINE).
-
- A new logical line only starts with block indentation.
- """
- self.next_physical_line()
- self.retained_warnings = []
- self._cont_stack = []
-
- def add_block_warning(self, token_position, state, valid_indentations):
- self.retained_warnings.append((token_position, state, valid_indentations))
-
- def get_valid_indentations(self, idx):
- """Returns the valid offsets for the token at the given position."""
- # The closing brace on a dict or the 'for' in a dict comprehension may
- # reset two indent levels because the dict value is ended implicitly
- stack_top = -1
- if (
- self._tokens.token(idx) in ("}", "for")
- and self._cont_stack[-1].token == ":"
- ):
- stack_top = -2
- indent = self._cont_stack[stack_top]
- if self._tokens.token(idx) in _CLOSING_BRACKETS:
- valid_indentations = indent.valid_outdent_strings
- else:
- valid_indentations = indent.valid_continuation_strings
- return indent, valid_indentations.copy()
-
- def _hanging_indent_after_bracket(self, bracket, position):
- """Extracts indentation information for a hanging indent
-
- Case of hanging indent after a bracket (including parenthesis)
-
- :param str bracket: bracket in question
- :param int position: Position of bracket in self._tokens
-
- :returns: the state and valid positions for hanging indentation
- :rtype: _ContinuedIndent
- """
- indentation = self._tokens.line_indent(position)
- if (
- self._is_block_opener
- and self._continuation_string == self._block_indent_string
- ):
- return _ContinuedIndent(
- HANGING_BLOCK,
- bracket,
- position,
- _Indentations(indentation + self._continuation_string, indentation),
- _BeforeBlockIndentations(
- indentation + self._continuation_string,
- indentation + self._continuation_string * 2,
- ),
- )
- if bracket == ":":
- # If the dict key was on the same line as the open brace, the new
- # correct indent should be relative to the key instead of the
- # current indent level
- paren_align = self._cont_stack[-1].valid_outdent_strings
- next_align = self._cont_stack[-1].valid_continuation_strings.copy()
- next_align_keys = list(next_align.keys())
- next_align[next_align_keys[0] + self._continuation_string] = True
- # Note that the continuation of
- # d = {
- # 'a': 'b'
- # 'c'
- # }
- # is handled by the special-casing for hanging continued string indents.
- return _ContinuedIndent(
- HANGING_DICT_VALUE, bracket, position, paren_align, next_align
- )
- return _ContinuedIndent(
- HANGING,
- bracket,
- position,
- _Indentations(indentation, indentation + self._continuation_string),
- _Indentations(indentation + self._continuation_string),
- )
-
- def _continuation_inside_bracket(self, bracket, position):
- """Extracts indentation information for a continued indent."""
- indentation = self._tokens.line_indent(position)
- token_indent = self._tokens.token_indent(position)
- next_token_indent = self._tokens.token_indent(position + 1)
- if (
- self._is_block_opener
- and next_token_indent == indentation + self._block_indent_string
- ):
- return _ContinuedIndent(
- CONTINUED_BLOCK,
- bracket,
- position,
- _Indentations(token_indent),
- _BeforeBlockIndentations(
- next_token_indent, next_token_indent + self._continuation_string
- ),
- )
- return _ContinuedIndent(
- CONTINUED,
- bracket,
- position,
- _Indentations(token_indent, next_token_indent),
- _Indentations(next_token_indent),
- )
-
- def pop_token(self):
- self._cont_stack.pop()
-
- def push_token(self, token, position):
- """Pushes a new token for continued indentation on the stack.
-
- Tokens that can modify continued indentation offsets are:
- * opening brackets
- * 'lambda'
- * : inside dictionaries
-
- push_token relies on the caller to filter out those
- interesting tokens.
-
- :param int token: The concrete token
- :param int position: The position of the token in the stream.
- """
- if _token_followed_by_eol(self._tokens, position):
- self._cont_stack.append(self._hanging_indent_after_bracket(token, position))
- else:
- self._cont_stack.append(self._continuation_inside_bracket(token, position))
-
-
-class FormatChecker(BaseTokenChecker):
- """checks for :
- * unauthorized constructions
- * strict indentation
- * line length
- """
-
- __implements__ = (ITokenChecker, IAstroidChecker, IRawChecker)
-
- # configuration section name
- name = "format"
- # messages
- msgs = MSGS
- # configuration options
- # for available dict keys/values see the optik parser 'add_option' method
- options = (
- (
- "max-line-length",
- {
- "default": 100,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of characters on a single line.",
- },
- ),
- (
- "ignore-long-lines",
- {
- "type": "regexp",
- "metavar": "<regexp>",
- "default": r"^\s*(# )?<?https?://\S+>?$",
- "help": (
- "Regexp for a line that is allowed to be longer than " "the limit."
- ),
- },
- ),
- (
- "single-line-if-stmt",
- {
- "default": False,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": (
- "Allow the body of an if to be on the same "
- "line as the test if there is no else."
- ),
- },
- ),
- (
- "single-line-class-stmt",
- {
- "default": False,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": (
- "Allow the body of a class to be on the same "
- "line as the declaration if body contains "
- "single statement."
- ),
- },
- ),
- (
- "no-space-check",
- {
- "default": ",".join(_DEFAULT_NO_SPACE_CHECK_CHOICES),
- "metavar": ",".join(_NO_SPACE_CHECK_CHOICES),
- "type": "multiple_choice",
- "choices": _NO_SPACE_CHECK_CHOICES,
- "help": (
- "List of optional constructs for which whitespace "
- "checking is disabled. "
- "`" + _DICT_SEPARATOR + "` is used to allow tabulation "
- "in dicts, etc.: {1 : 1,\\n222: 2}. "
- "`" + _TRAILING_COMMA + "` allows a space between comma "
- "and closing bracket: (a, ). "
- "`" + _EMPTY_LINE + "` allows space-only lines."
- ),
- },
- ),
- (
- "max-module-lines",
- {
- "default": 1000,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of lines in a module.",
- },
- ),
- (
- "indent-string",
- {
- "default": " ",
- "type": "non_empty_string",
- "metavar": "<string>",
- "help": "String used as indentation unit. This is usually "
- '" " (4 spaces) or "\\t" (1 tab).',
- },
- ),
- (
- "indent-after-paren",
- {
- "type": "int",
- "metavar": "<int>",
- "default": 4,
- "help": "Number of spaces of indent required inside a hanging "
- "or continued line.",
- },
- ),
- (
- "expected-line-ending-format",
- {
- "type": "choice",
- "metavar": "<empty or LF or CRLF>",
- "default": "",
- "choices": ["", "LF", "CRLF"],
- "help": (
- "Expected format of line ending, "
- "e.g. empty (any line ending), LF or CRLF."
- ),
- },
- ),
- )
-
- def __init__(self, linter=None):
- BaseTokenChecker.__init__(self, linter)
- self._lines = None
- self._visited_lines = None
- self._bracket_stack = [None]
-
- def _pop_token(self):
- self._bracket_stack.pop()
- self._current_line.pop_token()
-
- def _push_token(self, token, idx):
- self._bracket_stack.append(token)
- self._current_line.push_token(token, idx)
-
- def new_line(self, tokens, line_end, line_start):
- """a new line has been encountered, process it if necessary"""
- if _last_token_on_line_is(tokens, line_end, ";"):
- self.add_message("unnecessary-semicolon", line=tokens.start_line(line_end))
-
- line_num = tokens.start_line(line_start)
- line = tokens.line(line_start)
- if tokens.type(line_start) not in _JUNK_TOKENS:
- self._lines[line_num] = line.split("\n")[0]
- self.check_lines(line, line_num)
-
- def process_module(self, _module):
- self._keywords_with_parens = set()
-
- def _check_keyword_parentheses(self, tokens, start):
- """Check that there are not unnecessary parens after a keyword.
-
- Parens are unnecessary if there is exactly one balanced outer pair on a
- line, and it is followed by a colon, and contains no commas (i.e. is not a
- tuple).
-
- Args:
- tokens: list of Tokens; the entire list of Tokens.
- start: int; the position of the keyword in the token list.
- """
- # If the next token is not a paren, we're fine.
- if self._inside_brackets(":") and tokens[start][1] == "for":
- self._pop_token()
- if tokens[start + 1][1] != "(":
- return
-
- found_and_or = False
- depth = 0
- keyword_token = str(tokens[start][1])
- line_num = tokens[start][2][0]
-
- for i in range(start, len(tokens) - 1):
- token = tokens[i]
-
- # If we hit a newline, then assume any parens were for continuation.
- if token[0] == tokenize.NL:
- return
-
- if token[1] == "(":
- depth += 1
- elif token[1] == ")":
- depth -= 1
- if depth:
- continue
- # ')' can't happen after if (foo), since it would be a syntax error.
- if tokens[i + 1][1] in (":", ")", "]", "}", "in") or tokens[i + 1][
- 0
- ] in (tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT):
- # The empty tuple () is always accepted.
- if i == start + 2:
- return
- if keyword_token == "not":
- if not found_and_or:
- self.add_message(
- "superfluous-parens", line=line_num, args=keyword_token
- )
- elif keyword_token in ("return", "yield"):
- self.add_message(
- "superfluous-parens", line=line_num, args=keyword_token
- )
- elif keyword_token not in self._keywords_with_parens:
- if not found_and_or:
- self.add_message(
- "superfluous-parens", line=line_num, args=keyword_token
- )
- return
- elif depth == 1:
- # This is a tuple, which is always acceptable.
- if token[1] == ",":
- return
- # 'and' and 'or' are the only boolean operators with lower precedence
- # than 'not', so parens are only required when they are found.
- if token[1] in ("and", "or"):
- found_and_or = True
- # A yield inside an expression must always be in parentheses,
- # quit early without error.
- elif token[1] == "yield":
- return
- # A generator expression always has a 'for' token in it, and
- # the 'for' token is only legal inside parens when it is in a
- # generator expression. The parens are necessary here, so bail
- # without an error.
- elif token[1] == "for":
- return
-
- def _opening_bracket(self, tokens, i):
- self._push_token(tokens[i][1], i)
- # Special case: ignore slices
- if tokens[i][1] == "[" and tokens[i + 1][1] == ":":
- return
-
- if i > 0 and (
- tokens[i - 1][0] == tokenize.NAME
- and not (keyword.iskeyword(tokens[i - 1][1]))
- or tokens[i - 1][1] in _CLOSING_BRACKETS
- ):
- self._check_space(tokens, i, (_MUST_NOT, _MUST_NOT))
- else:
- self._check_space(tokens, i, (_IGNORE, _MUST_NOT))
-
- def _closing_bracket(self, tokens, i):
- if self._inside_brackets(":"):
- self._pop_token()
- self._pop_token()
- # Special case: ignore slices
- if tokens[i - 1][1] == ":" and tokens[i][1] == "]":
- return
- policy_before = _MUST_NOT
- if tokens[i][1] in _CLOSING_BRACKETS and tokens[i - 1][1] == ",":
- if _TRAILING_COMMA in self.config.no_space_check:
- policy_before = _IGNORE
-
- self._check_space(tokens, i, (policy_before, _IGNORE))
-
- def _has_valid_type_annotation(self, tokens, i):
- """Extended check of PEP-484 type hint presence"""
- if not self._inside_brackets("("):
- return False
- # token_info
- # type string start end line
- # 0 1 2 3 4
- bracket_level = 0
- for token in tokens[i - 1 :: -1]:
- if token[1] == ":":
- return True
- if token[1] == "(":
- return False
- if token[1] == "]":
- bracket_level += 1
- elif token[1] == "[":
- bracket_level -= 1
- elif token[1] == ",":
- if not bracket_level:
- return False
- elif token[1] in (".", "..."):
- continue
- elif token[0] not in (tokenize.NAME, tokenize.STRING, tokenize.NL):
- return False
- return False
-
- def _check_equals_spacing(self, tokens, i):
- """Check the spacing of a single equals sign."""
- if self._has_valid_type_annotation(tokens, i):
- self._check_space(tokens, i, (_MUST, _MUST))
- elif self._inside_brackets("(") or self._inside_brackets("lambda"):
- self._check_space(tokens, i, (_MUST_NOT, _MUST_NOT))
- else:
- self._check_space(tokens, i, (_MUST, _MUST))
-
- def _open_lambda(self, tokens, i): # pylint:disable=unused-argument
- self._push_token("lambda", i)
-
- def _handle_colon(self, tokens, i):
- # Special case: ignore slices
- if self._inside_brackets("["):
- return
- if self._inside_brackets("{") and _DICT_SEPARATOR in self.config.no_space_check:
- policy = (_IGNORE, _IGNORE)
- else:
- policy = (_MUST_NOT, _MUST)
- self._check_space(tokens, i, policy)
-
- if self._inside_brackets("lambda"):
- self._pop_token()
- elif self._inside_brackets("{"):
- self._push_token(":", i)
-
- def _handle_comma(self, tokens, i):
- # Only require a following whitespace if this is
- # not a hanging comma before a closing bracket.
- if tokens[i + 1][1] in _CLOSING_BRACKETS:
- self._check_space(tokens, i, (_MUST_NOT, _IGNORE))
- else:
- self._check_space(tokens, i, (_MUST_NOT, _MUST))
- if self._inside_brackets(":"):
- self._pop_token()
-
- def _check_surrounded_by_space(self, tokens, i):
- """Check that a binary operator is surrounded by exactly one space."""
- self._check_space(tokens, i, (_MUST, _MUST))
-
- def _check_space(self, tokens, i, policies):
- def _policy_string(policy):
- if policy == _MUST:
- return "Exactly one", "required"
- return "No", "allowed"
-
- def _name_construct(token):
- if token[1] == ",":
- return "comma"
- if token[1] == ":":
- return ":"
- if token[1] in "()[]{}":
- return "bracket"
- if token[1] in ("<", ">", "<=", ">=", "!=", "=="):
- return "comparison"
- if self._inside_brackets("("):
- return "keyword argument assignment"
- return "assignment"
-
- good_space = [True, True]
- token = tokens[i]
- pairs = [(tokens[i - 1], token), (token, tokens[i + 1])]
-
- for other_idx, (policy, token_pair) in enumerate(zip(policies, pairs)):
- if token_pair[other_idx][0] in _EOL or policy == _IGNORE:
- continue
-
- distance = _column_distance(*token_pair)
- if distance is None:
- continue
- good_space[other_idx] = (policy == _MUST and distance == 1) or (
- policy == _MUST_NOT and distance == 0
- )
-
- warnings = []
- if not any(good_space) and policies[0] == policies[1]:
- warnings.append((policies[0], "around"))
- else:
- for ok, policy, position in zip(good_space, policies, ("before", "after")):
- if not ok:
- warnings.append((policy, position))
- for policy, position in warnings:
- construct = _name_construct(token)
- count, state = _policy_string(policy)
- self.add_message(
- "bad-whitespace",
- line=token[2][0],
- args=(count, state, position, construct, _underline_token(token)),
- col_offset=token[2][1],
- )
-
- def _inside_brackets(self, left):
- return self._bracket_stack[-1] == left
-
- def _prepare_token_dispatcher(self):
- raw = [
- (_KEYWORD_TOKENS, self._check_keyword_parentheses),
- (_OPENING_BRACKETS, self._opening_bracket),
- (_CLOSING_BRACKETS, self._closing_bracket),
- (["="], self._check_equals_spacing),
- (_SPACED_OPERATORS, self._check_surrounded_by_space),
- ([","], self._handle_comma),
- ([":"], self._handle_colon),
- (["lambda"], self._open_lambda),
- ]
-
- dispatch = {}
- for tokens, handler in raw:
- for token in tokens:
- dispatch[token] = handler
- return dispatch
-
- def process_tokens(self, tokens):
- """process tokens and search for :
-
- _ non strict indentation (i.e. not always using the <indent> parameter as
- indent unit)
- _ too long lines (i.e. longer than <max_chars>)
- _ optionally bad construct (if given, bad_construct must be a compiled
- regular expression).
- """
- self._bracket_stack = [None]
- indents = [0]
- check_equal = False
- line_num = 0
- self._lines = {}
- self._visited_lines = {}
- token_handlers = self._prepare_token_dispatcher()
- self._last_line_ending = None
- last_blank_line_num = 0
-
- self._current_line = ContinuedLineState(tokens, self.config)
- for idx, (tok_type, token, start, _, line) in enumerate(tokens):
- if start[0] != line_num:
- line_num = start[0]
- # A tokenizer oddity: if an indented line contains a multi-line
- # docstring, the line member of the INDENT token does not contain
- # the full line; therefore we check the next token on the line.
- if tok_type == tokenize.INDENT:
- self.new_line(TokenWrapper(tokens), idx - 1, idx + 1)
- else:
- self.new_line(TokenWrapper(tokens), idx - 1, idx)
-
- if tok_type == tokenize.NEWLINE:
- # a program statement, or ENDMARKER, will eventually follow,
- # after some (possibly empty) run of tokens of the form
- # (NL | COMMENT)* (INDENT | DEDENT+)?
- # If an INDENT appears, setting check_equal is wrong, and will
- # be undone when we see the INDENT.
- check_equal = True
- self._process_retained_warnings(TokenWrapper(tokens), idx)
- self._current_line.next_logical_line()
- self._check_line_ending(token, line_num)
- elif tok_type == tokenize.INDENT:
- check_equal = False
- self.check_indent_level(token, indents[-1] + 1, line_num)
- indents.append(indents[-1] + 1)
- elif tok_type == tokenize.DEDENT:
- # there's nothing we need to check here! what's important is
- # that when the run of DEDENTs ends, the indentation of the
- # program statement (or ENDMARKER) that triggered the run is
- # equal to what's left at the top of the indents stack
- check_equal = True
- if len(indents) > 1:
- del indents[-1]
- elif tok_type == tokenize.NL:
- if not line.strip("\r\n"):
- last_blank_line_num = line_num
- self._check_continued_indentation(TokenWrapper(tokens), idx + 1)
- self._current_line.next_physical_line()
- elif tok_type not in (tokenize.COMMENT, tokenize.ENCODING):
- self._current_line.handle_line_start(idx)
- # This is the first concrete token following a NEWLINE, so it
- # must be the first token of the next program statement, or an
- # ENDMARKER; the "line" argument exposes the leading whitespace
- # for this statement; in the case of ENDMARKER, line is an empty
- # string, so will properly match the empty string with which the
- # "indents" stack was seeded
- if check_equal:
- check_equal = False
- self.check_indent_level(line, indents[-1], line_num)
-
- if tok_type == tokenize.NUMBER and token.endswith("l"):
- self.add_message("lowercase-l-suffix", line=line_num)
-
- try:
- handler = token_handlers[token]
- except KeyError:
- pass
- else:
- handler(tokens, idx)
-
- line_num -= 1 # to be ok with "wc -l"
- if line_num > self.config.max_module_lines:
- # Get the line where the too-many-lines (or its message id)
- # was disabled or default to 1.
- message_definition = self.linter.msgs_store.get_message_definitions(
- "too-many-lines"
- )[0]
- names = (message_definition.msgid, "too-many-lines")
- line = next(filter(None, map(self.linter._pragma_lineno.get, names)), 1)
- self.add_message(
- "too-many-lines",
- args=(line_num, self.config.max_module_lines),
- line=line,
- )
-
- # See if there are any trailing lines. Do not complain about empty
- # files like __init__.py markers.
- if line_num == last_blank_line_num and line_num > 0:
- self.add_message("trailing-newlines", line=line_num)
-
- def _check_line_ending(self, line_ending, line_num):
- # check if line endings are mixed
- if self._last_line_ending is not None:
- # line_ending == "" indicates a synthetic newline added at
- # the end of a file that does not, in fact, end with a
- # newline.
- if line_ending and line_ending != self._last_line_ending:
- self.add_message("mixed-line-endings", line=line_num)
-
- self._last_line_ending = line_ending
-
- # check if line ending is as expected
- expected = self.config.expected_line_ending_format
- if expected:
- # reduce multiple \n\n\n\n to one \n
- line_ending = reduce(lambda x, y: x + y if x != y else x, line_ending, "")
- line_ending = "LF" if line_ending == "\n" else "CRLF"
- if line_ending != expected:
- self.add_message(
- "unexpected-line-ending-format",
- args=(line_ending, expected),
- line=line_num,
- )
-
- def _process_retained_warnings(self, tokens, current_pos):
- single_line_block_stmt = not _last_token_on_line_is(tokens, current_pos, ":")
-
- for indent_pos, state, indentations in self._current_line.retained_warnings:
- block_type = indentations[tokens.token_indent(indent_pos)]
- hints = {k: v for k, v in indentations.items() if v != block_type}
- if single_line_block_stmt and block_type == WITH_BODY:
- self._add_continuation_message(state, hints, tokens, indent_pos)
- elif not single_line_block_stmt and block_type == SINGLE_LINE:
- self._add_continuation_message(state, hints, tokens, indent_pos)
-
- def _check_continued_indentation(self, tokens, next_idx):
- def same_token_around_nl(token_type):
- return (
- tokens.type(next_idx) == token_type
- and tokens.type(next_idx - 2) == token_type
- )
-
- # Do not issue any warnings if the next line is empty.
- if not self._current_line.has_content or tokens.type(next_idx) == tokenize.NL:
- return
-
- state, valid_indentations = self._current_line.get_valid_indentations(next_idx)
- # Special handling for hanging comments and strings. If the last line ended
- # with a comment (string) and the new line contains only a comment, the line
- # may also be indented to the start of the previous token.
- if same_token_around_nl(tokenize.COMMENT) or same_token_around_nl(
- tokenize.STRING
- ):
- valid_indentations[tokens.token_indent(next_idx - 2)] = True
-
- # We can only decide if the indentation of a continued line before opening
- # a new block is valid once we know of the body of the block is on the
- # same line as the block opener. Since the token processing is single-pass,
- # emitting those warnings is delayed until the block opener is processed.
- if (
- state.context_type in (HANGING_BLOCK, CONTINUED_BLOCK)
- and tokens.token_indent(next_idx) in valid_indentations
- ):
- self._current_line.add_block_warning(next_idx, state, valid_indentations)
- elif tokens.token_indent(next_idx) not in valid_indentations:
- length_indentation = len(tokens.token_indent(next_idx))
- if not any(
- length_indentation == 2 * len(indentation)
- for indentation in valid_indentations
- ):
- self._add_continuation_message(
- state, valid_indentations, tokens, next_idx
- )
-
- def _add_continuation_message(self, state, indentations, tokens, position):
- readable_type, readable_position = _CONTINUATION_MSG_PARTS[state.context_type]
- hint_line, delta_message = _get_indent_hint_line(
- indentations, tokens.token_indent(position)
- )
- self.add_message(
- "bad-continuation",
- line=tokens.start_line(position),
- args=(
- readable_type,
- readable_position,
- delta_message,
- tokens.line(position),
- hint_line,
- ),
- )
-
- @check_messages("multiple-statements")
- def visit_default(self, node):
- """check the node line number and check it if not yet done"""
- if not node.is_statement:
- return
- if not node.root().pure_python:
- return
- prev_sibl = node.previous_sibling()
- if prev_sibl is not None:
- prev_line = prev_sibl.fromlineno
- else:
- # The line on which a finally: occurs in a try/finally
- # is not directly represented in the AST. We infer it
- # by taking the last line of the body and adding 1, which
- # should be the line of finally:
- if (
- isinstance(node.parent, nodes.TryFinally)
- and node in node.parent.finalbody
- ):
- prev_line = node.parent.body[0].tolineno + 1
- else:
- prev_line = node.parent.statement().fromlineno
- line = node.fromlineno
- assert line, node
- if prev_line == line and self._visited_lines.get(line) != 2:
- self._check_multi_statement_line(node, line)
- return
- if line in self._visited_lines:
- return
- try:
- tolineno = node.blockstart_tolineno
- except AttributeError:
- tolineno = node.tolineno
- assert tolineno, node
- lines = []
- for line in range(line, tolineno + 1):
- self._visited_lines[line] = 1
- try:
- lines.append(self._lines[line].rstrip())
- except KeyError:
- lines.append("")
-
- def _check_multi_statement_line(self, node, line):
- """Check for lines containing multiple statements."""
- # Do not warn about multiple nested context managers
- # in with statements.
- if isinstance(node, nodes.With):
- return
- # For try... except... finally..., the two nodes
- # appear to be on the same line due to how the AST is built.
- if isinstance(node, nodes.TryExcept) and isinstance(
- node.parent, nodes.TryFinally
- ):
- return
- if (
- isinstance(node.parent, nodes.If)
- and not node.parent.orelse
- and self.config.single_line_if_stmt
- ):
- return
- if (
- isinstance(node.parent, nodes.ClassDef)
- and len(node.parent.body) == 1
- and self.config.single_line_class_stmt
- ):
- return
- self.add_message("multiple-statements", node=node)
- self._visited_lines[line] = 2
-
- def check_lines(self, lines, i):
- """check lines have less than a maximum number of characters
- """
- max_chars = self.config.max_line_length
- ignore_long_line = self.config.ignore_long_lines
-
- def check_line(line, i):
- if not line.endswith("\n"):
- self.add_message("missing-final-newline", line=i)
- else:
- # exclude \f (formfeed) from the rstrip
- stripped_line = line.rstrip("\t\n\r\v ")
- if not stripped_line and _EMPTY_LINE in self.config.no_space_check:
- # allow empty lines
- pass
- elif line[len(stripped_line) :] not in ("\n", "\r\n"):
- self.add_message(
- "trailing-whitespace", line=i, col_offset=len(stripped_line)
- )
- # Don't count excess whitespace in the line length.
- line = stripped_line
- mobj = OPTION_RGX.search(line)
- if mobj and "=" in line:
- front_of_equal, _, back_of_equal = mobj.group(1).partition("=")
- if front_of_equal.strip() == "disable":
- if "line-too-long" in {
- _msg_id.strip() for _msg_id in back_of_equal.split(",")
- }:
- return None
- line = line.rsplit("#", 1)[0].rstrip()
-
- if len(line) > max_chars and not ignore_long_line.search(line):
- self.add_message("line-too-long", line=i, args=(len(line), max_chars))
- return i + 1
-
- unsplit_ends = {
- "\v",
- "\x0b",
- "\f",
- "\x0c",
- "\x1c",
- "\x1d",
- "\x1e",
- "\x85",
- "\u2028",
- "\u2029",
- }
- unsplit = []
- for line in lines.splitlines(True):
- if line[-1] in unsplit_ends:
- unsplit.append(line)
- continue
-
- if unsplit:
- unsplit.append(line)
- line = "".join(unsplit)
- unsplit = []
-
- i = check_line(line, i)
- if i is None:
- break
-
- if unsplit:
- check_line("".join(unsplit), i)
-
- def check_indent_level(self, string, expected, line_num):
- """return the indent level of the string
- """
- indent = self.config.indent_string
- if indent == "\\t": # \t is not interpreted in the configuration file
- indent = "\t"
- level = 0
- unit_size = len(indent)
- while string[:unit_size] == indent:
- string = string[unit_size:]
- level += 1
- suppl = ""
- while string and string[0] in " \t":
- if string[0] != indent[0]:
- if string[0] == "\t":
- args = ("tab", "space")
- else:
- args = ("space", "tab")
- self.add_message("mixed-indentation", args=args, line=line_num)
- return level
- suppl += string[0]
- string = string[1:]
- if level != expected or suppl:
- i_type = "spaces"
- if indent[0] == "\t":
- i_type = "tabs"
- self.add_message(
- "bad-indentation",
- line=line_num,
- args=(level * unit_size + len(suppl), i_type, expected * unit_size),
- )
- return None
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(FormatChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/imports.py b/venv/Lib/site-packages/pylint/checkers/imports.py
deleted file mode 100644
index 42d4362..0000000
--- a/venv/Lib/site-packages/pylint/checkers/imports.py
+++ /dev/null
@@ -1,981 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2013 buck@yelp.com <buck@yelp.com>
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
-# Copyright (c) 2015 Cezar <celnazli@bitdefender.com>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Noam Yorav-Raphael <noamraph@gmail.com>
-# Copyright (c) 2015 James Morgensen <james.morgensen@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Jared Garst <cultofjared@gmail.com>
-# Copyright (c) 2016 Maik Röder <maikroeder@gmail.com>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Michka Popoff <michkapopoff@gmail.com>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2017 Erik Wright <erik.wright@shopify.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Marianna Polatoglou <mpolatoglou@bloomberg.net>
-# Copyright (c) 2019 Paul Renvoise <renvoisepaul@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""imports checkers for Python code"""
-
-import collections
-import copy
-import os
-import sys
-from distutils import sysconfig
-
-import astroid
-import isort
-from astroid import modutils
-from astroid.decorators import cached
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import (
- check_messages,
- is_from_fallback_block,
- node_ignores_exception,
-)
-from pylint.exceptions import EmptyReportError
-from pylint.graph import DotBackend, get_cycles
-from pylint.interfaces import IAstroidChecker
-from pylint.reporters.ureports.nodes import Paragraph, VerbatimText
-from pylint.utils import get_global_option
-
-
-def _qualified_names(modname):
- """Split the names of the given module into subparts
-
- For example,
- _qualified_names('pylint.checkers.ImportsChecker')
- returns
- ['pylint', 'pylint.checkers', 'pylint.checkers.ImportsChecker']
- """
- names = modname.split(".")
- return [".".join(names[0 : i + 1]) for i in range(len(names))]
-
-
-def _get_import_name(importnode, modname):
- """Get a prepared module name from the given import node
-
- In the case of relative imports, this will return the
- absolute qualified module name, which might be useful
- for debugging. Otherwise, the initial module name
- is returned unchanged.
- """
- if isinstance(importnode, astroid.ImportFrom):
- if importnode.level:
- root = importnode.root()
- if isinstance(root, astroid.Module):
- modname = root.relative_to_absolute_name(
- modname, level=importnode.level
- )
- return modname
-
-
-def _get_first_import(node, context, name, base, level, alias):
- """return the node where [base.]<name> is imported or None if not found
- """
- fullname = "%s.%s" % (base, name) if base else name
-
- first = None
- found = False
- for first in context.body:
- if first is node:
- continue
- if first.scope() is node.scope() and first.fromlineno > node.fromlineno:
- continue
- if isinstance(first, astroid.Import):
- if any(fullname == iname[0] for iname in first.names):
- found = True
- break
- elif isinstance(first, astroid.ImportFrom):
- if level == first.level:
- for imported_name, imported_alias in first.names:
- if fullname == "%s.%s" % (first.modname, imported_name):
- found = True
- break
- if (
- name != "*"
- and name == imported_name
- and not (alias or imported_alias)
- ):
- found = True
- break
- if found:
- break
- if found and not astroid.are_exclusive(first, node):
- return first
- return None
-
-
-def _ignore_import_failure(node, modname, ignored_modules):
- for submodule in _qualified_names(modname):
- if submodule in ignored_modules:
- return True
-
- return node_ignores_exception(node, ImportError)
-
-
-# utilities to represents import dependencies as tree and dot graph ###########
-
-
-def _make_tree_defs(mod_files_list):
- """get a list of 2-uple (module, list_of_files_which_import_this_module),
- it will return a dictionary to represent this as a tree
- """
- tree_defs = {}
- for mod, files in mod_files_list:
- node = (tree_defs, ())
- for prefix in mod.split("."):
- node = node[0].setdefault(prefix, [{}, []])
- node[1] += files
- return tree_defs
-
-
-def _repr_tree_defs(data, indent_str=None):
- """return a string which represents imports as a tree"""
- lines = []
- nodes = data.items()
- for i, (mod, (sub, files)) in enumerate(sorted(nodes, key=lambda x: x[0])):
- if not files:
- files = ""
- else:
- files = "(%s)" % ",".join(sorted(files))
- if indent_str is None:
- lines.append("%s %s" % (mod, files))
- sub_indent_str = " "
- else:
- lines.append(r"%s\-%s %s" % (indent_str, mod, files))
- if i == len(nodes) - 1:
- sub_indent_str = "%s " % indent_str
- else:
- sub_indent_str = "%s| " % indent_str
- if sub:
- lines.append(_repr_tree_defs(sub, sub_indent_str))
- return "\n".join(lines)
-
-
-def _dependencies_graph(filename, dep_info):
- """write dependencies as a dot (graphviz) file
- """
- done = {}
- printer = DotBackend(filename[:-4], rankdir="LR")
- printer.emit('URL="." node[shape="box"]')
- for modname, dependencies in sorted(dep_info.items()):
- done[modname] = 1
- printer.emit_node(modname)
- for depmodname in dependencies:
- if depmodname not in done:
- done[depmodname] = 1
- printer.emit_node(depmodname)
- for depmodname, dependencies in sorted(dep_info.items()):
- for modname in dependencies:
- printer.emit_edge(modname, depmodname)
- printer.generate(filename)
-
-
-def _make_graph(filename, dep_info, sect, gtype):
- """generate a dependencies graph and add some information about it in the
- report's section
- """
- _dependencies_graph(filename, dep_info)
- sect.append(Paragraph("%simports graph has been written to %s" % (gtype, filename)))
-
-
-# the import checker itself ###################################################
-
-MSGS = {
- "E0401": (
- "Unable to import %s",
- "import-error",
- "Used when pylint has been unable to import a module.",
- {"old_names": [("F0401", "old-import-error")]},
- ),
- "E0402": (
- "Attempted relative import beyond top-level package",
- "relative-beyond-top-level",
- "Used when a relative import tries to access too many levels "
- "in the current package.",
- ),
- "R0401": (
- "Cyclic import (%s)",
- "cyclic-import",
- "Used when a cyclic import between two or more modules is detected.",
- ),
- "W0401": (
- "Wildcard import %s",
- "wildcard-import",
- "Used when `from module import *` is detected.",
- ),
- "W0402": (
- "Uses of a deprecated module %r",
- "deprecated-module",
- "Used a module marked as deprecated is imported.",
- ),
- "W0404": (
- "Reimport %r (imported line %s)",
- "reimported",
- "Used when a module is reimported multiple times.",
- ),
- "W0406": (
- "Module import itself",
- "import-self",
- "Used when a module is importing itself.",
- ),
- "W0407": (
- "Prefer importing %r instead of %r",
- "preferred-module",
- "Used when a module imported has a preferred replacement module.",
- ),
- "W0410": (
- "__future__ import is not the first non docstring statement",
- "misplaced-future",
- "Python 2.5 and greater require __future__ import to be the "
- "first non docstring statement in the module.",
- ),
- "C0410": (
- "Multiple imports on one line (%s)",
- "multiple-imports",
- "Used when import statement importing multiple modules is detected.",
- ),
- "C0411": (
- "%s should be placed before %s",
- "wrong-import-order",
- "Used when PEP8 import order is not respected (standard imports "
- "first, then third-party libraries, then local imports)",
- ),
- "C0412": (
- "Imports from package %s are not grouped",
- "ungrouped-imports",
- "Used when imports are not grouped by packages",
- ),
- "C0413": (
- 'Import "%s" should be placed at the top of the module',
- "wrong-import-position",
- "Used when code and imports are mixed",
- ),
- "C0414": (
- "Import alias does not rename original package",
- "useless-import-alias",
- "Used when an import alias is same as original package."
- "e.g using import numpy as numpy instead of import numpy as np",
- ),
- "C0415": (
- "Import outside toplevel (%s)",
- "import-outside-toplevel",
- "Used when an import statement is used anywhere other than the module "
- "toplevel. Move this import to the top of the file.",
- ),
-}
-
-
-DEFAULT_STANDARD_LIBRARY = ()
-DEFAULT_KNOWN_THIRD_PARTY = ("enchant",)
-DEFAULT_PREFERRED_MODULES = ()
-
-
-class ImportsChecker(BaseChecker):
- """checks for
- * external modules dependencies
- * relative / wildcard imports
- * cyclic imports
- * uses of deprecated modules
- * uses of modules instead of preferred modules
- """
-
- __implements__ = IAstroidChecker
-
- name = "imports"
- msgs = MSGS
- priority = -2
- deprecated_modules = ("optparse", "tkinter.tix")
-
- options = (
- (
- "deprecated-modules",
- {
- "default": deprecated_modules,
- "type": "csv",
- "metavar": "<modules>",
- "help": "Deprecated modules which should not be used,"
- " separated by a comma.",
- },
- ),
- (
- "preferred-modules",
- {
- "default": DEFAULT_PREFERRED_MODULES,
- "type": "csv",
- "metavar": "<module:preferred-module>",
- "help": "Couples of modules and preferred modules,"
- " separated by a comma.",
- },
- ),
- (
- "import-graph",
- {
- "default": "",
- "type": "string",
- "metavar": "<file.dot>",
- "help": "Create a graph of every (i.e. internal and"
- " external) dependencies in the given file"
- " (report RP0402 must not be disabled).",
- },
- ),
- (
- "ext-import-graph",
- {
- "default": "",
- "type": "string",
- "metavar": "<file.dot>",
- "help": "Create a graph of external dependencies in the"
- " given file (report RP0402 must not be disabled).",
- },
- ),
- (
- "int-import-graph",
- {
- "default": "",
- "type": "string",
- "metavar": "<file.dot>",
- "help": "Create a graph of internal dependencies in the"
- " given file (report RP0402 must not be disabled).",
- },
- ),
- (
- "known-standard-library",
- {
- "default": DEFAULT_STANDARD_LIBRARY,
- "type": "csv",
- "metavar": "<modules>",
- "help": "Force import order to recognize a module as part of "
- "the standard compatibility libraries.",
- },
- ),
- (
- "known-third-party",
- {
- "default": DEFAULT_KNOWN_THIRD_PARTY,
- "type": "csv",
- "metavar": "<modules>",
- "help": "Force import order to recognize a module as part of "
- "a third party library.",
- },
- ),
- (
- "allow-any-import-level",
- {
- "default": (),
- "type": "csv",
- "metavar": "<modules>",
- "help": (
- "List of modules that can be imported at any level, not just "
- "the top level one."
- ),
- },
- ),
- (
- "analyse-fallback-blocks",
- {
- "default": False,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "Analyse import fallback blocks. This can be used to "
- "support both Python 2 and 3 compatible code, which "
- "means that the block might have code that exists "
- "only in one or another interpreter, leading to false "
- "positives when analysed.",
- },
- ),
- (
- "allow-wildcard-with-all",
- {
- "default": False,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "Allow wildcard imports from modules that define __all__.",
- },
- ),
- )
-
- def __init__(self, linter=None):
- BaseChecker.__init__(self, linter)
- self.stats = None
- self.import_graph = None
- self._imports_stack = []
- self._first_non_import_node = None
- self._module_pkg = {} # mapping of modules to the pkg they belong in
- self._allow_any_import_level = set()
- self.reports = (
- ("RP0401", "External dependencies", self._report_external_dependencies),
- ("RP0402", "Modules dependencies graph", self._report_dependencies_graph),
- )
-
- self._site_packages = self._compute_site_packages()
-
- @staticmethod
- def _compute_site_packages():
- def _normalized_path(path):
- return os.path.normcase(os.path.abspath(path))
-
- paths = set()
- real_prefix = getattr(sys, "real_prefix", None)
- for prefix in filter(None, (real_prefix, sys.prefix)):
- path = sysconfig.get_python_lib(prefix=prefix)
- path = _normalized_path(path)
- paths.add(path)
-
- # Handle Debian's derivatives /usr/local.
- if os.path.isfile("/etc/debian_version"):
- for prefix in filter(None, (real_prefix, sys.prefix)):
- libpython = os.path.join(
- prefix,
- "local",
- "lib",
- "python" + sysconfig.get_python_version(),
- "dist-packages",
- )
- paths.add(libpython)
- return paths
-
- def open(self):
- """called before visiting project (i.e set of modules)"""
- self.linter.add_stats(dependencies={})
- self.linter.add_stats(cycles=[])
- self.stats = self.linter.stats
- self.import_graph = collections.defaultdict(set)
- self._module_pkg = {} # mapping of modules to the pkg they belong in
- self._excluded_edges = collections.defaultdict(set)
- self._ignored_modules = get_global_option(self, "ignored-modules", default=[])
- # Build a mapping {'module': 'preferred-module'}
- self.preferred_modules = dict(
- module.split(":")
- for module in self.config.preferred_modules
- if ":" in module
- )
- self._allow_any_import_level = set(self.config.allow_any_import_level)
-
- def _import_graph_without_ignored_edges(self):
- filtered_graph = copy.deepcopy(self.import_graph)
- for node in filtered_graph:
- filtered_graph[node].difference_update(self._excluded_edges[node])
- return filtered_graph
-
- def close(self):
- """called before visiting project (i.e set of modules)"""
- if self.linter.is_message_enabled("cyclic-import"):
- graph = self._import_graph_without_ignored_edges()
- vertices = list(graph)
- for cycle in get_cycles(graph, vertices=vertices):
- self.add_message("cyclic-import", args=" -> ".join(cycle))
-
- @check_messages(*MSGS)
- def visit_import(self, node):
- """triggered when an import statement is seen"""
- self._check_reimport(node)
- self._check_import_as_rename(node)
- self._check_toplevel(node)
-
- names = [name for name, _ in node.names]
- if len(names) >= 2:
- self.add_message("multiple-imports", args=", ".join(names), node=node)
-
- for name in names:
- self._check_deprecated_module(node, name)
- self._check_preferred_module(node, name)
- imported_module = self._get_imported_module(node, name)
- if isinstance(node.parent, astroid.Module):
- # Allow imports nested
- self._check_position(node)
- if isinstance(node.scope(), astroid.Module):
- self._record_import(node, imported_module)
-
- if imported_module is None:
- continue
-
- self._add_imported_module(node, imported_module.name)
-
- @check_messages(*MSGS)
- def visit_importfrom(self, node):
- """triggered when a from statement is seen"""
- basename = node.modname
- imported_module = self._get_imported_module(node, basename)
-
- self._check_import_as_rename(node)
- self._check_misplaced_future(node)
- self._check_deprecated_module(node, basename)
- self._check_preferred_module(node, basename)
- self._check_wildcard_imports(node, imported_module)
- self._check_same_line_imports(node)
- self._check_reimport(node, basename=basename, level=node.level)
- self._check_toplevel(node)
-
- if isinstance(node.parent, astroid.Module):
- # Allow imports nested
- self._check_position(node)
- if isinstance(node.scope(), astroid.Module):
- self._record_import(node, imported_module)
- if imported_module is None:
- return
- for name, _ in node.names:
- if name != "*":
- self._add_imported_module(node, "%s.%s" % (imported_module.name, name))
- else:
- self._add_imported_module(node, imported_module.name)
-
- @check_messages(*MSGS)
- def leave_module(self, node):
- # Check imports are grouped by category (standard, 3rd party, local)
- std_imports, ext_imports, loc_imports = self._check_imports_order(node)
-
- # Check that imports are grouped by package within a given category
- met_import = set() #  set for 'import x' style
- met_from = set() #  set for 'from x import y' style
- current_package = None
- for import_node, import_name in std_imports + ext_imports + loc_imports:
- if not self.linter.is_message_enabled(
- "ungrouped-imports", import_node.fromlineno
- ):
- continue
- if isinstance(import_node, astroid.node_classes.ImportFrom):
- met = met_from
- else:
- met = met_import
- package, _, _ = import_name.partition(".")
- if current_package and current_package != package and package in met:
- self.add_message("ungrouped-imports", node=import_node, args=package)
- current_package = package
- met.add(package)
-
- self._imports_stack = []
- self._first_non_import_node = None
-
- def compute_first_non_import_node(self, node):
- if not self.linter.is_message_enabled("wrong-import-position", node.fromlineno):
- return
- # if the node does not contain an import instruction, and if it is the
- # first node of the module, keep a track of it (all the import positions
- # of the module will be compared to the position of this first
- # instruction)
- if self._first_non_import_node:
- return
- if not isinstance(node.parent, astroid.Module):
- return
- nested_allowed = [astroid.TryExcept, astroid.TryFinally]
- is_nested_allowed = [
- allowed for allowed in nested_allowed if isinstance(node, allowed)
- ]
- if is_nested_allowed and any(
- node.nodes_of_class((astroid.Import, astroid.ImportFrom))
- ):
- return
- if isinstance(node, astroid.Assign):
- # Add compatibility for module level dunder names
- # https://www.python.org/dev/peps/pep-0008/#module-level-dunder-names
- valid_targets = [
- isinstance(target, astroid.AssignName)
- and target.name.startswith("__")
- and target.name.endswith("__")
- for target in node.targets
- ]
- if all(valid_targets):
- return
- self._first_non_import_node = node
-
- visit_tryfinally = (
- visit_tryexcept
- ) = (
- visit_assignattr
- ) = (
- visit_assign
- ) = (
- visit_ifexp
- ) = visit_comprehension = visit_expr = visit_if = compute_first_non_import_node
-
- def visit_functiondef(self, node):
- if not self.linter.is_message_enabled("wrong-import-position", node.fromlineno):
- return
- # If it is the first non import instruction of the module, record it.
- if self._first_non_import_node:
- return
-
- # Check if the node belongs to an `If` or a `Try` block. If they
- # contain imports, skip recording this node.
- if not isinstance(node.parent.scope(), astroid.Module):
- return
-
- root = node
- while not isinstance(root.parent, astroid.Module):
- root = root.parent
-
- if isinstance(root, (astroid.If, astroid.TryFinally, astroid.TryExcept)):
- if any(root.nodes_of_class((astroid.Import, astroid.ImportFrom))):
- return
-
- self._first_non_import_node = node
-
- visit_classdef = visit_for = visit_while = visit_functiondef
-
- def _check_misplaced_future(self, node):
- basename = node.modname
- if basename == "__future__":
- # check if this is the first non-docstring statement in the module
- prev = node.previous_sibling()
- if prev:
- # consecutive future statements are possible
- if not (
- isinstance(prev, astroid.ImportFrom)
- and prev.modname == "__future__"
- ):
- self.add_message("misplaced-future", node=node)
- return
-
- def _check_same_line_imports(self, node):
- # Detect duplicate imports on the same line.
- names = (name for name, _ in node.names)
- counter = collections.Counter(names)
- for name, count in counter.items():
- if count > 1:
- self.add_message("reimported", node=node, args=(name, node.fromlineno))
-
- def _check_position(self, node):
- """Check `node` import or importfrom node position is correct
-
- Send a message if `node` comes before another instruction
- """
- # if a first non-import instruction has already been encountered,
- # it means the import comes after it and therefore is not well placed
- if self._first_non_import_node:
- self.add_message("wrong-import-position", node=node, args=node.as_string())
-
- def _record_import(self, node, importedmodnode):
- """Record the package `node` imports from"""
- if isinstance(node, astroid.ImportFrom):
- importedname = node.modname
- else:
- importedname = importedmodnode.name if importedmodnode else None
- if not importedname:
- importedname = node.names[0][0].split(".")[0]
-
- if isinstance(node, astroid.ImportFrom) and (node.level or 0) >= 1:
- # We need the importedname with first point to detect local package
- # Example of node:
- # 'from .my_package1 import MyClass1'
- # the output should be '.my_package1' instead of 'my_package1'
- # Example of node:
- # 'from . import my_package2'
- # the output should be '.my_package2' instead of '{pyfile}'
- importedname = "." + importedname
-
- self._imports_stack.append((node, importedname))
-
- @staticmethod
- def _is_fallback_import(node, imports):
- imports = [import_node for (import_node, _) in imports]
- return any(astroid.are_exclusive(import_node, node) for import_node in imports)
-
- def _check_imports_order(self, _module_node):
- """Checks imports of module `node` are grouped by category
-
- Imports must follow this order: standard, 3rd party, local
- """
- std_imports = []
- third_party_imports = []
- first_party_imports = []
- # need of a list that holds third or first party ordered import
- external_imports = []
- local_imports = []
- third_party_not_ignored = []
- first_party_not_ignored = []
- local_not_ignored = []
- isort_obj = isort.SortImports(
- file_contents="",
- known_third_party=self.config.known_third_party,
- known_standard_library=self.config.known_standard_library,
- )
- for node, modname in self._imports_stack:
- if modname.startswith("."):
- package = "." + modname.split(".")[1]
- else:
- package = modname.split(".")[0]
- nested = not isinstance(node.parent, astroid.Module)
- ignore_for_import_order = not self.linter.is_message_enabled(
- "wrong-import-order", node.fromlineno
- )
- import_category = isort_obj.place_module(package)
- node_and_package_import = (node, package)
- if import_category in ("FUTURE", "STDLIB"):
- std_imports.append(node_and_package_import)
- wrong_import = (
- third_party_not_ignored
- or first_party_not_ignored
- or local_not_ignored
- )
- if self._is_fallback_import(node, wrong_import):
- continue
- if wrong_import and not nested:
- self.add_message(
- "wrong-import-order",
- node=node,
- args=(
- 'standard import "%s"' % node.as_string(),
- '"%s"' % wrong_import[0][0].as_string(),
- ),
- )
- elif import_category == "THIRDPARTY":
- third_party_imports.append(node_and_package_import)
- external_imports.append(node_and_package_import)
- if not nested and not ignore_for_import_order:
- third_party_not_ignored.append(node_and_package_import)
- wrong_import = first_party_not_ignored or local_not_ignored
- if wrong_import and not nested:
- self.add_message(
- "wrong-import-order",
- node=node,
- args=(
- 'third party import "%s"' % node.as_string(),
- '"%s"' % wrong_import[0][0].as_string(),
- ),
- )
- elif import_category == "FIRSTPARTY":
- first_party_imports.append(node_and_package_import)
- external_imports.append(node_and_package_import)
- if not nested and not ignore_for_import_order:
- first_party_not_ignored.append(node_and_package_import)
- wrong_import = local_not_ignored
- if wrong_import and not nested:
- self.add_message(
- "wrong-import-order",
- node=node,
- args=(
- 'first party import "%s"' % node.as_string(),
- '"%s"' % wrong_import[0][0].as_string(),
- ),
- )
- elif import_category == "LOCALFOLDER":
- local_imports.append((node, package))
- if not nested and not ignore_for_import_order:
- local_not_ignored.append((node, package))
- return std_imports, external_imports, local_imports
-
- def _get_imported_module(self, importnode, modname):
- try:
- return importnode.do_import_module(modname)
- except astroid.TooManyLevelsError:
- if _ignore_import_failure(importnode, modname, self._ignored_modules):
- return None
-
- self.add_message("relative-beyond-top-level", node=importnode)
- except astroid.AstroidSyntaxError as exc:
- message = "Cannot import {!r} due to syntax error {!r}".format(
- modname, str(exc.error) # pylint: disable=no-member; false positive
- )
- self.add_message("syntax-error", line=importnode.lineno, args=message)
-
- except astroid.AstroidBuildingException:
- if not self.linter.is_message_enabled("import-error"):
- return None
- if _ignore_import_failure(importnode, modname, self._ignored_modules):
- return None
- if not self.config.analyse_fallback_blocks and is_from_fallback_block(
- importnode
- ):
- return None
-
- dotted_modname = _get_import_name(importnode, modname)
- self.add_message("import-error", args=repr(dotted_modname), node=importnode)
-
- def _add_imported_module(self, node, importedmodname):
- """notify an imported module, used to analyze dependencies"""
- module_file = node.root().file
- context_name = node.root().name
- base = os.path.splitext(os.path.basename(module_file))[0]
-
- try:
- importedmodname = modutils.get_module_part(importedmodname, module_file)
- except ImportError:
- pass
-
- if context_name == importedmodname:
- self.add_message("import-self", node=node)
-
- elif not modutils.is_standard_module(importedmodname):
- # if this is not a package __init__ module
- if base != "__init__" and context_name not in self._module_pkg:
- # record the module's parent, or the module itself if this is
- # a top level module, as the package it belongs to
- self._module_pkg[context_name] = context_name.rsplit(".", 1)[0]
-
- # handle dependencies
- importedmodnames = self.stats["dependencies"].setdefault(
- importedmodname, set()
- )
- if context_name not in importedmodnames:
- importedmodnames.add(context_name)
-
- # update import graph
- self.import_graph[context_name].add(importedmodname)
- if not self.linter.is_message_enabled("cyclic-import", line=node.lineno):
- self._excluded_edges[context_name].add(importedmodname)
-
- def _check_deprecated_module(self, node, mod_path):
- """check if the module is deprecated"""
- for mod_name in self.config.deprecated_modules:
- if mod_path == mod_name or mod_path.startswith(mod_name + "."):
- self.add_message("deprecated-module", node=node, args=mod_path)
-
- def _check_preferred_module(self, node, mod_path):
- """check if the module has a preferred replacement"""
- if mod_path in self.preferred_modules:
- self.add_message(
- "preferred-module",
- node=node,
- args=(self.preferred_modules[mod_path], mod_path),
- )
-
- def _check_import_as_rename(self, node):
- names = node.names
- for name in names:
- if not all(name):
- return
-
- real_name = name[0]
- splitted_packages = real_name.rsplit(".")
- real_name = splitted_packages[-1]
- imported_name = name[1]
- # consider only following cases
- # import x as x
- # and ignore following
- # import x.y.z as z
- if real_name == imported_name and len(splitted_packages) == 1:
- self.add_message("useless-import-alias", node=node)
-
- def _check_reimport(self, node, basename=None, level=None):
- """check if the import is necessary (i.e. not already done)"""
- if not self.linter.is_message_enabled("reimported"):
- return
-
- frame = node.frame()
- root = node.root()
- contexts = [(frame, level)]
- if root is not frame:
- contexts.append((root, None))
-
- for known_context, known_level in contexts:
- for name, alias in node.names:
- first = _get_first_import(
- node, known_context, name, basename, known_level, alias
- )
- if first is not None:
- self.add_message(
- "reimported", node=node, args=(name, first.fromlineno)
- )
-
- def _report_external_dependencies(self, sect, _, _dummy):
- """return a verbatim layout for displaying dependencies"""
- dep_info = _make_tree_defs(self._external_dependencies_info().items())
- if not dep_info:
- raise EmptyReportError()
- tree_str = _repr_tree_defs(dep_info)
- sect.append(VerbatimText(tree_str))
-
- def _report_dependencies_graph(self, sect, _, _dummy):
- """write dependencies as a dot (graphviz) file"""
- dep_info = self.stats["dependencies"]
- if not dep_info or not (
- self.config.import_graph
- or self.config.ext_import_graph
- or self.config.int_import_graph
- ):
- raise EmptyReportError()
- filename = self.config.import_graph
- if filename:
- _make_graph(filename, dep_info, sect, "")
- filename = self.config.ext_import_graph
- if filename:
- _make_graph(filename, self._external_dependencies_info(), sect, "external ")
- filename = self.config.int_import_graph
- if filename:
- _make_graph(filename, self._internal_dependencies_info(), sect, "internal ")
-
- def _filter_dependencies_graph(self, internal):
- """build the internal or the external dependency graph"""
- graph = collections.defaultdict(set)
- for importee, importers in self.stats["dependencies"].items():
- for importer in importers:
- package = self._module_pkg.get(importer, importer)
- is_inside = importee.startswith(package)
- if is_inside and internal or not is_inside and not internal:
- graph[importee].add(importer)
- return graph
-
- @cached
- def _external_dependencies_info(self):
- """return cached external dependencies information or build and
- cache them
- """
- return self._filter_dependencies_graph(internal=False)
-
- @cached
- def _internal_dependencies_info(self):
- """return cached internal dependencies information or build and
- cache them
- """
- return self._filter_dependencies_graph(internal=True)
-
- def _check_wildcard_imports(self, node, imported_module):
- if node.root().package:
- # Skip the check if in __init__.py issue #2026
- return
-
- wildcard_import_is_allowed = self._wildcard_import_is_allowed(imported_module)
- for name, _ in node.names:
- if name == "*" and not wildcard_import_is_allowed:
- self.add_message("wildcard-import", args=node.modname, node=node)
-
- def _wildcard_import_is_allowed(self, imported_module):
- return (
- self.config.allow_wildcard_with_all
- and imported_module is not None
- and "__all__" in imported_module.locals
- )
-
- def _check_toplevel(self, node):
- """Check whether the import is made outside the module toplevel.
- """
- # If the scope of the import is a module, then obviously it is
- # not outside the module toplevel.
- if isinstance(node.scope(), astroid.Module):
- return
-
- if isinstance(node, astroid.ImportFrom):
- module_names = [node.modname]
- else:
- module_names = [name[0] for name in node.names]
-
- # Get the full names of all the imports that are not whitelisted.
- scoped_imports = [
- name for name in module_names if name not in self._allow_any_import_level
- ]
-
- if scoped_imports:
- self.add_message(
- "import-outside-toplevel", args=", ".join(scoped_imports), node=node
- )
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(ImportsChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/logging.py b/venv/Lib/site-packages/pylint/checkers/logging.py
deleted file mode 100644
index 5ad0e76..0000000
--- a/venv/Lib/site-packages/pylint/checkers/logging.py
+++ /dev/null
@@ -1,384 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2009-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2009, 2012, 2014 Google, Inc.
-# Copyright (c) 2012 Mike Bryant <leachim@leachim.info>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Chris Murray <chris@chrismurray.scot>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2017 guillaume2 <guillaume.peillex@gmail.col>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 Mariatta Wijaya <mariatta@python.org>
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""checker for use of Python logging
-"""
-import string
-
-import astroid
-
-from pylint import checkers, interfaces
-from pylint.checkers import utils
-from pylint.checkers.utils import check_messages
-
-MSGS = {
- "W1201": (
- "Specify string format arguments as logging function parameters",
- "logging-not-lazy",
- "Used when a logging statement has a call form of "
- '"logging.<logging method>(format_string % (format_args...))". '
- "Such calls should leave string interpolation to the logging "
- "method itself and be written "
- '"logging.<logging method>(format_string, format_args...)" '
- "so that the program may avoid incurring the cost of the "
- "interpolation in those cases in which no message will be "
- "logged. For more, see "
- "http://www.python.org/dev/peps/pep-0282/.",
- ),
- "W1202": (
- "Use %s formatting in logging functions%s",
- "logging-format-interpolation",
- "Used when a logging statement has a call form of "
- '"logging.<logging method>(<string formatting>)".'
- " with invalid string formatting. "
- "Use another way for format the string instead.",
- ),
- "E1200": (
- "Unsupported logging format character %r (%#02x) at index %d",
- "logging-unsupported-format",
- "Used when an unsupported format character is used in a logging "
- "statement format string.",
- ),
- "E1201": (
- "Logging format string ends in middle of conversion specifier",
- "logging-format-truncated",
- "Used when a logging statement format string terminates before "
- "the end of a conversion specifier.",
- ),
- "E1205": (
- "Too many arguments for logging format string",
- "logging-too-many-args",
- "Used when a logging format string is given too many arguments.",
- ),
- "E1206": (
- "Not enough arguments for logging format string",
- "logging-too-few-args",
- "Used when a logging format string is given too few arguments.",
- ),
-}
-
-
-CHECKED_CONVENIENCE_FUNCTIONS = {
- "critical",
- "debug",
- "error",
- "exception",
- "fatal",
- "info",
- "warn",
- "warning",
-}
-
-
-def is_method_call(func, types=(), methods=()):
- """Determines if a BoundMethod node represents a method call.
-
- Args:
- func (astroid.BoundMethod): The BoundMethod AST node to check.
- types (Optional[String]): Optional sequence of caller type names to restrict check.
- methods (Optional[String]): Optional sequence of method names to restrict check.
-
- Returns:
- bool: true if the node represents a method call for the given type and
- method names, False otherwise.
- """
- return (
- isinstance(func, astroid.BoundMethod)
- and isinstance(func.bound, astroid.Instance)
- and (func.bound.name in types if types else True)
- and (func.name in methods if methods else True)
- )
-
-
-class LoggingChecker(checkers.BaseChecker):
- """Checks use of the logging module."""
-
- __implements__ = interfaces.IAstroidChecker
- name = "logging"
- msgs = MSGS
-
- options = (
- (
- "logging-modules",
- {
- "default": ("logging",),
- "type": "csv",
- "metavar": "<comma separated list>",
- "help": "Logging modules to check that the string format "
- "arguments are in logging function parameter format.",
- },
- ),
- (
- "logging-format-style",
- {
- "default": "old",
- "type": "choice",
- "metavar": "<old (%) or new ({) or fstr (f'')>",
- "choices": ["old", "new", "fstr"],
- "help": "Format style used to check logging format string. "
- "`old` means using % formatting, `new` is for `{}` formatting,"
- "and `fstr` is for f-strings.",
- },
- ),
- )
-
- def visit_module(self, node): # pylint: disable=unused-argument
- """Clears any state left in this checker from last module checked."""
- # The code being checked can just as easily "import logging as foo",
- # so it is necessary to process the imports and store in this field
- # what name the logging module is actually given.
- self._logging_names = set()
- logging_mods = self.config.logging_modules
-
- self._format_style = self.config.logging_format_style
- format_styles = {"old": "%", "new": "{", "fstr": "f-string"}
- format_style_help = ""
- if self._format_style == "old":
- format_style_help = " and pass the % parameters as arguments"
-
- self._format_style_args = (format_styles[self._format_style], format_style_help)
-
- self._logging_modules = set(logging_mods)
- self._from_imports = {}
- for logging_mod in logging_mods:
- parts = logging_mod.rsplit(".", 1)
- if len(parts) > 1:
- self._from_imports[parts[0]] = parts[1]
-
- def visit_importfrom(self, node):
- """Checks to see if a module uses a non-Python logging module."""
- try:
- logging_name = self._from_imports[node.modname]
- for module, as_name in node.names:
- if module == logging_name:
- self._logging_names.add(as_name or module)
- except KeyError:
- pass
-
- def visit_import(self, node):
- """Checks to see if this module uses Python's built-in logging."""
- for module, as_name in node.names:
- if module in self._logging_modules:
- self._logging_names.add(as_name or module)
-
- @check_messages(*MSGS)
- def visit_call(self, node):
- """Checks calls to logging methods."""
-
- def is_logging_name():
- return (
- isinstance(node.func, astroid.Attribute)
- and isinstance(node.func.expr, astroid.Name)
- and node.func.expr.name in self._logging_names
- )
-
- def is_logger_class():
- try:
- for inferred in node.func.infer():
- if isinstance(inferred, astroid.BoundMethod):
- parent = inferred._proxied.parent
- if isinstance(parent, astroid.ClassDef) and (
- parent.qname() == "logging.Logger"
- or any(
- ancestor.qname() == "logging.Logger"
- for ancestor in parent.ancestors()
- )
- ):
- return True, inferred._proxied.name
- except astroid.exceptions.InferenceError:
- pass
- return False, None
-
- if is_logging_name():
- name = node.func.attrname
- else:
- result, name = is_logger_class()
- if not result:
- return
- self._check_log_method(node, name)
-
- def _check_log_method(self, node, name):
- """Checks calls to logging.log(level, format, *format_args)."""
- if name == "log":
- if node.starargs or node.kwargs or len(node.args) < 2:
- # Either a malformed call, star args, or double-star args. Beyond
- # the scope of this checker.
- return
- format_pos = 1
- elif name in CHECKED_CONVENIENCE_FUNCTIONS:
- if node.starargs or node.kwargs or not node.args:
- # Either no args, star args, or double-star args. Beyond the
- # scope of this checker.
- return
- format_pos = 0
- else:
- return
-
- if isinstance(node.args[format_pos], astroid.BinOp):
- binop = node.args[format_pos]
- emit = binop.op == "%"
- if binop.op == "+":
- total_number_of_strings = sum(
- 1
- for operand in (binop.left, binop.right)
- if self._is_operand_literal_str(utils.safe_infer(operand))
- )
- emit = total_number_of_strings > 0
- if emit:
- self.add_message("logging-not-lazy", node=node)
- elif isinstance(node.args[format_pos], astroid.Call):
- self._check_call_func(node.args[format_pos])
- elif isinstance(node.args[format_pos], astroid.Const):
- self._check_format_string(node, format_pos)
- elif isinstance(
- node.args[format_pos], (astroid.FormattedValue, astroid.JoinedStr)
- ):
- if self._format_style != "fstr":
- self.add_message(
- "logging-format-interpolation",
- node=node,
- args=self._format_style_args,
- )
-
- @staticmethod
- def _is_operand_literal_str(operand):
- """
- Return True if the operand in argument is a literal string
- """
- return isinstance(operand, astroid.Const) and operand.name == "str"
-
- def _check_call_func(self, node):
- """Checks that function call is not format_string.format().
-
- Args:
- node (astroid.node_classes.Call):
- Call AST node to be checked.
- """
- func = utils.safe_infer(node.func)
- types = ("str", "unicode")
- methods = ("format",)
- if is_method_call(func, types, methods) and not is_complex_format_str(
- func.bound
- ):
- self.add_message(
- "logging-format-interpolation", node=node, args=self._format_style_args
- )
-
- def _check_format_string(self, node, format_arg):
- """Checks that format string tokens match the supplied arguments.
-
- Args:
- node (astroid.node_classes.NodeNG): AST node to be checked.
- format_arg (int): Index of the format string in the node arguments.
- """
- num_args = _count_supplied_tokens(node.args[format_arg + 1 :])
- if not num_args:
- # If no args were supplied the string is not interpolated and can contain
- # formatting characters - it's used verbatim. Don't check any further.
- return
-
- format_string = node.args[format_arg].value
- required_num_args = 0
- if isinstance(format_string, bytes):
- format_string = format_string.decode()
- if isinstance(format_string, str):
- try:
- if self._format_style == "old":
- keyword_args, required_num_args, _, _ = utils.parse_format_string(
- format_string
- )
- if keyword_args:
- # Keyword checking on logging strings is complicated by
- # special keywords - out of scope.
- return
- elif self._format_style == "new":
- keyword_arguments, implicit_pos_args, explicit_pos_args = utils.parse_format_method_string(
- format_string
- )
-
- keyword_args_cnt = len(
- set(k for k, l in keyword_arguments if not isinstance(k, int))
- )
- required_num_args = (
- keyword_args_cnt + implicit_pos_args + explicit_pos_args
- )
- else:
- self.add_message(
- "logging-format-interpolation",
- node=node,
- args=self._format_style_args,
- )
- except utils.UnsupportedFormatCharacter as ex:
- char = format_string[ex.index]
- self.add_message(
- "logging-unsupported-format",
- node=node,
- args=(char, ord(char), ex.index),
- )
- return
- except utils.IncompleteFormatString:
- self.add_message("logging-format-truncated", node=node)
- return
- if num_args > required_num_args:
- self.add_message("logging-too-many-args", node=node)
- elif num_args < required_num_args:
- self.add_message("logging-too-few-args", node=node)
-
-
-def is_complex_format_str(node):
- """Checks if node represents a string with complex formatting specs.
-
- Args:
- node (astroid.node_classes.NodeNG): AST node to check
- Returns:
- bool: True if inferred string uses complex formatting, False otherwise
- """
- inferred = utils.safe_infer(node)
- if inferred is None or not (
- isinstance(inferred, astroid.Const) and isinstance(inferred.value, str)
- ):
- return True
- try:
- parsed = list(string.Formatter().parse(inferred.value))
- except ValueError:
- # This format string is invalid
- return False
- for _, _, format_spec, _ in parsed:
- if format_spec:
- return True
- return False
-
-
-def _count_supplied_tokens(args):
- """Counts the number of tokens in an args list.
-
- The Python log functions allow for special keyword arguments: func,
- exc_info and extra. To handle these cases correctly, we only count
- arguments that aren't keywords.
-
- Args:
- args (list): AST nodes that are arguments for a log format string.
-
- Returns:
- int: Number of AST nodes that aren't keywords.
- """
- return sum(1 for arg in args if not isinstance(arg, astroid.Keyword))
-
-
-def register(linter):
- """Required method to auto-register this checker."""
- linter.register_checker(LoggingChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/misc.py b/venv/Lib/site-packages/pylint/checkers/misc.py
deleted file mode 100644
index dcf7a3e..0000000
--- a/venv/Lib/site-packages/pylint/checkers/misc.py
+++ /dev/null
@@ -1,171 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006, 2009-2013 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Alexandru Coman <fcoman@bitdefender.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 glegoux <gilles.legoux@gmail.com>
-# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Mikhail Fesenko <proggga@gmail.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@iki.fi>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-
-"""Check source code is ascii only or has an encoding declaration (PEP 263)"""
-
-import re
-import tokenize
-
-from pylint.checkers import BaseChecker
-from pylint.constants import OPTION_RGX
-from pylint.interfaces import IRawChecker, ITokenChecker
-from pylint.message import MessagesHandlerMixIn
-
-
-class ByIdManagedMessagesChecker(BaseChecker):
-
- """checks for messages that are enabled or disabled by id instead of symbol."""
-
- __implements__ = IRawChecker
-
- # configuration section name
- name = "miscellaneous"
- msgs = {
- "I0023": (
- "%s",
- "use-symbolic-message-instead",
- "Used when a message is enabled or disabled by id.",
- )
- }
-
- options = ()
-
- def process_module(self, module):
- """inspect the source file to find messages activated or deactivated by id."""
- managed_msgs = MessagesHandlerMixIn.get_by_id_managed_msgs()
- for (mod_name, msg_id, msg_symbol, lineno, is_disabled) in managed_msgs:
- if mod_name == module.name:
- if is_disabled:
- txt = "Id '{ident}' is used to disable '{symbol}' message emission".format(
- ident=msg_id, symbol=msg_symbol
- )
- else:
- txt = "Id '{ident}' is used to enable '{symbol}' message emission".format(
- ident=msg_id, symbol=msg_symbol
- )
- self.add_message("use-symbolic-message-instead", line=lineno, args=txt)
- MessagesHandlerMixIn.clear_by_id_managed_msgs()
-
-
-class EncodingChecker(BaseChecker):
-
- """checks for:
- * warning notes in the code like FIXME, XXX
- * encoding issues.
- """
-
- __implements__ = (IRawChecker, ITokenChecker)
-
- # configuration section name
- name = "miscellaneous"
- msgs = {
- "W0511": (
- "%s",
- "fixme",
- "Used when a warning note as FIXME or XXX is detected.",
- )
- }
-
- options = (
- (
- "notes",
- {
- "type": "csv",
- "metavar": "<comma separated values>",
- "default": ("FIXME", "XXX", "TODO"),
- "help": (
- "List of note tags to take in consideration, "
- "separated by a comma."
- ),
- },
- ),
- )
-
- def open(self):
- super().open()
- self._fixme_pattern = re.compile(
- r"#\s*(%s)\b" % "|".join(map(re.escape, self.config.notes)), re.I
- )
-
- def _check_encoding(self, lineno, line, file_encoding):
- try:
- return line.decode(file_encoding)
- except UnicodeDecodeError:
- pass
- except LookupError:
- if line.startswith("#") and "coding" in line and file_encoding in line:
- self.add_message(
- "syntax-error",
- line=lineno,
- args='Cannot decode using encoding "{}",'
- " bad encoding".format(file_encoding),
- )
-
- def process_module(self, module):
- """inspect the source file to find encoding problem"""
- if module.file_encoding:
- encoding = module.file_encoding
- else:
- encoding = "ascii"
-
- with module.stream() as stream:
- for lineno, line in enumerate(stream):
- self._check_encoding(lineno + 1, line, encoding)
-
- def process_tokens(self, tokens):
- """inspect the source to find fixme problems"""
- if not self.config.notes:
- return
- comments = (
- token_info for token_info in tokens if token_info.type == tokenize.COMMENT
- )
- for comment in comments:
- comment_text = comment.string[1:].lstrip() # trim '#' and whitespaces
-
- # handle pylint disable clauses
- disable_option_match = OPTION_RGX.search(comment_text)
- if disable_option_match:
- try:
- _, value = disable_option_match.group(1).split("=", 1)
- values = [_val.strip().upper() for _val in value.split(",")]
- if set(values) & set(self.config.notes):
- continue
- except ValueError:
- self.add_message(
- "bad-inline-option",
- args=disable_option_match.group(1).strip(),
- line=comment.start[0],
- )
- continue
-
- # emit warnings if necessary
- match = self._fixme_pattern.search("#" + comment_text.lower())
- if match:
- note = match.group(1)
- self.add_message(
- "fixme",
- col_offset=comment.string.lower().index(note.lower()),
- args=comment_text,
- line=comment.start[0],
- )
-
-
-def register(linter):
- """required method to auto register this checker"""
- linter.register_checker(EncodingChecker(linter))
- linter.register_checker(ByIdManagedMessagesChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/newstyle.py b/venv/Lib/site-packages/pylint/checkers/newstyle.py
deleted file mode 100644
index 46f4e4e..0000000
--- a/venv/Lib/site-packages/pylint/checkers/newstyle.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# Copyright (c) 2006, 2008-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""check for new / old style related problems
-"""
-import astroid
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import check_messages, has_known_bases, node_frame_class
-from pylint.interfaces import IAstroidChecker
-
-MSGS = {
- "E1003": (
- "Bad first argument %r given to super()",
- "bad-super-call",
- "Used when another argument than the current class is given as "
- "first argument of the super builtin.",
- )
-}
-
-
-class NewStyleConflictChecker(BaseChecker):
- """checks for usage of new style capabilities on old style classes and
- other new/old styles conflicts problems
- * use of property, __slots__, super
- * "super" usage
- """
-
- __implements__ = (IAstroidChecker,)
-
- # configuration section name
- name = "newstyle"
- # messages
- msgs = MSGS
- priority = -2
- # configuration options
- options = ()
-
- @check_messages("bad-super-call")
- def visit_functiondef(self, node):
- """check use of super"""
- # ignore actual functions or method within a new style class
- if not node.is_method():
- return
- klass = node.parent.frame()
- for stmt in node.nodes_of_class(astroid.Call):
- if node_frame_class(stmt) != node_frame_class(node):
- # Don't look down in other scopes.
- continue
-
- expr = stmt.func
- if not isinstance(expr, astroid.Attribute):
- continue
-
- call = expr.expr
- # skip the test if using super
- if not (
- isinstance(call, astroid.Call)
- and isinstance(call.func, astroid.Name)
- and call.func.name == "super"
- ):
- continue
-
- # super should not be used on an old style class
- if klass.newstyle or not has_known_bases(klass):
- # super first arg should not be the class
- if not call.args:
- continue
-
- # calling super(type(self), self) can lead to recursion loop
- # in derived classes
- arg0 = call.args[0]
- if (
- isinstance(arg0, astroid.Call)
- and isinstance(arg0.func, astroid.Name)
- and arg0.func.name == "type"
- ):
- self.add_message("bad-super-call", node=call, args=("type",))
- continue
-
- # calling super(self.__class__, self) can lead to recursion loop
- # in derived classes
- if (
- len(call.args) >= 2
- and isinstance(call.args[1], astroid.Name)
- and call.args[1].name == "self"
- and isinstance(arg0, astroid.Attribute)
- and arg0.attrname == "__class__"
- ):
- self.add_message(
- "bad-super-call", node=call, args=("self.__class__",)
- )
- continue
-
- try:
- supcls = call.args and next(call.args[0].infer(), None)
- except astroid.InferenceError:
- continue
-
- if klass is not supcls:
- name = None
- # if supcls is not Uninferable, then supcls was inferred
- # and use its name. Otherwise, try to look
- # for call.args[0].name
- if supcls:
- name = supcls.name
- elif call.args and hasattr(call.args[0], "name"):
- name = call.args[0].name
- if name:
- self.add_message("bad-super-call", node=call, args=(name,))
-
- visit_asyncfunctiondef = visit_functiondef
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(NewStyleConflictChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/python3.py b/venv/Lib/site-packages/pylint/checkers/python3.py
deleted file mode 100644
index 583b1c2..0000000
--- a/venv/Lib/site-packages/pylint/checkers/python3.py
+++ /dev/null
@@ -1,1398 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014-2015 Brett Cannon <brett@python.org>
-# Copyright (c) 2015 Simu Toni <simutoni@gmail.com>
-# Copyright (c) 2015 Pavel Roskin <proski@gnu.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2015 Cosmin Poieana <cmin@ropython.org>
-# Copyright (c) 2015 Viorel Stirbu <viorels@gmail.com>
-# Copyright (c) 2016, 2018 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2016-2017 Roy Williams <roy.williams.iii@gmail.com>
-# Copyright (c) 2016 Roy Williams <rwilliams@lyft.com>
-# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Erik <erik.eriksson@yahoo.com>
-# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2017 Daniel Miller <millerdev@gmail.com>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 ahirnish <ahirnish@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2018 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-# Copyright (c) 2018 gaurikholkar <f2013002@goa.bits-pilani.ac.in>
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Check Python 2 code for Python 2/3 source-compatible issues."""
-import re
-import tokenize
-from collections import namedtuple
-
-import astroid
-from astroid import bases
-
-from pylint import checkers, interfaces
-from pylint.checkers import utils
-from pylint.checkers.utils import find_try_except_wrapper_node, node_ignores_exception
-from pylint.constants import WarningScope
-from pylint.interfaces import INFERENCE, INFERENCE_FAILURE
-
-_ZERO = re.compile("^0+$")
-
-
-def _is_old_octal(literal):
- if _ZERO.match(literal):
- return False
- if re.match(r"0\d+", literal):
- try:
- int(literal, 8)
- except ValueError:
- return False
- return True
- return None
-
-
-def _inferred_value_is_dict(value):
- if isinstance(value, astroid.Dict):
- return True
- return isinstance(value, astroid.Instance) and "dict" in value.basenames
-
-
-def _is_builtin(node):
- return getattr(node, "name", None) in ("__builtin__", "builtins")
-
-
-_ACCEPTS_ITERATOR = {
- "iter",
- "list",
- "tuple",
- "sorted",
- "set",
- "sum",
- "any",
- "all",
- "enumerate",
- "dict",
- "filter",
- "reversed",
- "max",
- "min",
- "frozenset",
- "OrderedDict",
-}
-ATTRIBUTES_ACCEPTS_ITERATOR = {"join", "from_iterable"}
-_BUILTIN_METHOD_ACCEPTS_ITERATOR = {
- "builtins.list.extend",
- "builtins.dict.update",
- "builtins.set.update",
-}
-DICT_METHODS = {"items", "keys", "values"}
-
-
-def _in_iterating_context(node):
- """Check if the node is being used as an iterator.
-
- Definition is taken from lib2to3.fixer_util.in_special_context().
- """
- parent = node.parent
- # Since a call can't be the loop variant we only need to know if the node's
- # parent is a 'for' loop to know it's being used as the iterator for the
- # loop.
- if isinstance(parent, astroid.For):
- return True
- # Need to make sure the use of the node is in the iterator part of the
- # comprehension.
- if isinstance(parent, astroid.Comprehension):
- if parent.iter == node:
- return True
- # Various built-ins can take in an iterable or list and lead to the same
- # value.
- elif isinstance(parent, astroid.Call):
- if isinstance(parent.func, astroid.Name):
- if parent.func.name in _ACCEPTS_ITERATOR:
- return True
- elif isinstance(parent.func, astroid.Attribute):
- if parent.func.attrname in ATTRIBUTES_ACCEPTS_ITERATOR:
- return True
-
- inferred = utils.safe_infer(parent.func)
- if inferred:
- if inferred.qname() in _BUILTIN_METHOD_ACCEPTS_ITERATOR:
- return True
- root = inferred.root()
- if root and root.name == "itertools":
- return True
- # If the call is in an unpacking, there's no need to warn,
- # since it can be considered iterating.
- elif isinstance(parent, astroid.Assign) and isinstance(
- parent.targets[0], (astroid.List, astroid.Tuple)
- ):
- if len(parent.targets[0].elts) > 1:
- return True
- # If the call is in a containment check, we consider that to
- # be an iterating context
- elif (
- isinstance(parent, astroid.Compare)
- and len(parent.ops) == 1
- and parent.ops[0][0] == "in"
- ):
- return True
- # Also if it's an `yield from`, that's fair
- elif isinstance(parent, astroid.YieldFrom):
- return True
- if isinstance(parent, astroid.Starred):
- return True
- return False
-
-
-def _is_conditional_import(node):
- """Checks if an import node is in the context of a conditional.
- """
- parent = node.parent
- return isinstance(
- parent, (astroid.TryExcept, astroid.ExceptHandler, astroid.If, astroid.IfExp)
- )
-
-
-Branch = namedtuple("Branch", ["node", "is_py2_only"])
-
-
-class Python3Checker(checkers.BaseChecker):
-
- __implements__ = interfaces.IAstroidChecker
- enabled = False
- name = "python3"
-
- msgs = {
- # Errors for what will syntactically break in Python 3, warnings for
- # everything else.
- "E1601": (
- "print statement used",
- "print-statement",
- "Used when a print statement is used "
- "(`print` is a function in Python 3)",
- ),
- "E1602": (
- "Parameter unpacking specified",
- "parameter-unpacking",
- "Used when parameter unpacking is specified for a function"
- "(Python 3 doesn't allow it)",
- ),
- "E1603": (
- "Implicit unpacking of exceptions is not supported in Python 3",
- "unpacking-in-except",
- "Python3 will not allow implicit unpacking of "
- "exceptions in except clauses. "
- "See http://www.python.org/dev/peps/pep-3110/",
- {"old_names": [("W0712", "old-unpacking-in-except")]},
- ),
- "E1604": (
- "Use raise ErrorClass(args) instead of raise ErrorClass, args.",
- "old-raise-syntax",
- "Used when the alternate raise syntax "
- "'raise foo, bar' is used "
- "instead of 'raise foo(bar)'.",
- {"old_names": [("W0121", "old-old-raise-syntax")]},
- ),
- "E1605": (
- "Use of the `` operator",
- "backtick",
- 'Used when the deprecated "``" (backtick) operator is used '
- "instead of the str() function.",
- {"scope": WarningScope.NODE, "old_names": [("W0333", "old-backtick")]},
- ),
- "E1609": (
- "Import * only allowed at module level",
- "import-star-module-level",
- "Used when the import star syntax is used somewhere "
- "else than the module level.",
- {"maxversion": (3, 0)},
- ),
- "W1601": (
- "apply built-in referenced",
- "apply-builtin",
- "Used when the apply built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1602": (
- "basestring built-in referenced",
- "basestring-builtin",
- "Used when the basestring built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1603": (
- "buffer built-in referenced",
- "buffer-builtin",
- "Used when the buffer built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1604": (
- "cmp built-in referenced",
- "cmp-builtin",
- "Used when the cmp built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1605": (
- "coerce built-in referenced",
- "coerce-builtin",
- "Used when the coerce built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1606": (
- "execfile built-in referenced",
- "execfile-builtin",
- "Used when the execfile built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1607": (
- "file built-in referenced",
- "file-builtin",
- "Used when the file built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1608": (
- "long built-in referenced",
- "long-builtin",
- "Used when the long built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1609": (
- "raw_input built-in referenced",
- "raw_input-builtin",
- "Used when the raw_input built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1610": (
- "reduce built-in referenced",
- "reduce-builtin",
- "Used when the reduce built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1611": (
- "StandardError built-in referenced",
- "standarderror-builtin",
- "Used when the StandardError built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1612": (
- "unicode built-in referenced",
- "unicode-builtin",
- "Used when the unicode built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1613": (
- "xrange built-in referenced",
- "xrange-builtin",
- "Used when the xrange built-in function is referenced "
- "(missing from Python 3)",
- ),
- "W1614": (
- "__coerce__ method defined",
- "coerce-method",
- "Used when a __coerce__ method is defined "
- "(method is not used by Python 3)",
- ),
- "W1615": (
- "__delslice__ method defined",
- "delslice-method",
- "Used when a __delslice__ method is defined "
- "(method is not used by Python 3)",
- ),
- "W1616": (
- "__getslice__ method defined",
- "getslice-method",
- "Used when a __getslice__ method is defined "
- "(method is not used by Python 3)",
- ),
- "W1617": (
- "__setslice__ method defined",
- "setslice-method",
- "Used when a __setslice__ method is defined "
- "(method is not used by Python 3)",
- ),
- "W1618": (
- "import missing `from __future__ import absolute_import`",
- "no-absolute-import",
- "Used when an import is not accompanied by "
- "``from __future__ import absolute_import`` "
- "(default behaviour in Python 3)",
- ),
- "W1619": (
- "division w/o __future__ statement",
- "old-division",
- "Used for non-floor division w/o a float literal or "
- "``from __future__ import division`` "
- "(Python 3 returns a float for int division unconditionally)",
- ),
- "W1620": (
- "Calling a dict.iter*() method",
- "dict-iter-method",
- "Used for calls to dict.iterkeys(), itervalues() or iteritems() "
- "(Python 3 lacks these methods)",
- ),
- "W1621": (
- "Calling a dict.view*() method",
- "dict-view-method",
- "Used for calls to dict.viewkeys(), viewvalues() or viewitems() "
- "(Python 3 lacks these methods)",
- ),
- "W1622": (
- "Called a next() method on an object",
- "next-method-called",
- "Used when an object's next() method is called "
- "(Python 3 uses the next() built-in function)",
- ),
- "W1623": (
- "Assigning to a class's __metaclass__ attribute",
- "metaclass-assignment",
- "Used when a metaclass is specified by assigning to __metaclass__ "
- "(Python 3 specifies the metaclass as a class statement argument)",
- ),
- "W1624": (
- "Indexing exceptions will not work on Python 3",
- "indexing-exception",
- "Indexing exceptions will not work on Python 3. Use "
- "`exception.args[index]` instead.",
- {"old_names": [("W0713", "old-indexing-exception")]},
- ),
- "W1625": (
- "Raising a string exception",
- "raising-string",
- "Used when a string exception is raised. This will not "
- "work on Python 3.",
- {"old_names": [("W0701", "old-raising-string")]},
- ),
- "W1626": (
- "reload built-in referenced",
- "reload-builtin",
- "Used when the reload built-in function is referenced "
- "(missing from Python 3). You can use instead imp.reload "
- "or importlib.reload.",
- ),
- "W1627": (
- "__oct__ method defined",
- "oct-method",
- "Used when an __oct__ method is defined "
- "(method is not used by Python 3)",
- ),
- "W1628": (
- "__hex__ method defined",
- "hex-method",
- "Used when a __hex__ method is defined (method is not used by Python 3)",
- ),
- "W1629": (
- "__nonzero__ method defined",
- "nonzero-method",
- "Used when a __nonzero__ method is defined "
- "(method is not used by Python 3)",
- ),
- "W1630": (
- "__cmp__ method defined",
- "cmp-method",
- "Used when a __cmp__ method is defined (method is not used by Python 3)",
- ),
- # 'W1631': replaced by W1636
- "W1632": (
- "input built-in referenced",
- "input-builtin",
- "Used when the input built-in is referenced "
- "(backwards-incompatible semantics in Python 3)",
- ),
- "W1633": (
- "round built-in referenced",
- "round-builtin",
- "Used when the round built-in is referenced "
- "(backwards-incompatible semantics in Python 3)",
- ),
- "W1634": (
- "intern built-in referenced",
- "intern-builtin",
- "Used when the intern built-in is referenced "
- "(Moved to sys.intern in Python 3)",
- ),
- "W1635": (
- "unichr built-in referenced",
- "unichr-builtin",
- "Used when the unichr built-in is referenced (Use chr in Python 3)",
- ),
- "W1636": (
- "map built-in referenced when not iterating",
- "map-builtin-not-iterating",
- "Used when the map built-in is referenced in a non-iterating "
- "context (returns an iterator in Python 3)",
- {"old_names": [("W1631", "implicit-map-evaluation")]},
- ),
- "W1637": (
- "zip built-in referenced when not iterating",
- "zip-builtin-not-iterating",
- "Used when the zip built-in is referenced in a non-iterating "
- "context (returns an iterator in Python 3)",
- ),
- "W1638": (
- "range built-in referenced when not iterating",
- "range-builtin-not-iterating",
- "Used when the range built-in is referenced in a non-iterating "
- "context (returns a range in Python 3)",
- ),
- "W1639": (
- "filter built-in referenced when not iterating",
- "filter-builtin-not-iterating",
- "Used when the filter built-in is referenced in a non-iterating "
- "context (returns an iterator in Python 3)",
- ),
- "W1640": (
- "Using the cmp argument for list.sort / sorted",
- "using-cmp-argument",
- "Using the cmp argument for list.sort or the sorted "
- "builtin should be avoided, since it was removed in "
- "Python 3. Using either `key` or `functools.cmp_to_key` "
- "should be preferred.",
- ),
- "W1641": (
- "Implementing __eq__ without also implementing __hash__",
- "eq-without-hash",
- "Used when a class implements __eq__ but not __hash__. In Python 2, objects "
- "get object.__hash__ as the default implementation, in Python 3 objects get "
- "None as their default __hash__ implementation if they also implement __eq__.",
- ),
- "W1642": (
- "__div__ method defined",
- "div-method",
- "Used when a __div__ method is defined. Using `__truediv__` and setting"
- "__div__ = __truediv__ should be preferred."
- "(method is not used by Python 3)",
- ),
- "W1643": (
- "__idiv__ method defined",
- "idiv-method",
- "Used when an __idiv__ method is defined. Using `__itruediv__` and setting"
- "__idiv__ = __itruediv__ should be preferred."
- "(method is not used by Python 3)",
- ),
- "W1644": (
- "__rdiv__ method defined",
- "rdiv-method",
- "Used when a __rdiv__ method is defined. Using `__rtruediv__` and setting"
- "__rdiv__ = __rtruediv__ should be preferred."
- "(method is not used by Python 3)",
- ),
- "W1645": (
- "Exception.message removed in Python 3",
- "exception-message-attribute",
- "Used when the message attribute is accessed on an Exception. Use "
- "str(exception) instead.",
- ),
- "W1646": (
- "non-text encoding used in str.decode",
- "invalid-str-codec",
- "Used when using str.encode or str.decode with a non-text encoding. Use "
- "codecs module to handle arbitrary codecs.",
- ),
- "W1647": (
- "sys.maxint removed in Python 3",
- "sys-max-int",
- "Used when accessing sys.maxint. Use sys.maxsize instead.",
- ),
- "W1648": (
- "Module moved in Python 3",
- "bad-python3-import",
- "Used when importing a module that no longer exists in Python 3.",
- ),
- "W1649": (
- "Accessing a deprecated function on the string module",
- "deprecated-string-function",
- "Used when accessing a string function that has been deprecated in Python 3.",
- ),
- "W1650": (
- "Using str.translate with deprecated deletechars parameters",
- "deprecated-str-translate-call",
- "Used when using the deprecated deletechars parameters from str.translate. Use "
- "re.sub to remove the desired characters ",
- ),
- "W1651": (
- "Accessing a deprecated function on the itertools module",
- "deprecated-itertools-function",
- "Used when accessing a function on itertools that has been removed in Python 3.",
- ),
- "W1652": (
- "Accessing a deprecated fields on the types module",
- "deprecated-types-field",
- "Used when accessing a field on types that has been removed in Python 3.",
- ),
- "W1653": (
- "next method defined",
- "next-method-defined",
- "Used when a next method is defined that would be an iterator in Python 2 but "
- "is treated as a normal function in Python 3.",
- ),
- "W1654": (
- "dict.items referenced when not iterating",
- "dict-items-not-iterating",
- "Used when dict.items is referenced in a non-iterating "
- "context (returns an iterator in Python 3)",
- ),
- "W1655": (
- "dict.keys referenced when not iterating",
- "dict-keys-not-iterating",
- "Used when dict.keys is referenced in a non-iterating "
- "context (returns an iterator in Python 3)",
- ),
- "W1656": (
- "dict.values referenced when not iterating",
- "dict-values-not-iterating",
- "Used when dict.values is referenced in a non-iterating "
- "context (returns an iterator in Python 3)",
- ),
- "W1657": (
- "Accessing a removed attribute on the operator module",
- "deprecated-operator-function",
- "Used when accessing a field on operator module that has been "
- "removed in Python 3.",
- ),
- "W1658": (
- "Accessing a removed attribute on the urllib module",
- "deprecated-urllib-function",
- "Used when accessing a field on urllib module that has been "
- "removed or moved in Python 3.",
- ),
- "W1659": (
- "Accessing a removed xreadlines attribute",
- "xreadlines-attribute",
- "Used when accessing the xreadlines() function on a file stream, "
- "removed in Python 3.",
- ),
- "W1660": (
- "Accessing a removed attribute on the sys module",
- "deprecated-sys-function",
- "Used when accessing a field on sys module that has been "
- "removed in Python 3.",
- ),
- "W1661": (
- "Using an exception object that was bound by an except handler",
- "exception-escape",
- "Emitted when using an exception, that was bound in an except "
- "handler, outside of the except handler. On Python 3 these "
- "exceptions will be deleted once they get out "
- "of the except handler.",
- ),
- "W1662": (
- "Using a variable that was bound inside a comprehension",
- "comprehension-escape",
- "Emitted when using a variable, that was bound in a comprehension "
- "handler, outside of the comprehension itself. On Python 3 these "
- "variables will be deleted outside of the "
- "comprehension.",
- ),
- }
-
- _bad_builtins = frozenset(
- [
- "apply",
- "basestring",
- "buffer",
- "cmp",
- "coerce",
- "execfile",
- "file",
- "input", # Not missing, but incompatible semantics
- "intern",
- "long",
- "raw_input",
- "reduce",
- "round", # Not missing, but incompatible semantics
- "StandardError",
- "unichr",
- "unicode",
- "xrange",
- "reload",
- ]
- )
-
- _unused_magic_methods = frozenset(
- [
- "__coerce__",
- "__delslice__",
- "__getslice__",
- "__setslice__",
- "__oct__",
- "__hex__",
- "__nonzero__",
- "__cmp__",
- "__div__",
- "__idiv__",
- "__rdiv__",
- ]
- )
-
- _invalid_encodings = frozenset(
- [
- "base64_codec",
- "base64",
- "base_64",
- "bz2_codec",
- "bz2",
- "hex_codec",
- "hex",
- "quopri_codec",
- "quopri",
- "quotedprintable",
- "quoted_printable",
- "uu_codec",
- "uu",
- "zlib_codec",
- "zlib",
- "zip",
- "rot13",
- "rot_13",
- ]
- )
-
- _bad_python3_module_map = {
- "sys-max-int": {"sys": frozenset(["maxint"])},
- "deprecated-itertools-function": {
- "itertools": frozenset(
- ["izip", "ifilter", "imap", "izip_longest", "ifilterfalse"]
- )
- },
- "deprecated-types-field": {
- "types": frozenset(
- [
- "EllipsisType",
- "XRangeType",
- "ComplexType",
- "StringType",
- "TypeType",
- "LongType",
- "UnicodeType",
- "ClassType",
- "BufferType",
- "StringTypes",
- "NotImplementedType",
- "NoneType",
- "InstanceType",
- "FloatType",
- "SliceType",
- "UnboundMethodType",
- "ObjectType",
- "IntType",
- "TupleType",
- "ListType",
- "DictType",
- "FileType",
- "DictionaryType",
- "BooleanType",
- "DictProxyType",
- ]
- )
- },
- "bad-python3-import": frozenset(
- [
- "anydbm",
- "BaseHTTPServer",
- "__builtin__",
- "CGIHTTPServer",
- "ConfigParser",
- "copy_reg",
- "cPickle",
- "cStringIO",
- "Cookie",
- "cookielib",
- "dbhash",
- "dumbdbm",
- "dumbdb",
- "Dialog",
- "DocXMLRPCServer",
- "FileDialog",
- "FixTk",
- "gdbm",
- "htmlentitydefs",
- "HTMLParser",
- "httplib",
- "markupbase",
- "Queue",
- "repr",
- "robotparser",
- "ScrolledText",
- "SimpleDialog",
- "SimpleHTTPServer",
- "SimpleXMLRPCServer",
- "StringIO",
- "dummy_thread",
- "SocketServer",
- "test.test_support",
- "Tkinter",
- "Tix",
- "Tkconstants",
- "tkColorChooser",
- "tkCommonDialog",
- "Tkdnd",
- "tkFileDialog",
- "tkFont",
- "tkMessageBox",
- "tkSimpleDialog",
- "UserList",
- "UserString",
- "whichdb",
- "_winreg",
- "xmlrpclib",
- "audiodev",
- "Bastion",
- "bsddb185",
- "bsddb3",
- "Canvas",
- "cfmfile",
- "cl",
- "commands",
- "compiler",
- "dircache",
- "dl",
- "exception",
- "fpformat",
- "htmllib",
- "ihooks",
- "imageop",
- "imputil",
- "linuxaudiodev",
- "md5",
- "mhlib",
- "mimetools",
- "MimeWriter",
- "mimify",
- "multifile",
- "mutex",
- "new",
- "popen2",
- "posixfile",
- "pure",
- "rexec",
- "rfc822",
- "sets",
- "sha",
- "sgmllib",
- "sre",
- "stringold",
- "sunaudio",
- "sv",
- "test.testall",
- "thread",
- "timing",
- "toaiff",
- "user",
- "urllib2",
- "urlparse",
- ]
- ),
- "deprecated-string-function": {
- "string": frozenset(
- [
- "maketrans",
- "atof",
- "atoi",
- "atol",
- "capitalize",
- "expandtabs",
- "find",
- "rfind",
- "index",
- "rindex",
- "count",
- "lower",
- "letters",
- "split",
- "rsplit",
- "splitfields",
- "join",
- "joinfields",
- "lstrip",
- "rstrip",
- "strip",
- "swapcase",
- "translate",
- "upper",
- "ljust",
- "rjust",
- "center",
- "zfill",
- "replace",
- "lowercase",
- "letters",
- "uppercase",
- "atol_error",
- "atof_error",
- "atoi_error",
- "index_error",
- ]
- )
- },
- "deprecated-operator-function": {"operator": frozenset({"div"})},
- "deprecated-urllib-function": {
- "urllib": frozenset(
- {
- "addbase",
- "addclosehook",
- "addinfo",
- "addinfourl",
- "always_safe",
- "basejoin",
- "ftpcache",
- "ftperrors",
- "ftpwrapper",
- "getproxies",
- "getproxies_environment",
- "getproxies_macosx_sysconf",
- "main",
- "noheaders",
- "pathname2url",
- "proxy_bypass",
- "proxy_bypass_environment",
- "proxy_bypass_macosx_sysconf",
- "quote",
- "quote_plus",
- "reporthook",
- "splitattr",
- "splithost",
- "splitnport",
- "splitpasswd",
- "splitport",
- "splitquery",
- "splittag",
- "splittype",
- "splituser",
- "splitvalue",
- "unquote",
- "unquote_plus",
- "unwrap",
- "url2pathname",
- "urlcleanup",
- "urlencode",
- "urlopen",
- "urlretrieve",
- }
- )
- },
- "deprecated-sys-function": {"sys": frozenset({"exc_clear"})},
- }
-
- _python_2_tests = frozenset(
- [
- astroid.extract_node(x).repr_tree()
- for x in [
- "sys.version_info[0] == 2",
- "sys.version_info[0] < 3",
- "sys.version_info == (2, 7)",
- "sys.version_info <= (2, 7)",
- "sys.version_info < (3, 0)",
- ]
- ]
- )
-
- def __init__(self, *args, **kwargs):
- self._future_division = False
- self._future_absolute_import = False
- self._modules_warned_about = set()
- self._branch_stack = []
- super(Python3Checker, self).__init__(*args, **kwargs)
-
- # pylint: disable=keyword-arg-before-vararg, arguments-differ
- def add_message(self, msg_id, always_warn=False, *args, **kwargs):
- if always_warn or not (
- self._branch_stack and self._branch_stack[-1].is_py2_only
- ):
- super(Python3Checker, self).add_message(msg_id, *args, **kwargs)
-
- def _is_py2_test(self, node):
- if isinstance(node.test, astroid.Attribute) and isinstance(
- node.test.expr, astroid.Name
- ):
- if node.test.expr.name == "six" and node.test.attrname == "PY2":
- return True
- elif (
- isinstance(node.test, astroid.Compare)
- and node.test.repr_tree() in self._python_2_tests
- ):
- return True
- return False
-
- def visit_if(self, node):
- self._branch_stack.append(Branch(node, self._is_py2_test(node)))
-
- def leave_if(self, node):
- assert self._branch_stack.pop().node == node
-
- def visit_ifexp(self, node):
- self._branch_stack.append(Branch(node, self._is_py2_test(node)))
-
- def leave_ifexp(self, node):
- assert self._branch_stack.pop().node == node
-
- def visit_module(self, node): # pylint: disable=unused-argument
- """Clear checker state after previous module."""
- self._future_division = False
- self._future_absolute_import = False
-
- def visit_functiondef(self, node):
- if node.is_method():
- if node.name in self._unused_magic_methods:
- method_name = node.name
- if node.name.startswith("__"):
- method_name = node.name[2:-2]
- self.add_message(method_name + "-method", node=node)
- elif node.name == "next":
- # If there is a method named `next` declared, if it is invokable
- # with zero arguments then it implements the Iterator protocol.
- # This means if the method is an instance method or a
- # classmethod 1 argument should cause a failure, if it is a
- # staticmethod 0 arguments should cause a failure.
- failing_arg_count = 1
- if utils.decorated_with(node, [bases.BUILTINS + ".staticmethod"]):
- failing_arg_count = 0
- if len(node.args.args) == failing_arg_count:
- self.add_message("next-method-defined", node=node)
-
- @utils.check_messages("parameter-unpacking")
- def visit_arguments(self, node):
- for arg in node.args:
- if isinstance(arg, astroid.Tuple):
- self.add_message("parameter-unpacking", node=arg)
-
- @utils.check_messages("comprehension-escape")
- def visit_listcomp(self, node):
- names = {
- generator.target.name
- for generator in node.generators
- if isinstance(generator.target, astroid.AssignName)
- }
- scope = node.parent.scope()
- scope_names = scope.nodes_of_class(astroid.Name, skip_klass=astroid.FunctionDef)
- has_redefined_assign_name = any(
- assign_name
- for assign_name in scope.nodes_of_class(
- astroid.AssignName, skip_klass=astroid.FunctionDef
- )
- if assign_name.name in names and assign_name.lineno > node.lineno
- )
- if has_redefined_assign_name:
- return
-
- emitted_for_names = set()
- scope_names = list(scope_names)
- for scope_name in scope_names:
- if (
- scope_name.name not in names
- or scope_name.lineno <= node.lineno
- or scope_name.name in emitted_for_names
- or scope_name.scope() == node
- ):
- continue
-
- emitted_for_names.add(scope_name.name)
- self.add_message("comprehension-escape", node=scope_name)
-
- def visit_name(self, node):
- """Detect when a "bad" built-in is referenced."""
- found_node, _ = node.lookup(node.name)
- if not _is_builtin(found_node):
- return
- if node.name not in self._bad_builtins:
- return
- if node_ignores_exception(node) or isinstance(
- find_try_except_wrapper_node(node), astroid.ExceptHandler
- ):
- return
-
- message = node.name.lower() + "-builtin"
- self.add_message(message, node=node)
-
- @utils.check_messages("print-statement")
- def visit_print(self, node):
- self.add_message("print-statement", node=node, always_warn=True)
-
- def _warn_if_deprecated(self, node, module, attributes, report_on_modules=True):
- for message, module_map in self._bad_python3_module_map.items():
- if module in module_map and module not in self._modules_warned_about:
- if isinstance(module_map, frozenset):
- if report_on_modules:
- self._modules_warned_about.add(module)
- self.add_message(message, node=node)
- elif attributes and module_map[module].intersection(attributes):
- self.add_message(message, node=node)
-
- def visit_importfrom(self, node):
- if node.modname == "__future__":
- for name, _ in node.names:
- if name == "division":
- self._future_division = True
- elif name == "absolute_import":
- self._future_absolute_import = True
- else:
- if not self._future_absolute_import:
- if self.linter.is_message_enabled("no-absolute-import"):
- self.add_message("no-absolute-import", node=node)
- self._future_absolute_import = True
- if not _is_conditional_import(node) and not node.level:
- self._warn_if_deprecated(node, node.modname, {x[0] for x in node.names})
-
- if node.names[0][0] == "*":
- if self.linter.is_message_enabled("import-star-module-level"):
- if not isinstance(node.scope(), astroid.Module):
- self.add_message("import-star-module-level", node=node)
-
- def visit_import(self, node):
- if not self._future_absolute_import:
- if self.linter.is_message_enabled("no-absolute-import"):
- self.add_message("no-absolute-import", node=node)
- self._future_absolute_import = True
- if not _is_conditional_import(node):
- for name, _ in node.names:
- self._warn_if_deprecated(node, name, None)
-
- @utils.check_messages("metaclass-assignment")
- def visit_classdef(self, node):
- if "__metaclass__" in node.locals:
- self.add_message("metaclass-assignment", node=node)
- locals_and_methods = set(node.locals).union(x.name for x in node.mymethods())
- if "__eq__" in locals_and_methods and "__hash__" not in locals_and_methods:
- self.add_message("eq-without-hash", node=node)
-
- @utils.check_messages("old-division")
- def visit_binop(self, node):
- if not self._future_division and node.op == "/":
- for arg in (node.left, node.right):
- inferred = utils.safe_infer(arg)
- # If we can infer the object and that object is not an int, bail out.
- if inferred and not (
- (
- isinstance(inferred, astroid.Const)
- and isinstance(inferred.value, int)
- )
- or (
- isinstance(inferred, astroid.Instance)
- and inferred.name == "int"
- )
- ):
- break
- else:
- self.add_message("old-division", node=node)
-
- def _check_cmp_argument(self, node):
- # Check that the `cmp` argument is used
- kwargs = []
- if isinstance(node.func, astroid.Attribute) and node.func.attrname == "sort":
- inferred = utils.safe_infer(node.func.expr)
- if not inferred:
- return
-
- builtins_list = "{}.list".format(bases.BUILTINS)
- if isinstance(inferred, astroid.List) or inferred.qname() == builtins_list:
- kwargs = node.keywords
-
- elif isinstance(node.func, astroid.Name) and node.func.name == "sorted":
- inferred = utils.safe_infer(node.func)
- if not inferred:
- return
-
- builtins_sorted = "{}.sorted".format(bases.BUILTINS)
- if inferred.qname() == builtins_sorted:
- kwargs = node.keywords
-
- for kwarg in kwargs or []:
- if kwarg.arg == "cmp":
- self.add_message("using-cmp-argument", node=node)
- return
-
- @staticmethod
- def _is_constant_string_or_name(node):
- if isinstance(node, astroid.Const):
- return isinstance(node.value, str)
- return isinstance(node, astroid.Name)
-
- @staticmethod
- def _is_none(node):
- return isinstance(node, astroid.Const) and node.value is None
-
- @staticmethod
- def _has_only_n_positional_args(node, number_of_args):
- return len(node.args) == number_of_args and all(node.args) and not node.keywords
-
- @staticmethod
- def _could_be_string(inferred_types):
- confidence = INFERENCE if inferred_types else INFERENCE_FAILURE
- for inferred_type in inferred_types:
- if inferred_type is astroid.Uninferable:
- confidence = INFERENCE_FAILURE
- elif not (
- isinstance(inferred_type, astroid.Const)
- and isinstance(inferred_type.value, str)
- ):
- return None
- return confidence
-
- def visit_call(self, node):
- self._check_cmp_argument(node)
-
- if isinstance(node.func, astroid.Attribute):
- inferred_types = set()
- try:
- for inferred_receiver in node.func.expr.infer():
- if inferred_receiver is astroid.Uninferable:
- continue
- inferred_types.add(inferred_receiver)
- if isinstance(inferred_receiver, astroid.Module):
- self._warn_if_deprecated(
- node,
- inferred_receiver.name,
- {node.func.attrname},
- report_on_modules=False,
- )
- if (
- _inferred_value_is_dict(inferred_receiver)
- and node.func.attrname in DICT_METHODS
- ):
- if not _in_iterating_context(node):
- checker = "dict-{}-not-iterating".format(node.func.attrname)
- self.add_message(checker, node=node)
- except astroid.InferenceError:
- pass
- if node.args:
- is_str_confidence = self._could_be_string(inferred_types)
- if is_str_confidence:
- if (
- node.func.attrname in ("encode", "decode")
- and len(node.args) >= 1
- and node.args[0]
- ):
- first_arg = node.args[0]
- self._validate_encoding(first_arg, node)
- if (
- node.func.attrname == "translate"
- and self._has_only_n_positional_args(node, 2)
- and self._is_none(node.args[0])
- and self._is_constant_string_or_name(node.args[1])
- ):
- # The above statement looking for calls of the form:
- #
- # foo.translate(None, 'abc123')
- #
- # or
- #
- # foo.translate(None, some_variable)
- #
- # This check is somewhat broad and _may_ have some false positives, but
- # after checking several large codebases it did not have any false
- # positives while finding several real issues. This call pattern seems
- # rare enough that the trade off is worth it.
- self.add_message(
- "deprecated-str-translate-call",
- node=node,
- confidence=is_str_confidence,
- )
- return
- if node.keywords:
- return
- if node.func.attrname == "next":
- self.add_message("next-method-called", node=node)
- else:
- if node.func.attrname in ("iterkeys", "itervalues", "iteritems"):
- self.add_message("dict-iter-method", node=node)
- elif node.func.attrname in ("viewkeys", "viewvalues", "viewitems"):
- self.add_message("dict-view-method", node=node)
- elif isinstance(node.func, astroid.Name):
- found_node = node.func.lookup(node.func.name)[0]
- if _is_builtin(found_node):
- if node.func.name in ("filter", "map", "range", "zip"):
- if not _in_iterating_context(node):
- checker = "{}-builtin-not-iterating".format(node.func.name)
- self.add_message(checker, node=node)
- if node.func.name == "open" and node.keywords:
- kwargs = node.keywords
- for kwarg in kwargs or []:
- if kwarg.arg == "encoding":
- self._validate_encoding(kwarg.value, node)
- break
-
- def _validate_encoding(self, encoding, node):
- if isinstance(encoding, astroid.Const):
- value = encoding.value
- if value in self._invalid_encodings:
- self.add_message("invalid-str-codec", node=node)
-
- @utils.check_messages("indexing-exception")
- def visit_subscript(self, node):
- """ Look for indexing exceptions. """
- try:
- for inferred in node.value.infer():
- if not isinstance(inferred, astroid.Instance):
- continue
- if utils.inherit_from_std_ex(inferred):
- self.add_message("indexing-exception", node=node)
- except astroid.InferenceError:
- return
-
- def visit_assignattr(self, node):
- if isinstance(node.assign_type(), astroid.AugAssign):
- self.visit_attribute(node)
-
- def visit_delattr(self, node):
- self.visit_attribute(node)
-
- @utils.check_messages("exception-message-attribute", "xreadlines-attribute")
- def visit_attribute(self, node):
- """Look for removed attributes"""
- if node.attrname == "xreadlines":
- self.add_message("xreadlines-attribute", node=node)
- return
-
- exception_message = "message"
- try:
- for inferred in node.expr.infer():
- if isinstance(inferred, astroid.Instance) and utils.inherit_from_std_ex(
- inferred
- ):
- if node.attrname == exception_message:
-
- # Exceptions with .message clearly defined are an exception
- if exception_message in inferred.instance_attrs:
- continue
- self.add_message("exception-message-attribute", node=node)
- if isinstance(inferred, astroid.Module):
- self._warn_if_deprecated(
- node, inferred.name, {node.attrname}, report_on_modules=False
- )
- except astroid.InferenceError:
- return
-
- @utils.check_messages("unpacking-in-except", "comprehension-escape")
- def visit_excepthandler(self, node):
- """Visit an except handler block and check for exception unpacking."""
-
- def _is_used_in_except_block(node):
- scope = node.scope()
- current = node
- while (
- current
- and current != scope
- and not isinstance(current, astroid.ExceptHandler)
- ):
- current = current.parent
- return isinstance(current, astroid.ExceptHandler) and current.type != node
-
- if isinstance(node.name, (astroid.Tuple, astroid.List)):
- self.add_message("unpacking-in-except", node=node)
- return
-
- if not node.name:
- return
-
- # Find any names
- scope = node.parent.scope()
- scope_names = scope.nodes_of_class(astroid.Name, skip_klass=astroid.FunctionDef)
- scope_names = list(scope_names)
- potential_leaked_names = [
- scope_name
- for scope_name in scope_names
- if scope_name.name == node.name.name
- and scope_name.lineno > node.lineno
- and not _is_used_in_except_block(scope_name)
- ]
- reassignments_for_same_name = {
- assign_name.lineno
- for assign_name in scope.nodes_of_class(
- astroid.AssignName, skip_klass=astroid.FunctionDef
- )
- if assign_name.name == node.name.name
- }
- for leaked_name in potential_leaked_names:
- if any(
- node.lineno < elem < leaked_name.lineno
- for elem in reassignments_for_same_name
- ):
- continue
- self.add_message("exception-escape", node=leaked_name)
-
- @utils.check_messages("backtick")
- def visit_repr(self, node):
- self.add_message("backtick", node=node)
-
- @utils.check_messages("raising-string", "old-raise-syntax")
- def visit_raise(self, node):
- """Visit a raise statement and check for raising
- strings or old-raise-syntax.
- """
-
- # Ignore empty raise.
- if node.exc is None:
- return
- expr = node.exc
- if self._check_raise_value(node, expr):
- return
- try:
- value = next(astroid.unpack_infer(expr))
- except astroid.InferenceError:
- return
- self._check_raise_value(node, value)
-
- def _check_raise_value(self, node, expr):
- if isinstance(expr, astroid.Const):
- value = expr.value
- if isinstance(value, str):
- self.add_message("raising-string", node=node)
- return True
- return None
-
-
-class Python3TokenChecker(checkers.BaseTokenChecker):
- __implements__ = interfaces.ITokenChecker
- name = "python3"
- enabled = False
-
- msgs = {
- "E1606": (
- "Use of long suffix",
- "long-suffix",
- 'Used when "l" or "L" is used to mark a long integer. '
- "This will not work in Python 3, since `int` and `long` "
- "types have merged.",
- {"maxversion": (3, 0)},
- ),
- "E1607": (
- "Use of the <> operator",
- "old-ne-operator",
- 'Used when the deprecated "<>" operator is used instead '
- 'of "!=". This is removed in Python 3.',
- {"maxversion": (3, 0), "old_names": [("W0331", "old-old-ne-operator")]},
- ),
- "E1608": (
- "Use of old octal literal",
- "old-octal-literal",
- "Used when encountering the old octal syntax, "
- "removed in Python 3. To use the new syntax, "
- "prepend 0o on the number.",
- {"maxversion": (3, 0)},
- ),
- "E1610": (
- "Non-ascii bytes literals not supported in 3.x",
- "non-ascii-bytes-literal",
- "Used when non-ascii bytes literals are found in a program. "
- "They are no longer supported in Python 3.",
- {"maxversion": (3, 0)},
- ),
- }
-
- def process_tokens(self, tokens):
- for idx, (tok_type, token, start, _, _) in enumerate(tokens):
- if tok_type == tokenize.NUMBER:
- if token.lower().endswith("l"):
- # This has a different semantic than lowercase-l-suffix.
- self.add_message("long-suffix", line=start[0])
- elif _is_old_octal(token):
- self.add_message("old-octal-literal", line=start[0])
- if tokens[idx][1] == "<>":
- self.add_message("old-ne-operator", line=tokens[idx][2][0])
- if tok_type == tokenize.STRING and token.startswith("b"):
- if any(elem for elem in token if ord(elem) > 127):
- self.add_message("non-ascii-bytes-literal", line=start[0])
-
-
-def register(linter):
- linter.register_checker(Python3Checker(linter))
- linter.register_checker(Python3TokenChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/raw_metrics.py b/venv/Lib/site-packages/pylint/checkers/raw_metrics.py
deleted file mode 100644
index 0564398..0000000
--- a/venv/Lib/site-packages/pylint/checkers/raw_metrics.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# Copyright (c) 2007, 2010, 2013, 2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2013 Google, Inc.
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Mike Frysinger <vapier@gentoo.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-""" Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE).
- http://www.logilab.fr/ -- mailto:contact@logilab.fr
-
-Raw metrics checker
-"""
-
-import tokenize
-from typing import Any
-
-from pylint.checkers import BaseTokenChecker
-from pylint.exceptions import EmptyReportError
-from pylint.interfaces import ITokenChecker
-from pylint.reporters.ureports.nodes import Table
-
-
-def report_raw_stats(sect, stats, _):
- """calculate percentage of code / doc / comment / empty
- """
- total_lines = stats["total_lines"]
- if not total_lines:
- raise EmptyReportError()
- sect.description = "%s lines have been analyzed" % total_lines
- lines = ("type", "number", "%", "previous", "difference")
- for node_type in ("code", "docstring", "comment", "empty"):
- key = node_type + "_lines"
- total = stats[key]
- percent = float(total * 100) / total_lines
- lines += (node_type, str(total), "%.2f" % percent, "NC", "NC")
- sect.append(Table(children=lines, cols=5, rheaders=1))
-
-
-class RawMetricsChecker(BaseTokenChecker):
- """does not check anything but gives some raw metrics :
- * total number of lines
- * total number of code lines
- * total number of docstring lines
- * total number of comments lines
- * total number of empty lines
- """
-
- __implements__ = (ITokenChecker,)
-
- # configuration section name
- name = "metrics"
- # configuration options
- options = ()
- # messages
- msgs = {} # type: Any
- # reports
- reports = (("RP0701", "Raw metrics", report_raw_stats),)
-
- def __init__(self, linter):
- BaseTokenChecker.__init__(self, linter)
- self.stats = None
-
- def open(self):
- """init statistics"""
- self.stats = self.linter.add_stats(
- total_lines=0,
- code_lines=0,
- empty_lines=0,
- docstring_lines=0,
- comment_lines=0,
- )
-
- def process_tokens(self, tokens):
- """update stats"""
- i = 0
- tokens = list(tokens)
- while i < len(tokens):
- i, lines_number, line_type = get_type(tokens, i)
- self.stats["total_lines"] += lines_number
- self.stats[line_type] += lines_number
-
-
-JUNK = (tokenize.NL, tokenize.INDENT, tokenize.NEWLINE, tokenize.ENDMARKER)
-
-
-def get_type(tokens, start_index):
- """return the line type : docstring, comment, code, empty"""
- i = start_index
- tok_type = tokens[i][0]
- start = tokens[i][2]
- pos = start
- line_type = None
- while i < len(tokens) and tokens[i][2][0] == start[0]:
- tok_type = tokens[i][0]
- pos = tokens[i][3]
- if line_type is None:
- if tok_type == tokenize.STRING:
- line_type = "docstring_lines"
- elif tok_type == tokenize.COMMENT:
- line_type = "comment_lines"
- elif tok_type in JUNK:
- pass
- else:
- line_type = "code_lines"
- i += 1
- if line_type is None:
- line_type = "empty_lines"
- elif i < len(tokens) and tokens[i][0] == tokenize.NEWLINE:
- i += 1
- return i, pos[0] - start[0] + 1, line_type
-
-
-def register(linter):
- """ required method to auto register this checker """
- linter.register_checker(RawMetricsChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/refactoring.py b/venv/Lib/site-packages/pylint/checkers/refactoring.py
deleted file mode 100644
index 2831343..0000000
--- a/venv/Lib/site-packages/pylint/checkers/refactoring.py
+++ /dev/null
@@ -1,1510 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2016-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016-2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2017-2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2017 Hugo <hugovk@users.noreply.github.com>
-# Copyright (c) 2017 Łukasz Sznuk <ls@rdprojekt.pl>
-# Copyright (c) 2017 Alex Hearn <alex.d.hearn@gmail.com>
-# Copyright (c) 2017 Antonio Ossa <aaossa@uc.cl>
-# Copyright (c) 2018 Konstantin Manna <Konstantin@Manna.uno>
-# Copyright (c) 2018 Konstantin <Github@pheanex.de>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Matej Marušák <marusak.matej@gmail.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-# Copyright (c) 2018 Mr. Senko <atodorov@mrsenko.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Looks for code which can be refactored."""
-import builtins
-import collections
-import itertools
-import tokenize
-from functools import reduce
-
-import astroid
-from astroid import decorators
-
-from pylint import checkers, interfaces
-from pylint import utils as lint_utils
-from pylint.checkers import utils
-
-KNOWN_INFINITE_ITERATORS = {"itertools.count"}
-BUILTIN_EXIT_FUNCS = frozenset(("quit", "exit"))
-
-
-def _if_statement_is_always_returning(if_node, returning_node_class):
- for node in if_node.body:
- if isinstance(node, returning_node_class):
- return True
- return False
-
-
-def _is_len_call(node):
- """Checks if node is len(SOMETHING)."""
- return (
- isinstance(node, astroid.Call)
- and isinstance(node.func, astroid.Name)
- and node.func.name == "len"
- )
-
-
-def _is_constant_zero(node):
- return isinstance(node, astroid.Const) and node.value == 0
-
-
-def _node_is_test_condition(node):
- """ Checks if node is an if, while, assert or if expression statement."""
- return isinstance(node, (astroid.If, astroid.While, astroid.Assert, astroid.IfExp))
-
-
-def _is_trailing_comma(tokens, index):
- """Check if the given token is a trailing comma
-
- :param tokens: Sequence of modules tokens
- :type tokens: list[tokenize.TokenInfo]
- :param int index: Index of token under check in tokens
- :returns: True if the token is a comma which trails an expression
- :rtype: bool
- """
- token = tokens[index]
- if token.exact_type != tokenize.COMMA:
- return False
- # Must have remaining tokens on the same line such as NEWLINE
- left_tokens = itertools.islice(tokens, index + 1, None)
- same_line_remaining_tokens = list(
- itertools.takewhile(
- lambda other_token, _token=token: other_token.start[0] == _token.start[0],
- left_tokens,
- )
- )
- # Note: If the newline is tokenize.NEWLINE and not tokenize.NL
- # then the newline denotes the end of expression
- is_last_element = all(
- other_token.type in (tokenize.NEWLINE, tokenize.COMMENT)
- for other_token in same_line_remaining_tokens
- )
- if not same_line_remaining_tokens or not is_last_element:
- return False
-
- def get_curline_index_start():
- """Get the index denoting the start of the current line"""
- for subindex, token in enumerate(reversed(tokens[:index])):
- # See Lib/tokenize.py and Lib/token.py in cpython for more info
- if token.type in (tokenize.NEWLINE, tokenize.NL):
- return index - subindex
- return 0
-
- curline_start = get_curline_index_start()
- expected_tokens = {"return", "yield"}
- for prevtoken in tokens[curline_start:index]:
- if "=" in prevtoken.string or prevtoken.string in expected_tokens:
- return True
- return False
-
-
-class RefactoringChecker(checkers.BaseTokenChecker):
- """Looks for code which can be refactored
-
- This checker also mixes the astroid and the token approaches
- in order to create knowledge about whether an "else if" node
- is a true "else if" node, or an "elif" node.
- """
-
- __implements__ = (interfaces.ITokenChecker, interfaces.IAstroidChecker)
-
- name = "refactoring"
-
- msgs = {
- "R1701": (
- "Consider merging these isinstance calls to isinstance(%s, (%s))",
- "consider-merging-isinstance",
- "Used when multiple consecutive isinstance calls can be merged into one.",
- ),
- "R1706": (
- "Consider using ternary (%s)",
- "consider-using-ternary",
- "Used when one of known pre-python 2.5 ternary syntax is used.",
- ),
- "R1709": (
- "Boolean expression may be simplified to %s",
- "simplify-boolean-expression",
- "Emitted when redundant pre-python 2.5 ternary syntax is used.",
- ),
- "R1702": (
- "Too many nested blocks (%s/%s)",
- "too-many-nested-blocks",
- "Used when a function or a method has too many nested "
- "blocks. This makes the code less understandable and "
- "maintainable.",
- {"old_names": [("R0101", "old-too-many-nested-blocks")]},
- ),
- "R1703": (
- "The if statement can be replaced with %s",
- "simplifiable-if-statement",
- "Used when an if statement can be replaced with 'bool(test)'. ",
- {"old_names": [("R0102", "old-simplifiable-if-statement")]},
- ),
- "R1704": (
- "Redefining argument with the local name %r",
- "redefined-argument-from-local",
- "Used when a local name is redefining an argument, which might "
- "suggest a potential error. This is taken in account only for "
- "a handful of name binding operations, such as for iteration, "
- "with statement assignment and exception handler assignment.",
- ),
- "R1705": (
- 'Unnecessary "%s" after "return"',
- "no-else-return",
- "Used in order to highlight an unnecessary block of "
- "code following an if containing a return statement. "
- "As such, it will warn when it encounters an else "
- "following a chain of ifs, all of them containing a "
- "return statement.",
- ),
- "R1707": (
- "Disallow trailing comma tuple",
- "trailing-comma-tuple",
- "In Python, a tuple is actually created by the comma symbol, "
- "not by the parentheses. Unfortunately, one can actually create a "
- "tuple by misplacing a trailing comma, which can lead to potential "
- "weird bugs in your code. You should always use parentheses "
- "explicitly for creating a tuple.",
- ),
- "R1708": (
- "Do not raise StopIteration in generator, use return statement instead",
- "stop-iteration-return",
- "According to PEP479, the raise of StopIteration to end the loop of "
- "a generator may lead to hard to find bugs. This PEP specify that "
- "raise StopIteration has to be replaced by a simple return statement",
- ),
- "R1710": (
- "Either all return statements in a function should return an expression, "
- "or none of them should.",
- "inconsistent-return-statements",
- "According to PEP8, if any return statement returns an expression, "
- "any return statements where no value is returned should explicitly "
- "state this as return None, and an explicit return statement "
- "should be present at the end of the function (if reachable)",
- ),
- "R1711": (
- "Useless return at end of function or method",
- "useless-return",
- 'Emitted when a single "return" or "return None" statement is found '
- "at the end of function or method definition. This statement can safely be "
- "removed because Python will implicitly return None",
- ),
- "R1712": (
- "Consider using tuple unpacking for swapping variables",
- "consider-swap-variables",
- "You do not have to use a temporary variable in order to "
- 'swap variables. Using "tuple unpacking" to directly swap '
- "variables makes the intention more clear.",
- ),
- "R1713": (
- "Consider using str.join(sequence) for concatenating "
- "strings from an iterable",
- "consider-using-join",
- "Using str.join(sequence) is faster, uses less memory "
- "and increases readability compared to for-loop iteration.",
- ),
- "R1714": (
- 'Consider merging these comparisons with "in" to %r',
- "consider-using-in",
- "To check if a variable is equal to one of many values,"
- 'combine the values into a tuple and check if the variable is contained "in" it '
- "instead of checking for equality against each of the values."
- "This is faster and less verbose.",
- ),
- "R1715": (
- "Consider using dict.get for getting values from a dict "
- "if a key is present or a default if not",
- "consider-using-get",
- "Using the builtin dict.get for getting a value from a dictionary "
- "if a key is present or a default if not, is simpler and considered "
- "more idiomatic, although sometimes a bit slower",
- ),
- "R1716": (
- "Simplify chained comparison between the operands",
- "chained-comparison",
- "This message is emitted when pylint encounters boolean operation like"
- '"a < b and b < c", suggesting instead to refactor it to "a < b < c"',
- ),
- "R1717": (
- "Consider using a dictionary comprehension",
- "consider-using-dict-comprehension",
- "Emitted when we detect the creation of a dictionary "
- "using the dict() callable and a transient list. "
- "Although there is nothing syntactically wrong with this code, "
- "it is hard to read and can be simplified to a dict comprehension."
- "Also it is faster since you don't need to create another "
- "transient list",
- ),
- "R1718": (
- "Consider using a set comprehension",
- "consider-using-set-comprehension",
- "Although there is nothing syntactically wrong with this code, "
- "it is hard to read and can be simplified to a set comprehension."
- "Also it is faster since you don't need to create another "
- "transient list",
- ),
- "R1719": (
- "The if expression can be replaced with %s",
- "simplifiable-if-expression",
- "Used when an if expression can be replaced with 'bool(test)'. ",
- ),
- "R1720": (
- 'Unnecessary "%s" after "raise"',
- "no-else-raise",
- "Used in order to highlight an unnecessary block of "
- "code following an if containing a raise statement. "
- "As such, it will warn when it encounters an else "
- "following a chain of ifs, all of them containing a "
- "raise statement.",
- ),
- "R1721": (
- "Unnecessary use of a comprehension",
- "unnecessary-comprehension",
- "Instead of using an identitiy comprehension, "
- "consider using the list, dict or set constructor. "
- "It is faster and simpler.",
- ),
- "R1722": (
- "Consider using sys.exit()",
- "consider-using-sys-exit",
- "Instead of using exit() or quit(), consider using the sys.exit().",
- ),
- "R1723": (
- 'Unnecessary "%s" after "break"',
- "no-else-break",
- "Used in order to highlight an unnecessary block of "
- "code following an if containing a break statement. "
- "As such, it will warn when it encounters an else "
- "following a chain of ifs, all of them containing a "
- "break statement.",
- ),
- "R1724": (
- 'Unnecessary "%s" after "continue"',
- "no-else-continue",
- "Used in order to highlight an unnecessary block of "
- "code following an if containing a continue statement. "
- "As such, it will warn when it encounters an else "
- "following a chain of ifs, all of them containing a "
- "continue statement.",
- ),
- }
- options = (
- (
- "max-nested-blocks",
- {
- "default": 5,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of nested blocks for function / method body",
- },
- ),
- (
- "never-returning-functions",
- {
- "default": ("sys.exit",),
- "type": "csv",
- "help": "Complete name of functions that never returns. When checking "
- "for inconsistent-return-statements if a never returning function is "
- "called then it will be considered as an explicit return statement "
- "and no message will be printed.",
- },
- ),
- )
-
- priority = 0
-
- def __init__(self, linter=None):
- checkers.BaseTokenChecker.__init__(self, linter)
- self._return_nodes = {}
- self._init()
- self._never_returning_functions = None
-
- def _init(self):
- self._nested_blocks = []
- self._elifs = []
- self._nested_blocks_msg = None
- self._reported_swap_nodes = set()
-
- def open(self):
- # do this in open since config not fully initialized in __init__
- self._never_returning_functions = set(self.config.never_returning_functions)
-
- @decorators.cachedproperty
- def _dummy_rgx(self):
- return lint_utils.get_global_option(self, "dummy-variables-rgx", default=None)
-
- @staticmethod
- def _is_bool_const(node):
- return isinstance(node.value, astroid.Const) and isinstance(
- node.value.value, bool
- )
-
- def _is_actual_elif(self, node):
- """Check if the given node is an actual elif
-
- This is a problem we're having with the builtin ast module,
- which splits `elif` branches into a separate if statement.
- Unfortunately we need to know the exact type in certain
- cases.
- """
- if isinstance(node.parent, astroid.If):
- orelse = node.parent.orelse
- # current if node must directly follow an "else"
- if orelse and orelse == [node]:
- if (node.lineno, node.col_offset) in self._elifs:
- return True
- return False
-
- def _check_simplifiable_if(self, node):
- """Check if the given if node can be simplified.
-
- The if statement can be reduced to a boolean expression
- in some cases. For instance, if there are two branches
- and both of them return a boolean value that depends on
- the result of the statement's test, then this can be reduced
- to `bool(test)` without losing any functionality.
- """
-
- if self._is_actual_elif(node):
- # Not interested in if statements with multiple branches.
- return
- if len(node.orelse) != 1 or len(node.body) != 1:
- return
-
- # Check if both branches can be reduced.
- first_branch = node.body[0]
- else_branch = node.orelse[0]
- if isinstance(first_branch, astroid.Return):
- if not isinstance(else_branch, astroid.Return):
- return
- first_branch_is_bool = self._is_bool_const(first_branch)
- else_branch_is_bool = self._is_bool_const(else_branch)
- reduced_to = "'return bool(test)'"
- elif isinstance(first_branch, astroid.Assign):
- if not isinstance(else_branch, astroid.Assign):
- return
-
- # Check if we assign to the same value
- first_branch_targets = [
- target.name
- for target in first_branch.targets
- if isinstance(target, astroid.AssignName)
- ]
- else_branch_targets = [
- target.name
- for target in else_branch.targets
- if isinstance(target, astroid.AssignName)
- ]
- if not first_branch_targets or not else_branch_targets:
- return
- if sorted(first_branch_targets) != sorted(else_branch_targets):
- return
-
- first_branch_is_bool = self._is_bool_const(first_branch)
- else_branch_is_bool = self._is_bool_const(else_branch)
- reduced_to = "'var = bool(test)'"
- else:
- return
-
- if not first_branch_is_bool or not else_branch_is_bool:
- return
- if not first_branch.value.value:
- # This is a case that can't be easily simplified and
- # if it can be simplified, it will usually result in a
- # code that's harder to understand and comprehend.
- # Let's take for instance `arg and arg <= 3`. This could theoretically be
- # reduced to `not arg or arg > 3`, but the net result is that now the
- # condition is harder to understand, because it requires understanding of
- # an extra clause:
- # * first, there is the negation of truthness with `not arg`
- # * the second clause is `arg > 3`, which occurs when arg has a
- # a truth value, but it implies that `arg > 3` is equivalent
- # with `arg and arg > 3`, which means that the user must
- # think about this assumption when evaluating `arg > 3`.
- # The original form is easier to grasp.
- return
-
- self.add_message("simplifiable-if-statement", node=node, args=(reduced_to,))
-
- def process_tokens(self, tokens):
- # Process tokens and look for 'if' or 'elif'
- for index, token in enumerate(tokens):
- token_string = token[1]
- if token_string == "elif":
- # AST exists by the time process_tokens is called, so
- # it's safe to assume tokens[index+1]
- # exists. tokens[index+1][2] is the elif's position as
- # reported by CPython and PyPy,
- # tokens[index][2] is the actual position and also is
- # reported by IronPython.
- self._elifs.extend([tokens[index][2], tokens[index + 1][2]])
- elif _is_trailing_comma(tokens, index):
- if self.linter.is_message_enabled("trailing-comma-tuple"):
- self.add_message("trailing-comma-tuple", line=token.start[0])
-
- def leave_module(self, _):
- self._init()
-
- @utils.check_messages("too-many-nested-blocks")
- def visit_tryexcept(self, node):
- self._check_nested_blocks(node)
-
- visit_tryfinally = visit_tryexcept
- visit_while = visit_tryexcept
-
- def _check_redefined_argument_from_local(self, name_node):
- if self._dummy_rgx and self._dummy_rgx.match(name_node.name):
- return
- if not name_node.lineno:
- # Unknown position, maybe it is a manually built AST?
- return
-
- scope = name_node.scope()
- if not isinstance(scope, astroid.FunctionDef):
- return
-
- for defined_argument in scope.args.nodes_of_class(
- astroid.AssignName, skip_klass=(astroid.Lambda,)
- ):
- if defined_argument.name == name_node.name:
- self.add_message(
- "redefined-argument-from-local",
- node=name_node,
- args=(name_node.name,),
- )
-
- @utils.check_messages("redefined-argument-from-local", "too-many-nested-blocks")
- def visit_for(self, node):
- self._check_nested_blocks(node)
-
- for name in node.target.nodes_of_class(astroid.AssignName):
- self._check_redefined_argument_from_local(name)
-
- @utils.check_messages("redefined-argument-from-local")
- def visit_excepthandler(self, node):
- if node.name and isinstance(node.name, astroid.AssignName):
- self._check_redefined_argument_from_local(node.name)
-
- @utils.check_messages("redefined-argument-from-local")
- def visit_with(self, node):
- for _, names in node.items:
- if not names:
- continue
- for name in names.nodes_of_class(astroid.AssignName):
- self._check_redefined_argument_from_local(name)
-
- def _check_superfluous_else(self, node, msg_id, returning_node_class):
- if not node.orelse:
- # Not interested in if statements without else.
- return
-
- if self._is_actual_elif(node):
- # Not interested in elif nodes; only if
- return
-
- if _if_statement_is_always_returning(node, returning_node_class):
- orelse = node.orelse[0]
- followed_by_elif = (orelse.lineno, orelse.col_offset) in self._elifs
- self.add_message(
- msg_id, node=node, args="elif" if followed_by_elif else "else"
- )
-
- def _check_superfluous_else_return(self, node):
- return self._check_superfluous_else(
- node, msg_id="no-else-return", returning_node_class=astroid.Return
- )
-
- def _check_superfluous_else_raise(self, node):
- return self._check_superfluous_else(
- node, msg_id="no-else-raise", returning_node_class=astroid.Raise
- )
-
- def _check_superfluous_else_break(self, node):
- return self._check_superfluous_else(
- node, msg_id="no-else-break", returning_node_class=astroid.Break
- )
-
- def _check_superfluous_else_continue(self, node):
- return self._check_superfluous_else(
- node, msg_id="no-else-continue", returning_node_class=astroid.Continue
- )
-
- def _check_consider_get(self, node):
- def type_and_name_are_equal(node_a, node_b):
- for _type in [astroid.Name, astroid.AssignName]:
- if all(isinstance(_node, _type) for _node in [node_a, node_b]):
- return node_a.name == node_b.name
- if all(isinstance(_node, astroid.Const) for _node in [node_a, node_b]):
- return node_a.value == node_b.value
- return False
-
- if_block_ok = (
- isinstance(node.test, astroid.Compare)
- and len(node.body) == 1
- and isinstance(node.body[0], astroid.Assign)
- and isinstance(node.body[0].value, astroid.Subscript)
- and type_and_name_are_equal(node.body[0].value.value, node.test.ops[0][1])
- and isinstance(node.body[0].value.slice, astroid.Index)
- and type_and_name_are_equal(node.body[0].value.slice.value, node.test.left)
- and len(node.body[0].targets) == 1
- and isinstance(node.body[0].targets[0], astroid.AssignName)
- and isinstance(utils.safe_infer(node.test.ops[0][1]), astroid.Dict)
- )
-
- if if_block_ok and not node.orelse:
- self.add_message("consider-using-get", node=node)
- elif (
- if_block_ok
- and len(node.orelse) == 1
- and isinstance(node.orelse[0], astroid.Assign)
- and type_and_name_are_equal(
- node.orelse[0].targets[0], node.body[0].targets[0]
- )
- and len(node.orelse[0].targets) == 1
- ):
- self.add_message("consider-using-get", node=node)
-
- @utils.check_messages(
- "too-many-nested-blocks",
- "simplifiable-if-statement",
- "no-else-return",
- "no-else-raise",
- "no-else-break",
- "no-else-continue",
- "consider-using-get",
- )
- def visit_if(self, node):
- self._check_simplifiable_if(node)
- self._check_nested_blocks(node)
- self._check_superfluous_else_return(node)
- self._check_superfluous_else_raise(node)
- self._check_superfluous_else_break(node)
- self._check_superfluous_else_continue(node)
- self._check_consider_get(node)
-
- @utils.check_messages("simplifiable-if-expression")
- def visit_ifexp(self, node):
- self._check_simplifiable_ifexp(node)
-
- def _check_simplifiable_ifexp(self, node):
- if not isinstance(node.body, astroid.Const) or not isinstance(
- node.orelse, astroid.Const
- ):
- return
-
- if not isinstance(node.body.value, bool) or not isinstance(
- node.orelse.value, bool
- ):
- return
-
- if isinstance(node.test, astroid.Compare):
- test_reduced_to = "test"
- else:
- test_reduced_to = "bool(test)"
-
- if (node.body.value, node.orelse.value) == (True, False):
- reduced_to = "'{}'".format(test_reduced_to)
- elif (node.body.value, node.orelse.value) == (False, True):
- reduced_to = "'not test'"
- else:
- return
-
- self.add_message("simplifiable-if-expression", node=node, args=(reduced_to,))
-
- @utils.check_messages(
- "too-many-nested-blocks", "inconsistent-return-statements", "useless-return"
- )
- def leave_functiondef(self, node):
- # check left-over nested blocks stack
- self._emit_nested_blocks_message_if_needed(self._nested_blocks)
- # new scope = reinitialize the stack of nested blocks
- self._nested_blocks = []
- #  check consistent return statements
- self._check_consistent_returns(node)
- # check for single return or return None at the end
- self._check_return_at_the_end(node)
- self._return_nodes[node.name] = []
-
- @utils.check_messages("stop-iteration-return")
- def visit_raise(self, node):
- self._check_stop_iteration_inside_generator(node)
-
- def _check_stop_iteration_inside_generator(self, node):
- """Check if an exception of type StopIteration is raised inside a generator"""
- frame = node.frame()
- if not isinstance(frame, astroid.FunctionDef) or not frame.is_generator():
- return
- if utils.node_ignores_exception(node, StopIteration):
- return
- if not node.exc:
- return
- exc = utils.safe_infer(node.exc)
- if exc is None or exc is astroid.Uninferable:
- return
- if self._check_exception_inherit_from_stopiteration(exc):
- self.add_message("stop-iteration-return", node=node)
-
- @staticmethod
- def _check_exception_inherit_from_stopiteration(exc):
- """Return True if the exception node in argument inherit from StopIteration"""
- stopiteration_qname = "{}.StopIteration".format(utils.EXCEPTIONS_MODULE)
- return any(_class.qname() == stopiteration_qname for _class in exc.mro())
-
- def _check_consider_using_comprehension_constructor(self, node):
- if (
- isinstance(node.func, astroid.Name)
- and node.args
- and isinstance(node.args[0], astroid.ListComp)
- ):
- if node.func.name == "dict" and not isinstance(
- node.args[0].elt, astroid.Call
- ):
- message_name = "consider-using-dict-comprehension"
- self.add_message(message_name, node=node)
- elif node.func.name == "set":
- message_name = "consider-using-set-comprehension"
- self.add_message(message_name, node=node)
-
- @utils.check_messages(
- "stop-iteration-return",
- "consider-using-dict-comprehension",
- "consider-using-set-comprehension",
- "consider-using-sys-exit",
- )
- def visit_call(self, node):
- self._check_raising_stopiteration_in_generator_next_call(node)
- self._check_consider_using_comprehension_constructor(node)
- self._check_quit_exit_call(node)
-
- @staticmethod
- def _has_exit_in_scope(scope):
- exit_func = scope.locals.get("exit")
- return bool(
- exit_func and isinstance(exit_func[0], (astroid.ImportFrom, astroid.Import))
- )
-
- def _check_quit_exit_call(self, node):
-
- if isinstance(node.func, astroid.Name) and node.func.name in BUILTIN_EXIT_FUNCS:
- # If we have `exit` imported from `sys` in the current or global scope, exempt this instance.
- local_scope = node.scope()
- if self._has_exit_in_scope(local_scope) or self._has_exit_in_scope(
- node.root()
- ):
- return
- self.add_message("consider-using-sys-exit", node=node)
-
- def _check_raising_stopiteration_in_generator_next_call(self, node):
- """Check if a StopIteration exception is raised by the call to next function
-
- If the next value has a default value, then do not add message.
-
- :param node: Check to see if this Call node is a next function
- :type node: :class:`astroid.node_classes.Call`
- """
-
- def _looks_like_infinite_iterator(param):
- inferred = utils.safe_infer(param)
- if inferred:
- return inferred.qname() in KNOWN_INFINITE_ITERATORS
- return False
-
- if isinstance(node.func, astroid.Attribute):
- # A next() method, which is now what we want.
- return
-
- inferred = utils.safe_infer(node.func)
- if getattr(inferred, "name", "") == "next":
- frame = node.frame()
- # The next builtin can only have up to two
- # positional arguments and no keyword arguments
- has_sentinel_value = len(node.args) > 1
- if (
- isinstance(frame, astroid.FunctionDef)
- and frame.is_generator()
- and not has_sentinel_value
- and not utils.node_ignores_exception(node, StopIteration)
- and not _looks_like_infinite_iterator(node.args[0])
- ):
- self.add_message("stop-iteration-return", node=node)
-
- def _check_nested_blocks(self, node):
- """Update and check the number of nested blocks
- """
- # only check block levels inside functions or methods
- if not isinstance(node.scope(), astroid.FunctionDef):
- return
- # messages are triggered on leaving the nested block. Here we save the
- # stack in case the current node isn't nested in the previous one
- nested_blocks = self._nested_blocks[:]
- if node.parent == node.scope():
- self._nested_blocks = [node]
- else:
- # go through ancestors from the most nested to the less
- for ancestor_node in reversed(self._nested_blocks):
- if ancestor_node == node.parent:
- break
- self._nested_blocks.pop()
- # if the node is an elif, this should not be another nesting level
- if isinstance(node, astroid.If) and self._is_actual_elif(node):
- if self._nested_blocks:
- self._nested_blocks.pop()
- self._nested_blocks.append(node)
-
- # send message only once per group of nested blocks
- if len(nested_blocks) > len(self._nested_blocks):
- self._emit_nested_blocks_message_if_needed(nested_blocks)
-
- def _emit_nested_blocks_message_if_needed(self, nested_blocks):
- if len(nested_blocks) > self.config.max_nested_blocks:
- self.add_message(
- "too-many-nested-blocks",
- node=nested_blocks[0],
- args=(len(nested_blocks), self.config.max_nested_blocks),
- )
-
- @staticmethod
- def _duplicated_isinstance_types(node):
- """Get the duplicated types from the underlying isinstance calls.
-
- :param astroid.BoolOp node: Node which should contain a bunch of isinstance calls.
- :returns: Dictionary of the comparison objects from the isinstance calls,
- to duplicate values from consecutive calls.
- :rtype: dict
- """
- duplicated_objects = set()
- all_types = collections.defaultdict(set)
-
- for call in node.values:
- if not isinstance(call, astroid.Call) or len(call.args) != 2:
- continue
-
- inferred = utils.safe_infer(call.func)
- if not inferred or not utils.is_builtin_object(inferred):
- continue
-
- if inferred.name != "isinstance":
- continue
-
- isinstance_object = call.args[0].as_string()
- isinstance_types = call.args[1]
-
- if isinstance_object in all_types:
- duplicated_objects.add(isinstance_object)
-
- if isinstance(isinstance_types, astroid.Tuple):
- elems = [
- class_type.as_string() for class_type in isinstance_types.itered()
- ]
- else:
- elems = [isinstance_types.as_string()]
- all_types[isinstance_object].update(elems)
-
- # Remove all keys which not duplicated
- return {
- key: value for key, value in all_types.items() if key in duplicated_objects
- }
-
- def _check_consider_merging_isinstance(self, node):
- """Check isinstance calls which can be merged together."""
- if node.op != "or":
- return
-
- first_args = self._duplicated_isinstance_types(node)
- for duplicated_name, class_names in first_args.items():
- names = sorted(name for name in class_names)
- self.add_message(
- "consider-merging-isinstance",
- node=node,
- args=(duplicated_name, ", ".join(names)),
- )
-
- def _check_consider_using_in(self, node):
- allowed_ops = {"or": "==", "and": "!="}
-
- if node.op not in allowed_ops or len(node.values) < 2:
- return
-
- for value in node.values:
- if (
- not isinstance(value, astroid.Compare)
- or len(value.ops) != 1
- or value.ops[0][0] not in allowed_ops[node.op]
- ):
- return
- for comparable in value.left, value.ops[0][1]:
- if isinstance(comparable, astroid.Call):
- return
-
- # Gather variables and values from comparisons
- variables, values = [], []
- for value in node.values:
- variable_set = set()
- for comparable in value.left, value.ops[0][1]:
- if isinstance(comparable, astroid.Name):
- variable_set.add(comparable.as_string())
- values.append(comparable.as_string())
- variables.append(variable_set)
-
- # Look for (common-)variables that occur in all comparisons
- common_variables = reduce(lambda a, b: a.intersection(b), variables)
-
- if not common_variables:
- return
-
- # Gather information for the suggestion
- common_variable = sorted(list(common_variables))[0]
- comprehension = "in" if node.op == "or" else "not in"
- values = list(collections.OrderedDict.fromkeys(values))
- values.remove(common_variable)
- values_string = ", ".join(values) if len(values) != 1 else values[0] + ","
- suggestion = "%s %s (%s)" % (common_variable, comprehension, values_string)
-
- self.add_message("consider-using-in", node=node, args=(suggestion,))
-
- def _check_chained_comparison(self, node):
- """Check if there is any chained comparison in the expression.
-
- Add a refactoring message if a boolOp contains comparison like a < b and b < c,
- which can be chained as a < b < c.
-
- Care is taken to avoid simplifying a < b < c and b < d.
- """
- if node.op != "and" or len(node.values) < 2:
- return
-
- def _find_lower_upper_bounds(comparison_node, uses):
- left_operand = comparison_node.left
- for operator, right_operand in comparison_node.ops:
- for operand in (left_operand, right_operand):
- value = None
- if isinstance(operand, astroid.Name):
- value = operand.name
- elif isinstance(operand, astroid.Const):
- value = operand.value
-
- if value is None:
- continue
-
- if operator in ("<", "<="):
- if operand is left_operand:
- uses[value]["lower_bound"].add(comparison_node)
- elif operand is right_operand:
- uses[value]["upper_bound"].add(comparison_node)
- elif operator in (">", ">="):
- if operand is left_operand:
- uses[value]["upper_bound"].add(comparison_node)
- elif operand is right_operand:
- uses[value]["lower_bound"].add(comparison_node)
- left_operand = right_operand
-
- uses = collections.defaultdict(
- lambda: {"lower_bound": set(), "upper_bound": set()}
- )
- for comparison_node in node.values:
- if isinstance(comparison_node, astroid.Compare):
- _find_lower_upper_bounds(comparison_node, uses)
-
- for _, bounds in uses.items():
- num_shared = len(bounds["lower_bound"].intersection(bounds["upper_bound"]))
- num_lower_bounds = len(bounds["lower_bound"])
- num_upper_bounds = len(bounds["upper_bound"])
- if num_shared < num_lower_bounds and num_shared < num_upper_bounds:
- self.add_message("chained-comparison", node=node)
- break
-
- @utils.check_messages(
- "consider-merging-isinstance", "consider-using-in", "chained-comparison"
- )
- def visit_boolop(self, node):
- self._check_consider_merging_isinstance(node)
- self._check_consider_using_in(node)
- self._check_chained_comparison(node)
-
- @staticmethod
- def _is_simple_assignment(node):
- return (
- isinstance(node, astroid.Assign)
- and len(node.targets) == 1
- and isinstance(node.targets[0], astroid.node_classes.AssignName)
- and isinstance(node.value, astroid.node_classes.Name)
- )
-
- def _check_swap_variables(self, node):
- if not node.next_sibling() or not node.next_sibling().next_sibling():
- return
- assignments = [node, node.next_sibling(), node.next_sibling().next_sibling()]
- if not all(self._is_simple_assignment(node) for node in assignments):
- return
- if any(node in self._reported_swap_nodes for node in assignments):
- return
- left = [node.targets[0].name for node in assignments]
- right = [node.value.name for node in assignments]
- if left[0] == right[-1] and left[1:] == right[:-1]:
- self._reported_swap_nodes.update(assignments)
- message = "consider-swap-variables"
- self.add_message(message, node=node)
-
- @utils.check_messages(
- "simplify-boolean-expression",
- "consider-using-ternary",
- "consider-swap-variables",
- )
- def visit_assign(self, node):
- self._check_swap_variables(node)
- if self._is_and_or_ternary(node.value):
- cond, truth_value, false_value = self._and_or_ternary_arguments(node.value)
- else:
- return
-
- if all(
- isinstance(value, astroid.Compare) for value in (truth_value, false_value)
- ):
- return
-
- inferred_truth_value = utils.safe_infer(truth_value)
- if inferred_truth_value in (None, astroid.Uninferable):
- truth_boolean_value = True
- else:
- truth_boolean_value = truth_value.bool_value()
-
- if truth_boolean_value is False:
- message = "simplify-boolean-expression"
- suggestion = false_value.as_string()
- else:
- message = "consider-using-ternary"
- suggestion = "{truth} if {cond} else {false}".format(
- truth=truth_value.as_string(),
- cond=cond.as_string(),
- false=false_value.as_string(),
- )
- self.add_message(message, node=node, args=(suggestion,))
-
- visit_return = visit_assign
-
- def _check_consider_using_join(self, aug_assign):
- """
- We start with the augmented assignment and work our way upwards.
- Names of variables for nodes if match successful:
- result = '' # assign
- for number in ['1', '2', '3'] # for_loop
- result += number # aug_assign
- """
- for_loop = aug_assign.parent
- if not isinstance(for_loop, astroid.For) or len(for_loop.body) > 1:
- return
- assign = for_loop.previous_sibling()
- if not isinstance(assign, astroid.Assign):
- return
- result_assign_names = {
- target.name
- for target in assign.targets
- if isinstance(target, astroid.AssignName)
- }
-
- is_concat_loop = (
- aug_assign.op == "+="
- and isinstance(aug_assign.target, astroid.AssignName)
- and len(for_loop.body) == 1
- and aug_assign.target.name in result_assign_names
- and isinstance(assign.value, astroid.Const)
- and isinstance(assign.value.value, str)
- and isinstance(aug_assign.value, astroid.Name)
- and aug_assign.value.name == for_loop.target.name
- )
- if is_concat_loop:
- self.add_message("consider-using-join", node=aug_assign)
-
- @utils.check_messages("consider-using-join")
- def visit_augassign(self, node):
- self._check_consider_using_join(node)
-
- @utils.check_messages("unnecessary-comprehension")
- def visit_comprehension(self, node):
- self._check_unnecessary_comprehension(node)
-
- def _check_unnecessary_comprehension(self, node):
- if (
- isinstance(node.parent, astroid.GeneratorExp)
- or len(node.ifs) != 0
- or len(node.parent.generators) != 1
- or node.is_async
- ):
- return
-
- if (
- isinstance(node.parent, astroid.DictComp)
- and isinstance(node.parent.key, astroid.Name)
- and isinstance(node.parent.value, astroid.Name)
- and isinstance(node.target, astroid.Tuple)
- and all(isinstance(elt, astroid.AssignName) for elt in node.target.elts)
- ):
- expr_list = [node.parent.key.name, node.parent.value.name]
- target_list = [elt.name for elt in node.target.elts]
-
- elif isinstance(node.parent, (astroid.ListComp, astroid.SetComp)):
- expr = node.parent.elt
- if isinstance(expr, astroid.Name):
- expr_list = expr.name
- elif isinstance(expr, astroid.Tuple):
- if any(not isinstance(elt, astroid.Name) for elt in expr.elts):
- return
- expr_list = [elt.name for elt in expr.elts]
- else:
- expr_list = []
- target = node.parent.generators[0].target
- target_list = (
- target.name
- if isinstance(target, astroid.AssignName)
- else (
- [
- elt.name
- for elt in target.elts
- if isinstance(elt, astroid.AssignName)
- ]
- if isinstance(target, astroid.Tuple)
- else []
- )
- )
- else:
- return
- if expr_list == target_list != []:
- self.add_message("unnecessary-comprehension", node=node)
-
- @staticmethod
- def _is_and_or_ternary(node):
- """
- Returns true if node is 'condition and true_value or false_value' form.
-
- All of: condition, true_value and false_value should not be a complex boolean expression
- """
- return (
- isinstance(node, astroid.BoolOp)
- and node.op == "or"
- and len(node.values) == 2
- and isinstance(node.values[0], astroid.BoolOp)
- and not isinstance(node.values[1], astroid.BoolOp)
- and node.values[0].op == "and"
- and not isinstance(node.values[0].values[1], astroid.BoolOp)
- and len(node.values[0].values) == 2
- )
-
- @staticmethod
- def _and_or_ternary_arguments(node):
- false_value = node.values[1]
- condition, true_value = node.values[0].values
- return condition, true_value, false_value
-
- def visit_functiondef(self, node):
- self._return_nodes[node.name] = list(
- node.nodes_of_class(astroid.Return, skip_klass=astroid.FunctionDef)
- )
-
- def _check_consistent_returns(self, node):
- """Check that all return statements inside a function are consistent.
-
- Return statements are consistent if:
- - all returns are explicit and if there is no implicit return;
- - all returns are empty and if there is, possibly, an implicit return.
-
- Args:
- node (astroid.FunctionDef): the function holding the return statements.
-
- """
- # explicit return statements are those with a not None value
- explicit_returns = [
- _node for _node in self._return_nodes[node.name] if _node.value is not None
- ]
- if not explicit_returns:
- return
- if len(explicit_returns) == len(
- self._return_nodes[node.name]
- ) and self._is_node_return_ended(node):
- return
- self.add_message("inconsistent-return-statements", node=node)
-
- def _is_node_return_ended(self, node):
- """Check if the node ends with an explicit return statement.
-
- Args:
- node (astroid.NodeNG): node to be checked.
-
- Returns:
- bool: True if the node ends with an explicit statement, False otherwise.
-
- """
- #  Recursion base case
- if isinstance(node, astroid.Return):
- return True
- if isinstance(node, astroid.Call):
- try:
- funcdef_node = node.func.inferred()[0]
- if self._is_function_def_never_returning(funcdef_node):
- return True
- except astroid.InferenceError:
- pass
- # Avoid the check inside while loop as we don't know
- #  if they will be completed
- if isinstance(node, astroid.While):
- return True
- if isinstance(node, astroid.Raise):
- # a Raise statement doesn't need to end with a return statement
- # but if the exception raised is handled, then the handler has to
- # ends with a return statement
- if not node.exc:
- # Ignore bare raises
- return True
- if not utils.is_node_inside_try_except(node):
- # If the raise statement is not inside a try/except statement
- #  then the exception is raised and cannot be caught. No need
- #  to infer it.
- return True
- exc = utils.safe_infer(node.exc)
- if exc is None or exc is astroid.Uninferable:
- return False
- exc_name = exc.pytype().split(".")[-1]
- handlers = utils.get_exception_handlers(node, exc_name)
- handlers = list(handlers) if handlers is not None else []
- if handlers:
- # among all the handlers handling the exception at least one
- # must end with a return statement
- return any(
- self._is_node_return_ended(_handler) for _handler in handlers
- )
- # if no handlers handle the exception then it's ok
- return True
- if isinstance(node, astroid.If):
- # if statement is returning if there are exactly two return statements in its
- #  children : one for the body part, the other for the orelse part
- # Do not check if inner function definition are return ended.
- is_orelse_returning = any(
- self._is_node_return_ended(_ore)
- for _ore in node.orelse
- if not isinstance(_ore, astroid.FunctionDef)
- )
- is_if_returning = any(
- self._is_node_return_ended(_ifn)
- for _ifn in node.body
- if not isinstance(_ifn, astroid.FunctionDef)
- )
- return is_if_returning and is_orelse_returning
- #  recurses on the children of the node except for those which are except handler
- # because one cannot be sure that the handler will really be used
- return any(
- self._is_node_return_ended(_child)
- for _child in node.get_children()
- if not isinstance(_child, astroid.ExceptHandler)
- )
-
- def _is_function_def_never_returning(self, node):
- """Return True if the function never returns. False otherwise.
-
- Args:
- node (astroid.FunctionDef): function definition node to be analyzed.
-
- Returns:
- bool: True if the function never returns, False otherwise.
- """
- try:
- return node.qname() in self._never_returning_functions
- except TypeError:
- return False
-
- def _check_return_at_the_end(self, node):
- """Check for presence of a *single* return statement at the end of a
- function. "return" or "return None" are useless because None is the
- default return type if they are missing.
-
- NOTE: produces a message only if there is a single return statement
- in the function body. Otherwise _check_consistent_returns() is called!
- Per its implementation and PEP8 we can have a "return None" at the end
- of the function body if there are other return statements before that!
- """
- if len(self._return_nodes[node.name]) > 1:
- return
- if len(node.body) <= 1:
- return
-
- last = node.body[-1]
- if isinstance(last, astroid.Return):
- # e.g. "return"
- if last.value is None:
- self.add_message("useless-return", node=node)
- # return None"
- elif isinstance(last.value, astroid.Const) and (last.value.value is None):
- self.add_message("useless-return", node=node)
-
-
-class RecommandationChecker(checkers.BaseChecker):
- __implements__ = (interfaces.IAstroidChecker,)
- name = "refactoring"
- msgs = {
- "C0200": (
- "Consider using enumerate instead of iterating with range and len",
- "consider-using-enumerate",
- "Emitted when code that iterates with range and len is "
- "encountered. Such code can be simplified by using the "
- "enumerate builtin.",
- ),
- "C0201": (
- "Consider iterating the dictionary directly instead of calling .keys()",
- "consider-iterating-dictionary",
- "Emitted when the keys of a dictionary are iterated through the .keys() "
- "method. It is enough to just iterate through the dictionary itself, as "
- 'in "for key in dictionary".',
- ),
- }
-
- @staticmethod
- def _is_builtin(node, function):
- inferred = utils.safe_infer(node)
- if not inferred:
- return False
- return utils.is_builtin_object(inferred) and inferred.name == function
-
- @utils.check_messages("consider-iterating-dictionary")
- def visit_call(self, node):
- if not isinstance(node.func, astroid.Attribute):
- return
- if node.func.attrname != "keys":
- return
- if not isinstance(node.parent, (astroid.For, astroid.Comprehension)):
- return
-
- inferred = utils.safe_infer(node.func)
- if not isinstance(inferred, astroid.BoundMethod) or not isinstance(
- inferred.bound, astroid.Dict
- ):
- return
-
- if isinstance(node.parent, (astroid.For, astroid.Comprehension)):
- self.add_message("consider-iterating-dictionary", node=node)
-
- @utils.check_messages("consider-using-enumerate")
- def visit_for(self, node):
- """Emit a convention whenever range and len are used for indexing."""
- # Verify that we have a `range([start], len(...), [stop])` call and
- # that the object which is iterated is used as a subscript in the
- # body of the for.
-
- # Is it a proper range call?
- if not isinstance(node.iter, astroid.Call):
- return
- if not self._is_builtin(node.iter.func, "range"):
- return
- if len(node.iter.args) == 2 and not _is_constant_zero(node.iter.args[0]):
- return
- if len(node.iter.args) > 2:
- return
-
- # Is it a proper len call?
- if not isinstance(node.iter.args[-1], astroid.Call):
- return
- second_func = node.iter.args[-1].func
- if not self._is_builtin(second_func, "len"):
- return
- len_args = node.iter.args[-1].args
- if not len_args or len(len_args) != 1:
- return
- iterating_object = len_args[0]
- if not isinstance(iterating_object, astroid.Name):
- return
- # If we're defining __iter__ on self, enumerate won't work
- scope = node.scope()
- if iterating_object.name == "self" and scope.name == "__iter__":
- return
-
- # Verify that the body of the for loop uses a subscript
- # with the object that was iterated. This uses some heuristics
- # in order to make sure that the same object is used in the
- # for body.
- for child in node.body:
- for subscript in child.nodes_of_class(astroid.Subscript):
- if not isinstance(subscript.value, astroid.Name):
- continue
- if not isinstance(subscript.slice, astroid.Index):
- continue
- if not isinstance(subscript.slice.value, astroid.Name):
- continue
- if subscript.slice.value.name != node.target.name:
- continue
- if iterating_object.name != subscript.value.name:
- continue
- if subscript.value.scope() != node.scope():
- # Ignore this subscript if it's not in the same
- # scope. This means that in the body of the for
- # loop, another scope was created, where the same
- # name for the iterating object was used.
- continue
- self.add_message("consider-using-enumerate", node=node)
- return
-
-
-class NotChecker(checkers.BaseChecker):
- """checks for too many not in comparison expressions
-
- - "not not" should trigger a warning
- - "not" followed by a comparison should trigger a warning
- """
-
- __implements__ = (interfaces.IAstroidChecker,)
- msgs = {
- "C0113": (
- 'Consider changing "%s" to "%s"',
- "unneeded-not",
- "Used when a boolean expression contains an unneeded negation.",
- )
- }
- name = "refactoring"
- reverse_op = {
- "<": ">=",
- "<=": ">",
- ">": "<=",
- ">=": "<",
- "==": "!=",
- "!=": "==",
- "in": "not in",
- "is": "is not",
- }
- # sets are not ordered, so for example "not set(LEFT_VALS) <= set(RIGHT_VALS)" is
- # not equivalent to "set(LEFT_VALS) > set(RIGHT_VALS)"
- skipped_nodes = (astroid.Set,)
- # 'builtins' py3, '__builtin__' py2
- skipped_classnames = [
- "%s.%s" % (builtins.__name__, qname) for qname in ("set", "frozenset")
- ]
-
- @utils.check_messages("unneeded-not")
- def visit_unaryop(self, node):
- if node.op != "not":
- return
- operand = node.operand
-
- if isinstance(operand, astroid.UnaryOp) and operand.op == "not":
- self.add_message(
- "unneeded-not",
- node=node,
- args=(node.as_string(), operand.operand.as_string()),
- )
- elif isinstance(operand, astroid.Compare):
- left = operand.left
- # ignore multiple comparisons
- if len(operand.ops) > 1:
- return
- operator, right = operand.ops[0]
- if operator not in self.reverse_op:
- return
- # Ignore __ne__ as function of __eq__
- frame = node.frame()
- if frame.name == "__ne__" and operator == "==":
- return
- for _type in (utils.node_type(left), utils.node_type(right)):
- if not _type:
- return
- if isinstance(_type, self.skipped_nodes):
- return
- if (
- isinstance(_type, astroid.Instance)
- and _type.qname() in self.skipped_classnames
- ):
- return
- suggestion = "%s %s %s" % (
- left.as_string(),
- self.reverse_op[operator],
- right.as_string(),
- )
- self.add_message(
- "unneeded-not", node=node, args=(node.as_string(), suggestion)
- )
-
-
-class LenChecker(checkers.BaseChecker):
- """Checks for incorrect usage of len() inside conditions.
- Pep8 states:
- For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
-
- Yes: if not seq:
- if seq:
-
- No: if len(seq):
- if not len(seq):
-
- Problems detected:
- * if len(sequence):
- * if not len(sequence):
- * elif len(sequence):
- * elif not len(sequence):
- * while len(sequence):
- * while not len(sequence):
- * assert len(sequence):
- * assert not len(sequence):
- """
-
- __implements__ = (interfaces.IAstroidChecker,)
-
- # configuration section name
- name = "refactoring"
- msgs = {
- "C1801": (
- "Do not use `len(SEQUENCE)` without comparison to determine if a sequence is empty",
- "len-as-condition",
- "Used when Pylint detects that len(sequence) is being used "
- "without explicit comparison inside a condition to determine if a sequence is empty. "
- "Instead of coercing the length to a boolean, either "
- "rely on the fact that empty sequences are false or "
- "compare the length against a scalar.",
- )
- }
-
- priority = -2
- options = ()
-
- @utils.check_messages("len-as-condition")
- def visit_call(self, node):
- # a len(S) call is used inside a test condition
- # could be if, while, assert or if expression statement
- # e.g. `if len(S):`
- if _is_len_call(node):
- # the len() call could also be nested together with other
- # boolean operations, e.g. `if z or len(x):`
- parent = node.parent
- while isinstance(parent, astroid.BoolOp):
- parent = parent.parent
-
- # we're finally out of any nested boolean operations so check if
- # this len() call is part of a test condition
- if not _node_is_test_condition(parent):
- return
- if not (node is parent.test or parent.test.parent_of(node)):
- return
- self.add_message("len-as-condition", node=node)
-
- @utils.check_messages("len-as-condition")
- def visit_unaryop(self, node):
- """`not len(S)` must become `not S` regardless if the parent block
- is a test condition or something else (boolean expression)
- e.g. `if not len(S):`"""
- if (
- isinstance(node, astroid.UnaryOp)
- and node.op == "not"
- and _is_len_call(node.operand)
- ):
- self.add_message("len-as-condition", node=node)
-
-
-def register(linter):
- """Required method to auto register this checker."""
- linter.register_checker(RefactoringChecker(linter))
- linter.register_checker(NotChecker(linter))
- linter.register_checker(RecommandationChecker(linter))
- linter.register_checker(LenChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/similar.py b/venv/Lib/site-packages/pylint/checkers/similar.py
deleted file mode 100644
index 019b55f..0000000
--- a/venv/Lib/site-packages/pylint/checkers/similar.py
+++ /dev/null
@@ -1,452 +0,0 @@
-# Copyright (c) 2006, 2008-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012 Ry4an Brase <ry4an-hg@ry4an.org>
-# Copyright (c) 2012 Google, Inc.
-# Copyright (c) 2012 Anthony VEREZ <anthony.verez.external@cassidian.com>
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2017 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2017 Mikhail Fesenko <proggga@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-# pylint: disable=redefined-builtin
-"""a similarities / code duplication command line tool and pylint checker
-"""
-
-import sys
-from collections import defaultdict
-from getopt import getopt
-from itertools import groupby
-
-import astroid
-
-from pylint.checkers import BaseChecker, table_lines_from_stats
-from pylint.interfaces import IRawChecker
-from pylint.reporters.ureports.nodes import Table
-from pylint.utils import decoding_stream
-
-
-class Similar:
- """finds copy-pasted lines of code in a project"""
-
- def __init__(
- self,
- min_lines=4,
- ignore_comments=False,
- ignore_docstrings=False,
- ignore_imports=False,
- ):
- self.min_lines = min_lines
- self.ignore_comments = ignore_comments
- self.ignore_docstrings = ignore_docstrings
- self.ignore_imports = ignore_imports
- self.linesets = []
-
- def append_stream(self, streamid, stream, encoding=None):
- """append a file to search for similarities"""
- if encoding is None:
- readlines = stream.readlines
- else:
- readlines = decoding_stream(stream, encoding).readlines
- try:
- self.linesets.append(
- LineSet(
- streamid,
- readlines(),
- self.ignore_comments,
- self.ignore_docstrings,
- self.ignore_imports,
- )
- )
- except UnicodeDecodeError:
- pass
-
- def run(self):
- """start looking for similarities and display results on stdout"""
- self._display_sims(self._compute_sims())
-
- def _compute_sims(self):
- """compute similarities in appended files"""
- no_duplicates = defaultdict(list)
- for num, lineset1, idx1, lineset2, idx2 in self._iter_sims():
- duplicate = no_duplicates[num]
- for couples in duplicate:
- if (lineset1, idx1) in couples or (lineset2, idx2) in couples:
- couples.add((lineset1, idx1))
- couples.add((lineset2, idx2))
- break
- else:
- duplicate.append({(lineset1, idx1), (lineset2, idx2)})
- sims = []
- for num, ensembles in no_duplicates.items():
- for couples in ensembles:
- sims.append((num, couples))
- sims.sort()
- sims.reverse()
- return sims
-
- def _display_sims(self, sims):
- """display computed similarities on stdout"""
- nb_lignes_dupliquees = 0
- for num, couples in sims:
- print()
- print(num, "similar lines in", len(couples), "files")
- couples = sorted(couples)
- lineset = idx = None
- for lineset, idx in couples:
- print("==%s:%s" % (lineset.name, idx))
- if lineset:
- for line in lineset._real_lines[idx : idx + num]:
- print(" ", line.rstrip())
- nb_lignes_dupliquees += num * (len(couples) - 1)
- nb_total_lignes = sum([len(lineset) for lineset in self.linesets])
- print(
- "TOTAL lines=%s duplicates=%s percent=%.2f"
- % (
- nb_total_lignes,
- nb_lignes_dupliquees,
- nb_lignes_dupliquees * 100.0 / nb_total_lignes,
- )
- )
-
- def _find_common(self, lineset1, lineset2):
- """find similarities in the two given linesets"""
- lines1 = lineset1.enumerate_stripped
- lines2 = lineset2.enumerate_stripped
- find = lineset2.find
- index1 = 0
- min_lines = self.min_lines
- while index1 < len(lineset1):
- skip = 1
- num = 0
- for index2 in find(lineset1[index1]):
- non_blank = 0
- for num, ((_, line1), (_, line2)) in enumerate(
- zip(lines1(index1), lines2(index2))
- ):
- if line1 != line2:
- if non_blank > min_lines:
- yield num, lineset1, index1, lineset2, index2
- skip = max(skip, num)
- break
- if line1:
- non_blank += 1
- else:
- # we may have reach the end
- num += 1
- if non_blank > min_lines:
- yield num, lineset1, index1, lineset2, index2
- skip = max(skip, num)
- index1 += skip
-
- def _iter_sims(self):
- """iterate on similarities among all files, by making a cartesian
- product
- """
- for idx, lineset in enumerate(self.linesets[:-1]):
- for lineset2 in self.linesets[idx + 1 :]:
- for sim in self._find_common(lineset, lineset2):
- yield sim
-
-
-def stripped_lines(lines, ignore_comments, ignore_docstrings, ignore_imports):
- """return lines with leading/trailing whitespace and any ignored code
- features removed
- """
- if ignore_imports:
- tree = astroid.parse("".join(lines))
- node_is_import_by_lineno = (
- (node.lineno, isinstance(node, (astroid.Import, astroid.ImportFrom)))
- for node in tree.body
- )
- line_begins_import = {
- lineno: all(is_import for _, is_import in node_is_import_group)
- for lineno, node_is_import_group in groupby(
- node_is_import_by_lineno, key=lambda x: x[0]
- )
- }
- current_line_is_import = False
-
- strippedlines = []
- docstring = None
- for lineno, line in enumerate(lines, start=1):
- line = line.strip()
- if ignore_docstrings:
- if not docstring and any(
- line.startswith(i) for i in ['"""', "'''", 'r"""', "r'''"]
- ):
- docstring = line[:3]
- line = line[3:]
- if docstring:
- if line.endswith(docstring):
- docstring = None
- line = ""
- if ignore_imports:
- current_line_is_import = line_begins_import.get(
- lineno, current_line_is_import
- )
- if current_line_is_import:
- line = ""
- if ignore_comments:
- line = line.split("#", 1)[0].strip()
- strippedlines.append(line)
- return strippedlines
-
-
-class LineSet:
- """Holds and indexes all the lines of a single source file"""
-
- def __init__(
- self,
- name,
- lines,
- ignore_comments=False,
- ignore_docstrings=False,
- ignore_imports=False,
- ):
- self.name = name
- self._real_lines = lines
- self._stripped_lines = stripped_lines(
- lines, ignore_comments, ignore_docstrings, ignore_imports
- )
- self._index = self._mk_index()
-
- def __str__(self):
- return "<Lineset for %s>" % self.name
-
- def __len__(self):
- return len(self._real_lines)
-
- def __getitem__(self, index):
- return self._stripped_lines[index]
-
- def __lt__(self, other):
- return self.name < other.name
-
- def __hash__(self):
- return id(self)
-
- def enumerate_stripped(self, start_at=0):
- """return an iterator on stripped lines, starting from a given index
- if specified, else 0
- """
- idx = start_at
- if start_at:
- lines = self._stripped_lines[start_at:]
- else:
- lines = self._stripped_lines
- for line in lines:
- # if line:
- yield idx, line
- idx += 1
-
- def find(self, stripped_line):
- """return positions of the given stripped line in this set"""
- return self._index.get(stripped_line, ())
-
- def _mk_index(self):
- """create the index for this set"""
- index = defaultdict(list)
- for line_no, line in enumerate(self._stripped_lines):
- if line:
- index[line].append(line_no)
- return index
-
-
-MSGS = {
- "R0801": (
- "Similar lines in %s files\n%s",
- "duplicate-code",
- "Indicates that a set of similar lines has been detected "
- "among multiple file. This usually means that the code should "
- "be refactored to avoid this duplication.",
- )
-}
-
-
-def report_similarities(sect, stats, old_stats):
- """make a layout with some stats about duplication"""
- lines = ["", "now", "previous", "difference"]
- lines += table_lines_from_stats(
- stats, old_stats, ("nb_duplicated_lines", "percent_duplicated_lines")
- )
- sect.append(Table(children=lines, cols=4, rheaders=1, cheaders=1))
-
-
-# wrapper to get a pylint checker from the similar class
-class SimilarChecker(BaseChecker, Similar):
- """checks for similarities and duplicated code. This computation may be
- memory / CPU intensive, so you should disable it if you experiment some
- problems.
- """
-
- __implements__ = (IRawChecker,)
- # configuration section name
- name = "similarities"
- # messages
- msgs = MSGS
- # configuration options
- # for available dict keys/values see the optik parser 'add_option' method
- options = (
- (
- "min-similarity-lines", # type: ignore
- {
- "default": 4,
- "type": "int",
- "metavar": "<int>",
- "help": "Minimum lines number of a similarity.",
- },
- ),
- (
- "ignore-comments",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y or n>",
- "help": "Ignore comments when computing similarities.",
- },
- ),
- (
- "ignore-docstrings",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y or n>",
- "help": "Ignore docstrings when computing similarities.",
- },
- ),
- (
- "ignore-imports",
- {
- "default": False,
- "type": "yn",
- "metavar": "<y or n>",
- "help": "Ignore imports when computing similarities.",
- },
- ),
- )
- # reports
- reports = (("RP0801", "Duplication", report_similarities),) # type: ignore
-
- def __init__(self, linter=None):
- BaseChecker.__init__(self, linter)
- Similar.__init__(
- self, min_lines=4, ignore_comments=True, ignore_docstrings=True
- )
- self.stats = None
-
- def set_option(self, optname, value, action=None, optdict=None):
- """method called to set an option (registered in the options list)
-
- overridden to report options setting to Similar
- """
- BaseChecker.set_option(self, optname, value, action, optdict)
- if optname == "min-similarity-lines":
- self.min_lines = self.config.min_similarity_lines
- elif optname == "ignore-comments":
- self.ignore_comments = self.config.ignore_comments
- elif optname == "ignore-docstrings":
- self.ignore_docstrings = self.config.ignore_docstrings
- elif optname == "ignore-imports":
- self.ignore_imports = self.config.ignore_imports
-
- def open(self):
- """init the checkers: reset linesets and statistics information"""
- self.linesets = []
- self.stats = self.linter.add_stats(
- nb_duplicated_lines=0, percent_duplicated_lines=0
- )
-
- def process_module(self, node):
- """process a module
-
- the module's content is accessible via the stream object
-
- stream must implement the readlines method
- """
- with node.stream() as stream:
- self.append_stream(self.linter.current_name, stream, node.file_encoding)
-
- def close(self):
- """compute and display similarities on closing (i.e. end of parsing)"""
- total = sum(len(lineset) for lineset in self.linesets)
- duplicated = 0
- stats = self.stats
- for num, couples in self._compute_sims():
- msg = []
- lineset = idx = None
- for lineset, idx in couples:
- msg.append("==%s:%s" % (lineset.name, idx))
- msg.sort()
-
- if lineset:
- for line in lineset._real_lines[idx : idx + num]:
- msg.append(line.rstrip())
-
- self.add_message("R0801", args=(len(couples), "\n".join(msg)))
- duplicated += num * (len(couples) - 1)
- stats["nb_duplicated_lines"] = duplicated
- stats["percent_duplicated_lines"] = total and duplicated * 100.0 / total
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(SimilarChecker(linter))
-
-
-def usage(status=0):
- """display command line usage information"""
- print("finds copy pasted blocks in a set of files")
- print()
- print(
- "Usage: symilar [-d|--duplicates min_duplicated_lines] \
-[-i|--ignore-comments] [--ignore-docstrings] [--ignore-imports] file1..."
- )
- sys.exit(status)
-
-
-def Run(argv=None):
- """standalone command line access point"""
- if argv is None:
- argv = sys.argv[1:]
-
- s_opts = "hdi"
- l_opts = (
- "help",
- "duplicates=",
- "ignore-comments",
- "ignore-imports",
- "ignore-docstrings",
- )
- min_lines = 4
- ignore_comments = False
- ignore_docstrings = False
- ignore_imports = False
- opts, args = getopt(argv, s_opts, l_opts)
- for opt, val in opts:
- if opt in ("-d", "--duplicates"):
- min_lines = int(val)
- elif opt in ("-h", "--help"):
- usage()
- elif opt in ("-i", "--ignore-comments"):
- ignore_comments = True
- elif opt in ("--ignore-docstrings",):
- ignore_docstrings = True
- elif opt in ("--ignore-imports",):
- ignore_imports = True
- if not args:
- usage(1)
- sim = Similar(min_lines, ignore_comments, ignore_docstrings, ignore_imports)
- for filename in args:
- with open(filename) as stream:
- sim.append_stream(filename, stream)
- sim.run()
- sys.exit(0)
-
-
-if __name__ == "__main__":
- Run()
diff --git a/venv/Lib/site-packages/pylint/checkers/spelling.py b/venv/Lib/site-packages/pylint/checkers/spelling.py
deleted file mode 100644
index b1a5334..0000000
--- a/venv/Lib/site-packages/pylint/checkers/spelling.py
+++ /dev/null
@@ -1,411 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2015 Pavel Roskin <proski@gnu.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016-2017 Pedro Algarvio <pedro@algarvio.me>
-# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2017 Mikhail Fesenko <proggga@gmail.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Checker for spelling errors in comments and docstrings.
-"""
-
-import os
-import re
-import tokenize
-
-from pylint.checkers import BaseTokenChecker
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker, ITokenChecker
-
-try:
- import enchant
- from enchant.tokenize import ( # type: ignore
- get_tokenizer,
- Chunker,
- Filter,
- EmailFilter,
- URLFilter,
- WikiWordFilter,
- )
-except ImportError:
- enchant = None
- # pylint: disable=no-init
- class Filter: # type: ignore
- def _skip(self, word):
- raise NotImplementedError
-
- class Chunker: # type: ignore
- pass
-
-
-if enchant is not None:
- br = enchant.Broker()
- dicts = br.list_dicts()
- dict_choices = [""] + [d[0] for d in dicts]
- dicts = ["%s (%s)" % (d[0], d[1].name) for d in dicts]
- dicts = ", ".join(dicts)
- instr = ""
-else:
- dicts = "none"
- dict_choices = [""]
- instr = " To make it work, install the python-enchant package."
-
-
-class WordsWithDigigtsFilter(Filter):
- """Skips words with digits.
- """
-
- def _skip(self, word):
- for char in word:
- if char.isdigit():
- return True
- return False
-
-
-class WordsWithUnderscores(Filter):
- """Skips words with underscores.
-
- They are probably function parameter names.
- """
-
- def _skip(self, word):
- return "_" in word
-
-
-class CamelCasedWord(Filter):
- r"""Filter skipping over camelCasedWords.
- This filter skips any words matching the following regular expression:
-
- ^([a-z]\w+[A-Z]+\w+)
-
- That is, any words that are camelCasedWords.
- """
- _pattern = re.compile(r"^([a-z]+([\d]|[A-Z])(?:\w+)?)")
-
- def _skip(self, word):
- return bool(self._pattern.match(word))
-
-
-class SphinxDirectives(Filter):
- r"""Filter skipping over Sphinx Directives.
- This filter skips any words matching the following regular expression:
-
- ^:([a-z]+):`([^`]+)(`)?
-
- That is, for example, :class:`BaseQuery`
- """
- # The final ` in the pattern is optional because enchant strips it out
- _pattern = re.compile(r"^:([a-z]+):`([^`]+)(`)?")
-
- def _skip(self, word):
- return bool(self._pattern.match(word))
-
-
-class ForwardSlashChunkder(Chunker):
- """
- This chunker allows splitting words like 'before/after' into 'before' and 'after'
- """
-
- def next(self):
- while True:
- if not self._text:
- raise StopIteration()
- if "/" not in self._text:
- text = self._text
- self._offset = 0
- self._text = ""
- return (text, 0)
- pre_text, post_text = self._text.split("/", 1)
- self._text = post_text
- self._offset = 0
- if (
- not pre_text
- or not post_text
- or not pre_text[-1].isalpha()
- or not post_text[0].isalpha()
- ):
- self._text = ""
- self._offset = 0
- return (pre_text + "/" + post_text, 0)
- return (pre_text, 0)
-
- def _next(self):
- while True:
- if "/" not in self._text:
- return (self._text, 0)
- pre_text, post_text = self._text.split("/", 1)
- if not pre_text or not post_text:
- break
- if not pre_text[-1].isalpha() or not post_text[0].isalpha():
- raise StopIteration()
- self._text = pre_text + " " + post_text
- raise StopIteration()
-
-
-class SpellingChecker(BaseTokenChecker):
- """Check spelling in comments and docstrings"""
-
- __implements__ = (ITokenChecker, IAstroidChecker)
- name = "spelling"
- msgs = {
- "C0401": (
- "Wrong spelling of a word '%s' in a comment:\n%s\n"
- "%s\nDid you mean: '%s'?",
- "wrong-spelling-in-comment",
- "Used when a word in comment is not spelled correctly.",
- ),
- "C0402": (
- "Wrong spelling of a word '%s' in a docstring:\n%s\n"
- "%s\nDid you mean: '%s'?",
- "wrong-spelling-in-docstring",
- "Used when a word in docstring is not spelled correctly.",
- ),
- "C0403": (
- "Invalid characters %r in a docstring",
- "invalid-characters-in-docstring",
- "Used when a word in docstring cannot be checked by enchant.",
- ),
- }
- options = (
- (
- "spelling-dict",
- {
- "default": "",
- "type": "choice",
- "metavar": "<dict name>",
- "choices": dict_choices,
- "help": "Spelling dictionary name. "
- "Available dictionaries: %s.%s" % (dicts, instr),
- },
- ),
- (
- "spelling-ignore-words",
- {
- "default": "",
- "type": "string",
- "metavar": "<comma separated words>",
- "help": "List of comma separated words that " "should not be checked.",
- },
- ),
- (
- "spelling-private-dict-file",
- {
- "default": "",
- "type": "string",
- "metavar": "<path to file>",
- "help": "A path to a file that contains the private "
- "dictionary; one word per line.",
- },
- ),
- (
- "spelling-store-unknown-words",
- {
- "default": "n",
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "Tells whether to store unknown words to the "
- "private dictionary (see the "
- "--spelling-private-dict-file option) instead of "
- "raising a message.",
- },
- ),
- (
- "max-spelling-suggestions",
- {
- "default": 4,
- "type": "int",
- "metavar": "N",
- "help": "Limits count of emitted suggestions for " "spelling mistakes.",
- },
- ),
- )
-
- def open(self):
- self.initialized = False
- self.private_dict_file = None
-
- if enchant is None:
- return
- dict_name = self.config.spelling_dict
- if not dict_name:
- return
-
- self.ignore_list = [
- w.strip() for w in self.config.spelling_ignore_words.split(",")
- ]
- # "param" appears in docstring in param description and
- # "pylint" appears in comments in pylint pragmas.
- self.ignore_list.extend(["param", "pylint"])
-
- # Expand tilde to allow e.g. spelling-private-dict-file = ~/.pylintdict
- if self.config.spelling_private_dict_file:
- self.config.spelling_private_dict_file = os.path.expanduser(
- self.config.spelling_private_dict_file
- )
-
- if self.config.spelling_private_dict_file:
- self.spelling_dict = enchant.DictWithPWL(
- dict_name, self.config.spelling_private_dict_file
- )
- self.private_dict_file = open(self.config.spelling_private_dict_file, "a")
- else:
- self.spelling_dict = enchant.Dict(dict_name)
-
- if self.config.spelling_store_unknown_words:
- self.unknown_words = set()
-
- self.tokenizer = get_tokenizer(
- dict_name,
- chunkers=[ForwardSlashChunkder],
- filters=[
- EmailFilter,
- URLFilter,
- WikiWordFilter,
- WordsWithDigigtsFilter,
- WordsWithUnderscores,
- CamelCasedWord,
- SphinxDirectives,
- ],
- )
- self.initialized = True
-
- def close(self):
- if self.private_dict_file:
- self.private_dict_file.close()
-
- def _check_spelling(self, msgid, line, line_num):
- original_line = line
- try:
- initial_space = re.search(r"^[^\S]\s*", line).regs[0][1]
- except (IndexError, AttributeError):
- initial_space = 0
- if line.strip().startswith("#"):
- line = line.strip()[1:]
- starts_with_comment = True
- else:
- starts_with_comment = False
- for word, word_start_at in self.tokenizer(line.strip()):
- word_start_at += initial_space
- lower_cased_word = word.casefold()
-
- # Skip words from ignore list.
- if word in self.ignore_list or lower_cased_word in self.ignore_list:
- continue
-
- # Strip starting u' from unicode literals and r' from raw strings.
- if word.startswith(("u'", 'u"', "r'", 'r"')) and len(word) > 2:
- word = word[2:]
- lower_cased_word = lower_cased_word[2:]
-
- # If it is a known word, then continue.
- try:
- if self.spelling_dict.check(lower_cased_word):
- # The lower cased version of word passed spell checking
- continue
-
- # If we reached this far, it means there was a spelling mistake.
- # Let's retry with the original work because 'unicode' is a
- # spelling mistake but 'Unicode' is not
- if self.spelling_dict.check(word):
- continue
- except enchant.errors.Error:
- self.add_message(
- "invalid-characters-in-docstring", line=line_num, args=(word,)
- )
- continue
-
- # Store word to private dict or raise a message.
- if self.config.spelling_store_unknown_words:
- if lower_cased_word not in self.unknown_words:
- self.private_dict_file.write("%s\n" % lower_cased_word)
- self.unknown_words.add(lower_cased_word)
- else:
- # Present up to N suggestions.
- suggestions = self.spelling_dict.suggest(word)
- del suggestions[self.config.max_spelling_suggestions :]
-
- line_segment = line[word_start_at:]
- match = re.search(r"(\W|^)(%s)(\W|$)" % word, line_segment)
- if match:
- # Start position of second group in regex.
- col = match.regs[2][0]
- else:
- col = line_segment.index(word)
-
- col += word_start_at
-
- if starts_with_comment:
- col += 1
- indicator = (" " * col) + ("^" * len(word))
-
- self.add_message(
- msgid,
- line=line_num,
- args=(
- word,
- original_line,
- indicator,
- "'{}'".format("' or '".join(suggestions)),
- ),
- )
-
- def process_tokens(self, tokens):
- if not self.initialized:
- return
-
- # Process tokens and look for comments.
- for (tok_type, token, (start_row, _), _, _) in tokens:
- if tok_type == tokenize.COMMENT:
- if start_row == 1 and token.startswith("#!/"):
- # Skip shebang lines
- continue
- if token.startswith("# pylint:"):
- # Skip pylint enable/disable comments
- continue
- self._check_spelling("wrong-spelling-in-comment", token, start_row)
-
- @check_messages("wrong-spelling-in-docstring")
- def visit_module(self, node):
- if not self.initialized:
- return
- self._check_docstring(node)
-
- @check_messages("wrong-spelling-in-docstring")
- def visit_classdef(self, node):
- if not self.initialized:
- return
- self._check_docstring(node)
-
- @check_messages("wrong-spelling-in-docstring")
- def visit_functiondef(self, node):
- if not self.initialized:
- return
- self._check_docstring(node)
-
- visit_asyncfunctiondef = visit_functiondef
-
- def _check_docstring(self, node):
- """check the node has any spelling errors"""
- docstring = node.doc
- if not docstring:
- return
-
- start_line = node.lineno + 1
-
- # Go through lines of docstring
- for idx, line in enumerate(docstring.splitlines()):
- self._check_spelling("wrong-spelling-in-docstring", line, start_line + idx)
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(SpellingChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/stdlib.py b/venv/Lib/site-packages/pylint/checkers/stdlib.py
deleted file mode 100644
index a945107..0000000
--- a/venv/Lib/site-packages/pylint/checkers/stdlib.py
+++ /dev/null
@@ -1,452 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2013-2014 Google, Inc.
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Cosmin Poieana <cmin@ropython.org>
-# Copyright (c) 2014 Vlad Temian <vladtemian@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Cezar <celnazli@bitdefender.com>
-# Copyright (c) 2015 Chris Rebert <code@rebertia.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Jared Garst <cultofjared@gmail.com>
-# Copyright (c) 2017 Renat Galimov <renat2017@gmail.com>
-# Copyright (c) 2017 Martin <MartinBasti@users.noreply.github.com>
-# Copyright (c) 2017 Christopher Zurcher <zurcher@users.noreply.github.com>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2018 Banjamin Freeman <befreeman@users.noreply.github.com>
-# Copyright (c) 2018 Ioana Tagirta <ioana.tagirta@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Checkers for various standard library functions."""
-
-import sys
-
-import astroid
-from astroid.bases import Instance
-from astroid.node_classes import Const
-
-from pylint.checkers import BaseChecker, utils
-from pylint.interfaces import IAstroidChecker
-
-OPEN_FILES = {"open", "file"}
-UNITTEST_CASE = "unittest.case"
-THREADING_THREAD = "threading.Thread"
-COPY_COPY = "copy.copy"
-OS_ENVIRON = "os._Environ"
-ENV_GETTERS = {"os.getenv"}
-SUBPROCESS_POPEN = "subprocess.Popen"
-SUBPROCESS_RUN = "subprocess.run"
-OPEN_MODULE = "_io"
-
-
-def _check_mode_str(mode):
- # check type
- if not isinstance(mode, str):
- return False
- # check syntax
- modes = set(mode)
- _mode = "rwatb+Ux"
- creating = "x" in modes
- if modes - set(_mode) or len(mode) > len(modes):
- return False
- # check logic
- reading = "r" in modes
- writing = "w" in modes
- appending = "a" in modes
- text = "t" in modes
- binary = "b" in modes
- if "U" in modes:
- if writing or appending or creating:
- return False
- reading = True
- if text and binary:
- return False
- total = reading + writing + appending + creating
- if total > 1:
- return False
- if not (reading or writing or appending or creating):
- return False
- return True
-
-
-class StdlibChecker(BaseChecker):
- __implements__ = (IAstroidChecker,)
- name = "stdlib"
-
- msgs = {
- "W1501": (
- '"%s" is not a valid mode for open.',
- "bad-open-mode",
- "Python supports: r, w, a[, x] modes with b, +, "
- "and U (only with r) options. "
- "See http://docs.python.org/2/library/functions.html#open",
- ),
- "W1502": (
- "Using datetime.time in a boolean context.",
- "boolean-datetime",
- "Using datetime.time in a boolean context can hide "
- "subtle bugs when the time they represent matches "
- "midnight UTC. This behaviour was fixed in Python 3.5. "
- "See http://bugs.python.org/issue13936 for reference.",
- {"maxversion": (3, 5)},
- ),
- "W1503": (
- "Redundant use of %s with constant value %r",
- "redundant-unittest-assert",
- "The first argument of assertTrue and assertFalse is "
- "a condition. If a constant is passed as parameter, that "
- "condition will be always true. In this case a warning "
- "should be emitted.",
- ),
- "W1505": (
- "Using deprecated method %s()",
- "deprecated-method",
- "The method is marked as deprecated and will be removed in "
- "a future version of Python. Consider looking for an "
- "alternative in the documentation.",
- ),
- "W1506": (
- "threading.Thread needs the target function",
- "bad-thread-instantiation",
- "The warning is emitted when a threading.Thread class "
- "is instantiated without the target function being passed. "
- "By default, the first parameter is the group param, not the target param. ",
- ),
- "W1507": (
- "Using copy.copy(os.environ). Use os.environ.copy() instead. ",
- "shallow-copy-environ",
- "os.environ is not a dict object but proxy object, so "
- "shallow copy has still effects on original object. "
- "See https://bugs.python.org/issue15373 for reference. ",
- ),
- "E1507": (
- "%s does not support %s type argument",
- "invalid-envvar-value",
- "Env manipulation functions support only string type arguments. "
- "See https://docs.python.org/3/library/os.html#os.getenv. ",
- ),
- "W1508": (
- "%s default type is %s. Expected str or None.",
- "invalid-envvar-default",
- "Env manipulation functions return None or str values. "
- "Supplying anything different as a default may cause bugs. "
- "See https://docs.python.org/3/library/os.html#os.getenv. ",
- ),
- "W1509": (
- "Using preexec_fn keyword which may be unsafe in the presence "
- "of threads",
- "subprocess-popen-preexec-fn",
- "The preexec_fn parameter is not safe to use in the presence "
- "of threads in your application. The child process could "
- "deadlock before exec is called. If you must use it, keep it "
- "trivial! Minimize the number of libraries you call into."
- "https://docs.python.org/3/library/subprocess.html#popen-constructor",
- ),
- "W1510": (
- "Using subprocess.run without explicitly set `check` is not recommended.",
- "subprocess-run-check",
- "The check parameter should always be used with explicitly set "
- "`check` keyword to make clear what the error-handling behavior is."
- "https://docs.python.org/3/library/subprocess.html#subprocess.runs",
- ),
- }
-
- deprecated = {
- 0: {
- "cgi.parse_qs",
- "cgi.parse_qsl",
- "ctypes.c_buffer",
- "distutils.command.register.register.check_metadata",
- "distutils.command.sdist.sdist.check_metadata",
- "tkinter.Misc.tk_menuBar",
- "tkinter.Menu.tk_bindForTraversal",
- },
- 2: {
- (2, 6, 0): {
- "commands.getstatus",
- "os.popen2",
- "os.popen3",
- "os.popen4",
- "macostools.touched",
- },
- (2, 7, 0): {
- "unittest.case.TestCase.assertEquals",
- "unittest.case.TestCase.assertNotEquals",
- "unittest.case.TestCase.assertAlmostEquals",
- "unittest.case.TestCase.assertNotAlmostEquals",
- "unittest.case.TestCase.assert_",
- "xml.etree.ElementTree.Element.getchildren",
- "xml.etree.ElementTree.Element.getiterator",
- "xml.etree.ElementTree.XMLParser.getiterator",
- "xml.etree.ElementTree.XMLParser.doctype",
- },
- },
- 3: {
- (3, 0, 0): {
- "inspect.getargspec",
- "failUnlessEqual",
- "assertEquals",
- "failIfEqual",
- "assertNotEquals",
- "failUnlessAlmostEqual",
- "assertAlmostEquals",
- "failIfAlmostEqual",
- "assertNotAlmostEquals",
- "failUnless",
- "assert_",
- "failUnlessRaises",
- "failIf",
- "assertRaisesRegexp",
- "assertRegexpMatches",
- "assertNotRegexpMatches",
- },
- (3, 1, 0): {
- "base64.encodestring",
- "base64.decodestring",
- "ntpath.splitunc",
- },
- (3, 2, 0): {
- "cgi.escape",
- "configparser.RawConfigParser.readfp",
- "xml.etree.ElementTree.Element.getchildren",
- "xml.etree.ElementTree.Element.getiterator",
- "xml.etree.ElementTree.XMLParser.getiterator",
- "xml.etree.ElementTree.XMLParser.doctype",
- },
- (3, 3, 0): {
- "inspect.getmoduleinfo",
- "logging.warn",
- "logging.Logger.warn",
- "logging.LoggerAdapter.warn",
- "nntplib._NNTPBase.xpath",
- "platform.popen",
- },
- (3, 4, 0): {
- "importlib.find_loader",
- "plistlib.readPlist",
- "plistlib.writePlist",
- "plistlib.readPlistFromBytes",
- "plistlib.writePlistToBytes",
- },
- (3, 4, 4): {"asyncio.tasks.async"},
- (3, 5, 0): {
- "fractions.gcd",
- "inspect.getargvalues",
- "inspect.formatargspec",
- "inspect.formatargvalues",
- "inspect.getcallargs",
- "platform.linux_distribution",
- "platform.dist",
- },
- (3, 6, 0): {"importlib._bootstrap_external.FileLoader.load_module"},
- },
- }
-
- def _check_bad_thread_instantiation(self, node):
- if not node.kwargs and not node.keywords and len(node.args) <= 1:
- self.add_message("bad-thread-instantiation", node=node)
-
- def _check_for_preexec_fn_in_popen(self, node):
- if node.keywords:
- for keyword in node.keywords:
- if keyword.arg == "preexec_fn":
- self.add_message("subprocess-popen-preexec-fn", node=node)
-
- def _check_for_check_kw_in_run(self, node):
- kwargs = {keyword.arg for keyword in (node.keywords or ())}
- if "check" not in kwargs:
- self.add_message("subprocess-run-check", node=node)
-
- def _check_shallow_copy_environ(self, node):
- arg = utils.get_argument_from_call(node, position=0)
- for inferred in arg.inferred():
- if inferred.qname() == OS_ENVIRON:
- self.add_message("shallow-copy-environ", node=node)
- break
-
- @utils.check_messages(
- "bad-open-mode",
- "redundant-unittest-assert",
- "deprecated-method",
- "bad-thread-instantiation",
- "shallow-copy-environ",
- "invalid-envvar-value",
- "invalid-envvar-default",
- "subprocess-popen-preexec-fn",
- "subprocess-run-check",
- )
- def visit_call(self, node):
- """Visit a Call node."""
- try:
- for inferred in node.func.infer():
- if inferred is astroid.Uninferable:
- continue
- if inferred.root().name == OPEN_MODULE:
- if getattr(node.func, "name", None) in OPEN_FILES:
- self._check_open_mode(node)
- elif inferred.root().name == UNITTEST_CASE:
- self._check_redundant_assert(node, inferred)
- elif isinstance(inferred, astroid.ClassDef):
- if inferred.qname() == THREADING_THREAD:
- self._check_bad_thread_instantiation(node)
- elif inferred.qname() == SUBPROCESS_POPEN:
- self._check_for_preexec_fn_in_popen(node)
- elif isinstance(inferred, astroid.FunctionDef):
- name = inferred.qname()
- if name == COPY_COPY:
- self._check_shallow_copy_environ(node)
- elif name in ENV_GETTERS:
- self._check_env_function(node, inferred)
- elif name == SUBPROCESS_RUN:
- self._check_for_check_kw_in_run(node)
- self._check_deprecated_method(node, inferred)
- except astroid.InferenceError:
- return
-
- @utils.check_messages("boolean-datetime")
- def visit_unaryop(self, node):
- if node.op == "not":
- self._check_datetime(node.operand)
-
- @utils.check_messages("boolean-datetime")
- def visit_if(self, node):
- self._check_datetime(node.test)
-
- @utils.check_messages("boolean-datetime")
- def visit_ifexp(self, node):
- self._check_datetime(node.test)
-
- @utils.check_messages("boolean-datetime")
- def visit_boolop(self, node):
- for value in node.values:
- self._check_datetime(value)
-
- def _check_deprecated_method(self, node, inferred):
- py_vers = sys.version_info[0]
-
- if isinstance(node.func, astroid.Attribute):
- func_name = node.func.attrname
- elif isinstance(node.func, astroid.Name):
- func_name = node.func.name
- else:
- # Not interested in other nodes.
- return
-
- # Reject nodes which aren't of interest to us.
- acceptable_nodes = (
- astroid.BoundMethod,
- astroid.UnboundMethod,
- astroid.FunctionDef,
- )
- if not isinstance(inferred, acceptable_nodes):
- return
-
- qname = inferred.qname()
- if any(name in self.deprecated[0] for name in (qname, func_name)):
- self.add_message("deprecated-method", node=node, args=(func_name,))
- else:
- for since_vers, func_list in self.deprecated[py_vers].items():
- if since_vers <= sys.version_info and any(
- name in func_list for name in (qname, func_name)
- ):
- self.add_message("deprecated-method", node=node, args=(func_name,))
- break
-
- def _check_redundant_assert(self, node, infer):
- if (
- isinstance(infer, astroid.BoundMethod)
- and node.args
- and isinstance(node.args[0], astroid.Const)
- and infer.name in ["assertTrue", "assertFalse"]
- ):
- self.add_message(
- "redundant-unittest-assert",
- args=(infer.name, node.args[0].value),
- node=node,
- )
-
- def _check_datetime(self, node):
- """ Check that a datetime was inferred.
- If so, emit boolean-datetime warning.
- """
- try:
- inferred = next(node.infer())
- except astroid.InferenceError:
- return
- if isinstance(inferred, Instance) and inferred.qname() == "datetime.time":
- self.add_message("boolean-datetime", node=node)
-
- def _check_open_mode(self, node):
- """Check that the mode argument of an open or file call is valid."""
- try:
- mode_arg = utils.get_argument_from_call(node, position=1, keyword="mode")
- except utils.NoSuchArgumentError:
- return
- if mode_arg:
- mode_arg = utils.safe_infer(mode_arg)
- if isinstance(mode_arg, astroid.Const) and not _check_mode_str(
- mode_arg.value
- ):
- self.add_message("bad-open-mode", node=node, args=mode_arg.value)
-
- def _check_env_function(self, node, infer):
- env_name_kwarg = "key"
- env_value_kwarg = "default"
- if node.keywords:
- kwargs = {keyword.arg: keyword.value for keyword in node.keywords}
- else:
- kwargs = None
- if node.args:
- env_name_arg = node.args[0]
- elif kwargs and env_name_kwarg in kwargs:
- env_name_arg = kwargs[env_name_kwarg]
- else:
- env_name_arg = None
-
- if env_name_arg:
- self._check_invalid_envvar_value(
- node=node,
- message="invalid-envvar-value",
- call_arg=utils.safe_infer(env_name_arg),
- infer=infer,
- allow_none=False,
- )
-
- if len(node.args) == 2:
- env_value_arg = node.args[1]
- elif kwargs and env_value_kwarg in kwargs:
- env_value_arg = kwargs[env_value_kwarg]
- else:
- env_value_arg = None
-
- if env_value_arg:
- self._check_invalid_envvar_value(
- node=node,
- infer=infer,
- message="invalid-envvar-default",
- call_arg=utils.safe_infer(env_value_arg),
- allow_none=True,
- )
-
- def _check_invalid_envvar_value(self, node, infer, message, call_arg, allow_none):
- if call_arg in (astroid.Uninferable, None):
- return
-
- name = infer.qname()
- if isinstance(call_arg, Const):
- emit = False
- if call_arg.value is None:
- emit = not allow_none
- elif not isinstance(call_arg.value, str):
- emit = True
- if emit:
- self.add_message(message, node=node, args=(name, call_arg.pytype()))
- else:
- self.add_message(message, node=node, args=(name, call_arg.pytype()))
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(StdlibChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/strings.py b/venv/Lib/site-packages/pylint/checkers/strings.py
deleted file mode 100644
index 9470f46..0000000
--- a/venv/Lib/site-packages/pylint/checkers/strings.py
+++ /dev/null
@@ -1,755 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2009 Charles Hebert <charles.hebert@logilab.fr>
-# Copyright (c) 2010-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2010 Daniel Harding <dharding@gmail.com>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Rene Zhang <rz99@cornell.edu>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016, 2018 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2016 Peter Dawyndt <Peter.Dawyndt@UGent.be>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Checker for string formatting operations.
-"""
-
-import builtins
-import numbers
-import tokenize
-from collections import Counter
-
-import astroid
-from astroid.arguments import CallSite
-from astroid.node_classes import Const
-
-from pylint.checkers import BaseChecker, BaseTokenChecker, utils
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker, IRawChecker, ITokenChecker
-
-_AST_NODE_STR_TYPES = ("__builtin__.unicode", "__builtin__.str", "builtins.str")
-
-MSGS = {
- "E1300": (
- "Unsupported format character %r (%#02x) at index %d",
- "bad-format-character",
- "Used when an unsupported format character is used in a format string.",
- ),
- "E1301": (
- "Format string ends in middle of conversion specifier",
- "truncated-format-string",
- "Used when a format string terminates before the end of a "
- "conversion specifier.",
- ),
- "E1302": (
- "Mixing named and unnamed conversion specifiers in format string",
- "mixed-format-string",
- "Used when a format string contains both named (e.g. '%(foo)d') "
- "and unnamed (e.g. '%d') conversion specifiers. This is also "
- "used when a named conversion specifier contains * for the "
- "minimum field width and/or precision.",
- ),
- "E1303": (
- "Expected mapping for format string, not %s",
- "format-needs-mapping",
- "Used when a format string that uses named conversion specifiers "
- "is used with an argument that is not a mapping.",
- ),
- "W1300": (
- "Format string dictionary key should be a string, not %s",
- "bad-format-string-key",
- "Used when a format string that uses named conversion specifiers "
- "is used with a dictionary whose keys are not all strings.",
- ),
- "W1301": (
- "Unused key %r in format string dictionary",
- "unused-format-string-key",
- "Used when a format string that uses named conversion specifiers "
- "is used with a dictionary that contains keys not required by the "
- "format string.",
- ),
- "E1304": (
- "Missing key %r in format string dictionary",
- "missing-format-string-key",
- "Used when a format string that uses named conversion specifiers "
- "is used with a dictionary that doesn't contain all the keys "
- "required by the format string.",
- ),
- "E1305": (
- "Too many arguments for format string",
- "too-many-format-args",
- "Used when a format string that uses unnamed conversion "
- "specifiers is given too many arguments.",
- ),
- "E1306": (
- "Not enough arguments for format string",
- "too-few-format-args",
- "Used when a format string that uses unnamed conversion "
- "specifiers is given too few arguments",
- ),
- "E1307": (
- "Argument %r does not match format type %r",
- "bad-string-format-type",
- "Used when a type required by format string "
- "is not suitable for actual argument type",
- ),
- "E1310": (
- "Suspicious argument in %s.%s call",
- "bad-str-strip-call",
- "The argument to a str.{l,r,}strip call contains a duplicate character, ",
- ),
- "W1302": (
- "Invalid format string",
- "bad-format-string",
- "Used when a PEP 3101 format string is invalid.",
- ),
- "W1303": (
- "Missing keyword argument %r for format string",
- "missing-format-argument-key",
- "Used when a PEP 3101 format string that uses named fields "
- "doesn't receive one or more required keywords.",
- ),
- "W1304": (
- "Unused format argument %r",
- "unused-format-string-argument",
- "Used when a PEP 3101 format string that uses named "
- "fields is used with an argument that "
- "is not required by the format string.",
- ),
- "W1305": (
- "Format string contains both automatic field numbering "
- "and manual field specification",
- "format-combined-specification",
- "Used when a PEP 3101 format string contains both automatic "
- "field numbering (e.g. '{}') and manual field "
- "specification (e.g. '{0}').",
- ),
- "W1306": (
- "Missing format attribute %r in format specifier %r",
- "missing-format-attribute",
- "Used when a PEP 3101 format string uses an "
- "attribute specifier ({0.length}), but the argument "
- "passed for formatting doesn't have that attribute.",
- ),
- "W1307": (
- "Using invalid lookup key %r in format specifier %r",
- "invalid-format-index",
- "Used when a PEP 3101 format string uses a lookup specifier "
- "({a[1]}), but the argument passed for formatting "
- "doesn't contain or doesn't have that key as an attribute.",
- ),
- "W1308": (
- "Duplicate string formatting argument %r, consider passing as named argument",
- "duplicate-string-formatting-argument",
- "Used when we detect that a string formatting is "
- "repeating an argument instead of using named string arguments",
- ),
-}
-
-OTHER_NODES = (
- astroid.Const,
- astroid.List,
- astroid.Lambda,
- astroid.FunctionDef,
- astroid.ListComp,
- astroid.SetComp,
- astroid.GeneratorExp,
-)
-
-BUILTINS_STR = builtins.__name__ + ".str"
-BUILTINS_FLOAT = builtins.__name__ + ".float"
-BUILTINS_INT = builtins.__name__ + ".int"
-
-
-def get_access_path(key, parts):
- """ Given a list of format specifiers, returns
- the final access path (e.g. a.b.c[0][1]).
- """
- path = []
- for is_attribute, specifier in parts:
- if is_attribute:
- path.append(".{}".format(specifier))
- else:
- path.append("[{!r}]".format(specifier))
- return str(key) + "".join(path)
-
-
-def arg_matches_format_type(arg_type, format_type):
- if format_type in "sr":
- # All types can be printed with %s and %r
- return True
- if isinstance(arg_type, astroid.Instance):
- arg_type = arg_type.pytype()
- if arg_type == BUILTINS_STR:
- return format_type == "c"
- if arg_type == BUILTINS_FLOAT:
- return format_type in "deEfFgGn%"
- if arg_type == BUILTINS_INT:
- # Integers allow all types
- return True
- return False
- return True
-
-
-class StringFormatChecker(BaseChecker):
- """Checks string formatting operations to ensure that the format string
- is valid and the arguments match the format string.
- """
-
- __implements__ = (IAstroidChecker,)
- name = "string"
- msgs = MSGS
-
- # pylint: disable=too-many-branches
- @check_messages(*MSGS)
- def visit_binop(self, node):
- if node.op != "%":
- return
- left = node.left
- args = node.right
-
- if not (isinstance(left, astroid.Const) and isinstance(left.value, str)):
- return
- format_string = left.value
- try:
- required_keys, required_num_args, required_key_types, required_arg_types = utils.parse_format_string(
- format_string
- )
- except utils.UnsupportedFormatCharacter as exc:
- formatted = format_string[exc.index]
- self.add_message(
- "bad-format-character",
- node=node,
- args=(formatted, ord(formatted), exc.index),
- )
- return
- except utils.IncompleteFormatString:
- self.add_message("truncated-format-string", node=node)
- return
- if required_keys and required_num_args:
- # The format string uses both named and unnamed format
- # specifiers.
- self.add_message("mixed-format-string", node=node)
- elif required_keys:
- # The format string uses only named format specifiers.
- # Check that the RHS of the % operator is a mapping object
- # that contains precisely the set of keys required by the
- # format string.
- if isinstance(args, astroid.Dict):
- keys = set()
- unknown_keys = False
- for k, _ in args.items:
- if isinstance(k, astroid.Const):
- key = k.value
- if isinstance(key, str):
- keys.add(key)
- else:
- self.add_message(
- "bad-format-string-key", node=node, args=key
- )
- else:
- # One of the keys was something other than a
- # constant. Since we can't tell what it is,
- # suppress checks for missing keys in the
- # dictionary.
- unknown_keys = True
- if not unknown_keys:
- for key in required_keys:
- if key not in keys:
- self.add_message(
- "missing-format-string-key", node=node, args=key
- )
- for key in keys:
- if key not in required_keys:
- self.add_message(
- "unused-format-string-key", node=node, args=key
- )
- for key, arg in args.items:
- if not isinstance(key, astroid.Const):
- continue
- format_type = required_key_types.get(key.value, None)
- arg_type = utils.safe_infer(arg)
- if (
- format_type is not None
- and arg_type not in (None, astroid.Uninferable)
- and not arg_matches_format_type(arg_type, format_type)
- ):
- self.add_message(
- "bad-string-format-type",
- node=node,
- args=(arg_type.pytype(), format_type),
- )
- elif isinstance(args, (OTHER_NODES, astroid.Tuple)):
- type_name = type(args).__name__
- self.add_message("format-needs-mapping", node=node, args=type_name)
- # else:
- # The RHS of the format specifier is a name or
- # expression. It may be a mapping object, so
- # there's nothing we can check.
- else:
- # The format string uses only unnamed format specifiers.
- # Check that the number of arguments passed to the RHS of
- # the % operator matches the number required by the format
- # string.
- args_elts = ()
- if isinstance(args, astroid.Tuple):
- rhs_tuple = utils.safe_infer(args)
- num_args = None
- if hasattr(rhs_tuple, "elts"):
- args_elts = rhs_tuple.elts
- num_args = len(args_elts)
- elif isinstance(args, (OTHER_NODES, (astroid.Dict, astroid.DictComp))):
- args_elts = [args]
- num_args = 1
- else:
- # The RHS of the format specifier is a name or
- # expression. It could be a tuple of unknown size, so
- # there's nothing we can check.
- num_args = None
- if num_args is not None:
- if num_args > required_num_args:
- self.add_message("too-many-format-args", node=node)
- elif num_args < required_num_args:
- self.add_message("too-few-format-args", node=node)
- for arg, format_type in zip(args_elts, required_arg_types):
- if not arg:
- continue
- arg_type = utils.safe_infer(arg)
- if arg_type not in (
- None,
- astroid.Uninferable,
- ) and not arg_matches_format_type(arg_type, format_type):
- self.add_message(
- "bad-string-format-type",
- node=node,
- args=(arg_type.pytype(), format_type),
- )
-
- @check_messages(*MSGS)
- def visit_call(self, node):
- func = utils.safe_infer(node.func)
- if (
- isinstance(func, astroid.BoundMethod)
- and isinstance(func.bound, astroid.Instance)
- and func.bound.name in ("str", "unicode", "bytes")
- ):
- if func.name in ("strip", "lstrip", "rstrip") and node.args:
- arg = utils.safe_infer(node.args[0])
- if not isinstance(arg, astroid.Const) or not isinstance(arg.value, str):
- return
- if len(arg.value) != len(set(arg.value)):
- self.add_message(
- "bad-str-strip-call",
- node=node,
- args=(func.bound.name, func.name),
- )
- elif func.name == "format":
- self._check_new_format(node, func)
-
- def _detect_vacuous_formatting(self, node, positional_arguments):
- counter = Counter(
- arg.name for arg in positional_arguments if isinstance(arg, astroid.Name)
- )
- for name, count in counter.items():
- if count == 1:
- continue
- self.add_message(
- "duplicate-string-formatting-argument", node=node, args=(name,)
- )
-
- def _check_new_format(self, node, func):
- """Check the new string formatting. """
- # Skip ormat nodes which don't have an explicit string on the
- # left side of the format operation.
- # We do this because our inference engine can't properly handle
- # redefinitions of the original string.
- # Note that there may not be any left side at all, if the format method
- # has been assigned to another variable. See issue 351. For example:
- #
- # fmt = 'some string {}'.format
- # fmt('arg')
- if isinstance(node.func, astroid.Attribute) and not isinstance(
- node.func.expr, astroid.Const
- ):
- return
- if node.starargs or node.kwargs:
- return
- try:
- strnode = next(func.bound.infer())
- except astroid.InferenceError:
- return
- if not (isinstance(strnode, astroid.Const) and isinstance(strnode.value, str)):
- return
- try:
- call_site = CallSite.from_call(node)
- except astroid.InferenceError:
- return
-
- try:
- fields, num_args, manual_pos = utils.parse_format_method_string(
- strnode.value
- )
- except utils.IncompleteFormatString:
- self.add_message("bad-format-string", node=node)
- return
-
- positional_arguments = call_site.positional_arguments
- named_arguments = call_site.keyword_arguments
- named_fields = {field[0] for field in fields if isinstance(field[0], str)}
- if num_args and manual_pos:
- self.add_message("format-combined-specification", node=node)
- return
-
- check_args = False
- # Consider "{[0]} {[1]}" as num_args.
- num_args += sum(1 for field in named_fields if field == "")
- if named_fields:
- for field in named_fields:
- if field and field not in named_arguments:
- self.add_message(
- "missing-format-argument-key", node=node, args=(field,)
- )
- for field in named_arguments:
- if field not in named_fields:
- self.add_message(
- "unused-format-string-argument", node=node, args=(field,)
- )
- # num_args can be 0 if manual_pos is not.
- num_args = num_args or manual_pos
- if positional_arguments or num_args:
- empty = any(True for field in named_fields if field == "")
- if named_arguments or empty:
- # Verify the required number of positional arguments
- # only if the .format got at least one keyword argument.
- # This means that the format strings accepts both
- # positional and named fields and we should warn
- # when one of the them is missing or is extra.
- check_args = True
- else:
- check_args = True
- if check_args:
- # num_args can be 0 if manual_pos is not.
- num_args = num_args or manual_pos
- if len(positional_arguments) > num_args:
- self.add_message("too-many-format-args", node=node)
- elif len(positional_arguments) < num_args:
- self.add_message("too-few-format-args", node=node)
-
- self._detect_vacuous_formatting(node, positional_arguments)
- self._check_new_format_specifiers(node, fields, named_arguments)
-
- def _check_new_format_specifiers(self, node, fields, named):
- """
- Check attribute and index access in the format
- string ("{0.a}" and "{0[a]}").
- """
- for key, specifiers in fields:
- # Obtain the argument. If it can't be obtained
- # or inferred, skip this check.
- if key == "":
- # {[0]} will have an unnamed argument, defaulting
- # to 0. It will not be present in `named`, so use the value
- # 0 for it.
- key = 0
- if isinstance(key, numbers.Number):
- try:
- argname = utils.get_argument_from_call(node, key)
- except utils.NoSuchArgumentError:
- continue
- else:
- if key not in named:
- continue
- argname = named[key]
- if argname in (astroid.Uninferable, None):
- continue
- try:
- argument = utils.safe_infer(argname)
- except astroid.InferenceError:
- continue
- if not specifiers or not argument:
- # No need to check this key if it doesn't
- # use attribute / item access
- continue
- if argument.parent and isinstance(argument.parent, astroid.Arguments):
- # Ignore any object coming from an argument,
- # because we can't infer its value properly.
- continue
- previous = argument
- parsed = []
- for is_attribute, specifier in specifiers:
- if previous is astroid.Uninferable:
- break
- parsed.append((is_attribute, specifier))
- if is_attribute:
- try:
- previous = previous.getattr(specifier)[0]
- except astroid.NotFoundError:
- if (
- hasattr(previous, "has_dynamic_getattr")
- and previous.has_dynamic_getattr()
- ):
- # Don't warn if the object has a custom __getattr__
- break
- path = get_access_path(key, parsed)
- self.add_message(
- "missing-format-attribute",
- args=(specifier, path),
- node=node,
- )
- break
- else:
- warn_error = False
- if hasattr(previous, "getitem"):
- try:
- previous = previous.getitem(astroid.Const(specifier))
- except (
- astroid.AstroidIndexError,
- astroid.AstroidTypeError,
- astroid.AttributeInferenceError,
- ):
- warn_error = True
- except astroid.InferenceError:
- break
- if previous is astroid.Uninferable:
- break
- else:
- try:
- # Lookup __getitem__ in the current node,
- # but skip further checks, because we can't
- # retrieve the looked object
- previous.getattr("__getitem__")
- break
- except astroid.NotFoundError:
- warn_error = True
- if warn_error:
- path = get_access_path(key, parsed)
- self.add_message(
- "invalid-format-index", args=(specifier, path), node=node
- )
- break
-
- try:
- previous = next(previous.infer())
- except astroid.InferenceError:
- # can't check further if we can't infer it
- break
-
-
-class StringConstantChecker(BaseTokenChecker):
- """Check string literals"""
-
- __implements__ = (IAstroidChecker, ITokenChecker, IRawChecker)
- name = "string"
- msgs = {
- "W1401": (
- "Anomalous backslash in string: '%s'. "
- "String constant might be missing an r prefix.",
- "anomalous-backslash-in-string",
- "Used when a backslash is in a literal string but not as an escape.",
- ),
- "W1402": (
- "Anomalous Unicode escape in byte string: '%s'. "
- "String constant might be missing an r or u prefix.",
- "anomalous-unicode-escape-in-string",
- "Used when an escape like \\u is encountered in a byte "
- "string where it has no effect.",
- ),
- "W1403": (
- "Implicit string concatenation found in %s",
- "implicit-str-concat-in-sequence",
- "String literals are implicitly concatenated in a "
- "literal iterable definition : "
- "maybe a comma is missing ?",
- ),
- }
- options = (
- (
- "check-str-concat-over-line-jumps",
- {
- "default": False,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "This flag controls whether the "
- "implicit-str-concat-in-sequence should generate a warning "
- "on implicit string concatenation in sequences defined over "
- "several lines.",
- },
- ),
- )
-
- # Characters that have a special meaning after a backslash in either
- # Unicode or byte strings.
- ESCAPE_CHARACTERS = "abfnrtvx\n\r\t\\'\"01234567"
-
- # Characters that have a special meaning after a backslash but only in
- # Unicode strings.
- UNICODE_ESCAPE_CHARACTERS = "uUN"
-
- def __init__(self, *args, **kwargs):
- super(StringConstantChecker, self).__init__(*args, **kwargs)
- self.string_tokens = {} # token position -> (token value, next token)
-
- def process_module(self, module):
- self._unicode_literals = "unicode_literals" in module.future_imports
-
- def process_tokens(self, tokens):
- encoding = "ascii"
- for i, (tok_type, token, start, _, line) in enumerate(tokens):
- if tok_type == tokenize.ENCODING:
- # this is always the first token processed
- encoding = token
- elif tok_type == tokenize.STRING:
- # 'token' is the whole un-parsed token; we can look at the start
- # of it to see whether it's a raw or unicode string etc.
- self.process_string_token(token, start[0])
- # We figure the next token, ignoring comments & newlines:
- j = i + 1
- while j < len(tokens) and tokens[j].type in (
- tokenize.NEWLINE,
- tokenize.NL,
- tokenize.COMMENT,
- ):
- j += 1
- next_token = tokens[j] if j < len(tokens) else None
- if encoding != "ascii":
- # We convert `tokenize` character count into a byte count,
- # to match with astroid `.col_offset`
- start = (start[0], len(line[: start[1]].encode(encoding)))
- self.string_tokens[start] = (str_eval(token), next_token)
-
- @check_messages(*(msgs.keys()))
- def visit_list(self, node):
- self.check_for_concatenated_strings(node, "list")
-
- @check_messages(*(msgs.keys()))
- def visit_set(self, node):
- self.check_for_concatenated_strings(node, "set")
-
- @check_messages(*(msgs.keys()))
- def visit_tuple(self, node):
- self.check_for_concatenated_strings(node, "tuple")
-
- def check_for_concatenated_strings(self, iterable_node, iterable_type):
- for elt in iterable_node.elts:
- if isinstance(elt, Const) and elt.pytype() in _AST_NODE_STR_TYPES:
- if elt.col_offset < 0:
- # This can happen in case of escaped newlines
- continue
- if (elt.lineno, elt.col_offset) not in self.string_tokens:
- # This may happen with Latin1 encoding
- # cf. https://github.com/PyCQA/pylint/issues/2610
- continue
- matching_token, next_token = self.string_tokens[
- (elt.lineno, elt.col_offset)
- ]
- # We detect string concatenation: the AST Const is the
- # combination of 2 string tokens
- if matching_token != elt.value and next_token is not None:
- if next_token.type == tokenize.STRING and (
- next_token.start[0] == elt.lineno
- or self.config.check_str_concat_over_line_jumps
- ):
- self.add_message(
- "implicit-str-concat-in-sequence",
- line=elt.lineno,
- args=(iterable_type,),
- )
-
- def process_string_token(self, token, start_row):
- quote_char = None
- index = None
- for index, char in enumerate(token):
- if char in "'\"":
- quote_char = char
- break
- if quote_char is None:
- return
-
- prefix = token[:index].lower() # markers like u, b, r.
- after_prefix = token[index:]
- if after_prefix[:3] == after_prefix[-3:] == 3 * quote_char:
- string_body = after_prefix[3:-3]
- else:
- string_body = after_prefix[1:-1] # Chop off quotes
- # No special checks on raw strings at the moment.
- if "r" not in prefix:
- self.process_non_raw_string_token(prefix, string_body, start_row)
-
- def process_non_raw_string_token(self, prefix, string_body, start_row):
- """check for bad escapes in a non-raw string.
-
- prefix: lowercase string of eg 'ur' string prefix markers.
- string_body: the un-parsed body of the string, not including the quote
- marks.
- start_row: integer line number in the source.
- """
- # Walk through the string; if we see a backslash then escape the next
- # character, and skip over it. If we see a non-escaped character,
- # alert, and continue.
- #
- # Accept a backslash when it escapes a backslash, or a quote, or
- # end-of-line, or one of the letters that introduce a special escape
- # sequence <http://docs.python.org/reference/lexical_analysis.html>
- #
- index = 0
- while True:
- index = string_body.find("\\", index)
- if index == -1:
- break
- # There must be a next character; having a backslash at the end
- # of the string would be a SyntaxError.
- next_char = string_body[index + 1]
- match = string_body[index : index + 2]
- if next_char in self.UNICODE_ESCAPE_CHARACTERS:
- if "u" in prefix:
- pass
- elif "b" not in prefix:
- pass # unicode by default
- else:
- self.add_message(
- "anomalous-unicode-escape-in-string",
- line=start_row,
- args=(match,),
- col_offset=index,
- )
- elif next_char not in self.ESCAPE_CHARACTERS:
- self.add_message(
- "anomalous-backslash-in-string",
- line=start_row,
- args=(match,),
- col_offset=index,
- )
- # Whether it was a valid escape or not, backslash followed by
- # another character can always be consumed whole: the second
- # character can never be the start of a new backslash escape.
- index += 2
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(StringFormatChecker(linter))
- linter.register_checker(StringConstantChecker(linter))
-
-
-def str_eval(token):
- """
- Mostly replicate `ast.literal_eval(token)` manually to avoid any performance hit.
- This supports f-strings, contrary to `ast.literal_eval`.
- We have to support all string literal notations:
- https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
- """
- if token[0:2].lower() in ("fr", "rf"):
- token = token[2:]
- elif token[0].lower() in ("r", "u", "f"):
- token = token[1:]
- if token[0:3] in ('"""', "'''"):
- return token[3:-3]
- return token[1:-1]
diff --git a/venv/Lib/site-packages/pylint/checkers/typecheck.py b/venv/Lib/site-packages/pylint/checkers/typecheck.py
deleted file mode 100644
index a288f49..0000000
--- a/venv/Lib/site-packages/pylint/checkers/typecheck.py
+++ /dev/null
@@ -1,1770 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2009 James Lingard <jchl@aristanetworks.com>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 David Shea <dshea@redhat.com>
-# Copyright (c) 2014 Steven Myint <hg@stevenmyint.com>
-# Copyright (c) 2014 Holger Peters <email@holger-peters.de>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Anentropic <ego@anentropic.com>
-# Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
-# Copyright (c) 2015 Rene Zhang <rz99@cornell.edu>
-# Copyright (c) 2015 Radu Ciorba <radu@devrandom.ro>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2016 Jürgen Hermann <jh@web.de>
-# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2016 Filipe Brandenburger <filbranden@google.com>
-# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2017 Derek Gustafson <degustaf@gmail.com>
-# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 Ben Green <benhgreen@icloud.com>
-# Copyright (c) 2018 Konstantin <Github@pheanex.de>
-# Copyright (c) 2018 Justin Li <justinnhli@users.noreply.github.com>
-# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""try to find more bugs in the code using astroid inference capabilities
-"""
-
-import builtins
-import fnmatch
-import heapq
-import itertools
-import operator
-import re
-import shlex
-import sys
-import types
-from collections import deque
-from collections.abc import Sequence
-from functools import singledispatch
-
-import astroid
-import astroid.arguments
-import astroid.context
-import astroid.nodes
-from astroid import bases, decorators, exceptions, modutils, objects
-from astroid.interpreter import dunder_lookup
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import (
- check_messages,
- decorated_with,
- decorated_with_property,
- has_known_bases,
- is_builtin_object,
- is_comprehension,
- is_inside_abstract_class,
- is_iterable,
- is_mapping,
- is_overload_stub,
- is_super,
- node_ignores_exception,
- safe_infer,
- supports_delitem,
- supports_getitem,
- supports_membership_test,
- supports_setitem,
-)
-from pylint.interfaces import INFERENCE, IAstroidChecker
-from pylint.utils import get_global_option
-
-BUILTINS = builtins.__name__
-STR_FORMAT = {"%s.str.format" % BUILTINS}
-ASYNCIO_COROUTINE = "asyncio.coroutines.coroutine"
-
-
-def _unflatten(iterable):
- for index, elem in enumerate(iterable):
- if isinstance(elem, Sequence) and not isinstance(elem, str):
- for single_elem in _unflatten(elem):
- yield single_elem
- elif elem and not index:
- # We're interested only in the first element.
- yield elem
-
-
-def _flatten_container(iterable):
- # Flatten nested containers into a single iterable
- for item in iterable:
- if isinstance(item, (list, tuple, types.GeneratorType)):
- yield from _flatten_container(item)
- else:
- yield item
-
-
-def _is_owner_ignored(owner, attrname, ignored_classes, ignored_modules):
- """Check if the given owner should be ignored
-
- This will verify if the owner's module is in *ignored_modules*
- or the owner's module fully qualified name is in *ignored_modules*
- or if the *ignored_modules* contains a pattern which catches
- the fully qualified name of the module.
-
- Also, similar checks are done for the owner itself, if its name
- matches any name from the *ignored_classes* or if its qualified
- name can be found in *ignored_classes*.
- """
- ignored_modules = set(ignored_modules)
- module_name = owner.root().name
- module_qname = owner.root().qname()
-
- for ignore in ignored_modules:
- # Try to match the module name / fully qualified name directly
- if module_qname in ignored_modules or module_name in ignored_modules:
- return True
-
- # Try to see if the ignores pattern match against the module name.
- if fnmatch.fnmatch(module_qname, ignore):
- return True
-
- # Otherwise we might have a root module name being ignored,
- # and the qualified owner has more levels of depth.
- parts = deque(module_name.split("."))
- current_module = ""
-
- while parts:
- part = parts.popleft()
- if not current_module:
- current_module = part
- else:
- current_module += ".{}".format(part)
- if current_module in ignored_modules:
- return True
-
- # Match against ignored classes.
- ignored_classes = set(ignored_classes)
- if hasattr(owner, "qname"):
- qname = owner.qname()
- else:
- qname = ""
- return any(ignore in (attrname, qname) for ignore in ignored_classes)
-
-
-@singledispatch
-def _node_names(node):
- if not hasattr(node, "locals"):
- return []
- return node.locals.keys()
-
-
-@_node_names.register(astroid.ClassDef)
-@_node_names.register(astroid.Instance)
-def _(node):
- values = itertools.chain(node.instance_attrs.keys(), node.locals.keys())
-
- try:
- mro = node.mro()[1:]
- except (NotImplementedError, TypeError):
- mro = node.ancestors()
-
- other_values = [value for cls in mro for value in _node_names(cls)]
- return itertools.chain(values, other_values)
-
-
-def _string_distance(seq1, seq2):
- seq2_length = len(seq2)
-
- row = list(range(1, seq2_length + 1)) + [0]
- for seq1_index, seq1_char in enumerate(seq1):
- last_row = row
- row = [0] * seq2_length + [seq1_index + 1]
-
- for seq2_index, seq2_char in enumerate(seq2):
- row[seq2_index] = min(
- last_row[seq2_index] + 1,
- row[seq2_index - 1] + 1,
- last_row[seq2_index - 1] + (seq1_char != seq2_char),
- )
-
- return row[seq2_length - 1]
-
-
-def _similar_names(owner, attrname, distance_threshold, max_choices):
- """Given an owner and a name, try to find similar names
-
- The similar names are searched given a distance metric and only
- a given number of choices will be returned.
- """
- possible_names = []
- names = _node_names(owner)
-
- for name in names:
- if name == attrname:
- continue
-
- distance = _string_distance(attrname, name)
- if distance <= distance_threshold:
- possible_names.append((name, distance))
-
- # Now get back the values with a minimum, up to the given
- # limit or choices.
- picked = [
- name
- for (name, _) in heapq.nsmallest(
- max_choices, possible_names, key=operator.itemgetter(1)
- )
- ]
- return sorted(picked)
-
-
-def _missing_member_hint(owner, attrname, distance_threshold, max_choices):
- names = _similar_names(owner, attrname, distance_threshold, max_choices)
- if not names:
- # No similar name.
- return ""
-
- names = list(map(repr, names))
- if len(names) == 1:
- names = ", ".join(names)
- else:
- names = "one of {} or {}".format(", ".join(names[:-1]), names[-1])
-
- return "; maybe {}?".format(names)
-
-
-MSGS = {
- "E1101": (
- "%s %r has no %r member%s",
- "no-member",
- "Used when a variable is accessed for an unexistent member.",
- {"old_names": [("E1103", "maybe-no-member")]},
- ),
- "I1101": (
- "%s %r has no %r member%s, but source is unavailable. Consider "
- "adding this module to extension-pkg-whitelist if you want "
- "to perform analysis based on run-time introspection of living objects.",
- "c-extension-no-member",
- "Used when a variable is accessed for non-existent member of C "
- "extension. Due to unavailability of source static analysis is impossible, "
- "but it may be performed by introspecting living objects in run-time.",
- ),
- "E1102": (
- "%s is not callable",
- "not-callable",
- "Used when an object being called has been inferred to a non "
- "callable object.",
- ),
- "E1111": (
- "Assigning result of a function call, where the function has no return",
- "assignment-from-no-return",
- "Used when an assignment is done on a function call but the "
- "inferred function doesn't return anything.",
- ),
- "E1120": (
- "No value for argument %s in %s call",
- "no-value-for-parameter",
- "Used when a function call passes too few arguments.",
- ),
- "E1121": (
- "Too many positional arguments for %s call",
- "too-many-function-args",
- "Used when a function call passes too many positional arguments.",
- ),
- "E1123": (
- "Unexpected keyword argument %r in %s call",
- "unexpected-keyword-arg",
- "Used when a function call passes a keyword argument that "
- "doesn't correspond to one of the function's parameter names.",
- ),
- "E1124": (
- "Argument %r passed by position and keyword in %s call",
- "redundant-keyword-arg",
- "Used when a function call would result in assigning multiple "
- "values to a function parameter, one value from a positional "
- "argument and one from a keyword argument.",
- ),
- "E1125": (
- "Missing mandatory keyword argument %r in %s call",
- "missing-kwoa",
- (
- "Used when a function call does not pass a mandatory"
- " keyword-only argument."
- ),
- ),
- "E1126": (
- "Sequence index is not an int, slice, or instance with __index__",
- "invalid-sequence-index",
- "Used when a sequence type is indexed with an invalid type. "
- "Valid types are ints, slices, and objects with an __index__ "
- "method.",
- ),
- "E1127": (
- "Slice index is not an int, None, or instance with __index__",
- "invalid-slice-index",
- "Used when a slice index is not an integer, None, or an object "
- "with an __index__ method.",
- ),
- "E1128": (
- "Assigning result of a function call, where the function returns None",
- "assignment-from-none",
- "Used when an assignment is done on a function call but the "
- "inferred function returns nothing but None.",
- {"old_names": [("W1111", "old-assignment-from-none")]},
- ),
- "E1129": (
- "Context manager '%s' doesn't implement __enter__ and __exit__.",
- "not-context-manager",
- "Used when an instance in a with statement doesn't implement "
- "the context manager protocol(__enter__/__exit__).",
- ),
- "E1130": (
- "%s",
- "invalid-unary-operand-type",
- "Emitted when a unary operand is used on an object which does not "
- "support this type of operation.",
- ),
- "E1131": (
- "%s",
- "unsupported-binary-operation",
- "Emitted when a binary arithmetic operation between two "
- "operands is not supported.",
- ),
- "E1132": (
- "Got multiple values for keyword argument %r in function call",
- "repeated-keyword",
- "Emitted when a function call got multiple values for a keyword.",
- ),
- "E1135": (
- "Value '%s' doesn't support membership test",
- "unsupported-membership-test",
- "Emitted when an instance in membership test expression doesn't "
- "implement membership protocol (__contains__/__iter__/__getitem__).",
- ),
- "E1136": (
- "Value '%s' is unsubscriptable",
- "unsubscriptable-object",
- "Emitted when a subscripted value doesn't support subscription "
- "(i.e. doesn't define __getitem__ method or __class_getitem__ for a class).",
- ),
- "E1137": (
- "%r does not support item assignment",
- "unsupported-assignment-operation",
- "Emitted when an object does not support item assignment "
- "(i.e. doesn't define __setitem__ method).",
- ),
- "E1138": (
- "%r does not support item deletion",
- "unsupported-delete-operation",
- "Emitted when an object does not support item deletion "
- "(i.e. doesn't define __delitem__ method).",
- ),
- "E1139": (
- "Invalid metaclass %r used",
- "invalid-metaclass",
- "Emitted whenever we can detect that a class is using, "
- "as a metaclass, something which might be invalid for using as "
- "a metaclass.",
- ),
- "E1140": (
- "Dict key is unhashable",
- "unhashable-dict-key",
- "Emitted when a dict key is not hashable "
- "(i.e. doesn't define __hash__ method).",
- ),
- "E1141": (
- "Unpacking a dictionary in iteration without calling .items()",
- "dict-iter-missing-items",
- "Emitted when trying to iterate through a dict without calling .items()",
- ),
- "W1113": (
- "Keyword argument before variable positional arguments list "
- "in the definition of %s function",
- "keyword-arg-before-vararg",
- "When defining a keyword argument before variable positional arguments, one can "
- "end up in having multiple values passed for the aforementioned parameter in "
- "case the method is called with keyword arguments.",
- ),
- "W1114": (
- "Positional arguments appear to be out of order",
- "arguments-out-of-order",
- "Emitted when the caller's argument names fully match the parameter "
- "names in the function signature but do not have the same order.",
- ),
-}
-
-# builtin sequence types in Python 2 and 3.
-SEQUENCE_TYPES = {
- "str",
- "unicode",
- "list",
- "tuple",
- "bytearray",
- "xrange",
- "range",
- "bytes",
- "memoryview",
-}
-
-
-def _emit_no_member(node, owner, owner_name, ignored_mixins=True, ignored_none=True):
- """Try to see if no-member should be emitted for the given owner.
-
- The following cases are ignored:
-
- * the owner is a function and it has decorators.
- * the owner is an instance and it has __getattr__, __getattribute__ implemented
- * the module is explicitly ignored from no-member checks
- * the owner is a class and the name can be found in its metaclass.
- * The access node is protected by an except handler, which handles
- AttributeError, Exception or bare except.
- """
- # pylint: disable=too-many-return-statements
- if node_ignores_exception(node, AttributeError):
- return False
- if ignored_none and isinstance(owner, astroid.Const) and owner.value is None:
- return False
- if is_super(owner) or getattr(owner, "type", None) == "metaclass":
- return False
- if owner_name and ignored_mixins and owner_name[-5:].lower() == "mixin":
- return False
- if isinstance(owner, astroid.FunctionDef) and owner.decorators:
- return False
- if isinstance(owner, (astroid.Instance, astroid.ClassDef)):
- if owner.has_dynamic_getattr():
- # Issue #2565: Don't ignore enums, as they have a `__getattr__` but it's not
- # invoked at this point.
- try:
- metaclass = owner.metaclass()
- except exceptions.MroError:
- return False
- if metaclass:
- return metaclass.qname() == "enum.EnumMeta"
- return False
- if not has_known_bases(owner):
- return False
-
- # Exclude typed annotations, since these might actually exist
- # at some point during the runtime of the program.
- attribute = owner.locals.get(node.attrname, [None])[0]
- if (
- attribute
- and isinstance(attribute, astroid.AssignName)
- and isinstance(attribute.parent, astroid.AnnAssign)
- ):
- return False
- if isinstance(owner, objects.Super):
- # Verify if we are dealing with an invalid Super object.
- # If it is invalid, then there's no point in checking that
- # it has the required attribute. Also, don't fail if the
- # MRO is invalid.
- try:
- owner.super_mro()
- except (exceptions.MroError, exceptions.SuperError):
- return False
- if not all(map(has_known_bases, owner.type.mro())):
- return False
- if isinstance(owner, astroid.Module):
- try:
- owner.getattr("__getattr__")
- return False
- except astroid.NotFoundError:
- pass
- if owner_name and node.attrname.startswith("_" + owner_name):
- # Test if an attribute has been mangled ('private' attribute)
- unmangled_name = node.attrname.split("_" + owner_name)[-1]
- try:
- if owner.getattr(unmangled_name, context=None) is not None:
- return False
- except astroid.NotFoundError:
- return True
- return True
-
-
-def _determine_callable(callable_obj):
- # Ordering is important, since BoundMethod is a subclass of UnboundMethod,
- # and Function inherits Lambda.
- parameters = 0
- if hasattr(callable_obj, "implicit_parameters"):
- parameters = callable_obj.implicit_parameters()
- if isinstance(callable_obj, astroid.BoundMethod):
- # Bound methods have an extra implicit 'self' argument.
- return callable_obj, parameters, callable_obj.type
- if isinstance(callable_obj, astroid.UnboundMethod):
- return callable_obj, parameters, "unbound method"
- if isinstance(callable_obj, astroid.FunctionDef):
- return callable_obj, parameters, callable_obj.type
- if isinstance(callable_obj, astroid.Lambda):
- return callable_obj, parameters, "lambda"
- if isinstance(callable_obj, astroid.ClassDef):
- # Class instantiation, lookup __new__ instead.
- # If we only find object.__new__, we can safely check __init__
- # instead. If __new__ belongs to builtins, then we look
- # again for __init__ in the locals, since we won't have
- # argument information for the builtin __new__ function.
- try:
- # Use the last definition of __new__.
- new = callable_obj.local_attr("__new__")[-1]
- except exceptions.NotFoundError:
- new = None
-
- from_object = new and new.parent.scope().name == "object"
- from_builtins = new and new.root().name in sys.builtin_module_names
-
- if not new or from_object or from_builtins:
- try:
- # Use the last definition of __init__.
- callable_obj = callable_obj.local_attr("__init__")[-1]
- except exceptions.NotFoundError:
- # do nothing, covered by no-init.
- raise ValueError
- else:
- callable_obj = new
-
- if not isinstance(callable_obj, astroid.FunctionDef):
- raise ValueError
- # both have an extra implicit 'cls'/'self' argument.
- return callable_obj, parameters, "constructor"
-
- raise ValueError
-
-
-def _has_parent_of_type(node, node_type, statement):
- """Check if the given node has a parent of the given type."""
- parent = node.parent
- while not isinstance(parent, node_type) and statement.parent_of(parent):
- parent = parent.parent
- return isinstance(parent, node_type)
-
-
-def _no_context_variadic_keywords(node, scope):
- statement = node.statement()
- variadics = ()
-
- if isinstance(scope, astroid.Lambda) and not isinstance(scope, astroid.FunctionDef):
- variadics = list(node.keywords or []) + node.kwargs
- else:
- if isinstance(statement, (astroid.Return, astroid.Expr)) and isinstance(
- statement.value, astroid.Call
- ):
- call = statement.value
- variadics = list(call.keywords or []) + call.kwargs
-
- return _no_context_variadic(node, scope.args.kwarg, astroid.Keyword, variadics)
-
-
-def _no_context_variadic_positional(node, scope):
- variadics = ()
- if isinstance(scope, astroid.Lambda) and not isinstance(scope, astroid.FunctionDef):
- variadics = node.starargs + node.kwargs
- else:
- statement = node.statement()
- if isinstance(statement, (astroid.Expr, astroid.Return)) and isinstance(
- statement.value, astroid.Call
- ):
- call = statement.value
- variadics = call.starargs + call.kwargs
-
- return _no_context_variadic(node, scope.args.vararg, astroid.Starred, variadics)
-
-
-def _no_context_variadic(node, variadic_name, variadic_type, variadics):
- """Verify if the given call node has variadic nodes without context
-
- This is a workaround for handling cases of nested call functions
- which don't have the specific call context at hand.
- Variadic arguments (variable positional arguments and variable
- keyword arguments) are inferred, inherently wrong, by astroid
- as a Tuple, respectively a Dict with empty elements.
- This can lead pylint to believe that a function call receives
- too few arguments.
- """
- scope = node.scope()
- is_in_lambda_scope = not isinstance(scope, astroid.FunctionDef) and isinstance(
- scope, astroid.Lambda
- )
- statement = node.statement()
- for name in statement.nodes_of_class(astroid.Name):
- if name.name != variadic_name:
- continue
-
- inferred = safe_infer(name)
- if isinstance(inferred, (astroid.List, astroid.Tuple)):
- length = len(inferred.elts)
- elif isinstance(inferred, astroid.Dict):
- length = len(inferred.items)
- else:
- continue
-
- if is_in_lambda_scope and isinstance(inferred.parent, astroid.Arguments):
- # The statement of the variadic will be the assignment itself,
- # so we need to go the lambda instead
- inferred_statement = inferred.parent.parent
- else:
- inferred_statement = inferred.statement()
-
- if not length and isinstance(inferred_statement, astroid.Lambda):
- is_in_starred_context = _has_parent_of_type(node, variadic_type, statement)
- used_as_starred_argument = any(
- variadic.value == name or variadic.value.parent_of(name)
- for variadic in variadics
- )
- if is_in_starred_context or used_as_starred_argument:
- return True
- return False
-
-
-def _is_invalid_metaclass(metaclass):
- try:
- mro = metaclass.mro()
- except NotImplementedError:
- # Cannot have a metaclass which is not a newstyle class.
- return True
- else:
- if not any(is_builtin_object(cls) and cls.name == "type" for cls in mro):
- return True
- return False
-
-
-def _infer_from_metaclass_constructor(cls, func):
- """Try to infer what the given *func* constructor is building
-
- :param astroid.FunctionDef func:
- A metaclass constructor. Metaclass definitions can be
- functions, which should accept three arguments, the name of
- the class, the bases of the class and the attributes.
- The function could return anything, but usually it should
- be a proper metaclass.
- :param astroid.ClassDef cls:
- The class for which the *func* parameter should generate
- a metaclass.
- :returns:
- The class generated by the function or None,
- if we couldn't infer it.
- :rtype: astroid.ClassDef
- """
- context = astroid.context.InferenceContext()
-
- class_bases = astroid.List()
- class_bases.postinit(elts=cls.bases)
-
- attrs = astroid.Dict()
- local_names = [(name, values[-1]) for name, values in cls.locals.items()]
- attrs.postinit(local_names)
-
- builder_args = astroid.Tuple()
- builder_args.postinit([cls.name, class_bases, attrs])
-
- context.callcontext = astroid.context.CallContext(builder_args)
- try:
- inferred = next(func.infer_call_result(func, context), None)
- except astroid.InferenceError:
- return None
- return inferred or None
-
-
-def _is_c_extension(module_node):
- return (
- not modutils.is_standard_module(module_node.name)
- and not module_node.fully_defined()
- )
-
-
-class TypeChecker(BaseChecker):
- """try to find bugs in the code using type inference
- """
-
- __implements__ = (IAstroidChecker,)
-
- # configuration section name
- name = "typecheck"
- # messages
- msgs = MSGS
- priority = -1
- # configuration options
- options = (
- (
- "ignore-on-opaque-inference",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "This flag controls whether pylint should warn about "
- "no-member and similar checks whenever an opaque object "
- "is returned when inferring. The inference can return "
- "multiple potential results while evaluating a Python object, "
- "but some branches might not be evaluated, which results in "
- "partial inference. In that case, it might be useful to still emit "
- "no-member and other checks for the rest of the inferred objects.",
- },
- ),
- (
- "ignore-mixin-members",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": 'Tells whether missing members accessed in mixin \
-class should be ignored. A mixin class is detected if its name ends with \
-"mixin" (case insensitive).',
- },
- ),
- (
- "ignore-none",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "Tells whether to warn about missing members when the owner "
- "of the attribute is inferred to be None.",
- },
- ),
- (
- "ignored-modules",
- {
- "default": (),
- "type": "csv",
- "metavar": "<module names>",
- "help": "List of module names for which member attributes "
- "should not be checked (useful for modules/projects "
- "where namespaces are manipulated during runtime and "
- "thus existing member attributes cannot be "
- "deduced by static analysis). It supports qualified "
- "module names, as well as Unix pattern matching.",
- },
- ),
- # the defaults here are *stdlib* names that (almost) always
- # lead to false positives, since their idiomatic use is
- # 'too dynamic' for pylint to grok.
- (
- "ignored-classes",
- {
- "default": ("optparse.Values", "thread._local", "_thread._local"),
- "type": "csv",
- "metavar": "<members names>",
- "help": "List of class names for which member attributes "
- "should not be checked (useful for classes with "
- "dynamically set attributes). This supports "
- "the use of qualified names.",
- },
- ),
- (
- "generated-members",
- {
- "default": (),
- "type": "string",
- "metavar": "<members names>",
- "help": "List of members which are set dynamically and \
-missed by pylint inference system, and so shouldn't trigger E1101 when \
-accessed. Python regular expressions are accepted.",
- },
- ),
- (
- "contextmanager-decorators",
- {
- "default": ["contextlib.contextmanager"],
- "type": "csv",
- "metavar": "<decorator names>",
- "help": "List of decorators that produce context managers, "
- "such as contextlib.contextmanager. Add to this list "
- "to register other decorators that produce valid "
- "context managers.",
- },
- ),
- (
- "missing-member-hint-distance",
- {
- "default": 1,
- "type": "int",
- "metavar": "<member hint edit distance>",
- "help": "The minimum edit distance a name should have in order "
- "to be considered a similar match for a missing member name.",
- },
- ),
- (
- "missing-member-max-choices",
- {
- "default": 1,
- "type": "int",
- "metavar": "<member hint max choices>",
- "help": "The total number of similar names that should be taken in "
- "consideration when showing a hint for a missing member.",
- },
- ),
- (
- "missing-member-hint",
- {
- "default": True,
- "type": "yn",
- "metavar": "<missing member hint>",
- "help": "Show a hint with possible names when a member name was not "
- "found. The aspect of finding the hint is based on edit distance.",
- },
- ),
- (
- "signature-mutators",
- {
- "default": [],
- "type": "csv",
- "metavar": "<decorator names>",
- "help": "List of decorators that change the signature of "
- "a decorated function.",
- },
- ),
- )
-
- @decorators.cachedproperty
- def _suggestion_mode(self):
- return get_global_option(self, "suggestion-mode", default=True)
-
- def open(self):
- # do this in open since config not fully initialized in __init__
- # generated_members may contain regular expressions
- # (surrounded by quote `"` and followed by a comma `,`)
- # REQUEST,aq_parent,"[a-zA-Z]+_set{1,2}"' =>
- # ('REQUEST', 'aq_parent', '[a-zA-Z]+_set{1,2}')
- if isinstance(self.config.generated_members, str):
- gen = shlex.shlex(self.config.generated_members)
- gen.whitespace += ","
- gen.wordchars += r"[]-+\.*?()|"
- self.config.generated_members = tuple(tok.strip('"') for tok in gen)
-
- @check_messages("keyword-arg-before-vararg")
- def visit_functiondef(self, node):
- # check for keyword arg before varargs
- if node.args.vararg and node.args.defaults:
- self.add_message("keyword-arg-before-vararg", node=node, args=(node.name))
-
- visit_asyncfunctiondef = visit_functiondef
-
- @check_messages("invalid-metaclass")
- def visit_classdef(self, node):
- def _metaclass_name(metaclass):
- if isinstance(metaclass, (astroid.ClassDef, astroid.FunctionDef)):
- return metaclass.name
- return metaclass.as_string()
-
- metaclass = node.declared_metaclass()
- if not metaclass:
- return
-
- if isinstance(metaclass, astroid.FunctionDef):
- # Try to infer the result.
- metaclass = _infer_from_metaclass_constructor(node, metaclass)
- if not metaclass:
- # Don't do anything if we cannot infer the result.
- return
-
- if isinstance(metaclass, astroid.ClassDef):
- if _is_invalid_metaclass(metaclass):
- self.add_message(
- "invalid-metaclass", node=node, args=(_metaclass_name(metaclass),)
- )
- else:
- self.add_message(
- "invalid-metaclass", node=node, args=(_metaclass_name(metaclass),)
- )
-
- def visit_assignattr(self, node):
- if isinstance(node.assign_type(), astroid.AugAssign):
- self.visit_attribute(node)
-
- def visit_delattr(self, node):
- self.visit_attribute(node)
-
- @check_messages("no-member", "c-extension-no-member")
- def visit_attribute(self, node):
- """check that the accessed attribute exists
-
- to avoid too much false positives for now, we'll consider the code as
- correct if a single of the inferred nodes has the accessed attribute.
-
- function/method, super call and metaclasses are ignored
- """
- for pattern in self.config.generated_members:
- # attribute is marked as generated, stop here
- if re.match(pattern, node.attrname):
- return
- if re.match(pattern, node.as_string()):
- return
-
- try:
- inferred = list(node.expr.infer())
- except exceptions.InferenceError:
- return
-
- # list of (node, nodename) which are missing the attribute
- missingattr = set()
-
- non_opaque_inference_results = [
- owner
- for owner in inferred
- if owner is not astroid.Uninferable
- and not isinstance(owner, astroid.nodes.Unknown)
- ]
- if (
- len(non_opaque_inference_results) != len(inferred)
- and self.config.ignore_on_opaque_inference
- ):
- # There is an ambiguity in the inference. Since we can't
- # make sure that we won't emit a false positive, we just stop
- # whenever the inference returns an opaque inference object.
- return
- for owner in non_opaque_inference_results:
- name = getattr(owner, "name", None)
- if _is_owner_ignored(
- owner, name, self.config.ignored_classes, self.config.ignored_modules
- ):
- continue
-
- try:
- if not [
- n
- for n in owner.getattr(node.attrname)
- if not isinstance(n.statement(), astroid.AugAssign)
- ]:
- missingattr.add((owner, name))
- continue
- except AttributeError:
- continue
- except exceptions.NotFoundError:
- # This can't be moved before the actual .getattr call,
- # because there can be more values inferred and we are
- # stopping after the first one which has the attribute in question.
- # The problem is that if the first one has the attribute,
- # but we continue to the next values which doesn't have the
- # attribute, then we'll have a false positive.
- # So call this only after the call has been made.
- if not _emit_no_member(
- node,
- owner,
- name,
- ignored_mixins=self.config.ignore_mixin_members,
- ignored_none=self.config.ignore_none,
- ):
- continue
- missingattr.add((owner, name))
- continue
- # stop on the first found
- break
- else:
- # we have not found any node with the attributes, display the
- # message for inferred nodes
- done = set()
- for owner, name in missingattr:
- if isinstance(owner, astroid.Instance):
- actual = owner._proxied
- else:
- actual = owner
- if actual in done:
- continue
- done.add(actual)
-
- msg, hint = self._get_nomember_msgid_hint(node, owner)
- self.add_message(
- msg,
- node=node,
- args=(owner.display_type(), name, node.attrname, hint),
- confidence=INFERENCE,
- )
-
- def _get_nomember_msgid_hint(self, node, owner):
- suggestions_are_possible = self._suggestion_mode and isinstance(
- owner, astroid.Module
- )
- if suggestions_are_possible and _is_c_extension(owner):
- msg = "c-extension-no-member"
- hint = ""
- else:
- msg = "no-member"
- if self.config.missing_member_hint:
- hint = _missing_member_hint(
- owner,
- node.attrname,
- self.config.missing_member_hint_distance,
- self.config.missing_member_max_choices,
- )
- else:
- hint = ""
- return msg, hint
-
- @check_messages("assignment-from-no-return", "assignment-from-none")
- def visit_assign(self, node):
- """check that if assigning to a function call, the function is
- possibly returning something valuable
- """
- if not isinstance(node.value, astroid.Call):
- return
-
- function_node = safe_infer(node.value.func)
- funcs = (astroid.FunctionDef, astroid.UnboundMethod, astroid.BoundMethod)
- if not isinstance(function_node, funcs):
- return
-
- # Unwrap to get the actual function object
- if isinstance(function_node, astroid.BoundMethod) and isinstance(
- function_node._proxied, astroid.UnboundMethod
- ):
- function_node = function_node._proxied._proxied
-
- # Make sure that it's a valid function that we can analyze.
- # Ordered from less expensive to more expensive checks.
- # pylint: disable=too-many-boolean-expressions
- if (
- not function_node.is_function
- or isinstance(function_node, astroid.AsyncFunctionDef)
- or function_node.decorators
- or function_node.is_generator()
- or function_node.is_abstract(pass_is_abstract=False)
- or not function_node.root().fully_defined()
- ):
- return
-
- returns = list(
- function_node.nodes_of_class(astroid.Return, skip_klass=astroid.FunctionDef)
- )
- if not returns:
- self.add_message("assignment-from-no-return", node=node)
- else:
- for rnode in returns:
- if not (
- isinstance(rnode.value, astroid.Const)
- and rnode.value.value is None
- or rnode.value is None
- ):
- break
- else:
- self.add_message("assignment-from-none", node=node)
-
- def _check_uninferable_call(self, node):
- """
- Check that the given uninferable Call node does not
- call an actual function.
- """
- if not isinstance(node.func, astroid.Attribute):
- return
-
- # Look for properties. First, obtain
- # the lhs of the Attribute node and search the attribute
- # there. If that attribute is a property or a subclass of properties,
- # then most likely it's not callable.
-
- expr = node.func.expr
- klass = safe_infer(expr)
- if (
- klass is None
- or klass is astroid.Uninferable
- or not isinstance(klass, astroid.Instance)
- ):
- return
-
- try:
- attrs = klass._proxied.getattr(node.func.attrname)
- except exceptions.NotFoundError:
- return
-
- for attr in attrs:
- if attr is astroid.Uninferable:
- continue
- if not isinstance(attr, astroid.FunctionDef):
- continue
-
- # Decorated, see if it is decorated with a property.
- # Also, check the returns and see if they are callable.
- if decorated_with_property(attr):
-
- try:
- all_returns_are_callable = all(
- return_node.callable() or return_node is astroid.Uninferable
- for return_node in attr.infer_call_result(node)
- )
- except astroid.InferenceError:
- continue
-
- if not all_returns_are_callable:
- self.add_message(
- "not-callable", node=node, args=node.func.as_string()
- )
- break
-
- def _check_argument_order(self, node, call_site, called, called_param_names):
- """Match the supplied argument names against the function parameters.
- Warn if some argument names are not in the same order as they are in
- the function signature.
- """
- # Check for called function being an object instance function
- # If so, ignore the initial 'self' argument in the signature
- try:
- is_classdef = isinstance(called.parent, astroid.scoped_nodes.ClassDef)
- if is_classdef and called_param_names[0] == "self":
- called_param_names = called_param_names[1:]
- except IndexError:
- return
-
- try:
- # extract argument names, if they have names
- calling_parg_names = [p.name for p in call_site.positional_arguments]
-
- # Additionally get names of keyword arguments to use in a full match
- # against parameters
- calling_kwarg_names = [
- arg.name for arg in call_site.keyword_arguments.values()
- ]
- except AttributeError:
- # the type of arg does not provide a `.name`. In this case we
- # stop checking for out-of-order arguments because it is only relevant
- # for named variables.
- return
-
- # Don't check for ordering if there is an unmatched arg or param
- arg_set = set(calling_parg_names) | set(calling_kwarg_names)
- param_set = set(called_param_names)
- if arg_set != param_set:
- return
-
- # Warn based on the equality of argument ordering
- if calling_parg_names != called_param_names[: len(calling_parg_names)]:
- self.add_message("arguments-out-of-order", node=node, args=())
-
- # pylint: disable=too-many-branches,too-many-locals
- @check_messages(*(list(MSGS.keys())))
- def visit_call(self, node):
- """check that called functions/methods are inferred to callable objects,
- and that the arguments passed to the function match the parameters in
- the inferred function's definition
- """
- called = safe_infer(node.func)
- # only function, generator and object defining __call__ are allowed
- # Ignore instances of descriptors since astroid cannot properly handle them
- # yet
- if called and not called.callable():
- if isinstance(called, astroid.Instance) and (
- not has_known_bases(called)
- or (
- called.parent is not None
- and isinstance(called.scope(), astroid.ClassDef)
- and "__get__" in called.locals
- )
- ):
- # Don't emit if we can't make sure this object is callable.
- pass
- else:
- self.add_message("not-callable", node=node, args=node.func.as_string())
-
- self._check_uninferable_call(node)
- try:
- called, implicit_args, callable_name = _determine_callable(called)
- except ValueError:
- # Any error occurred during determining the function type, most of
- # those errors are handled by different warnings.
- return
-
- if called.args.args is None:
- # Built-in functions have no argument information.
- return
-
- if len(called.argnames()) != len(set(called.argnames())):
- # Duplicate parameter name (see duplicate-argument). We can't really
- # make sense of the function call in this case, so just return.
- return
-
- # Build the set of keyword arguments, checking for duplicate keywords,
- # and count the positional arguments.
- call_site = astroid.arguments.CallSite.from_call(node)
-
- # Warn about duplicated keyword arguments, such as `f=24, **{'f': 24}`
- for keyword in call_site.duplicated_keywords:
- self.add_message("repeated-keyword", node=node, args=(keyword,))
-
- if call_site.has_invalid_arguments() or call_site.has_invalid_keywords():
- # Can't make sense of this.
- return
-
- # Has the function signature changed in ways we cannot reliably detect?
- if hasattr(called, "decorators") and decorated_with(
- called, self.config.signature_mutators
- ):
- return
-
- num_positional_args = len(call_site.positional_arguments)
- keyword_args = list(call_site.keyword_arguments.keys())
- overload_function = is_overload_stub(called)
-
- # Determine if we don't have a context for our call and we use variadics.
- node_scope = node.scope()
- if isinstance(node_scope, (astroid.Lambda, astroid.FunctionDef)):
- has_no_context_positional_variadic = _no_context_variadic_positional(
- node, node_scope
- )
- has_no_context_keywords_variadic = _no_context_variadic_keywords(
- node, node_scope
- )
- else:
- has_no_context_positional_variadic = (
- has_no_context_keywords_variadic
- ) = False
-
- # These are coming from the functools.partial implementation in astroid
- already_filled_positionals = getattr(called, "filled_positionals", 0)
- already_filled_keywords = getattr(called, "filled_keywords", {})
-
- keyword_args += list(already_filled_keywords)
- num_positional_args += implicit_args + already_filled_positionals
-
- # Analyze the list of formal parameters.
- args = list(itertools.chain(called.args.posonlyargs or (), called.args.args))
- num_mandatory_parameters = len(args) - len(called.args.defaults)
- parameters = []
- parameter_name_to_index = {}
- for i, arg in enumerate(args):
- if isinstance(arg, astroid.Tuple):
- name = None
- # Don't store any parameter names within the tuple, since those
- # are not assignable from keyword arguments.
- else:
- assert isinstance(arg, astroid.AssignName)
- # This occurs with:
- # def f( (a), (b) ): pass
- name = arg.name
- parameter_name_to_index[name] = i
- if i >= num_mandatory_parameters:
- defval = called.args.defaults[i - num_mandatory_parameters]
- else:
- defval = None
- parameters.append([(name, defval), False])
-
- kwparams = {}
- for i, arg in enumerate(called.args.kwonlyargs):
- if isinstance(arg, astroid.Keyword):
- name = arg.arg
- else:
- assert isinstance(arg, astroid.AssignName)
- name = arg.name
- kwparams[name] = [called.args.kw_defaults[i], False]
-
- self._check_argument_order(
- node, call_site, called, [p[0][0] for p in parameters]
- )
-
- # 1. Match the positional arguments.
- for i in range(num_positional_args):
- if i < len(parameters):
- parameters[i][1] = True
- elif called.args.vararg is not None:
- # The remaining positional arguments get assigned to the *args
- # parameter.
- break
- else:
- if not overload_function:
- # Too many positional arguments.
- self.add_message(
- "too-many-function-args", node=node, args=(callable_name,)
- )
- break
-
- # 2. Match the keyword arguments.
- for keyword in keyword_args:
- if keyword in parameter_name_to_index:
- i = parameter_name_to_index[keyword]
- if parameters[i][1]:
- # Duplicate definition of function parameter.
-
- # Might be too hardcoded, but this can actually
- # happen when using str.format and `self` is passed
- # by keyword argument, as in `.format(self=self)`.
- # It's perfectly valid to so, so we're just skipping
- # it if that's the case.
- if not (keyword == "self" and called.qname() in STR_FORMAT):
- self.add_message(
- "redundant-keyword-arg",
- node=node,
- args=(keyword, callable_name),
- )
- else:
- parameters[i][1] = True
- elif keyword in kwparams:
- if kwparams[keyword][1]:
- # Duplicate definition of function parameter.
- self.add_message(
- "redundant-keyword-arg",
- node=node,
- args=(keyword, callable_name),
- )
- else:
- kwparams[keyword][1] = True
- elif called.args.kwarg is not None:
- # The keyword argument gets assigned to the **kwargs parameter.
- pass
- elif not overload_function:
- # Unexpected keyword argument.
- self.add_message(
- "unexpected-keyword-arg", node=node, args=(keyword, callable_name)
- )
-
- # 3. Match the **kwargs, if any.
- if node.kwargs:
- for i, [(name, defval), assigned] in enumerate(parameters):
- # Assume that *kwargs provides values for all remaining
- # unassigned named parameters.
- if name is not None:
- parameters[i][1] = True
- else:
- # **kwargs can't assign to tuples.
- pass
-
- # Check that any parameters without a default have been assigned
- # values.
- for [(name, defval), assigned] in parameters:
- if (defval is None) and not assigned:
- if name is None:
- display_name = "<tuple>"
- else:
- display_name = repr(name)
- if not has_no_context_positional_variadic and not overload_function:
- self.add_message(
- "no-value-for-parameter",
- node=node,
- args=(display_name, callable_name),
- )
-
- for name in kwparams:
- defval, assigned = kwparams[name]
- if defval is None and not assigned and not has_no_context_keywords_variadic:
- self.add_message("missing-kwoa", node=node, args=(name, callable_name))
-
- @check_messages("invalid-sequence-index")
- def visit_extslice(self, node):
- # Check extended slice objects as if they were used as a sequence
- # index to check if the object being sliced can support them
- return self.visit_index(node)
-
- @check_messages("invalid-sequence-index")
- def visit_index(self, node):
- if not node.parent or not hasattr(node.parent, "value"):
- return None
- # Look for index operations where the parent is a sequence type.
- # If the types can be determined, only allow indices to be int,
- # slice or instances with __index__.
- parent_type = safe_infer(node.parent.value)
- if not isinstance(
- parent_type, (astroid.ClassDef, astroid.Instance)
- ) or not has_known_bases(parent_type):
- return None
-
- # Determine what method on the parent this index will use
- # The parent of this node will be a Subscript, and the parent of that
- # node determines if the Subscript is a get, set, or delete operation.
- if node.parent.ctx is astroid.Store:
- methodname = "__setitem__"
- elif node.parent.ctx is astroid.Del:
- methodname = "__delitem__"
- else:
- methodname = "__getitem__"
-
- # Check if this instance's __getitem__, __setitem__, or __delitem__, as
- # appropriate to the statement, is implemented in a builtin sequence
- # type. This way we catch subclasses of sequence types but skip classes
- # that override __getitem__ and which may allow non-integer indices.
- try:
- methods = dunder_lookup.lookup(parent_type, methodname)
- if methods is astroid.Uninferable:
- return None
- itemmethod = methods[0]
- except (
- exceptions.NotFoundError,
- exceptions.AttributeInferenceError,
- IndexError,
- ):
- return None
-
- if (
- not isinstance(itemmethod, astroid.FunctionDef)
- or itemmethod.root().name != BUILTINS
- or not itemmethod.parent
- or itemmethod.parent.name not in SEQUENCE_TYPES
- ):
- return None
-
- # For ExtSlice objects coming from visit_extslice, no further
- # inference is necessary, since if we got this far the ExtSlice
- # is an error.
- if isinstance(node, astroid.ExtSlice):
- index_type = node
- else:
- index_type = safe_infer(node)
- if index_type is None or index_type is astroid.Uninferable:
- return None
- # Constants must be of type int
- if isinstance(index_type, astroid.Const):
- if isinstance(index_type.value, int):
- return None
- # Instance values must be int, slice, or have an __index__ method
- elif isinstance(index_type, astroid.Instance):
- if index_type.pytype() in (BUILTINS + ".int", BUILTINS + ".slice"):
- return None
- try:
- index_type.getattr("__index__")
- return None
- except exceptions.NotFoundError:
- pass
- elif isinstance(index_type, astroid.Slice):
- # Delegate to visit_slice. A slice can be present
- # here after inferring the index node, which could
- # be a `slice(...)` call for instance.
- return self.visit_slice(index_type)
-
- # Anything else is an error
- self.add_message("invalid-sequence-index", node=node)
- return None
-
- @check_messages("invalid-slice-index")
- def visit_slice(self, node):
- # Check the type of each part of the slice
- invalid_slices = 0
- for index in (node.lower, node.upper, node.step):
- if index is None:
- continue
-
- index_type = safe_infer(index)
- if index_type is None or index_type is astroid.Uninferable:
- continue
-
- # Constants must of type int or None
- if isinstance(index_type, astroid.Const):
- if isinstance(index_type.value, (int, type(None))):
- continue
- # Instance values must be of type int, None or an object
- # with __index__
- elif isinstance(index_type, astroid.Instance):
- if index_type.pytype() in (BUILTINS + ".int", BUILTINS + ".NoneType"):
- continue
-
- try:
- index_type.getattr("__index__")
- return
- except exceptions.NotFoundError:
- pass
- invalid_slices += 1
-
- if not invalid_slices:
- return
-
- # Anything else is an error, unless the object that is indexed
- # is a custom object, which knows how to handle this kind of slices
- parent = node.parent
- if isinstance(parent, astroid.ExtSlice):
- parent = parent.parent
- if isinstance(parent, astroid.Subscript):
- inferred = safe_infer(parent.value)
- if inferred is None or inferred is astroid.Uninferable:
- # Don't know what this is
- return
- known_objects = (
- astroid.List,
- astroid.Dict,
- astroid.Tuple,
- astroid.objects.FrozenSet,
- astroid.Set,
- )
- if not isinstance(inferred, known_objects):
- # Might be an instance that knows how to handle this slice object
- return
- for _ in range(invalid_slices):
- self.add_message("invalid-slice-index", node=node)
-
- @check_messages("not-context-manager")
- def visit_with(self, node):
- for ctx_mgr, _ in node.items:
- context = astroid.context.InferenceContext()
- inferred = safe_infer(ctx_mgr, context=context)
- if inferred is None or inferred is astroid.Uninferable:
- continue
-
- if isinstance(inferred, bases.Generator):
- # Check if we are dealing with a function decorated
- # with contextlib.contextmanager.
- if decorated_with(
- inferred.parent, self.config.contextmanager_decorators
- ):
- continue
- # If the parent of the generator is not the context manager itself,
- # that means that it could have been returned from another
- # function which was the real context manager.
- # The following approach is more of a hack rather than a real
- # solution: walk all the inferred statements for the
- # given *ctx_mgr* and if you find one function scope
- # which is decorated, consider it to be the real
- # manager and give up, otherwise emit not-context-manager.
- # See the test file for not_context_manager for a couple
- # of self explaining tests.
-
- # Retrieve node from all previusly visited nodes in the the inference history
- context_path_names = filter(None, _unflatten(context.path))
- inferred_paths = _flatten_container(
- safe_infer(path) for path in context_path_names
- )
- for inferred_path in inferred_paths:
- if not inferred_path:
- continue
- scope = inferred_path.scope()
- if not isinstance(scope, astroid.FunctionDef):
- continue
- if decorated_with(scope, self.config.contextmanager_decorators):
- break
- else:
- self.add_message(
- "not-context-manager", node=node, args=(inferred.name,)
- )
- else:
- try:
- inferred.getattr("__enter__")
- inferred.getattr("__exit__")
- except exceptions.NotFoundError:
- if isinstance(inferred, astroid.Instance):
- # If we do not know the bases of this class,
- # just skip it.
- if not has_known_bases(inferred):
- continue
- # Just ignore mixin classes.
- if self.config.ignore_mixin_members:
- if inferred.name[-5:].lower() == "mixin":
- continue
-
- self.add_message(
- "not-context-manager", node=node, args=(inferred.name,)
- )
-
- @check_messages("invalid-unary-operand-type")
- def visit_unaryop(self, node):
- """Detect TypeErrors for unary operands."""
-
- for error in node.type_errors():
- # Let the error customize its output.
- self.add_message("invalid-unary-operand-type", args=str(error), node=node)
-
- @check_messages("unsupported-binary-operation")
- def _visit_binop(self, node):
- """Detect TypeErrors for binary arithmetic operands."""
- self._check_binop_errors(node)
-
- @check_messages("unsupported-binary-operation")
- def _visit_augassign(self, node):
- """Detect TypeErrors for augmented binary arithmetic operands."""
- self._check_binop_errors(node)
-
- def _check_binop_errors(self, node):
- for error in node.type_errors():
- # Let the error customize its output.
- if any(
- isinstance(obj, astroid.ClassDef) and not has_known_bases(obj)
- for obj in (error.left_type, error.right_type)
- ):
- continue
- self.add_message("unsupported-binary-operation", args=str(error), node=node)
-
- def _check_membership_test(self, node):
- if is_inside_abstract_class(node):
- return
- if is_comprehension(node):
- return
- inferred = safe_infer(node)
- if inferred is None or inferred is astroid.Uninferable:
- return
- if not supports_membership_test(inferred):
- self.add_message(
- "unsupported-membership-test", args=node.as_string(), node=node
- )
-
- @check_messages("unsupported-membership-test")
- def visit_compare(self, node):
- if len(node.ops) != 1:
- return
-
- op, right = node.ops[0]
- if op in ["in", "not in"]:
- self._check_membership_test(right)
-
- @check_messages(
- "unsubscriptable-object",
- "unsupported-assignment-operation",
- "unsupported-delete-operation",
- "unhashable-dict-key",
- )
- def visit_subscript(self, node):
- supported_protocol = None
- if isinstance(node.value, (astroid.ListComp, astroid.DictComp)):
- return
-
- if isinstance(node.value, astroid.Dict):
- # Assert dict key is hashable
- inferred = safe_infer(node.slice.value)
- if inferred not in (None, astroid.Uninferable):
- try:
- hash_fn = next(inferred.igetattr("__hash__"))
- except astroid.InferenceError:
- pass
- else:
- if getattr(hash_fn, "value", True) is None:
- self.add_message("unhashable-dict-key", node=node.value)
-
- if node.ctx == astroid.Load:
- supported_protocol = supports_getitem
- msg = "unsubscriptable-object"
- elif node.ctx == astroid.Store:
- supported_protocol = supports_setitem
- msg = "unsupported-assignment-operation"
- elif node.ctx == astroid.Del:
- supported_protocol = supports_delitem
- msg = "unsupported-delete-operation"
-
- if isinstance(node.value, astroid.SetComp):
- self.add_message(msg, args=node.value.as_string(), node=node.value)
- return
-
- if is_inside_abstract_class(node):
- return
-
- inferred = safe_infer(node.value)
- if inferred is None or inferred is astroid.Uninferable:
- return
-
- if not supported_protocol(inferred):
- self.add_message(msg, args=node.value.as_string(), node=node.value)
-
- @check_messages("dict-items-missing-iter")
- def visit_for(self, node):
- if not isinstance(node.target, astroid.node_classes.Tuple):
- # target is not a tuple
- return
- if not len(node.target.elts) == 2:
- # target is not a tuple of two elements
- return
-
- iterable = node.iter
- if not isinstance(iterable, astroid.node_classes.Name):
- # it's not a bare variable
- return
-
- inferred = safe_infer(iterable)
- if not inferred:
- return
- if not isinstance(inferred, astroid.node_classes.Dict):
- # the iterable is not a dict
- return
-
- self.add_message("dict-iter-missing-items", node=node)
-
-
-class IterableChecker(BaseChecker):
- """
- Checks for non-iterables used in an iterable context.
- Contexts include:
- - for-statement
- - starargs in function call
- - `yield from`-statement
- - list, dict and set comprehensions
- - generator expressions
- Also checks for non-mappings in function call kwargs.
- """
-
- __implements__ = (IAstroidChecker,)
- name = "typecheck"
-
- msgs = {
- "E1133": (
- "Non-iterable value %s is used in an iterating context",
- "not-an-iterable",
- "Used when a non-iterable value is used in place where "
- "iterable is expected",
- ),
- "E1134": (
- "Non-mapping value %s is used in a mapping context",
- "not-a-mapping",
- "Used when a non-mapping value is used in place where "
- "mapping is expected",
- ),
- }
-
- @staticmethod
- def _is_asyncio_coroutine(node):
- if not isinstance(node, astroid.Call):
- return False
-
- inferred_func = safe_infer(node.func)
- if not isinstance(inferred_func, astroid.FunctionDef):
- return False
- if not inferred_func.decorators:
- return False
- for decorator in inferred_func.decorators.nodes:
- inferred_decorator = safe_infer(decorator)
- if not isinstance(inferred_decorator, astroid.FunctionDef):
- continue
- if inferred_decorator.qname() != ASYNCIO_COROUTINE:
- continue
- return True
- return False
-
- def _check_iterable(self, node, check_async=False):
- if is_inside_abstract_class(node) or is_comprehension(node):
- return
- inferred = safe_infer(node)
- if not inferred:
- return
- if not is_iterable(inferred, check_async=check_async):
- self.add_message("not-an-iterable", args=node.as_string(), node=node)
-
- def _check_mapping(self, node):
- if is_inside_abstract_class(node):
- return
- if isinstance(node, astroid.DictComp):
- return
- inferred = safe_infer(node)
- if inferred is None or inferred is astroid.Uninferable:
- return
- if not is_mapping(inferred):
- self.add_message("not-a-mapping", args=node.as_string(), node=node)
-
- @check_messages("not-an-iterable")
- def visit_for(self, node):
- self._check_iterable(node.iter)
-
- @check_messages("not-an-iterable")
- def visit_asyncfor(self, node):
- self._check_iterable(node.iter, check_async=True)
-
- @check_messages("not-an-iterable")
- def visit_yieldfrom(self, node):
- if self._is_asyncio_coroutine(node.value):
- return
- self._check_iterable(node.value)
-
- @check_messages("not-an-iterable", "not-a-mapping")
- def visit_call(self, node):
- for stararg in node.starargs:
- self._check_iterable(stararg.value)
- for kwarg in node.kwargs:
- self._check_mapping(kwarg.value)
-
- @check_messages("not-an-iterable")
- def visit_listcomp(self, node):
- for gen in node.generators:
- self._check_iterable(gen.iter, check_async=gen.is_async)
-
- @check_messages("not-an-iterable")
- def visit_dictcomp(self, node):
- for gen in node.generators:
- self._check_iterable(gen.iter, check_async=gen.is_async)
-
- @check_messages("not-an-iterable")
- def visit_setcomp(self, node):
- for gen in node.generators:
- self._check_iterable(gen.iter, check_async=gen.is_async)
-
- @check_messages("not-an-iterable")
- def visit_generatorexp(self, node):
- for gen in node.generators:
- self._check_iterable(gen.iter, check_async=gen.is_async)
-
-
-def register(linter):
- """required method to auto register this checker """
- linter.register_checker(TypeChecker(linter))
- linter.register_checker(IterableChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/checkers/utils.py b/venv/Lib/site-packages/pylint/checkers/utils.py
deleted file mode 100644
index 2a6820a..0000000
--- a/venv/Lib/site-packages/pylint/checkers/utils.py
+++ /dev/null
@@ -1,1253 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2007, 2009-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2009 Mads Kiilerich <mads@kiilerich.com>
-# Copyright (c) 2010 Daniel Harding <dharding@gmail.com>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com>
-# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Ricardo Gemignani <ricardo.gemignani@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Radu Ciorba <radu@devrandom.ro>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016, 2018 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2016-2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016-2017 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2016 Brian C. Lane <bcl@redhat.com>
-# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 ttenhoeve-aa <ttenhoeve@appannie.com>
-# Copyright (c) 2018 Bryce Guinta <bryce.guinta@protonmail.com>
-# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-# Copyright (c) 2018 Brian Shaginaw <brian.shaginaw@warbyparker.com>
-# Copyright (c) 2018 Caio Carrara <ccarrara@redhat.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""some functions that may be useful for various checkers
-"""
-import builtins
-import itertools
-import numbers
-import re
-import string
-from functools import lru_cache, partial
-from typing import Callable, Dict, Iterable, List, Match, Optional, Set, Tuple, Union
-
-import astroid
-from astroid import bases as _bases
-from astroid import helpers, scoped_nodes
-from astroid.exceptions import _NonDeducibleTypeHierarchy
-
-import _string # pylint: disable=wrong-import-position, wrong-import-order
-
-BUILTINS_NAME = builtins.__name__
-COMP_NODE_TYPES = (
- astroid.ListComp,
- astroid.SetComp,
- astroid.DictComp,
- astroid.GeneratorExp,
-)
-EXCEPTIONS_MODULE = "builtins"
-ABC_METHODS = {
- "abc.abstractproperty",
- "abc.abstractmethod",
- "abc.abstractclassmethod",
- "abc.abstractstaticmethod",
-}
-TYPING_PROTOCOLS = frozenset({"typing.Protocol", "typing_extensions.Protocol"})
-ITER_METHOD = "__iter__"
-AITER_METHOD = "__aiter__"
-NEXT_METHOD = "__next__"
-GETITEM_METHOD = "__getitem__"
-CLASS_GETITEM_METHOD = "__class_getitem__"
-SETITEM_METHOD = "__setitem__"
-DELITEM_METHOD = "__delitem__"
-CONTAINS_METHOD = "__contains__"
-KEYS_METHOD = "keys"
-
-# Dictionary which maps the number of expected parameters a
-# special method can have to a set of special methods.
-# The following keys are used to denote the parameters restrictions:
-#
-# * None: variable number of parameters
-# * number: exactly that number of parameters
-# * tuple: this are the odd ones. Basically it means that the function
-# can work with any number of arguments from that tuple,
-# although it's best to implement it in order to accept
-# all of them.
-_SPECIAL_METHODS_PARAMS = {
- None: ("__new__", "__init__", "__call__"),
- 0: (
- "__del__",
- "__repr__",
- "__str__",
- "__bytes__",
- "__hash__",
- "__bool__",
- "__dir__",
- "__len__",
- "__length_hint__",
- "__iter__",
- "__reversed__",
- "__neg__",
- "__pos__",
- "__abs__",
- "__invert__",
- "__complex__",
- "__int__",
- "__float__",
- "__neg__",
- "__pos__",
- "__abs__",
- "__complex__",
- "__int__",
- "__float__",
- "__index__",
- "__enter__",
- "__aenter__",
- "__getnewargs_ex__",
- "__getnewargs__",
- "__getstate__",
- "__reduce__",
- "__copy__",
- "__unicode__",
- "__nonzero__",
- "__await__",
- "__aiter__",
- "__anext__",
- "__fspath__",
- ),
- 1: (
- "__format__",
- "__lt__",
- "__le__",
- "__eq__",
- "__ne__",
- "__gt__",
- "__ge__",
- "__getattr__",
- "__getattribute__",
- "__delattr__",
- "__delete__",
- "__instancecheck__",
- "__subclasscheck__",
- "__getitem__",
- "__missing__",
- "__delitem__",
- "__contains__",
- "__add__",
- "__sub__",
- "__mul__",
- "__truediv__",
- "__floordiv__",
- "__rfloordiv__",
- "__mod__",
- "__divmod__",
- "__lshift__",
- "__rshift__",
- "__and__",
- "__xor__",
- "__or__",
- "__radd__",
- "__rsub__",
- "__rmul__",
- "__rtruediv__",
- "__rmod__",
- "__rdivmod__",
- "__rpow__",
- "__rlshift__",
- "__rrshift__",
- "__rand__",
- "__rxor__",
- "__ror__",
- "__iadd__",
- "__isub__",
- "__imul__",
- "__itruediv__",
- "__ifloordiv__",
- "__imod__",
- "__ilshift__",
- "__irshift__",
- "__iand__",
- "__ixor__",
- "__ior__",
- "__ipow__",
- "__setstate__",
- "__reduce_ex__",
- "__deepcopy__",
- "__cmp__",
- "__matmul__",
- "__rmatmul__",
- "__div__",
- ),
- 2: ("__setattr__", "__get__", "__set__", "__setitem__", "__set_name__"),
- 3: ("__exit__", "__aexit__"),
- (0, 1): ("__round__",),
-}
-
-SPECIAL_METHODS_PARAMS = {
- name: params
- for params, methods in _SPECIAL_METHODS_PARAMS.items()
- for name in methods # type: ignore
-}
-PYMETHODS = set(SPECIAL_METHODS_PARAMS)
-
-
-class NoSuchArgumentError(Exception):
- pass
-
-
-def is_inside_except(node):
- """Returns true if node is inside the name of an except handler."""
- current = node
- while current and not isinstance(current.parent, astroid.ExceptHandler):
- current = current.parent
-
- return current and current is current.parent.name
-
-
-def is_inside_lambda(node: astroid.node_classes.NodeNG) -> bool:
- """Return true if given node is inside lambda"""
- parent = node.parent
- while parent is not None:
- if isinstance(parent, astroid.Lambda):
- return True
- parent = parent.parent
- return False
-
-
-def get_all_elements(
- node: astroid.node_classes.NodeNG
-) -> Iterable[astroid.node_classes.NodeNG]:
- """Recursively returns all atoms in nested lists and tuples."""
- if isinstance(node, (astroid.Tuple, astroid.List)):
- for child in node.elts:
- yield from get_all_elements(child)
- else:
- yield node
-
-
-def clobber_in_except(
- node: astroid.node_classes.NodeNG
-) -> Tuple[bool, Optional[Tuple[str, str]]]:
- """Checks if an assignment node in an except handler clobbers an existing
- variable.
-
- Returns (True, args for W0623) if assignment clobbers an existing variable,
- (False, None) otherwise.
- """
- if isinstance(node, astroid.AssignAttr):
- return True, (node.attrname, "object %r" % (node.expr.as_string(),))
- if isinstance(node, astroid.AssignName):
- name = node.name
- if is_builtin(name):
- return True, (name, "builtins")
-
- stmts = node.lookup(name)[1]
- if stmts and not isinstance(
- stmts[0].assign_type(),
- (astroid.Assign, astroid.AugAssign, astroid.ExceptHandler),
- ):
- return True, (name, "outer scope (line %s)" % stmts[0].fromlineno)
- return False, None
-
-
-def is_super(node: astroid.node_classes.NodeNG) -> bool:
- """return True if the node is referencing the "super" builtin function
- """
- if getattr(node, "name", None) == "super" and node.root().name == BUILTINS_NAME:
- return True
- return False
-
-
-def is_error(node: astroid.node_classes.NodeNG) -> bool:
- """return true if the function does nothing but raising an exception"""
- raises = False
- returns = False
- for child_node in node.nodes_of_class((astroid.Raise, astroid.Return)):
- if isinstance(child_node, astroid.Raise):
- raises = True
- if isinstance(child_node, astroid.Return):
- returns = True
- return raises and not returns
-
-
-builtins = builtins.__dict__.copy() # type: ignore
-SPECIAL_BUILTINS = ("__builtins__",) # '__path__', '__file__')
-
-
-def is_builtin_object(node: astroid.node_classes.NodeNG) -> bool:
- """Returns True if the given node is an object from the __builtin__ module."""
- return node and node.root().name == BUILTINS_NAME
-
-
-def is_builtin(name: str) -> bool:
- """return true if <name> could be considered as a builtin defined by python
- """
- return name in builtins or name in SPECIAL_BUILTINS # type: ignore
-
-
-def is_defined_in_scope(
- var_node: astroid.node_classes.NodeNG,
- varname: str,
- scope: astroid.node_classes.NodeNG,
-) -> bool:
- if isinstance(scope, astroid.If):
- for node in scope.body:
- if (
- isinstance(node, astroid.Assign)
- and any(
- isinstance(target, astroid.AssignName) and target.name == varname
- for target in node.targets
- )
- ) or (isinstance(node, astroid.Nonlocal) and varname in node.names):
- return True
- elif isinstance(scope, (COMP_NODE_TYPES, astroid.For)):
- for ass_node in scope.nodes_of_class(astroid.AssignName):
- if ass_node.name == varname:
- return True
- elif isinstance(scope, astroid.With):
- for expr, ids in scope.items:
- if expr.parent_of(var_node):
- break
- if ids and isinstance(ids, astroid.AssignName) and ids.name == varname:
- return True
- elif isinstance(scope, (astroid.Lambda, astroid.FunctionDef)):
- if scope.args.is_argument(varname):
- # If the name is found inside a default value
- # of a function, then let the search continue
- # in the parent's tree.
- if scope.args.parent_of(var_node):
- try:
- scope.args.default_value(varname)
- scope = scope.parent
- is_defined_in_scope(var_node, varname, scope)
- except astroid.NoDefault:
- pass
- return True
- if getattr(scope, "name", None) == varname:
- return True
- elif isinstance(scope, astroid.ExceptHandler):
- if isinstance(scope.name, astroid.AssignName):
- ass_node = scope.name
- if ass_node.name == varname:
- return True
- return False
-
-
-def is_defined_before(var_node: astroid.node_classes.NodeNG) -> bool:
- """return True if the variable node is defined by a parent node (list,
- set, dict, or generator comprehension, lambda) or in a previous sibling
- node on the same line (statement_defining ; statement_using)
- """
- varname = var_node.name
- _node = var_node.parent
- while _node:
- if is_defined_in_scope(var_node, varname, _node):
- return True
- _node = _node.parent
- # possibly multiple statements on the same line using semi colon separator
- stmt = var_node.statement()
- _node = stmt.previous_sibling()
- lineno = stmt.fromlineno
- while _node and _node.fromlineno == lineno:
- for assign_node in _node.nodes_of_class(astroid.AssignName):
- if assign_node.name == varname:
- return True
- for imp_node in _node.nodes_of_class((astroid.ImportFrom, astroid.Import)):
- if varname in [name[1] or name[0] for name in imp_node.names]:
- return True
- _node = _node.previous_sibling()
- return False
-
-
-def is_default_argument(node: astroid.node_classes.NodeNG) -> bool:
- """return true if the given Name node is used in function or lambda
- default argument's value
- """
- parent = node.scope()
- if isinstance(parent, (astroid.FunctionDef, astroid.Lambda)):
- for default_node in parent.args.defaults:
- for default_name_node in default_node.nodes_of_class(astroid.Name):
- if default_name_node is node:
- return True
- return False
-
-
-def is_func_decorator(node: astroid.node_classes.NodeNG) -> bool:
- """return true if the name is used in function decorator"""
- parent = node.parent
- while parent is not None:
- if isinstance(parent, astroid.Decorators):
- return True
- if parent.is_statement or isinstance(
- parent,
- (astroid.Lambda, scoped_nodes.ComprehensionScope, scoped_nodes.ListComp),
- ):
- break
- parent = parent.parent
- return False
-
-
-def is_ancestor_name(
- frame: astroid.node_classes.NodeNG, node: astroid.node_classes.NodeNG
-) -> bool:
- """return True if `frame` is an astroid.Class node with `node` in the
- subtree of its bases attribute
- """
- try:
- bases = frame.bases
- except AttributeError:
- return False
- for base in bases:
- if node in base.nodes_of_class(astroid.Name):
- return True
- return False
-
-
-def assign_parent(node: astroid.node_classes.NodeNG) -> astroid.node_classes.NodeNG:
- """return the higher parent which is not an AssignName, Tuple or List node
- """
- while node and isinstance(node, (astroid.AssignName, astroid.Tuple, astroid.List)):
- node = node.parent
- return node
-
-
-def overrides_a_method(class_node: astroid.node_classes.NodeNG, name: str) -> bool:
- """return True if <name> is a method overridden from an ancestor"""
- for ancestor in class_node.ancestors():
- if name in ancestor and isinstance(ancestor[name], astroid.FunctionDef):
- return True
- return False
-
-
-def check_messages(*messages: str) -> Callable:
- """decorator to store messages that are handled by a checker method"""
-
- def store_messages(func):
- func.checks_msgs = messages
- return func
-
- return store_messages
-
-
-class IncompleteFormatString(Exception):
- """A format string ended in the middle of a format specifier."""
-
-
-class UnsupportedFormatCharacter(Exception):
- """A format character in a format string is not one of the supported
- format characters."""
-
- def __init__(self, index):
- Exception.__init__(self, index)
- self.index = index
-
-
-def parse_format_string(
- format_string: str
-) -> Tuple[Set[str], int, Dict[str, str], List[str]]:
- """Parses a format string, returning a tuple of (keys, num_args), where keys
- is the set of mapping keys in the format string, and num_args is the number
- of arguments required by the format string. Raises
- IncompleteFormatString or UnsupportedFormatCharacter if a
- parse error occurs."""
- keys = set()
- key_types = dict()
- pos_types = []
- num_args = 0
-
- def next_char(i):
- i += 1
- if i == len(format_string):
- raise IncompleteFormatString
- return (i, format_string[i])
-
- i = 0
- while i < len(format_string):
- char = format_string[i]
- if char == "%":
- i, char = next_char(i)
- # Parse the mapping key (optional).
- key = None
- if char == "(":
- depth = 1
- i, char = next_char(i)
- key_start = i
- while depth != 0:
- if char == "(":
- depth += 1
- elif char == ")":
- depth -= 1
- i, char = next_char(i)
- key_end = i - 1
- key = format_string[key_start:key_end]
-
- # Parse the conversion flags (optional).
- while char in "#0- +":
- i, char = next_char(i)
- # Parse the minimum field width (optional).
- if char == "*":
- num_args += 1
- i, char = next_char(i)
- else:
- while char in string.digits:
- i, char = next_char(i)
- # Parse the precision (optional).
- if char == ".":
- i, char = next_char(i)
- if char == "*":
- num_args += 1
- i, char = next_char(i)
- else:
- while char in string.digits:
- i, char = next_char(i)
- # Parse the length modifier (optional).
- if char in "hlL":
- i, char = next_char(i)
- # Parse the conversion type (mandatory).
- flags = "diouxXeEfFgGcrs%a"
- if char not in flags:
- raise UnsupportedFormatCharacter(i)
- if key:
- keys.add(key)
- key_types[key] = char
- elif char != "%":
- num_args += 1
- pos_types.append(char)
- i += 1
- return keys, num_args, key_types, pos_types
-
-
-def split_format_field_names(format_string) -> Tuple[str, Iterable[Tuple[bool, str]]]:
- try:
- return _string.formatter_field_name_split(format_string)
- except ValueError:
- raise IncompleteFormatString()
-
-
-def collect_string_fields(format_string) -> Iterable[Optional[str]]:
- """ Given a format string, return an iterator
- of all the valid format fields. It handles nested fields
- as well.
- """
- formatter = string.Formatter()
- try:
- parseiterator = formatter.parse(format_string)
- for result in parseiterator:
- if all(item is None for item in result[1:]):
- # not a replacement format
- continue
- name = result[1]
- nested = result[2]
- yield name
- if nested:
- for field in collect_string_fields(nested):
- yield field
- except ValueError as exc:
- # Probably the format string is invalid.
- if exc.args[0].startswith("cannot switch from manual"):
- # On Jython, parsing a string with both manual
- # and automatic positions will fail with a ValueError,
- # while on CPython it will simply return the fields,
- # the validation being done in the interpreter (?).
- # We're just returning two mixed fields in order
- # to trigger the format-combined-specification check.
- yield ""
- yield "1"
- return
- raise IncompleteFormatString(format_string)
-
-
-def parse_format_method_string(
- format_string: str
-) -> Tuple[List[Tuple[str, List[Tuple[bool, str]]]], int, int]:
- """
- Parses a PEP 3101 format string, returning a tuple of
- (keyword_arguments, implicit_pos_args_cnt, explicit_pos_args),
- where keyword_arguments is the set of mapping keys in the format string, implicit_pos_args_cnt
- is the number of arguments required by the format string and
- explicit_pos_args is the number of arguments passed with the position.
- """
- keyword_arguments = []
- implicit_pos_args_cnt = 0
- explicit_pos_args = set()
- for name in collect_string_fields(format_string):
- if name and str(name).isdigit():
- explicit_pos_args.add(str(name))
- elif name:
- keyname, fielditerator = split_format_field_names(name)
- if isinstance(keyname, numbers.Number):
- # In Python 2 it will return long which will lead
- # to different output between 2 and 3
- explicit_pos_args.add(str(keyname))
- keyname = int(keyname)
- try:
- keyword_arguments.append((keyname, list(fielditerator)))
- except ValueError:
- raise IncompleteFormatString()
- else:
- implicit_pos_args_cnt += 1
- return keyword_arguments, implicit_pos_args_cnt, len(explicit_pos_args)
-
-
-def is_attr_protected(attrname: str) -> bool:
- """return True if attribute name is protected (start with _ and some other
- details), False otherwise.
- """
- return (
- attrname[0] == "_"
- and attrname != "_"
- and not (attrname.startswith("__") and attrname.endswith("__"))
- )
-
-
-def node_frame_class(node: astroid.node_classes.NodeNG) -> Optional[astroid.ClassDef]:
- """Return the class that is wrapping the given node
-
- The function returns a class for a method node (or a staticmethod or a
- classmethod), otherwise it returns `None`.
- """
- klass = node.frame()
-
- while klass is not None and not isinstance(klass, astroid.ClassDef):
- if klass.parent is None:
- klass = None
- else:
- klass = klass.parent.frame()
-
- return klass
-
-
-def is_attr_private(attrname: str) -> Optional[Match[str]]:
- """Check that attribute name is private (at least two leading underscores,
- at most one trailing underscore)
- """
- regex = re.compile("^_{2,}.*[^_]+_?$")
- return regex.match(attrname)
-
-
-def get_argument_from_call(
- call_node: astroid.Call, position: int = None, keyword: str = None
-) -> astroid.Name:
- """Returns the specified argument from a function call.
-
- :param astroid.Call call_node: Node representing a function call to check.
- :param int position: position of the argument.
- :param str keyword: the keyword of the argument.
-
- :returns: The node representing the argument, None if the argument is not found.
- :rtype: astroid.Name
- :raises ValueError: if both position and keyword are None.
- :raises NoSuchArgumentError: if no argument at the provided position or with
- the provided keyword.
- """
- if position is None and keyword is None:
- raise ValueError("Must specify at least one of: position or keyword.")
- if position is not None:
- try:
- return call_node.args[position]
- except IndexError:
- pass
- if keyword and call_node.keywords:
- for arg in call_node.keywords:
- if arg.arg == keyword:
- return arg.value
-
- raise NoSuchArgumentError
-
-
-def inherit_from_std_ex(node: astroid.node_classes.NodeNG) -> bool:
- """
- Return true if the given class node is subclass of
- exceptions.Exception.
- """
- ancestors = node.ancestors() if hasattr(node, "ancestors") else []
- for ancestor in itertools.chain([node], ancestors):
- if (
- ancestor.name in ("Exception", "BaseException")
- and ancestor.root().name == EXCEPTIONS_MODULE
- ):
- return True
- return False
-
-
-def error_of_type(handler: astroid.ExceptHandler, error_type) -> bool:
- """
- Check if the given exception handler catches
- the given error_type.
-
- The *handler* parameter is a node, representing an ExceptHandler node.
- The *error_type* can be an exception, such as AttributeError,
- the name of an exception, or it can be a tuple of errors.
- The function will return True if the handler catches any of the
- given errors.
- """
-
- def stringify_error(error):
- if not isinstance(error, str):
- return error.__name__
- return error
-
- if not isinstance(error_type, tuple):
- error_type = (error_type,) # type: ignore
- expected_errors = {stringify_error(error) for error in error_type} # type: ignore
- if not handler.type:
- return True
- return handler.catch(expected_errors)
-
-
-def decorated_with_property(node: astroid.FunctionDef) -> bool:
- """Detect if the given function node is decorated with a property. """
- if not node.decorators:
- return False
- for decorator in node.decorators.nodes:
- try:
- if _is_property_decorator(decorator):
- return True
- except astroid.InferenceError:
- pass
- return False
-
-
-def _is_property_kind(node, *kinds):
- if not isinstance(node, (astroid.UnboundMethod, astroid.FunctionDef)):
- return False
- if node.decorators:
- for decorator in node.decorators.nodes:
- if isinstance(decorator, astroid.Attribute) and decorator.attrname in kinds:
- return True
- return False
-
-
-def is_property_setter(node: astroid.FunctionDef) -> bool:
- """Check if the given node is a property setter"""
- return _is_property_kind(node, "setter")
-
-
-def is_property_setter_or_deleter(node: astroid.FunctionDef) -> bool:
- """Check if the given node is either a property setter or a deleter"""
- return _is_property_kind(node, "setter", "deleter")
-
-
-def _is_property_decorator(decorator: astroid.Name) -> bool:
- for inferred in decorator.infer():
- if isinstance(inferred, astroid.ClassDef):
- if inferred.root().name == BUILTINS_NAME and inferred.name == "property":
- return True
- for ancestor in inferred.ancestors():
- if (
- ancestor.name == "property"
- and ancestor.root().name == BUILTINS_NAME
- ):
- return True
- return False
-
-
-def decorated_with(
- func: Union[astroid.FunctionDef, astroid.BoundMethod, astroid.UnboundMethod],
- qnames: Iterable[str],
-) -> bool:
- """Determine if the `func` node has a decorator with the qualified name `qname`."""
- decorators = func.decorators.nodes if func.decorators else []
- for decorator_node in decorators:
- if isinstance(decorator_node, astroid.Call):
- # We only want to infer the function name
- decorator_node = decorator_node.func
- try:
- if any(
- i is not None and i.qname() in qnames or i.name in qnames
- for i in decorator_node.infer()
- ):
- return True
- except astroid.InferenceError:
- continue
- return False
-
-
-@lru_cache(maxsize=1024)
-def unimplemented_abstract_methods(
- node: astroid.node_classes.NodeNG, is_abstract_cb: astroid.FunctionDef = None
-) -> Dict[str, astroid.node_classes.NodeNG]:
- """
- Get the unimplemented abstract methods for the given *node*.
-
- A method can be considered abstract if the callback *is_abstract_cb*
- returns a ``True`` value. The check defaults to verifying that
- a method is decorated with abstract methods.
- The function will work only for new-style classes. For old-style
- classes, it will simply return an empty dictionary.
- For the rest of them, it will return a dictionary of abstract method
- names and their inferred objects.
- """
- if is_abstract_cb is None:
- is_abstract_cb = partial(decorated_with, qnames=ABC_METHODS)
- visited = {} # type: Dict[str, astroid.node_classes.NodeNG]
- try:
- mro = reversed(node.mro())
- except NotImplementedError:
- # Old style class, it will not have a mro.
- return {}
- except astroid.ResolveError:
- # Probably inconsistent hierarchy, don'try
- # to figure this out here.
- return {}
- for ancestor in mro:
- for obj in ancestor.values():
- inferred = obj
- if isinstance(obj, astroid.AssignName):
- inferred = safe_infer(obj)
- if not inferred:
- # Might be an abstract function,
- # but since we don't have enough information
- # in order to take this decision, we're taking
- # the *safe* decision instead.
- if obj.name in visited:
- del visited[obj.name]
- continue
- if not isinstance(inferred, astroid.FunctionDef):
- if obj.name in visited:
- del visited[obj.name]
- if isinstance(inferred, astroid.FunctionDef):
- # It's critical to use the original name,
- # since after inferring, an object can be something
- # else than expected, as in the case of the
- # following assignment.
- #
- # class A:
- # def keys(self): pass
- # __iter__ = keys
- abstract = is_abstract_cb(inferred)
- if abstract:
- visited[obj.name] = inferred
- elif not abstract and obj.name in visited:
- del visited[obj.name]
- return visited
-
-
-def find_try_except_wrapper_node(
- node: astroid.node_classes.NodeNG
-) -> Union[astroid.ExceptHandler, astroid.TryExcept]:
- """Return the ExceptHandler or the TryExcept node in which the node is."""
- current = node
- ignores = (astroid.ExceptHandler, astroid.TryExcept)
- while current and not isinstance(current.parent, ignores):
- current = current.parent
-
- if current and isinstance(current.parent, ignores):
- return current.parent
- return None
-
-
-def is_from_fallback_block(node: astroid.node_classes.NodeNG) -> bool:
- """Check if the given node is from a fallback import block."""
- context = find_try_except_wrapper_node(node)
- if not context:
- return False
-
- if isinstance(context, astroid.ExceptHandler):
- other_body = context.parent.body
- handlers = context.parent.handlers
- else:
- other_body = itertools.chain.from_iterable(
- handler.body for handler in context.handlers
- )
- handlers = context.handlers
-
- has_fallback_imports = any(
- isinstance(import_node, (astroid.ImportFrom, astroid.Import))
- for import_node in other_body
- )
- ignores_import_error = _except_handlers_ignores_exception(handlers, ImportError)
- return ignores_import_error or has_fallback_imports
-
-
-def _except_handlers_ignores_exception(
- handlers: astroid.ExceptHandler, exception
-) -> bool:
- func = partial(error_of_type, error_type=(exception,))
- return any(map(func, handlers))
-
-
-def get_exception_handlers(
- node: astroid.node_classes.NodeNG, exception=Exception
-) -> Optional[List[astroid.ExceptHandler]]:
- """Return the collections of handlers handling the exception in arguments.
-
- Args:
- node (astroid.NodeNG): A node that is potentially wrapped in a try except.
- exception (builtin.Exception or str): exception or name of the exception.
-
- Returns:
- list: the collection of handlers that are handling the exception or None.
-
- """
- context = find_try_except_wrapper_node(node)
- if isinstance(context, astroid.TryExcept):
- return [
- handler for handler in context.handlers if error_of_type(handler, exception)
- ]
- return []
-
-
-def is_node_inside_try_except(node: astroid.Raise) -> bool:
- """Check if the node is directly under a Try/Except statement.
- (but not under an ExceptHandler!)
-
- Args:
- node (astroid.Raise): the node raising the exception.
-
- Returns:
- bool: True if the node is inside a try/except statement, False otherwise.
- """
- context = find_try_except_wrapper_node(node)
- return isinstance(context, astroid.TryExcept)
-
-
-def node_ignores_exception(
- node: astroid.node_classes.NodeNG, exception=Exception
-) -> bool:
- """Check if the node is in a TryExcept which handles the given exception.
-
- If the exception is not given, the function is going to look for bare
- excepts.
- """
- managing_handlers = get_exception_handlers(node, exception)
- if not managing_handlers:
- return False
- return any(managing_handlers)
-
-
-def class_is_abstract(node: astroid.ClassDef) -> bool:
- """return true if the given class node should be considered as an abstract
- class
- """
- for method in node.methods():
- if method.parent.frame() is node:
- if method.is_abstract(pass_is_abstract=False):
- return True
- return False
-
-
-def _supports_protocol_method(value: astroid.node_classes.NodeNG, attr: str) -> bool:
- try:
- attributes = value.getattr(attr)
- except astroid.NotFoundError:
- return False
-
- first = attributes[0]
- if isinstance(first, astroid.AssignName):
- if isinstance(first.parent.value, astroid.Const):
- return False
- return True
-
-
-def is_comprehension(node: astroid.node_classes.NodeNG) -> bool:
- comprehensions = (
- astroid.ListComp,
- astroid.SetComp,
- astroid.DictComp,
- astroid.GeneratorExp,
- )
- return isinstance(node, comprehensions)
-
-
-def _supports_mapping_protocol(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol_method(
- value, GETITEM_METHOD
- ) and _supports_protocol_method(value, KEYS_METHOD)
-
-
-def _supports_membership_test_protocol(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol_method(value, CONTAINS_METHOD)
-
-
-def _supports_iteration_protocol(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol_method(value, ITER_METHOD) or _supports_protocol_method(
- value, GETITEM_METHOD
- )
-
-
-def _supports_async_iteration_protocol(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol_method(value, AITER_METHOD)
-
-
-def _supports_getitem_protocol(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol_method(value, GETITEM_METHOD)
-
-
-def _supports_setitem_protocol(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol_method(value, SETITEM_METHOD)
-
-
-def _supports_delitem_protocol(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol_method(value, DELITEM_METHOD)
-
-
-def _is_abstract_class_name(name: str) -> bool:
- lname = name.lower()
- is_mixin = lname.endswith("mixin")
- is_abstract = lname.startswith("abstract")
- is_base = lname.startswith("base") or lname.endswith("base")
- return is_mixin or is_abstract or is_base
-
-
-def is_inside_abstract_class(node: astroid.node_classes.NodeNG) -> bool:
- while node is not None:
- if isinstance(node, astroid.ClassDef):
- if class_is_abstract(node):
- return True
- name = getattr(node, "name", None)
- if name is not None and _is_abstract_class_name(name):
- return True
- node = node.parent
- return False
-
-
-def _supports_protocol(
- value: astroid.node_classes.NodeNG, protocol_callback: astroid.FunctionDef
-) -> bool:
- if isinstance(value, astroid.ClassDef):
- if not has_known_bases(value):
- return True
- # classobj can only be iterable if it has an iterable metaclass
- meta = value.metaclass()
- if meta is not None:
- if protocol_callback(meta):
- return True
- if isinstance(value, astroid.BaseInstance):
- if not has_known_bases(value):
- return True
- if value.has_dynamic_getattr():
- return True
- if protocol_callback(value):
- return True
-
- if (
- isinstance(value, _bases.Proxy)
- and isinstance(value._proxied, astroid.BaseInstance)
- and has_known_bases(value._proxied)
- ):
- value = value._proxied
- return protocol_callback(value)
-
- return False
-
-
-def is_iterable(value: astroid.node_classes.NodeNG, check_async: bool = False) -> bool:
- if check_async:
- protocol_check = _supports_async_iteration_protocol
- else:
- protocol_check = _supports_iteration_protocol
- return _supports_protocol(value, protocol_check)
-
-
-def is_mapping(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol(value, _supports_mapping_protocol)
-
-
-def supports_membership_test(value: astroid.node_classes.NodeNG) -> bool:
- supported = _supports_protocol(value, _supports_membership_test_protocol)
- return supported or is_iterable(value)
-
-
-def supports_getitem(value: astroid.node_classes.NodeNG) -> bool:
- if isinstance(value, astroid.ClassDef):
- if _supports_protocol_method(value, CLASS_GETITEM_METHOD):
- return True
- return _supports_protocol(value, _supports_getitem_protocol)
-
-
-def supports_setitem(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol(value, _supports_setitem_protocol)
-
-
-def supports_delitem(value: astroid.node_classes.NodeNG) -> bool:
- return _supports_protocol(value, _supports_delitem_protocol)
-
-
-@lru_cache(maxsize=1024)
-def safe_infer(
- node: astroid.node_classes.NodeNG, context=None
-) -> Optional[astroid.node_classes.NodeNG]:
- """Return the inferred value for the given node.
-
- Return None if inference failed or if there is some ambiguity (more than
- one node has been inferred).
- """
- try:
- inferit = node.infer(context=context)
- value = next(inferit)
- except astroid.InferenceError:
- return None
- try:
- next(inferit)
- return None # None if there is ambiguity on the inferred node
- except astroid.InferenceError:
- return None # there is some kind of ambiguity
- except StopIteration:
- return value
-
-
-def has_known_bases(klass: astroid.ClassDef, context=None) -> bool:
- """Return true if all base classes of a class could be inferred."""
- try:
- return klass._all_bases_known
- except AttributeError:
- pass
- for base in klass.bases:
- result = safe_infer(base, context=context)
- if (
- not isinstance(result, astroid.ClassDef)
- or result is klass
- or not has_known_bases(result, context=context)
- ):
- klass._all_bases_known = False
- return False
- klass._all_bases_known = True
- return True
-
-
-def is_none(node: astroid.node_classes.NodeNG) -> bool:
- return (
- node is None
- or (isinstance(node, astroid.Const) and node.value is None)
- or (isinstance(node, astroid.Name) and node.name == "None")
- )
-
-
-def node_type(node: astroid.node_classes.NodeNG) -> Optional[type]:
- """Return the inferred type for `node`
-
- If there is more than one possible type, or if inferred type is Uninferable or None,
- return None
- """
- # check there is only one possible type for the assign node. Else we
- # don't handle it for now
- types = set()
- try:
- for var_type in node.infer():
- if var_type == astroid.Uninferable or is_none(var_type):
- continue
- types.add(var_type)
- if len(types) > 1:
- return None
- except astroid.InferenceError:
- return None
- return types.pop() if types else None
-
-
-def is_registered_in_singledispatch_function(node: astroid.FunctionDef) -> bool:
- """Check if the given function node is a singledispatch function."""
-
- singledispatch_qnames = (
- "functools.singledispatch",
- "singledispatch.singledispatch",
- )
-
- if not isinstance(node, astroid.FunctionDef):
- return False
-
- decorators = node.decorators.nodes if node.decorators else []
- for decorator in decorators:
- # func.register are function calls
- if not isinstance(decorator, astroid.Call):
- continue
-
- func = decorator.func
- if not isinstance(func, astroid.Attribute) or func.attrname != "register":
- continue
-
- try:
- func_def = next(func.expr.infer())
- except astroid.InferenceError:
- continue
-
- if isinstance(func_def, astroid.FunctionDef):
- # pylint: disable=redundant-keyword-arg; some flow inference goes wrong here
- return decorated_with(func_def, singledispatch_qnames)
-
- return False
-
-
-def get_node_last_lineno(node: astroid.node_classes.NodeNG) -> int:
- """
- Get the last lineno of the given node. For a simple statement this will just be node.lineno,
- but for a node that has child statements (e.g. a method) this will be the lineno of the last
- child statement recursively.
- """
- # 'finalbody' is always the last clause in a try statement, if present
- if getattr(node, "finalbody", False):
- return get_node_last_lineno(node.finalbody[-1])
- # For if, while, and for statements 'orelse' is always the last clause.
- # For try statements 'orelse' is the last in the absence of a 'finalbody'
- if getattr(node, "orelse", False):
- return get_node_last_lineno(node.orelse[-1])
- # try statements have the 'handlers' last if there is no 'orelse' or 'finalbody'
- if getattr(node, "handlers", False):
- return get_node_last_lineno(node.handlers[-1])
- # All compound statements have a 'body'
- if getattr(node, "body", False):
- return get_node_last_lineno(node.body[-1])
- # Not a compound statement
- return node.lineno
-
-
-def is_postponed_evaluation_enabled(node: astroid.node_classes.NodeNG) -> bool:
- """Check if the postponed evaluation of annotations is enabled"""
- name = "annotations"
- module = node.root()
- stmt = module.locals.get(name)
- return (
- stmt
- and isinstance(stmt[0], astroid.ImportFrom)
- and stmt[0].modname == "__future__"
- )
-
-
-def is_subclass_of(child: astroid.ClassDef, parent: astroid.ClassDef) -> bool:
- """
- Check if first node is a subclass of second node.
- :param child: Node to check for subclass.
- :param parent: Node to check for superclass.
- :returns: True if child is derived from parent. False otherwise.
- """
- if not all(isinstance(node, astroid.ClassDef) for node in (child, parent)):
- return False
-
- for ancestor in child.ancestors():
- try:
- if helpers.is_subtype(ancestor, parent):
- return True
- except _NonDeducibleTypeHierarchy:
- continue
- return False
-
-
-@lru_cache(maxsize=1024)
-def is_overload_stub(node: astroid.node_classes.NodeNG) -> bool:
- """Check if a node if is a function stub decorated with typing.overload.
-
- :param node: Node to check.
- :returns: True if node is an overload function stub. False otherwise.
- """
- decorators = getattr(node, "decorators", None)
- return bool(decorators and decorated_with(node, ["typing.overload", "overload"]))
-
-
-def is_protocol_class(cls: astroid.node_classes.NodeNG) -> bool:
- """Check if the given node represents a protocol class
-
- :param cls: The node to check
- :returns: True if the node is a typing protocol class, false otherwise.
- """
- if not isinstance(cls, astroid.ClassDef):
- return False
-
- # Use .ancestors() since not all protocol classes can have
- # their mro deduced.
- return any(parent.qname() in TYPING_PROTOCOLS for parent in cls.ancestors())
diff --git a/venv/Lib/site-packages/pylint/checkers/variables.py b/venv/Lib/site-packages/pylint/checkers/variables.py
deleted file mode 100644
index e13f9b5..0000000
--- a/venv/Lib/site-packages/pylint/checkers/variables.py
+++ /dev/null
@@ -1,1987 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2009 Mads Kiilerich <mads@kiilerich.com>
-# Copyright (c) 2010 Daniel Harding <dharding@gmail.com>
-# Copyright (c) 2011-2014, 2017 Google, Inc.
-# Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com>
-# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Ricardo Gemignani <ricardo.gemignani@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
-# Copyright (c) 2015 Radu Ciorba <radu@devrandom.ro>
-# Copyright (c) 2015 Simu Toni <simutoni@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016, 2018 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2016, 2018 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com>
-# Copyright (c) 2016-2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Grant Welch <gwelch925+github@gmail.com>
-# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Dan Garrette <dhgarrette@gmail.com>
-# Copyright (c) 2018 Bryce Guinta <bryce.guinta@protonmail.com>
-# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Marianna Polatoglou <mpolatoglou@bloomberg.net>
-# Copyright (c) 2018 mar-chi-pan <mar.polatoglou@gmail.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""variables checkers for Python code
-"""
-import collections
-import copy
-import itertools
-import os
-import re
-from functools import lru_cache
-
-import astroid
-from astroid import decorators, modutils, objects
-from astroid.context import InferenceContext
-
-from pylint.checkers import BaseChecker, utils
-from pylint.checkers.utils import is_postponed_evaluation_enabled
-from pylint.interfaces import HIGH, INFERENCE, INFERENCE_FAILURE, IAstroidChecker
-from pylint.utils import get_global_option
-
-SPECIAL_OBJ = re.compile("^_{2}[a-z]+_{2}$")
-FUTURE = "__future__"
-# regexp for ignored argument name
-IGNORED_ARGUMENT_NAMES = re.compile("_.*|^ignored_|^unused_")
-# In Python 3.7 abc has a Python implementation which is preferred
-# by astroid. Unfortunately this also messes up our explicit checks
-# for `abc`
-METACLASS_NAME_TRANSFORMS = {"_py_abc": "abc"}
-TYPING_TYPE_CHECKS_GUARDS = frozenset({"typing.TYPE_CHECKING", "TYPE_CHECKING"})
-BUILTIN_RANGE = "builtins.range"
-TYPING_MODULE = "typing"
-TYPING_NAMES = frozenset(
- {
- "Any",
- "Callable",
- "ClassVar",
- "Generic",
- "Optional",
- "Tuple",
- "Type",
- "TypeVar",
- "Union",
- "AbstractSet",
- "ByteString",
- "Container",
- "ContextManager",
- "Hashable",
- "ItemsView",
- "Iterable",
- "Iterator",
- "KeysView",
- "Mapping",
- "MappingView",
- "MutableMapping",
- "MutableSequence",
- "MutableSet",
- "Sequence",
- "Sized",
- "ValuesView",
- "Awaitable",
- "AsyncIterator",
- "AsyncIterable",
- "Coroutine",
- "Collection",
- "AsyncGenerator",
- "AsyncContextManager",
- "Reversible",
- "SupportsAbs",
- "SupportsBytes",
- "SupportsComplex",
- "SupportsFloat",
- "SupportsInt",
- "SupportsRound",
- "Counter",
- "Deque",
- "Dict",
- "DefaultDict",
- "List",
- "Set",
- "FrozenSet",
- "NamedTuple",
- "Generator",
- "AnyStr",
- "Text",
- "Pattern",
- }
-)
-
-
-def _is_from_future_import(stmt, name):
- """Check if the name is a future import from another module."""
- try:
- module = stmt.do_import_module(stmt.modname)
- except astroid.AstroidBuildingException:
- return None
-
- for local_node in module.locals.get(name, []):
- if isinstance(local_node, astroid.ImportFrom) and local_node.modname == FUTURE:
- return True
- return None
-
-
-def in_for_else_branch(parent, stmt):
- """Returns True if stmt in inside the else branch for a parent For stmt."""
- return isinstance(parent, astroid.For) and any(
- else_stmt.parent_of(stmt) or else_stmt == stmt for else_stmt in parent.orelse
- )
-
-
-@lru_cache(maxsize=1000)
-def overridden_method(klass, name):
- """get overridden method if any"""
- try:
- parent = next(klass.local_attr_ancestors(name))
- except (StopIteration, KeyError):
- return None
- try:
- meth_node = parent[name]
- except KeyError:
- # We have found an ancestor defining <name> but it's not in the local
- # dictionary. This may happen with astroid built from living objects.
- return None
- if isinstance(meth_node, astroid.FunctionDef):
- return meth_node
- return None
-
-
-def _get_unpacking_extra_info(node, inferred):
- """return extra information to add to the message for unpacking-non-sequence
- and unbalanced-tuple-unpacking errors
- """
- more = ""
- inferred_module = inferred.root().name
- if node.root().name == inferred_module:
- if node.lineno == inferred.lineno:
- more = " %s" % inferred.as_string()
- elif inferred.lineno:
- more = " defined at line %s" % inferred.lineno
- elif inferred.lineno:
- more = " defined at line %s of %s" % (inferred.lineno, inferred_module)
- return more
-
-
-def _detect_global_scope(node, frame, defframe):
- """ Detect that the given frames shares a global
- scope.
-
- Two frames shares a global scope when neither
- of them are hidden under a function scope, as well
- as any of parent scope of them, until the root scope.
- In this case, depending from something defined later on
- will not work, because it is still undefined.
-
- Example:
- class A:
- # B has the same global scope as `C`, leading to a NameError.
- class B(C): ...
- class C: ...
-
- """
- def_scope = scope = None
- if frame and frame.parent:
- scope = frame.parent.scope()
- if defframe and defframe.parent:
- def_scope = defframe.parent.scope()
- if isinstance(frame, astroid.FunctionDef):
- # If the parent of the current node is a
- # function, then it can be under its scope
- # (defined in, which doesn't concern us) or
- # the `->` part of annotations. The same goes
- # for annotations of function arguments, they'll have
- # their parent the Arguments node.
- if not isinstance(node.parent, (astroid.FunctionDef, astroid.Arguments)):
- return False
- elif any(
- not isinstance(f, (astroid.ClassDef, astroid.Module)) for f in (frame, defframe)
- ):
- # Not interested in other frames, since they are already
- # not in a global scope.
- return False
-
- break_scopes = []
- for current_scope in (scope, def_scope):
- # Look for parent scopes. If there is anything different
- # than a module or a class scope, then they frames don't
- # share a global scope.
- parent_scope = current_scope
- while parent_scope:
- if not isinstance(parent_scope, (astroid.ClassDef, astroid.Module)):
- break_scopes.append(parent_scope)
- break
- if parent_scope.parent:
- parent_scope = parent_scope.parent.scope()
- else:
- break
- if break_scopes and len(set(break_scopes)) != 1:
- # Store different scopes than expected.
- # If the stored scopes are, in fact, the very same, then it means
- # that the two frames (frame and defframe) shares the same scope,
- # and we could apply our lineno analysis over them.
- # For instance, this works when they are inside a function, the node
- # that uses a definition and the definition itself.
- return False
- # At this point, we are certain that frame and defframe shares a scope
- # and the definition of the first depends on the second.
- return frame.lineno < defframe.lineno
-
-
-def _infer_name_module(node, name):
- context = InferenceContext()
- context.lookupname = name
- return node.infer(context, asname=False)
-
-
-def _fix_dot_imports(not_consumed):
- """ Try to fix imports with multiple dots, by returning a dictionary
- with the import names expanded. The function unflattens root imports,
- like 'xml' (when we have both 'xml.etree' and 'xml.sax'), to 'xml.etree'
- and 'xml.sax' respectively.
- """
- names = {}
- for name, stmts in not_consumed.items():
- if any(
- isinstance(stmt, astroid.AssignName)
- and isinstance(stmt.assign_type(), astroid.AugAssign)
- for stmt in stmts
- ):
- continue
- for stmt in stmts:
- if not isinstance(stmt, (astroid.ImportFrom, astroid.Import)):
- continue
- for imports in stmt.names:
- second_name = None
- import_module_name = imports[0]
- if import_module_name == "*":
- # In case of wildcard imports,
- # pick the name from inside the imported module.
- second_name = name
- else:
- name_matches_dotted_import = False
- if (
- import_module_name.startswith(name)
- and import_module_name.find(".") > -1
- ):
- name_matches_dotted_import = True
-
- if name_matches_dotted_import or name in imports:
- # Most likely something like 'xml.etree',
- # which will appear in the .locals as 'xml'.
- # Only pick the name if it wasn't consumed.
- second_name = import_module_name
- if second_name and second_name not in names:
- names[second_name] = stmt
- return sorted(names.items(), key=lambda a: a[1].fromlineno)
-
-
-def _find_frame_imports(name, frame):
- """
- Detect imports in the frame, with the required
- *name*. Such imports can be considered assignments.
- Returns True if an import for the given name was found.
- """
- imports = frame.nodes_of_class((astroid.Import, astroid.ImportFrom))
- for import_node in imports:
- for import_name, import_alias in import_node.names:
- # If the import uses an alias, check only that.
- # Otherwise, check only the import name.
- if import_alias:
- if import_alias == name:
- return True
- elif import_name and import_name == name:
- return True
- return None
-
-
-def _import_name_is_global(stmt, global_names):
- for import_name, import_alias in stmt.names:
- # If the import uses an alias, check only that.
- # Otherwise, check only the import name.
- if import_alias:
- if import_alias in global_names:
- return True
- elif import_name in global_names:
- return True
- return False
-
-
-def _flattened_scope_names(iterator):
- values = (set(stmt.names) for stmt in iterator)
- return set(itertools.chain.from_iterable(values))
-
-
-def _assigned_locally(name_node):
- """
- Checks if name_node has corresponding assign statement in same scope
- """
- assign_stmts = name_node.scope().nodes_of_class(astroid.AssignName)
- return any(a.name == name_node.name for a in assign_stmts)
-
-
-def _is_type_checking_import(node):
- parent = node.parent
- if not isinstance(parent, astroid.If):
- return False
- test = parent.test
- return test.as_string() in TYPING_TYPE_CHECKS_GUARDS
-
-
-def _has_locals_call_after_node(stmt, scope):
- skip_nodes = (
- astroid.FunctionDef,
- astroid.ClassDef,
- astroid.Import,
- astroid.ImportFrom,
- )
- for call in scope.nodes_of_class(astroid.Call, skip_klass=skip_nodes):
- inferred = utils.safe_infer(call.func)
- if (
- utils.is_builtin_object(inferred)
- and getattr(inferred, "name", None) == "locals"
- ):
- if stmt.lineno < call.lineno:
- return True
- return False
-
-
-MSGS = {
- "E0601": (
- "Using variable %r before assignment",
- "used-before-assignment",
- "Used when a local variable is accessed before its assignment.",
- ),
- "E0602": (
- "Undefined variable %r",
- "undefined-variable",
- "Used when an undefined variable is accessed.",
- ),
- "E0603": (
- "Undefined variable name %r in __all__",
- "undefined-all-variable",
- "Used when an undefined variable name is referenced in __all__.",
- ),
- "E0604": (
- "Invalid object %r in __all__, must contain only strings",
- "invalid-all-object",
- "Used when an invalid (non-string) object occurs in __all__.",
- ),
- "E0611": (
- "No name %r in module %r",
- "no-name-in-module",
- "Used when a name cannot be found in a module.",
- ),
- "W0601": (
- "Global variable %r undefined at the module level",
- "global-variable-undefined",
- 'Used when a variable is defined through the "global" statement '
- "but the variable is not defined in the module scope.",
- ),
- "W0602": (
- "Using global for %r but no assignment is done",
- "global-variable-not-assigned",
- 'Used when a variable is defined through the "global" statement '
- "but no assignment to this variable is done.",
- ),
- "W0603": (
- "Using the global statement", # W0121
- "global-statement",
- 'Used when you use the "global" statement to update a global '
- "variable. Pylint just try to discourage this "
- "usage. That doesn't mean you cannot use it !",
- ),
- "W0604": (
- "Using the global statement at the module level", # W0103
- "global-at-module-level",
- 'Used when you use the "global" statement at the module level '
- "since it has no effect",
- ),
- "W0611": (
- "Unused %s",
- "unused-import",
- "Used when an imported module or variable is not used.",
- ),
- "W0612": (
- "Unused variable %r",
- "unused-variable",
- "Used when a variable is defined but not used.",
- ),
- "W0613": (
- "Unused argument %r",
- "unused-argument",
- "Used when a function or method argument is not used.",
- ),
- "W0614": (
- "Unused import %s from wildcard import",
- "unused-wildcard-import",
- "Used when an imported module or variable is not used from a "
- "`'from X import *'` style import.",
- ),
- "W0621": (
- "Redefining name %r from outer scope (line %s)",
- "redefined-outer-name",
- "Used when a variable's name hides a name defined in the outer scope.",
- ),
- "W0622": (
- "Redefining built-in %r",
- "redefined-builtin",
- "Used when a variable or function override a built-in.",
- ),
- "W0623": (
- "Redefining name %r from %s in exception handler",
- "redefine-in-handler",
- "Used when an exception handler assigns the exception to an existing name",
- ),
- "W0631": (
- "Using possibly undefined loop variable %r",
- "undefined-loop-variable",
- "Used when a loop variable (i.e. defined by a for loop or "
- "a list comprehension or a generator expression) is used outside "
- "the loop.",
- ),
- "W0632": (
- "Possible unbalanced tuple unpacking with "
- "sequence%s: "
- "left side has %d label(s), right side has %d value(s)",
- "unbalanced-tuple-unpacking",
- "Used when there is an unbalanced tuple unpacking in assignment",
- {"old_names": [("E0632", "old-unbalanced-tuple-unpacking")]},
- ),
- "E0633": (
- "Attempting to unpack a non-sequence%s",
- "unpacking-non-sequence",
- "Used when something which is not "
- "a sequence is used in an unpack assignment",
- {"old_names": [("W0633", "old-unpacking-non-sequence")]},
- ),
- "W0640": (
- "Cell variable %s defined in loop",
- "cell-var-from-loop",
- "A variable used in a closure is defined in a loop. "
- "This will result in all closures using the same value for "
- "the closed-over variable.",
- ),
- "W0641": (
- "Possibly unused variable %r",
- "possibly-unused-variable",
- "Used when a variable is defined but might not be used. "
- "The possibility comes from the fact that locals() might be used, "
- "which could consume or not the said variable",
- ),
- "W0642": (
- "Invalid assignment to %s in method",
- "self-cls-assignment",
- "Invalid assignment to self or cls in instance or class method "
- "respectively.",
- ),
-}
-
-
-ScopeConsumer = collections.namedtuple(
- "ScopeConsumer", "to_consume consumed scope_type"
-)
-
-
-class NamesConsumer:
- """
- A simple class to handle consumed, to consume and scope type info of node locals
- """
-
- def __init__(self, node, scope_type):
- self._atomic = ScopeConsumer(copy.copy(node.locals), {}, scope_type)
-
- def __repr__(self):
- msg = "\nto_consume : {:s}\n".format(
- ", ".join(
- [
- "{}->{}".format(key, val)
- for key, val in self._atomic.to_consume.items()
- ]
- )
- )
- msg += "consumed : {:s}\n".format(
- ", ".join(
- [
- "{}->{}".format(key, val)
- for key, val in self._atomic.consumed.items()
- ]
- )
- )
- msg += "scope_type : {:s}\n".format(self._atomic.scope_type)
- return msg
-
- def __iter__(self):
- return iter(self._atomic)
-
- @property
- def to_consume(self):
- return self._atomic.to_consume
-
- @property
- def consumed(self):
- return self._atomic.consumed
-
- @property
- def scope_type(self):
- return self._atomic.scope_type
-
- def mark_as_consumed(self, name, new_node):
- """
- Mark the name as consumed and delete it from
- the to_consume dictionary
- """
- self.consumed[name] = new_node
- del self.to_consume[name]
-
- def get_next_to_consume(self, node):
- # mark the name as consumed if it's defined in this scope
- name = node.name
- parent_node = node.parent
- found_node = self.to_consume.get(name)
- if (
- found_node
- and isinstance(parent_node, astroid.Assign)
- and parent_node == found_node[0].parent
- ):
- lhs = found_node[0].parent.targets[0]
- if lhs.name == name: # this name is defined in this very statement
- found_node = None
- return found_node
-
-
-# pylint: disable=too-many-public-methods
-class VariablesChecker(BaseChecker):
- """checks for
- * unused variables / imports
- * undefined variables
- * redefinition of variable from builtins or from an outer scope
- * use of variable before assignment
- * __all__ consistency
- * self/cls assignment
- """
-
- __implements__ = IAstroidChecker
-
- name = "variables"
- msgs = MSGS
- priority = -1
- options = (
- (
- "init-import",
- {
- "default": 0,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "Tells whether we should check for unused import in "
- "__init__ files.",
- },
- ),
- (
- "dummy-variables-rgx",
- {
- "default": "_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_",
- "type": "regexp",
- "metavar": "<regexp>",
- "help": "A regular expression matching the name of dummy "
- "variables (i.e. expected to not be used).",
- },
- ),
- (
- "additional-builtins",
- {
- "default": (),
- "type": "csv",
- "metavar": "<comma separated list>",
- "help": "List of additional names supposed to be defined in "
- "builtins. Remember that you should avoid defining new builtins "
- "when possible.",
- },
- ),
- (
- "callbacks",
- {
- "default": ("cb_", "_cb"),
- "type": "csv",
- "metavar": "<callbacks>",
- "help": "List of strings which can identify a callback "
- "function by name. A callback name must start or "
- "end with one of those strings.",
- },
- ),
- (
- "redefining-builtins-modules",
- {
- "default": (
- "six.moves",
- "past.builtins",
- "future.builtins",
- "builtins",
- "io",
- ),
- "type": "csv",
- "metavar": "<comma separated list>",
- "help": "List of qualified module names which can have objects "
- "that can redefine builtins.",
- },
- ),
- (
- "ignored-argument-names",
- {
- "default": IGNORED_ARGUMENT_NAMES,
- "type": "regexp",
- "metavar": "<regexp>",
- "help": "Argument names that match this expression will be "
- "ignored. Default to name with leading underscore.",
- },
- ),
- (
- "allow-global-unused-variables",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y_or_n>",
- "help": "Tells whether unused global variables should be treated as a violation.",
- },
- ),
- )
-
- def __init__(self, linter=None):
- BaseChecker.__init__(self, linter)
- self._to_consume = (
- None
- ) # list of tuples: (to_consume:dict, consumed:dict, scope_type:str)
- self._checking_mod_attr = None
- self._loop_variables = []
- self._type_annotation_names = []
- self._postponed_evaluation_enabled = False
-
- @utils.check_messages("redefined-outer-name")
- def visit_for(self, node):
- assigned_to = [
- var.name for var in node.target.nodes_of_class(astroid.AssignName)
- ]
-
- # Only check variables that are used
- dummy_rgx = self.config.dummy_variables_rgx
- assigned_to = [var for var in assigned_to if not dummy_rgx.match(var)]
-
- for variable in assigned_to:
- for outer_for, outer_variables in self._loop_variables:
- if variable in outer_variables and not in_for_else_branch(
- outer_for, node
- ):
- self.add_message(
- "redefined-outer-name",
- args=(variable, outer_for.fromlineno),
- node=node,
- )
- break
-
- self._loop_variables.append((node, assigned_to))
-
- @utils.check_messages("redefined-outer-name")
- def leave_for(self, node):
- self._loop_variables.pop()
- self._store_type_annotation_names(node)
-
- def visit_module(self, node):
- """visit module : update consumption analysis variable
- checks globals doesn't overrides builtins
- """
- self._to_consume = [NamesConsumer(node, "module")]
- self._postponed_evaluation_enabled = is_postponed_evaluation_enabled(node)
-
- for name, stmts in node.locals.items():
- if utils.is_builtin(name) and not utils.is_inside_except(stmts[0]):
- if self._should_ignore_redefined_builtin(stmts[0]) or name == "__doc__":
- continue
- self.add_message("redefined-builtin", args=name, node=stmts[0])
-
- @utils.check_messages(
- "unused-import",
- "unused-wildcard-import",
- "redefined-builtin",
- "undefined-all-variable",
- "invalid-all-object",
- "unused-variable",
- )
- def leave_module(self, node):
- """leave module: check globals
- """
- assert len(self._to_consume) == 1
-
- self._check_metaclasses(node)
- not_consumed = self._to_consume.pop().to_consume
- # attempt to check for __all__ if defined
- if "__all__" in node.locals:
- self._check_all(node, not_consumed)
-
- # check for unused globals
- self._check_globals(not_consumed)
-
- # don't check unused imports in __init__ files
- if not self.config.init_import and node.package:
- return
-
- self._check_imports(not_consumed)
-
- def visit_classdef(self, node):
- """visit class: update consumption analysis variable
- """
- self._to_consume.append(NamesConsumer(node, "class"))
-
- def leave_classdef(self, _):
- """leave class: update consumption analysis variable
- """
- # do not check for not used locals here (no sense)
- self._to_consume.pop()
-
- def visit_lambda(self, node):
- """visit lambda: update consumption analysis variable
- """
- self._to_consume.append(NamesConsumer(node, "lambda"))
-
- def leave_lambda(self, _):
- """leave lambda: update consumption analysis variable
- """
- # do not check for not used locals here
- self._to_consume.pop()
-
- def visit_generatorexp(self, node):
- """visit genexpr: update consumption analysis variable
- """
- self._to_consume.append(NamesConsumer(node, "comprehension"))
-
- def leave_generatorexp(self, _):
- """leave genexpr: update consumption analysis variable
- """
- # do not check for not used locals here
- self._to_consume.pop()
-
- def visit_dictcomp(self, node):
- """visit dictcomp: update consumption analysis variable
- """
- self._to_consume.append(NamesConsumer(node, "comprehension"))
-
- def leave_dictcomp(self, _):
- """leave dictcomp: update consumption analysis variable
- """
- # do not check for not used locals here
- self._to_consume.pop()
-
- def visit_setcomp(self, node):
- """visit setcomp: update consumption analysis variable
- """
- self._to_consume.append(NamesConsumer(node, "comprehension"))
-
- def leave_setcomp(self, _):
- """leave setcomp: update consumption analysis variable
- """
- # do not check for not used locals here
- self._to_consume.pop()
-
- def visit_functiondef(self, node):
- """visit function: update consumption analysis variable and check locals
- """
- self._to_consume.append(NamesConsumer(node, "function"))
- if not (
- self.linter.is_message_enabled("redefined-outer-name")
- or self.linter.is_message_enabled("redefined-builtin")
- ):
- return
- globs = node.root().globals
- for name, stmt in node.items():
- if utils.is_inside_except(stmt):
- continue
- if name in globs and not isinstance(stmt, astroid.Global):
- definition = globs[name][0]
- if (
- isinstance(definition, astroid.ImportFrom)
- and definition.modname == FUTURE
- ):
- # It is a __future__ directive, not a symbol.
- continue
-
- # Do not take in account redefined names for the purpose
- # of type checking.:
- if any(
- isinstance(definition.parent, astroid.If)
- and definition.parent.test.as_string() in TYPING_TYPE_CHECKS_GUARDS
- for definition in globs[name]
- ):
- continue
-
- line = definition.fromlineno
- if not self._is_name_ignored(stmt, name):
- self.add_message(
- "redefined-outer-name", args=(name, line), node=stmt
- )
-
- elif utils.is_builtin(name) and not self._should_ignore_redefined_builtin(
- stmt
- ):
- # do not print Redefining builtin for additional builtins
- self.add_message("redefined-builtin", args=name, node=stmt)
-
- def leave_functiondef(self, node):
- """leave function: check function's locals are consumed"""
- self._check_metaclasses(node)
-
- if node.type_comment_returns:
- self._store_type_annotation_node(node.type_comment_returns)
- if node.type_comment_args:
- for argument_annotation in node.type_comment_args:
- self._store_type_annotation_node(argument_annotation)
-
- not_consumed = self._to_consume.pop().to_consume
- if not (
- self.linter.is_message_enabled("unused-variable")
- or self.linter.is_message_enabled("possibly-unused-variable")
- or self.linter.is_message_enabled("unused-argument")
- ):
- return
-
- # Don't check arguments of function which are only raising an exception.
- if utils.is_error(node):
- return
-
- # Don't check arguments of abstract methods or within an interface.
- is_method = node.is_method()
- if is_method and node.is_abstract():
- return
-
- global_names = _flattened_scope_names(node.nodes_of_class(astroid.Global))
- nonlocal_names = _flattened_scope_names(node.nodes_of_class(astroid.Nonlocal))
- for name, stmts in not_consumed.items():
- self._check_is_unused(name, node, stmts[0], global_names, nonlocal_names)
-
- visit_asyncfunctiondef = visit_functiondef
- leave_asyncfunctiondef = leave_functiondef
-
- @utils.check_messages(
- "global-variable-undefined",
- "global-variable-not-assigned",
- "global-statement",
- "global-at-module-level",
- "redefined-builtin",
- )
- def visit_global(self, node):
- """check names imported exists in the global scope"""
- frame = node.frame()
- if isinstance(frame, astroid.Module):
- self.add_message("global-at-module-level", node=node)
- return
-
- module = frame.root()
- default_message = True
- locals_ = node.scope().locals
- for name in node.names:
- try:
- assign_nodes = module.getattr(name)
- except astroid.NotFoundError:
- # unassigned global, skip
- assign_nodes = []
-
- not_defined_locally_by_import = not any(
- isinstance(local, astroid.node_classes.Import)
- for local in locals_.get(name, ())
- )
- if not assign_nodes and not_defined_locally_by_import:
- self.add_message("global-variable-not-assigned", args=name, node=node)
- default_message = False
- continue
-
- for anode in assign_nodes:
- if (
- isinstance(anode, astroid.AssignName)
- and anode.name in module.special_attributes
- ):
- self.add_message("redefined-builtin", args=name, node=node)
- break
- if anode.frame() is module:
- # module level assignment
- break
- else:
- if not_defined_locally_by_import:
- # global undefined at the module scope
- self.add_message("global-variable-undefined", args=name, node=node)
- default_message = False
-
- if default_message:
- self.add_message("global-statement", node=node)
-
- def visit_assignname(self, node):
- if isinstance(node.assign_type(), astroid.AugAssign):
- self.visit_name(node)
-
- def visit_delname(self, node):
- self.visit_name(node)
-
- @utils.check_messages(*MSGS)
- def visit_name(self, node):
- """check that a name is defined if the current scope and doesn't
- redefine a built-in
- """
- stmt = node.statement()
- if stmt.fromlineno is None:
- # name node from an astroid built from live code, skip
- assert not stmt.root().file.endswith(".py")
- return
-
- name = node.name
- frame = stmt.scope()
- # if the name node is used as a function default argument's value or as
- # a decorator, then start from the parent frame of the function instead
- # of the function frame - and thus open an inner class scope
- if (
- utils.is_default_argument(node)
- or utils.is_func_decorator(node)
- or utils.is_ancestor_name(frame, node)
- ):
- start_index = len(self._to_consume) - 2
- else:
- start_index = len(self._to_consume) - 1
- # iterates through parent scopes, from the inner to the outer
- base_scope_type = self._to_consume[start_index].scope_type
- # pylint: disable=too-many-nested-blocks; refactoring this block is a pain.
- for i in range(start_index, -1, -1):
- current_consumer = self._to_consume[i]
- # if the current scope is a class scope but it's not the inner
- # scope, ignore it. This prevents to access this scope instead of
- # the globals one in function members when there are some common
- # names. The only exception is when the starting scope is a
- # comprehension and its direct outer scope is a class
- if (
- current_consumer.scope_type == "class"
- and i != start_index
- and not (base_scope_type == "comprehension" and i == start_index - 1)
- ):
- if self._ignore_class_scope(node):
- continue
-
- # the name has already been consumed, only check it's not a loop
- # variable used outside the loop
- # avoid the case where there are homonyms inside function scope and
- #  comprehension current scope (avoid bug #1731)
- if name in current_consumer.consumed and not (
- current_consumer.scope_type == "comprehension"
- and self._has_homonym_in_upper_function_scope(node, i)
- ):
- defnode = utils.assign_parent(current_consumer.consumed[name][0])
- self._check_late_binding_closure(node, defnode)
- self._loopvar_name(node, name)
- break
-
- found_node = current_consumer.get_next_to_consume(node)
- if found_node is None:
- continue
-
- # checks for use before assignment
- defnode = utils.assign_parent(current_consumer.to_consume[name][0])
-
- if defnode is not None:
- self._check_late_binding_closure(node, defnode)
- defstmt = defnode.statement()
- defframe = defstmt.frame()
- # The class reuses itself in the class scope.
- recursive_klass = (
- frame is defframe
- and defframe.parent_of(node)
- and isinstance(defframe, astroid.ClassDef)
- and node.name == defframe.name
- )
-
- if (
- recursive_klass
- and utils.is_inside_lambda(node)
- and (
- not utils.is_default_argument(node)
- or node.scope().parent.scope() is not defframe
- )
- ):
- # Self-referential class references are fine in lambda's --
- # As long as they are not part of the default argument directly
- # under the scope of the parent self-referring class.
- # Example of valid default argument:
- # class MyName3:
- # myattr = 1
- # mylambda3 = lambda: lambda a=MyName3: a
- # Example of invalid default argument:
- # class MyName4:
- # myattr = 1
- # mylambda4 = lambda a=MyName4: lambda: a
-
- # If the above conditional is True,
- # there is no possibility of undefined-variable
- # Also do not consume class name
- # (since consuming blocks subsequent checks)
- # -- quit
- break
-
- maybee0601, annotation_return, use_outer_definition = self._is_variable_violation(
- node,
- name,
- defnode,
- stmt,
- defstmt,
- frame,
- defframe,
- base_scope_type,
- recursive_klass,
- )
-
- if use_outer_definition:
- continue
-
- if (
- maybee0601
- and not utils.is_defined_before(node)
- and not astroid.are_exclusive(stmt, defstmt, ("NameError",))
- ):
-
- # Used and defined in the same place, e.g `x += 1` and `del x`
- defined_by_stmt = defstmt is stmt and isinstance(
- node, (astroid.DelName, astroid.AssignName)
- )
- if (
- recursive_klass
- or defined_by_stmt
- or annotation_return
- or isinstance(defstmt, astroid.Delete)
- ):
- if not utils.node_ignores_exception(node, NameError):
-
- # Handle postponed evaluation of annotations
- if not (
- self._postponed_evaluation_enabled
- and isinstance(
- stmt,
- (
- astroid.AnnAssign,
- astroid.FunctionDef,
- astroid.Arguments,
- ),
- )
- and name in node.root().locals
- ):
- self.add_message(
- "undefined-variable", args=name, node=node
- )
- elif base_scope_type != "lambda":
- # E0601 may *not* occurs in lambda scope.
-
- # Handle postponed evaluation of annotations
- if not (
- self._postponed_evaluation_enabled
- and isinstance(
- stmt, (astroid.AnnAssign, astroid.FunctionDef)
- )
- ):
- self.add_message(
- "used-before-assignment", args=name, node=node
- )
- elif base_scope_type == "lambda":
- # E0601 can occur in class-level scope in lambdas, as in
- # the following example:
- # class A:
- # x = lambda attr: f + attr
- # f = 42
- if isinstance(frame, astroid.ClassDef) and name in frame.locals:
- if isinstance(node.parent, astroid.Arguments):
- if stmt.fromlineno <= defstmt.fromlineno:
- # Doing the following is fine:
- # class A:
- # x = 42
- # y = lambda attr=x: attr
- self.add_message(
- "used-before-assignment", args=name, node=node
- )
- else:
- self.add_message(
- "undefined-variable", args=name, node=node
- )
- elif current_consumer.scope_type == "lambda":
- self.add_message("undefined-variable", node=node, args=name)
-
- current_consumer.mark_as_consumed(name, found_node)
- # check it's not a loop variable used outside the loop
- self._loopvar_name(node, name)
- break
- else:
- # we have not found the name, if it isn't a builtin, that's an
- # undefined name !
- if not (
- name in astroid.Module.scope_attrs
- or utils.is_builtin(name)
- or name in self.config.additional_builtins
- ):
- if not utils.node_ignores_exception(node, NameError):
- self.add_message("undefined-variable", args=name, node=node)
-
- @utils.check_messages("no-name-in-module")
- def visit_import(self, node):
- """check modules attribute accesses"""
- if not self._analyse_fallback_blocks and utils.is_from_fallback_block(node):
- # No need to verify this, since ImportError is already
- # handled by the client code.
- return
-
- for name, _ in node.names:
- parts = name.split(".")
- try:
- module = next(_infer_name_module(node, parts[0]))
- except astroid.ResolveError:
- continue
- self._check_module_attrs(node, module, parts[1:])
-
- @utils.check_messages("no-name-in-module")
- def visit_importfrom(self, node):
- """check modules attribute accesses"""
- if not self._analyse_fallback_blocks and utils.is_from_fallback_block(node):
- # No need to verify this, since ImportError is already
- # handled by the client code.
- return
-
- name_parts = node.modname.split(".")
- try:
- module = node.do_import_module(name_parts[0])
- except astroid.AstroidBuildingException:
- return
- module = self._check_module_attrs(node, module, name_parts[1:])
- if not module:
- return
- for name, _ in node.names:
- if name == "*":
- continue
- self._check_module_attrs(node, module, name.split("."))
-
- @utils.check_messages(
- "unbalanced-tuple-unpacking", "unpacking-non-sequence", "self-cls-assignment"
- )
- def visit_assign(self, node):
- """Check unbalanced tuple unpacking for assignments
- and unpacking non-sequences as well as in case self/cls
- get assigned.
- """
- self._check_self_cls_assign(node)
- if not isinstance(node.targets[0], (astroid.Tuple, astroid.List)):
- return
-
- targets = node.targets[0].itered()
- try:
- inferred = utils.safe_infer(node.value)
- if inferred is not None:
- self._check_unpacking(inferred, node, targets)
- except astroid.InferenceError:
- return
-
- # listcomp have now also their scope
- def visit_listcomp(self, node):
- """visit dictcomp: update consumption analysis variable
- """
- self._to_consume.append(NamesConsumer(node, "comprehension"))
-
- def leave_listcomp(self, _):
- """leave dictcomp: update consumption analysis variable
- """
- # do not check for not used locals here
- self._to_consume.pop()
-
- def leave_assign(self, node):
- self._store_type_annotation_names(node)
-
- def leave_with(self, node):
- self._store_type_annotation_names(node)
-
- def visit_arguments(self, node):
- for annotation in node.type_comment_args:
- self._store_type_annotation_node(annotation)
-
- # Relying on other checker's options, which might not have been initialized yet.
- @decorators.cachedproperty
- def _analyse_fallback_blocks(self):
- return get_global_option(self, "analyse-fallback-blocks", default=False)
-
- @decorators.cachedproperty
- def _ignored_modules(self):
- return get_global_option(self, "ignored-modules", default=[])
-
- @decorators.cachedproperty
- def _allow_global_unused_variables(self):
- return get_global_option(self, "allow-global-unused-variables", default=True)
-
- @staticmethod
- def _defined_in_function_definition(node, frame):
- in_annotation_or_default = False
- if isinstance(frame, astroid.FunctionDef) and node.statement() is frame:
- in_annotation_or_default = (
- node in frame.args.annotations
- or node in frame.args.kwonlyargs_annotations
- or node is frame.args.varargannotation
- or node is frame.args.kwargannotation
- ) or frame.args.parent_of(node)
- return in_annotation_or_default
-
- @staticmethod
- def _is_variable_violation(
- node,
- name,
- defnode,
- stmt,
- defstmt,
- frame,
- defframe,
- base_scope_type,
- recursive_klass,
- ):
- # pylint: disable=too-many-nested-blocks
- # node: Node to check for violation
- # name: name of node to check violation for
- # frame: Scope of statement of node
- # base_scope_type: local scope type
- maybee0601 = True
- annotation_return = False
- use_outer_definition = False
- if frame is not defframe:
- maybee0601 = _detect_global_scope(node, frame, defframe)
- elif defframe.parent is None:
- # we are at the module level, check the name is not
- # defined in builtins
- if name in defframe.scope_attrs or astroid.builtin_lookup(name)[1]:
- maybee0601 = False
- else:
- # we are in a local scope, check the name is not
- # defined in global or builtin scope
- # skip this lookup if name is assigned later in function scope/lambda
- # Note: the node.frame() is not the same as the `frame` argument which is
- # equivalent to frame.statement().scope()
- forbid_lookup = (
- isinstance(frame, astroid.FunctionDef)
- or isinstance(node.frame(), astroid.Lambda)
- ) and _assigned_locally(node)
- if not forbid_lookup and defframe.root().lookup(name)[1]:
- maybee0601 = False
- use_outer_definition = stmt == defstmt and not isinstance(
- defnode, astroid.node_classes.Comprehension
- )
- else:
- # check if we have a nonlocal
- if name in defframe.locals:
- maybee0601 = not any(
- isinstance(child, astroid.Nonlocal) and name in child.names
- for child in defframe.get_children()
- )
-
- if (
- base_scope_type == "lambda"
- and isinstance(frame, astroid.ClassDef)
- and name in frame.locals
- ):
-
- # This rule verifies that if the definition node of the
- # checked name is an Arguments node and if the name
- # is used a default value in the arguments defaults
- # and the actual definition of the variable label
- # is happening before the Arguments definition.
- #
- # bar = None
- # foo = lambda bar=bar: bar
- #
- # In this case, maybee0601 should be False, otherwise
- # it should be True.
- maybee0601 = not (
- isinstance(defnode, astroid.Arguments)
- and node in defnode.defaults
- and frame.locals[name][0].fromlineno < defstmt.fromlineno
- )
- elif isinstance(defframe, astroid.ClassDef) and isinstance(
- frame, astroid.FunctionDef
- ):
- # Special rule for function return annotations,
- # which uses the same name as the class where
- # the function lives.
- if node is frame.returns and defframe.parent_of(frame.returns):
- maybee0601 = annotation_return = True
-
- if (
- maybee0601
- and defframe.name in defframe.locals
- and defframe.locals[name][0].lineno < frame.lineno
- ):
- # Detect class assignments with the same
- # name as the class. In this case, no warning
- # should be raised.
- maybee0601 = False
- if isinstance(node.parent, astroid.Arguments):
- maybee0601 = stmt.fromlineno <= defstmt.fromlineno
- elif recursive_klass:
- maybee0601 = True
- else:
- maybee0601 = maybee0601 and stmt.fromlineno <= defstmt.fromlineno
- if maybee0601 and stmt.fromlineno == defstmt.fromlineno:
- if (
- isinstance(defframe, astroid.FunctionDef)
- and frame is defframe
- and defframe.parent_of(node)
- and stmt is not defstmt
- ):
- # Single statement function, with the statement on the
- # same line as the function definition
- maybee0601 = False
-
- # Look for type checking definitions inside a type checking guard.
- if isinstance(defstmt, (astroid.Import, astroid.ImportFrom)):
- defstmt_parent = defstmt.parent
-
- if (
- isinstance(defstmt_parent, astroid.If)
- and defstmt_parent.test.as_string() in TYPING_TYPE_CHECKS_GUARDS
- ):
- # Exempt those definitions that are used inside the type checking
- # guard or that are defined in both type checking guard branches.
- used_in_branch = defstmt_parent.parent_of(node)
- defined_in_or_else = False
-
- for definition in defstmt_parent.orelse:
- if isinstance(definition, astroid.Assign):
- defined_in_or_else = any(
- target.name == name for target in definition.targets
- )
- if defined_in_or_else:
- break
-
- if not used_in_branch and not defined_in_or_else:
- maybee0601 = True
-
- return maybee0601, annotation_return, use_outer_definition
-
- def _ignore_class_scope(self, node):
- """
- Return True if the node is in a local class scope, as an assignment.
-
- :param node: Node considered
- :type node: astroid.Node
- :return: True if the node is in a local class scope, as an assignment. False otherwise.
- :rtype: bool
- """
- # Detect if we are in a local class scope, as an assignment.
- # For example, the following is fair game.
- #
- # class A:
- # b = 1
- # c = lambda b=b: b * b
- #
- # class B:
- # tp = 1
- # def func(self, arg: tp):
- # ...
- # class C:
- # tp = 2
- # def func(self, arg=tp):
- # ...
-
- name = node.name
- frame = node.statement().scope()
- in_annotation_or_default = self._defined_in_function_definition(node, frame)
- if in_annotation_or_default:
- frame_locals = frame.parent.scope().locals
- else:
- frame_locals = frame.locals
- return not (
- (isinstance(frame, astroid.ClassDef) or in_annotation_or_default)
- and name in frame_locals
- )
-
- def _loopvar_name(self, node, name):
- # filter variables according to node's scope
- if not self.linter.is_message_enabled("undefined-loop-variable"):
- return
- astmts = [stmt for stmt in node.lookup(name)[1] if hasattr(stmt, "assign_type")]
- # If this variable usage exists inside a function definition
- # that exists in the same loop,
- # the usage is safe because the function will not be defined either if
- # the variable is not defined.
- scope = node.scope()
- if isinstance(scope, astroid.FunctionDef) and any(
- asmt.statement().parent_of(scope) for asmt in astmts
- ):
- return
-
- # filter variables according their respective scope test is_statement
- # and parent to avoid #74747. This is not a total fix, which would
- # introduce a mechanism similar to special attribute lookup in
- # modules. Also, in order to get correct inference in this case, the
- # scope lookup rules would need to be changed to return the initial
- # assignment (which does not exist in code per se) as well as any later
- # modifications.
- if (
- not astmts
- or (astmts[0].is_statement or astmts[0].parent)
- and astmts[0].statement().parent_of(node)
- ):
- _astmts = []
- else:
- _astmts = astmts[:1]
- for i, stmt in enumerate(astmts[1:]):
- if astmts[i].statement().parent_of(stmt) and not in_for_else_branch(
- astmts[i].statement(), stmt
- ):
- continue
- _astmts.append(stmt)
- astmts = _astmts
- if len(astmts) != 1:
- return
-
- assign = astmts[0].assign_type()
- if not (
- isinstance(
- assign, (astroid.For, astroid.Comprehension, astroid.GeneratorExp)
- )
- and assign.statement() is not node.statement()
- ):
- return
-
- # For functions we can do more by inferring the length of the itered object
- if not isinstance(assign, astroid.For):
- self.add_message("undefined-loop-variable", args=name, node=node)
- return
-
- try:
- inferred = next(assign.iter.infer())
- except astroid.InferenceError:
- self.add_message("undefined-loop-variable", args=name, node=node)
- else:
- if (
- isinstance(inferred, astroid.Instance)
- and inferred.qname() == BUILTIN_RANGE
- ):
- # Consider range() objects safe, even if they might not yield any results.
- return
-
- # Consider sequences.
- sequences = (
- astroid.List,
- astroid.Tuple,
- astroid.Dict,
- astroid.Set,
- objects.FrozenSet,
- )
- if not isinstance(inferred, sequences):
- self.add_message("undefined-loop-variable", args=name, node=node)
- return
-
- elements = getattr(inferred, "elts", getattr(inferred, "items", []))
- if not elements:
- self.add_message("undefined-loop-variable", args=name, node=node)
-
- def _check_is_unused(self, name, node, stmt, global_names, nonlocal_names):
- # pylint: disable=too-many-branches
- # Ignore some special names specified by user configuration.
- if self._is_name_ignored(stmt, name):
- return
- # Ignore names that were added dynamically to the Function scope
- if (
- isinstance(node, astroid.FunctionDef)
- and name == "__class__"
- and len(node.locals["__class__"]) == 1
- and isinstance(node.locals["__class__"][0], astroid.ClassDef)
- ):
- return
-
- # Ignore names imported by the global statement.
- if isinstance(stmt, (astroid.Global, astroid.Import, astroid.ImportFrom)):
- # Detect imports, assigned to global statements.
- if global_names and _import_name_is_global(stmt, global_names):
- return
-
- argnames = list(
- itertools.chain(node.argnames(), [arg.name for arg in node.args.kwonlyargs])
- )
- # Care about functions with unknown argument (builtins)
- if name in argnames:
- self._check_unused_arguments(name, node, stmt, argnames)
- else:
- if stmt.parent and isinstance(
- stmt.parent, (astroid.Assign, astroid.AnnAssign)
- ):
- if name in nonlocal_names:
- return
-
- qname = asname = None
- if isinstance(stmt, (astroid.Import, astroid.ImportFrom)):
- # Need the complete name, which we don't have in .locals.
- if len(stmt.names) > 1:
- import_names = next(
- (names for names in stmt.names if name in names), None
- )
- else:
- import_names = stmt.names[0]
- if import_names:
- qname, asname = import_names
- name = asname or qname
-
- if _has_locals_call_after_node(stmt, node.scope()):
- message_name = "possibly-unused-variable"
- else:
- if isinstance(stmt, astroid.Import):
- if asname is not None:
- msg = "%s imported as %s" % (qname, asname)
- else:
- msg = "import %s" % name
- self.add_message("unused-import", args=msg, node=stmt)
- return
- if isinstance(stmt, astroid.ImportFrom):
- if asname is not None:
- msg = "%s imported from %s as %s" % (
- qname,
- stmt.modname,
- asname,
- )
- else:
- msg = "%s imported from %s" % (name, stmt.modname)
- self.add_message("unused-import", args=msg, node=stmt)
- return
- message_name = "unused-variable"
-
- # Don't check function stubs created only for type information
- if utils.is_overload_stub(node):
- return
-
- self.add_message(message_name, args=name, node=stmt)
-
- def _is_name_ignored(self, stmt, name):
- authorized_rgx = self.config.dummy_variables_rgx
- if (
- isinstance(stmt, astroid.AssignName)
- and isinstance(stmt.parent, astroid.Arguments)
- or isinstance(stmt, astroid.Arguments)
- ):
- regex = self.config.ignored_argument_names
- else:
- regex = authorized_rgx
- return regex and regex.match(name)
-
- def _check_unused_arguments(self, name, node, stmt, argnames):
- is_method = node.is_method()
- klass = node.parent.frame()
- if is_method and isinstance(klass, astroid.ClassDef):
- confidence = (
- INFERENCE if utils.has_known_bases(klass) else INFERENCE_FAILURE
- )
- else:
- confidence = HIGH
-
- if is_method:
- # Don't warn for the first argument of a (non static) method
- if node.type != "staticmethod" and name == argnames[0]:
- return
- # Don't warn for argument of an overridden method
- overridden = overridden_method(klass, node.name)
- if overridden is not None and name in overridden.argnames():
- return
- if node.name in utils.PYMETHODS and node.name not in (
- "__init__",
- "__new__",
- ):
- return
- # Don't check callback arguments
- if any(
- node.name.startswith(cb) or node.name.endswith(cb)
- for cb in self.config.callbacks
- ):
- return
- # Don't check arguments of singledispatch.register function.
- if utils.is_registered_in_singledispatch_function(node):
- return
-
- # Don't check function stubs created only for type information
- if utils.is_overload_stub(node):
- return
-
- # Don't check protocol classes
- if utils.is_protocol_class(klass):
- return
-
- self.add_message("unused-argument", args=name, node=stmt, confidence=confidence)
-
- def _check_late_binding_closure(self, node, assignment_node):
- def _is_direct_lambda_call():
- return (
- isinstance(node_scope.parent, astroid.Call)
- and node_scope.parent.func is node_scope
- )
-
- node_scope = node.scope()
- if not isinstance(node_scope, (astroid.Lambda, astroid.FunctionDef)):
- return
- if isinstance(node.parent, astroid.Arguments):
- return
-
- if isinstance(assignment_node, astroid.Comprehension):
- if assignment_node.parent.parent_of(node.scope()):
- self.add_message("cell-var-from-loop", node=node, args=node.name)
- else:
- assign_scope = assignment_node.scope()
- maybe_for = assignment_node
- while not isinstance(maybe_for, astroid.For):
- if maybe_for is assign_scope:
- break
- maybe_for = maybe_for.parent
- else:
- if (
- maybe_for.parent_of(node_scope)
- and not _is_direct_lambda_call()
- and not isinstance(node_scope.statement(), astroid.Return)
- ):
- self.add_message("cell-var-from-loop", node=node, args=node.name)
-
- def _should_ignore_redefined_builtin(self, stmt):
- if not isinstance(stmt, astroid.ImportFrom):
- return False
- return stmt.modname in self.config.redefining_builtins_modules
-
- def _has_homonym_in_upper_function_scope(self, node, index):
- """
- Return True if there is a node with the same name in the to_consume dict of an upper scope
- and if that scope is a function
-
- :param node: node to check for
- :type node: astroid.Node
- :param index: index of the current consumer inside self._to_consume
- :type index: int
- :return: True if there is a node with the same name in the to_consume dict of an upper scope
- and if that scope is a function
- :rtype: bool
- """
- for _consumer in self._to_consume[index - 1 :: -1]:
- if _consumer.scope_type == "function" and node.name in _consumer.to_consume:
- return True
- return False
-
- def _store_type_annotation_node(self, type_annotation):
- """Given a type annotation, store all the name nodes it refers to"""
- if isinstance(type_annotation, astroid.Name):
- self._type_annotation_names.append(type_annotation.name)
- return
-
- if not isinstance(type_annotation, astroid.Subscript):
- return
-
- if (
- isinstance(type_annotation.value, astroid.Attribute)
- and isinstance(type_annotation.value.expr, astroid.Name)
- and type_annotation.value.expr.name == TYPING_MODULE
- ):
- self._type_annotation_names.append(TYPING_MODULE)
- return
-
- self._type_annotation_names.extend(
- annotation.name
- for annotation in type_annotation.nodes_of_class(astroid.Name)
- )
-
- def _store_type_annotation_names(self, node):
- type_annotation = node.type_annotation
- if not type_annotation:
- return
- self._store_type_annotation_node(node.type_annotation)
-
- def _check_self_cls_assign(self, node):
- """Check that self/cls don't get assigned"""
- assign_names = {
- target.name
- for target in node.targets
- if isinstance(target, astroid.AssignName)
- }
- scope = node.scope()
- nonlocals_with_same_name = any(
- child
- for child in scope.body
- if isinstance(child, astroid.Nonlocal) and assign_names & set(child.names)
- )
- if nonlocals_with_same_name:
- scope = node.scope().parent.scope()
-
- if not (
- isinstance(scope, astroid.scoped_nodes.FunctionDef)
- and scope.is_method()
- and "builtins.staticmethod" not in scope.decoratornames()
- ):
- return
- argument_names = scope.argnames()
- if not argument_names:
- return
- self_cls_name = argument_names[0]
- target_assign_names = (
- target.name
- for target in node.targets
- if isinstance(target, astroid.node_classes.AssignName)
- )
- if self_cls_name in target_assign_names:
- self.add_message("self-cls-assignment", node=node, args=(self_cls_name))
-
- def _check_unpacking(self, inferred, node, targets):
- """ Check for unbalanced tuple unpacking
- and unpacking non sequences.
- """
- if utils.is_inside_abstract_class(node):
- return
- if utils.is_comprehension(node):
- return
- if inferred is astroid.Uninferable:
- return
- if (
- isinstance(inferred.parent, astroid.Arguments)
- and isinstance(node.value, astroid.Name)
- and node.value.name == inferred.parent.vararg
- ):
- # Variable-length argument, we can't determine the length.
- return
- if isinstance(inferred, (astroid.Tuple, astroid.List)):
- # attempt to check unpacking is properly balanced
- values = inferred.itered()
- if len(targets) != len(values):
- # Check if we have starred nodes.
- if any(isinstance(target, astroid.Starred) for target in targets):
- return
- self.add_message(
- "unbalanced-tuple-unpacking",
- node=node,
- args=(
- _get_unpacking_extra_info(node, inferred),
- len(targets),
- len(values),
- ),
- )
- # attempt to check unpacking may be possible (ie RHS is iterable)
- else:
- if not utils.is_iterable(inferred):
- self.add_message(
- "unpacking-non-sequence",
- node=node,
- args=(_get_unpacking_extra_info(node, inferred),),
- )
-
- def _check_module_attrs(self, node, module, module_names):
- """check that module_names (list of string) are accessible through the
- given module
- if the latest access name corresponds to a module, return it
- """
- assert isinstance(module, astroid.Module), module
- while module_names:
- name = module_names.pop(0)
- if name == "__dict__":
- module = None
- break
- try:
- module = next(module.getattr(name)[0].infer())
- if module is astroid.Uninferable:
- return None
- except astroid.NotFoundError:
- if module.name in self._ignored_modules:
- return None
- self.add_message(
- "no-name-in-module", args=(name, module.name), node=node
- )
- return None
- except astroid.InferenceError:
- return None
- if module_names:
- modname = module.name if module else "__dict__"
- self.add_message(
- "no-name-in-module", node=node, args=(".".join(module_names), modname)
- )
- return None
- if isinstance(module, astroid.Module):
- return module
- return None
-
- def _check_all(self, node, not_consumed):
- assigned = next(node.igetattr("__all__"))
- if assigned is astroid.Uninferable:
- return
-
- for elt in getattr(assigned, "elts", ()):
- try:
- elt_name = next(elt.infer())
- except astroid.InferenceError:
- continue
- if elt_name is astroid.Uninferable:
- continue
- if not elt_name.parent:
- continue
-
- if not isinstance(elt_name, astroid.Const) or not isinstance(
- elt_name.value, str
- ):
- self.add_message("invalid-all-object", args=elt.as_string(), node=elt)
- continue
-
- elt_name = elt_name.value
- # If elt is in not_consumed, remove it from not_consumed
- if elt_name in not_consumed:
- del not_consumed[elt_name]
- continue
-
- if elt_name not in node.locals:
- if not node.package:
- self.add_message(
- "undefined-all-variable", args=(elt_name,), node=elt
- )
- else:
- basename = os.path.splitext(node.file)[0]
- if os.path.basename(basename) == "__init__":
- name = node.name + "." + elt_name
- try:
- modutils.file_from_modpath(name.split("."))
- except ImportError:
- self.add_message(
- "undefined-all-variable", args=(elt_name,), node=elt
- )
- except SyntaxError:
- # don't yield a syntax-error warning,
- # because it will be later yielded
- # when the file will be checked
- pass
-
- def _check_globals(self, not_consumed):
- if self._allow_global_unused_variables:
- return
- for name, nodes in not_consumed.items():
- for node in nodes:
- self.add_message("unused-variable", args=(name,), node=node)
-
- def _check_imports(self, not_consumed):
- local_names = _fix_dot_imports(not_consumed)
- checked = set()
- for name, stmt in local_names:
- for imports in stmt.names:
- real_name = imported_name = imports[0]
- if imported_name == "*":
- real_name = name
- as_name = imports[1]
- if real_name in checked:
- continue
- if name not in (real_name, as_name):
- continue
- checked.add(real_name)
-
- if isinstance(stmt, astroid.Import) or (
- isinstance(stmt, astroid.ImportFrom) and not stmt.modname
- ):
- if isinstance(stmt, astroid.ImportFrom) and SPECIAL_OBJ.search(
- imported_name
- ):
- # Filter special objects (__doc__, __all__) etc.,
- # because they can be imported for exporting.
- continue
-
- if imported_name in self._type_annotation_names:
- # Most likely a typing import if it wasn't used so far.
- continue
-
- if as_name == "_":
- continue
- if as_name is None:
- msg = "import %s" % imported_name
- else:
- msg = "%s imported as %s" % (imported_name, as_name)
- if not _is_type_checking_import(stmt):
- self.add_message("unused-import", args=msg, node=stmt)
- elif isinstance(stmt, astroid.ImportFrom) and stmt.modname != FUTURE:
- if SPECIAL_OBJ.search(imported_name):
- # Filter special objects (__doc__, __all__) etc.,
- # because they can be imported for exporting.
- continue
-
- if _is_from_future_import(stmt, name):
- # Check if the name is in fact loaded from a
- # __future__ import in another module.
- continue
-
- if imported_name in self._type_annotation_names:
- # Most likely a typing import if it wasn't used so far.
- continue
-
- if imported_name == "*":
- self.add_message("unused-wildcard-import", args=name, node=stmt)
- else:
- if as_name is None:
- msg = "%s imported from %s" % (imported_name, stmt.modname)
- else:
- fields = (imported_name, stmt.modname, as_name)
- msg = "%s imported from %s as %s" % fields
- if not _is_type_checking_import(stmt):
- self.add_message("unused-import", args=msg, node=stmt)
- del self._to_consume
-
- def _check_metaclasses(self, node):
- """ Update consumption analysis for metaclasses. """
- consumed = [] # [(scope_locals, consumed_key)]
-
- for child_node in node.get_children():
- if isinstance(child_node, astroid.ClassDef):
- consumed.extend(self._check_classdef_metaclasses(child_node, node))
-
- # Pop the consumed items, in order to avoid having
- # unused-import and unused-variable false positives
- for scope_locals, name in consumed:
- scope_locals.pop(name, None)
-
- def _check_classdef_metaclasses(self, klass, parent_node):
- if not klass._metaclass:
- # Skip if this class doesn't use explicitly a metaclass, but inherits it from ancestors
- return []
-
- consumed = [] # [(scope_locals, consumed_key)]
- metaclass = klass.metaclass()
-
- name = None
- if isinstance(klass._metaclass, astroid.Name):
- name = klass._metaclass.name
- elif metaclass:
- name = metaclass.root().name
-
- found = None
- name = METACLASS_NAME_TRANSFORMS.get(name, name)
- if name:
- # check enclosing scopes starting from most local
- for scope_locals, _, _ in self._to_consume[::-1]:
- found = scope_locals.get(name)
- if found:
- consumed.append((scope_locals, name))
- break
-
- if found is None and not metaclass:
- name = None
- if isinstance(klass._metaclass, astroid.Name):
- name = klass._metaclass.name
- elif isinstance(klass._metaclass, astroid.Attribute):
- name = klass._metaclass.as_string()
-
- if name is not None:
- if not (
- name in astroid.Module.scope_attrs
- or utils.is_builtin(name)
- or name in self.config.additional_builtins
- or name in parent_node.locals
- ):
- self.add_message("undefined-variable", node=klass, args=(name,))
-
- return consumed
-
-
-def register(linter):
- """required method to auto register this checker"""
- linter.register_checker(VariablesChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/config.py b/venv/Lib/site-packages/pylint/config.py
deleted file mode 100644
index 0925575..0000000
--- a/venv/Lib/site-packages/pylint/config.py
+++ /dev/null
@@ -1,913 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2010, 2012-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2008 pyves@crater.logilab.fr <pyves@crater.logilab.fr>
-# Copyright (c) 2010 Julien Jehannet <julien.jehannet@logilab.fr>
-# Copyright (c) 2013 Google, Inc.
-# Copyright (c) 2013 John McGehee <jmcgehee@altera.com>
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Aru Sahni <arusahni@gmail.com>
-# Copyright (c) 2015 John Kirkham <jakirkham@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Erik <erik.eriksson@yahoo.com>
-# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2017-2018 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 ahirnish <ahirnish@gmail.com>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2018 Gary Tyler McLeod <mail@garytyler.com>
-# Copyright (c) 2018 Konstantin <Github@pheanex.de>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""utilities for Pylint configuration :
-
-* pylintrc
-* pylint.d (PYLINTHOME)
-"""
-import collections
-import configparser
-import contextlib
-import copy
-import io
-import optparse
-import os
-import pickle
-import re
-import sys
-import time
-from typing import Any, Dict, Tuple
-
-from pylint import utils
-
-USER_HOME = os.path.expanduser("~")
-if "PYLINTHOME" in os.environ:
- PYLINT_HOME = os.environ["PYLINTHOME"]
- if USER_HOME == "~":
- USER_HOME = os.path.dirname(PYLINT_HOME)
-elif USER_HOME == "~":
- PYLINT_HOME = ".pylint.d"
-else:
- PYLINT_HOME = os.path.join(USER_HOME, ".pylint.d")
-
-
-def _get_pdata_path(base_name, recurs):
- base_name = base_name.replace(os.sep, "_")
- return os.path.join(PYLINT_HOME, "%s%s%s" % (base_name, recurs, ".stats"))
-
-
-def load_results(base):
- data_file = _get_pdata_path(base, 1)
- try:
- with open(data_file, "rb") as stream:
- return pickle.load(stream)
- except Exception: # pylint: disable=broad-except
- return {}
-
-
-def save_results(results, base):
- if not os.path.exists(PYLINT_HOME):
- try:
- os.mkdir(PYLINT_HOME)
- except OSError:
- print("Unable to create directory %s" % PYLINT_HOME, file=sys.stderr)
- data_file = _get_pdata_path(base, 1)
- try:
- with open(data_file, "wb") as stream:
- pickle.dump(results, stream)
- except (IOError, OSError) as ex:
- print("Unable to create file %s: %s" % (data_file, ex), file=sys.stderr)
-
-
-def find_pylintrc():
- """search the pylint rc file and return its path if it find it, else None
- """
- # is there a pylint rc file in the current directory ?
- if os.path.exists("pylintrc"):
- return os.path.abspath("pylintrc")
- if os.path.exists(".pylintrc"):
- return os.path.abspath(".pylintrc")
- if os.path.isfile("__init__.py"):
- curdir = os.path.abspath(os.getcwd())
- while os.path.isfile(os.path.join(curdir, "__init__.py")):
- curdir = os.path.abspath(os.path.join(curdir, ".."))
- if os.path.isfile(os.path.join(curdir, "pylintrc")):
- return os.path.join(curdir, "pylintrc")
- if os.path.isfile(os.path.join(curdir, ".pylintrc")):
- return os.path.join(curdir, ".pylintrc")
- if "PYLINTRC" in os.environ and os.path.exists(os.environ["PYLINTRC"]):
- pylintrc = os.environ["PYLINTRC"]
- else:
- user_home = os.path.expanduser("~")
- if user_home in ("~", "/root"):
- pylintrc = ".pylintrc"
- else:
- pylintrc = os.path.join(user_home, ".pylintrc")
- if not os.path.isfile(pylintrc):
- pylintrc = os.path.join(user_home, ".config", "pylintrc")
- if not os.path.isfile(pylintrc):
- if os.path.isfile("/etc/pylintrc"):
- pylintrc = "/etc/pylintrc"
- else:
- pylintrc = None
- return pylintrc
-
-
-PYLINTRC = find_pylintrc()
-
-ENV_HELP = (
- """
-The following environment variables are used:
- * PYLINTHOME
- Path to the directory where persistent data for the run will be stored. If
-not found, it defaults to ~/.pylint.d/ or .pylint.d (in the current working
-directory).
- * PYLINTRC
- Path to the configuration file. See the documentation for the method used
-to search for configuration file.
-"""
- % globals() # type: ignore
-)
-
-
-class UnsupportedAction(Exception):
- """raised by set_option when it doesn't know what to do for an action"""
-
-
-def _multiple_choice_validator(choices, name, value):
- values = utils._check_csv(value)
- for csv_value in values:
- if csv_value not in choices:
- msg = "option %s: invalid value: %r, should be in %s"
- raise optparse.OptionValueError(msg % (name, csv_value, choices))
- return values
-
-
-def _choice_validator(choices, name, value):
- if value not in choices:
- msg = "option %s: invalid value: %r, should be in %s"
- raise optparse.OptionValueError(msg % (name, value, choices))
- return value
-
-
-# pylint: disable=unused-argument
-def _csv_validator(_, name, value):
- return utils._check_csv(value)
-
-
-# pylint: disable=unused-argument
-def _regexp_validator(_, name, value):
- if hasattr(value, "pattern"):
- return value
- return re.compile(value)
-
-
-# pylint: disable=unused-argument
-def _regexp_csv_validator(_, name, value):
- return [_regexp_validator(_, name, val) for val in _csv_validator(_, name, value)]
-
-
-def _yn_validator(opt, _, value):
- if isinstance(value, int):
- return bool(value)
- if value in ("y", "yes"):
- return True
- if value in ("n", "no"):
- return False
- msg = "option %s: invalid yn value %r, should be in (y, yes, n, no)"
- raise optparse.OptionValueError(msg % (opt, value))
-
-
-def _non_empty_string_validator(opt, _, value):
- if not value:
- msg = "indent string can't be empty."
- raise optparse.OptionValueError(msg)
- return utils._unquote(value)
-
-
-VALIDATORS = {
- "string": utils._unquote,
- "int": int,
- "regexp": re.compile,
- "regexp_csv": _regexp_csv_validator,
- "csv": _csv_validator,
- "yn": _yn_validator,
- "choice": lambda opt, name, value: _choice_validator(opt["choices"], name, value),
- "multiple_choice": lambda opt, name, value: _multiple_choice_validator(
- opt["choices"], name, value
- ),
- "non_empty_string": _non_empty_string_validator,
-}
-
-
-def _call_validator(opttype, optdict, option, value):
- if opttype not in VALIDATORS:
- raise Exception('Unsupported type "%s"' % opttype)
- try:
- return VALIDATORS[opttype](optdict, option, value)
- except TypeError:
- try:
- return VALIDATORS[opttype](value)
- except Exception:
- raise optparse.OptionValueError(
- "%s value (%r) should be of type %s" % (option, value, opttype)
- )
-
-
-def _validate(value, optdict, name=""):
- """return a validated value for an option according to its type
-
- optional argument name is only used for error message formatting
- """
- try:
- _type = optdict["type"]
- except KeyError:
- return value
- return _call_validator(_type, optdict, name, value)
-
-
-def _level_options(group, outputlevel):
- return [
- option
- for option in group.option_list
- if (getattr(option, "level", 0) or 0) <= outputlevel
- and option.help is not optparse.SUPPRESS_HELP
- ]
-
-
-def _expand_default(self, option):
- """Patch OptionParser.expand_default with custom behaviour
-
- This will handle defaults to avoid overriding values in the
- configuration file.
- """
- if self.parser is None or not self.default_tag:
- return option.help
- optname = option._long_opts[0][2:]
- try:
- provider = self.parser.options_manager._all_options[optname]
- except KeyError:
- value = None
- else:
- optdict = provider.get_option_def(optname)
- optname = provider.option_attrname(optname, optdict)
- value = getattr(provider.config, optname, optdict)
- value = utils._format_option_value(optdict, value)
- if value is optparse.NO_DEFAULT or not value:
- value = self.NO_DEFAULT_VALUE
- return option.help.replace(self.default_tag, str(value))
-
-
-@contextlib.contextmanager
-def _patch_optparse():
- orig_default = optparse.HelpFormatter
- try:
- optparse.HelpFormatter.expand_default = _expand_default
- yield
- finally:
- optparse.HelpFormatter.expand_default = orig_default
-
-
-def _multiple_choices_validating_option(opt, name, value):
- return _multiple_choice_validator(opt.choices, name, value)
-
-
-# pylint: disable=no-member
-class Option(optparse.Option):
- TYPES = optparse.Option.TYPES + (
- "regexp",
- "regexp_csv",
- "csv",
- "yn",
- "multiple_choice",
- "non_empty_string",
- )
- ATTRS = optparse.Option.ATTRS + ["hide", "level"]
- TYPE_CHECKER = copy.copy(optparse.Option.TYPE_CHECKER)
- TYPE_CHECKER["regexp"] = _regexp_validator
- TYPE_CHECKER["regexp_csv"] = _regexp_csv_validator
- TYPE_CHECKER["csv"] = _csv_validator
- TYPE_CHECKER["yn"] = _yn_validator
- TYPE_CHECKER["multiple_choice"] = _multiple_choices_validating_option
- TYPE_CHECKER["non_empty_string"] = _non_empty_string_validator
-
- def __init__(self, *opts, **attrs):
- optparse.Option.__init__(self, *opts, **attrs)
- if hasattr(self, "hide") and self.hide:
- self.help = optparse.SUPPRESS_HELP
-
- def _check_choice(self):
- if self.type in ("choice", "multiple_choice"):
- if self.choices is None:
- raise optparse.OptionError(
- "must supply a list of choices for type 'choice'", self
- )
- if not isinstance(self.choices, (tuple, list)):
- raise optparse.OptionError(
- "choices must be a list of strings ('%s' supplied)"
- % str(type(self.choices)).split("'")[1],
- self,
- )
- elif self.choices is not None:
- raise optparse.OptionError(
- "must not supply choices for type %r" % self.type, self
- )
-
- # pylint: disable=unsupported-assignment-operation
- optparse.Option.CHECK_METHODS[2] = _check_choice # type: ignore
-
- def process(self, opt, value, values, parser):
- # First, convert the value(s) to the right type. Howl if any
- # value(s) are bogus.
- value = self.convert_value(opt, value)
- if self.type == "named":
- existent = getattr(values, self.dest)
- if existent:
- existent.update(value)
- value = existent
- # And then take whatever action is expected of us.
- # This is a separate method to make life easier for
- # subclasses to add new actions.
- return self.take_action(self.action, self.dest, opt, value, values, parser)
-
-
-class OptionParser(optparse.OptionParser):
- def __init__(self, option_class, *args, **kwargs):
- optparse.OptionParser.__init__(self, option_class=Option, *args, **kwargs)
-
- def format_option_help(self, formatter=None):
- if formatter is None:
- formatter = self.formatter
- outputlevel = getattr(formatter, "output_level", 0)
- formatter.store_option_strings(self)
- result = []
- result.append(formatter.format_heading("Options"))
- formatter.indent()
- if self.option_list:
- result.append(optparse.OptionContainer.format_option_help(self, formatter))
- result.append("\n")
- for group in self.option_groups:
- if group.level <= outputlevel and (
- group.description or _level_options(group, outputlevel)
- ):
- result.append(group.format_help(formatter))
- result.append("\n")
- formatter.dedent()
- # Drop the last "\n", or the header if no options or option groups:
- return "".join(result[:-1])
-
- def _match_long_opt(self, opt):
- """Disable abbreviations."""
- if opt not in self._long_opt:
- raise optparse.BadOptionError(opt)
- return opt
-
-
-# pylint: disable=abstract-method; by design?
-class _ManHelpFormatter(optparse.HelpFormatter):
- def __init__(
- self, indent_increment=0, max_help_position=24, width=79, short_first=0
- ):
- optparse.HelpFormatter.__init__(
- self, indent_increment, max_help_position, width, short_first
- )
-
- def format_heading(self, heading):
- return ".SH %s\n" % heading.upper()
-
- def format_description(self, description):
- return description
-
- def format_option(self, option):
- try:
- optstring = option.option_strings
- except AttributeError:
- optstring = self.format_option_strings(option)
- if option.help:
- help_text = self.expand_default(option)
- help_string = " ".join([l.strip() for l in help_text.splitlines()])
- help_string = help_string.replace("\\", "\\\\")
- help_string = help_string.replace("[current:", "[default:")
- else:
- help_string = ""
- return """.IP "%s"
-%s
-""" % (
- optstring,
- help_string,
- )
-
- def format_head(self, optparser, pkginfo, section=1):
- long_desc = ""
- try:
- pgm = optparser._get_prog_name()
- except AttributeError:
- # py >= 2.4.X (dunno which X exactly, at least 2)
- pgm = optparser.get_prog_name()
- short_desc = self.format_short_description(pgm, pkginfo.description)
- if hasattr(pkginfo, "long_desc"):
- long_desc = self.format_long_description(pgm, pkginfo.long_desc)
- return "%s\n%s\n%s\n%s" % (
- self.format_title(pgm, section),
- short_desc,
- self.format_synopsis(pgm),
- long_desc,
- )
-
- @staticmethod
- def format_title(pgm, section):
- date = "%d-%02d-%02d" % time.localtime()[:3]
- return '.TH %s %s "%s" %s' % (pgm, section, date, pgm)
-
- @staticmethod
- def format_short_description(pgm, short_desc):
- return """.SH NAME
-.B %s
-\\- %s
-""" % (
- pgm,
- short_desc.strip(),
- )
-
- @staticmethod
- def format_synopsis(pgm):
- return (
- """.SH SYNOPSIS
-.B %s
-[
-.I OPTIONS
-] [
-.I <arguments>
-]
-"""
- % pgm
- )
-
- @staticmethod
- def format_long_description(pgm, long_desc):
- long_desc = "\n".join(line.lstrip() for line in long_desc.splitlines())
- long_desc = long_desc.replace("\n.\n", "\n\n")
- if long_desc.lower().startswith(pgm):
- long_desc = long_desc[len(pgm) :]
- return """.SH DESCRIPTION
-.B %s
-%s
-""" % (
- pgm,
- long_desc.strip(),
- )
-
- @staticmethod
- def format_tail(pkginfo):
- tail = """.SH SEE ALSO
-/usr/share/doc/pythonX.Y-%s/
-
-.SH BUGS
-Please report bugs on the project\'s mailing list:
-%s
-
-.SH AUTHOR
-%s <%s>
-""" % (
- getattr(pkginfo, "debian_name", pkginfo.modname),
- pkginfo.mailinglist,
- pkginfo.author,
- pkginfo.author_email,
- )
-
- if hasattr(pkginfo, "copyright"):
- tail += (
- """
-.SH COPYRIGHT
-%s
-"""
- % pkginfo.copyright
- )
-
- return tail
-
-
-class OptionsManagerMixIn:
- """Handle configuration from both a configuration file and command line options"""
-
- def __init__(self, usage, config_file=None, version=None):
- self.config_file = config_file
- self.reset_parsers(usage, version=version)
- # list of registered options providers
- self.options_providers = []
- # dictionary associating option name to checker
- self._all_options = collections.OrderedDict()
- self._short_options = {}
- self._nocallback_options = {}
- self._mygroups = {}
- # verbosity
- self._maxlevel = 0
-
- def reset_parsers(self, usage="", version=None):
- # configuration file parser
- self.cfgfile_parser = configparser.ConfigParser(
- inline_comment_prefixes=("#", ";")
- )
- # command line parser
- self.cmdline_parser = OptionParser(Option, usage=usage, version=version)
- self.cmdline_parser.options_manager = self
- self._optik_option_attrs = set(self.cmdline_parser.option_class.ATTRS)
-
- def register_options_provider(self, provider, own_group=True):
- """register an options provider"""
- assert provider.priority <= 0, "provider's priority can't be >= 0"
- for i in range(len(self.options_providers)):
- if provider.priority > self.options_providers[i].priority:
- self.options_providers.insert(i, provider)
- break
- else:
- self.options_providers.append(provider)
- non_group_spec_options = [
- option for option in provider.options if "group" not in option[1]
- ]
- groups = getattr(provider, "option_groups", ())
- if own_group and non_group_spec_options:
- self.add_option_group(
- provider.name.upper(),
- provider.__doc__,
- non_group_spec_options,
- provider,
- )
- else:
- for opt, optdict in non_group_spec_options:
- self.add_optik_option(provider, self.cmdline_parser, opt, optdict)
- for gname, gdoc in groups:
- gname = gname.upper()
- goptions = [
- option
- for option in provider.options
- if option[1].get("group", "").upper() == gname
- ]
- self.add_option_group(gname, gdoc, goptions, provider)
-
- def add_option_group(self, group_name, _, options, provider):
- # add option group to the command line parser
- if group_name in self._mygroups:
- group = self._mygroups[group_name]
- else:
- group = optparse.OptionGroup(
- self.cmdline_parser, title=group_name.capitalize()
- )
- self.cmdline_parser.add_option_group(group)
- group.level = provider.level
- self._mygroups[group_name] = group
- # add section to the config file
- if (
- group_name != "DEFAULT"
- and group_name not in self.cfgfile_parser._sections
- ):
- self.cfgfile_parser.add_section(group_name)
- # add provider's specific options
- for opt, optdict in options:
- self.add_optik_option(provider, group, opt, optdict)
-
- def add_optik_option(self, provider, optikcontainer, opt, optdict):
- args, optdict = self.optik_option(provider, opt, optdict)
- option = optikcontainer.add_option(*args, **optdict)
- self._all_options[opt] = provider
- self._maxlevel = max(self._maxlevel, option.level or 0)
-
- def optik_option(self, provider, opt, optdict):
- """get our personal option definition and return a suitable form for
- use with optik/optparse
- """
- optdict = copy.copy(optdict)
- if "action" in optdict:
- self._nocallback_options[provider] = opt
- else:
- optdict["action"] = "callback"
- optdict["callback"] = self.cb_set_provider_option
- # default is handled here and *must not* be given to optik if you
- # want the whole machinery to work
- if "default" in optdict:
- if (
- "help" in optdict
- and optdict.get("default") is not None
- and optdict["action"] not in ("store_true", "store_false")
- ):
- optdict["help"] += " [current: %default]"
- del optdict["default"]
- args = ["--" + str(opt)]
- if "short" in optdict:
- self._short_options[optdict["short"]] = opt
- args.append("-" + optdict["short"])
- del optdict["short"]
- # cleanup option definition dict before giving it to optik
- for key in list(optdict.keys()):
- if key not in self._optik_option_attrs:
- optdict.pop(key)
- return args, optdict
-
- def cb_set_provider_option(self, option, opt, value, parser):
- """optik callback for option setting"""
- if opt.startswith("--"):
- # remove -- on long option
- opt = opt[2:]
- else:
- # short option, get its long equivalent
- opt = self._short_options[opt[1:]]
- # trick since we can't set action='store_true' on options
- if value is None:
- value = 1
- self.global_set_option(opt, value)
-
- def global_set_option(self, opt, value):
- """set option on the correct option provider"""
- self._all_options[opt].set_option(opt, value)
-
- def generate_config(self, stream=None, skipsections=(), encoding=None):
- """write a configuration file according to the current configuration
- into the given stream or stdout
- """
- options_by_section = {}
- sections = []
- for provider in self.options_providers:
- for section, options in provider.options_by_section():
- if section is None:
- section = provider.name
- if section in skipsections:
- continue
- options = [
- (n, d, v)
- for (n, d, v) in options
- if d.get("type") is not None and not d.get("deprecated")
- ]
- if not options:
- continue
- if section not in sections:
- sections.append(section)
- alloptions = options_by_section.setdefault(section, [])
- alloptions += options
- stream = stream or sys.stdout
- printed = False
- for section in sections:
- if printed:
- print("\n", file=stream)
- utils.format_section(
- stream, section.upper(), sorted(options_by_section[section])
- )
- printed = True
-
- def generate_manpage(self, pkginfo, section=1, stream=None):
- with _patch_optparse():
- _generate_manpage(
- self.cmdline_parser,
- pkginfo,
- section,
- stream=stream or sys.stdout,
- level=self._maxlevel,
- )
-
- def load_provider_defaults(self):
- """initialize configuration using default values"""
- for provider in self.options_providers:
- provider.load_defaults()
-
- def read_config_file(self, config_file=None, verbose=None):
- """read the configuration file but do not load it (i.e. dispatching
- values to each options provider)
- """
- helplevel = 1
- while helplevel <= self._maxlevel:
- opt = "-".join(["long"] * helplevel) + "-help"
- if opt in self._all_options:
- break # already processed
- # pylint: disable=unused-argument
- def helpfunc(option, opt, val, p, level=helplevel):
- print(self.help(level))
- sys.exit(0)
-
- helpmsg = "%s verbose help." % " ".join(["more"] * helplevel)
- optdict = {"action": "callback", "callback": helpfunc, "help": helpmsg}
- provider = self.options_providers[0]
- self.add_optik_option(provider, self.cmdline_parser, opt, optdict)
- provider.options += ((opt, optdict),)
- helplevel += 1
- if config_file is None:
- config_file = self.config_file
- if config_file is not None:
- config_file = os.path.expanduser(config_file)
- if not os.path.exists(config_file):
- raise IOError("The config file {:s} doesn't exist!".format(config_file))
-
- use_config_file = config_file and os.path.exists(config_file)
- if use_config_file:
- parser = self.cfgfile_parser
-
- # Use this encoding in order to strip the BOM marker, if any.
- with io.open(config_file, "r", encoding="utf_8_sig") as fp:
- parser.read_file(fp)
-
- # normalize sections'title
- for sect, values in list(parser._sections.items()):
- if not sect.isupper() and values:
- parser._sections[sect.upper()] = values
-
- if not verbose:
- return
-
- if use_config_file:
- msg = "Using config file {}".format(os.path.abspath(config_file))
- else:
- msg = "No config file found, using default configuration"
- print(msg, file=sys.stderr)
-
- def load_config_file(self):
- """dispatch values previously read from a configuration file to each
- options provider)
- """
- parser = self.cfgfile_parser
- for section in parser.sections():
- for option, value in parser.items(section):
- try:
- self.global_set_option(option, value)
- except (KeyError, optparse.OptionError):
- continue
-
- def load_configuration(self, **kwargs):
- """override configuration according to given parameters"""
- return self.load_configuration_from_config(kwargs)
-
- def load_configuration_from_config(self, config):
- for opt, opt_value in config.items():
- opt = opt.replace("_", "-")
- provider = self._all_options[opt]
- provider.set_option(opt, opt_value)
-
- def load_command_line_configuration(self, args=None):
- """Override configuration according to command line parameters
-
- return additional arguments
- """
- with _patch_optparse():
- if args is None:
- args = sys.argv[1:]
- else:
- args = list(args)
- (options, args) = self.cmdline_parser.parse_args(args=args)
- for provider in self._nocallback_options:
- config = provider.config
- for attr in config.__dict__.keys():
- value = getattr(options, attr, None)
- if value is None:
- continue
- setattr(config, attr, value)
- return args
-
- def add_help_section(self, title, description, level=0):
- """add a dummy option section for help purpose """
- group = optparse.OptionGroup(
- self.cmdline_parser, title=title.capitalize(), description=description
- )
- group.level = level
- self._maxlevel = max(self._maxlevel, level)
- self.cmdline_parser.add_option_group(group)
-
- def help(self, level=0):
- """return the usage string for available options """
- self.cmdline_parser.formatter.output_level = level
- with _patch_optparse():
- return self.cmdline_parser.format_help()
-
-
-class OptionsProviderMixIn:
- """Mixin to provide options to an OptionsManager"""
-
- # those attributes should be overridden
- priority = -1
- name = "default"
- options = () # type: Tuple[Tuple[str, Dict[str, Any]], ...]
- level = 0
-
- def __init__(self):
- self.config = optparse.Values()
- self.load_defaults()
-
- def load_defaults(self):
- """initialize the provider using default values"""
- for opt, optdict in self.options:
- action = optdict.get("action")
- if action != "callback":
- # callback action have no default
- if optdict is None:
- optdict = self.get_option_def(opt)
- default = optdict.get("default")
- self.set_option(opt, default, action, optdict)
-
- def option_attrname(self, opt, optdict=None):
- """get the config attribute corresponding to opt"""
- if optdict is None:
- optdict = self.get_option_def(opt)
- return optdict.get("dest", opt.replace("-", "_"))
-
- def option_value(self, opt):
- """get the current value for the given option"""
- return getattr(self.config, self.option_attrname(opt), None)
-
- def set_option(self, optname, value, action=None, optdict=None):
- """method called to set an option (registered in the options list)"""
- if optdict is None:
- optdict = self.get_option_def(optname)
- if value is not None:
- value = _validate(value, optdict, optname)
- if action is None:
- action = optdict.get("action", "store")
- if action == "store":
- setattr(self.config, self.option_attrname(optname, optdict), value)
- elif action in ("store_true", "count"):
- setattr(self.config, self.option_attrname(optname, optdict), 0)
- elif action == "store_false":
- setattr(self.config, self.option_attrname(optname, optdict), 1)
- elif action == "append":
- optname = self.option_attrname(optname, optdict)
- _list = getattr(self.config, optname, None)
- if _list is None:
- if isinstance(value, (list, tuple)):
- _list = value
- elif value is not None:
- _list = []
- _list.append(value)
- setattr(self.config, optname, _list)
- elif isinstance(_list, tuple):
- setattr(self.config, optname, _list + (value,))
- else:
- _list.append(value)
- elif action == "callback":
- optdict["callback"](None, optname, value, None)
- else:
- raise UnsupportedAction(action)
-
- def get_option_def(self, opt):
- """return the dictionary defining an option given its name"""
- assert self.options
- for option in self.options:
- if option[0] == opt:
- return option[1]
- raise optparse.OptionError(
- "no such option %s in section %r" % (opt, self.name), opt
- )
-
- def options_by_section(self):
- """return an iterator on options grouped by section
-
- (section, [list of (optname, optdict, optvalue)])
- """
- sections = {}
- for optname, optdict in self.options:
- sections.setdefault(optdict.get("group"), []).append(
- (optname, optdict, self.option_value(optname))
- )
- if None in sections:
- yield None, sections.pop(None)
- for section, options in sorted(sections.items()):
- yield section.upper(), options
-
- def options_and_values(self, options=None):
- if options is None:
- options = self.options
- for optname, optdict in options:
- yield (optname, optdict, self.option_value(optname))
-
-
-class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn):
- """basic mixin for simple configurations which don't need the
- manager / providers model
- """
-
- def __init__(self, *args, **kwargs):
- if not args:
- kwargs.setdefault("usage", "")
- OptionsManagerMixIn.__init__(self, *args, **kwargs)
- OptionsProviderMixIn.__init__(self)
- if not getattr(self, "option_groups", None):
- self.option_groups = []
- for _, optdict in self.options:
- try:
- gdef = (optdict["group"].upper(), "")
- except KeyError:
- continue
- if gdef not in self.option_groups:
- self.option_groups.append(gdef)
- self.register_options_provider(self, own_group=False)
-
-
-def _generate_manpage(optparser, pkginfo, section=1, stream=sys.stdout, level=0):
- formatter = _ManHelpFormatter()
- formatter.output_level = level
- formatter.parser = optparser
- print(formatter.format_head(optparser, pkginfo, section), file=stream)
- print(optparser.format_option_help(formatter), file=stream)
- print(formatter.format_tail(pkginfo), file=stream)
diff --git a/venv/Lib/site-packages/pylint/constants.py b/venv/Lib/site-packages/pylint/constants.py
deleted file mode 100644
index 852fc15..0000000
--- a/venv/Lib/site-packages/pylint/constants.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import re
-
-# Allow stopping after the first semicolon/hash encountered,
-# so that an option can be continued with the reasons
-# why it is active or disabled.
-OPTION_RGX = re.compile(r"\s*#.*\bpylint:\s*([^;#]+)[;#]{0,1}")
-
-PY_EXTS = (".py", ".pyc", ".pyo", ".pyw", ".so", ".dll")
-
-MSG_STATE_CONFIDENCE = 2
-_MSG_ORDER = "EWRCIF"
-MSG_STATE_SCOPE_CONFIG = 0
-MSG_STATE_SCOPE_MODULE = 1
-
-# The line/node distinction does not apply to fatal errors and reports.
-_SCOPE_EXEMPT = "FR"
-
-MSG_TYPES = {
- "I": "info",
- "C": "convention",
- "R": "refactor",
- "W": "warning",
- "E": "error",
- "F": "fatal",
-}
-MSG_TYPES_LONG = {v: k for k, v in MSG_TYPES.items()}
-
-MSG_TYPES_STATUS = {"I": 0, "C": 16, "R": 8, "W": 4, "E": 2, "F": 1}
-
-# You probably don't want to change the MAIN_CHECKER_NAME
-# This would affect rcfile generation and retro-compatibility
-# on all project using [MASTER] in their rcfile.
-MAIN_CHECKER_NAME = "master"
-
-
-class WarningScope:
- LINE = "line-based-msg"
- NODE = "node-based-msg"
diff --git a/venv/Lib/site-packages/pylint/epylint.py b/venv/Lib/site-packages/pylint/epylint.py
deleted file mode 100644
index 85f1c86..0000000
--- a/venv/Lib/site-packages/pylint/epylint.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# -*- coding: utf-8;
-# mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4
-# -*- vim:fenc=utf-8:ft=python:et:sw=4:ts=4:sts=4
-
-# Copyright (c) 2008-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2014 Jakob Normark <jakobnormark@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Manuel Vázquez Acosta <mva.led@gmail.com>
-# Copyright (c) 2014 Derek Harland <derek.harland@finq.co.nz>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Mihai Balint <balint.mihai@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Daniela Plascencia <daplascen@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Ryan McGuire <ryan@enigmacurry.com>
-# Copyright (c) 2018 thernstig <30827238+thernstig@users.noreply.github.com>
-# Copyright (c) 2018 Radostin Stoyanov <rst0git@users.noreply.github.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Emacs and Flymake compatible Pylint.
-
-This script is for integration with emacs and is compatible with flymake mode.
-
-epylint walks out of python packages before invoking pylint. This avoids
-reporting import errors that occur when a module within a package uses the
-absolute import path to get another module within this package.
-
-For example:
- - Suppose a package is structured as
-
- a/__init__.py
- a/b/x.py
- a/c/y.py
-
- - Then if y.py imports x as "from a.b import x" the following produces pylint
- errors
-
- cd a/c; pylint y.py
-
- - The following obviously doesn't
-
- pylint a/c/y.py
-
- - As this script will be invoked by emacs within the directory of the file
- we are checking we need to go out of it to avoid these false positives.
-
-
-You may also use py_run to run pylint with desired options and get back (or not)
-its output.
-"""
-import os
-import os.path as osp
-import shlex
-import sys
-from io import StringIO
-from subprocess import PIPE, Popen
-
-
-def _get_env():
- """Extracts the environment PYTHONPATH and appends the current sys.path to
- those."""
- env = dict(os.environ)
- env["PYTHONPATH"] = os.pathsep.join(sys.path)
- return env
-
-
-def lint(filename, options=()):
- """Pylint the given file.
-
- When run from emacs we will be in the directory of a file, and passed its
- filename. If this file is part of a package and is trying to import other
- modules from within its own package or another package rooted in a directory
- below it, pylint will classify it as a failed import.
-
- To get around this, we traverse down the directory tree to find the root of
- the package this module is in. We then invoke pylint from this directory.
-
- Finally, we must correct the filenames in the output generated by pylint so
- Emacs doesn't become confused (it will expect just the original filename,
- while pylint may extend it with extra directories if we've traversed down
- the tree)
- """
- # traverse downwards until we are out of a python package
- full_path = osp.abspath(filename)
- parent_path = osp.dirname(full_path)
- child_path = osp.basename(full_path)
-
- while parent_path != "/" and osp.exists(osp.join(parent_path, "__init__.py")):
- child_path = osp.join(osp.basename(parent_path), child_path)
- parent_path = osp.dirname(parent_path)
-
- # Start pylint
- # Ensure we use the python and pylint associated with the running epylint
- run_cmd = "import sys; from pylint.lint import Run; Run(sys.argv[1:])"
- cmd = (
- [sys.executable, "-c", run_cmd]
- + [
- "--msg-template",
- "{path}:{line}: {category} ({msg_id}, {symbol}, {obj}) {msg}",
- "-r",
- "n",
- child_path,
- ]
- + list(options)
- )
- process = Popen(
- cmd, stdout=PIPE, cwd=parent_path, env=_get_env(), universal_newlines=True
- )
-
- for line in process.stdout:
- # remove pylintrc warning
- if line.startswith("No config file found"):
- continue
-
- # modify the file name thats output to reverse the path traversal we made
- parts = line.split(":")
- if parts and parts[0] == child_path:
- line = ":".join([filename] + parts[1:])
- print(line, end=" ")
-
- process.wait()
- return process.returncode
-
-
-def py_run(command_options="", return_std=False, stdout=None, stderr=None):
- """Run pylint from python
-
- ``command_options`` is a string containing ``pylint`` command line options;
- ``return_std`` (boolean) indicates return of created standard output
- and error (see below);
- ``stdout`` and ``stderr`` are 'file-like' objects in which standard output
- could be written.
-
- Calling agent is responsible for stdout/err management (creation, close).
- Default standard output and error are those from sys,
- or standalone ones (``subprocess.PIPE``) are used
- if they are not set and ``return_std``.
-
- If ``return_std`` is set to ``True``, this function returns a 2-uple
- containing standard output and error related to created process,
- as follows: ``(stdout, stderr)``.
-
- To silently run Pylint on a module, and get its standard output and error:
- >>> (pylint_stdout, pylint_stderr) = py_run( 'module_name.py', True)
- """
- # Detect if we use Python as executable or not, else default to `python`
- executable = sys.executable if "python" in sys.executable else "python"
-
- # Create command line to call pylint
- epylint_part = [executable, "-c", "from pylint import epylint;epylint.Run()"]
- options = shlex.split(command_options, posix=not sys.platform.startswith("win"))
- cli = epylint_part + options
-
- # Providing standard output and/or error if not set
- if stdout is None:
- if return_std:
- stdout = PIPE
- else:
- stdout = sys.stdout
- if stderr is None:
- if return_std:
- stderr = PIPE
- else:
- stderr = sys.stderr
- # Call pylint in a subprocess
- process = Popen(
- cli,
- shell=False,
- stdout=stdout,
- stderr=stderr,
- env=_get_env(),
- universal_newlines=True,
- )
- proc_stdout, proc_stderr = process.communicate()
- # Return standard output and error
- if return_std:
- return StringIO(proc_stdout), StringIO(proc_stderr)
- return None
-
-
-def Run():
- if len(sys.argv) == 1:
- print("Usage: %s <filename> [options]" % sys.argv[0])
- sys.exit(1)
- elif not osp.exists(sys.argv[1]):
- print("%s does not exist" % sys.argv[1])
- sys.exit(1)
- else:
- sys.exit(lint(sys.argv[1], sys.argv[2:]))
-
-
-if __name__ == "__main__":
- Run()
diff --git a/venv/Lib/site-packages/pylint/exceptions.py b/venv/Lib/site-packages/pylint/exceptions.py
deleted file mode 100644
index d5dd17f..0000000
--- a/venv/Lib/site-packages/pylint/exceptions.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Exception classes raised by various operations within pylint."""
-
-
-class InvalidMessageError(Exception):
- """raised when a message creation, registration or addition is rejected"""
-
-
-class UnknownMessageError(Exception):
- """raised when an unregistered message id is encountered"""
-
-
-class EmptyReportError(Exception):
- """raised when a report is empty and so should not be displayed"""
-
-
-class InvalidReporterError(Exception):
- """raised when selected reporter is invalid (e.g. not found)"""
-
-
-class InvalidArgsError(ValueError):
- """raised when passed arguments are invalid, e.g., have the wrong length"""
diff --git a/venv/Lib/site-packages/pylint/extensions/__init__.py b/venv/Lib/site-packages/pylint/extensions/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__init__.py
+++ /dev/null
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 03323e7..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/_check_docs_utils.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/_check_docs_utils.cpython-37.pyc
deleted file mode 100644
index 271e216..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/_check_docs_utils.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/bad_builtin.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/bad_builtin.cpython-37.pyc
deleted file mode 100644
index bb50903..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/bad_builtin.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/broad_try_clause.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/broad_try_clause.cpython-37.pyc
deleted file mode 100644
index cd3cd71..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/broad_try_clause.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/check_docs.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/check_docs.cpython-37.pyc
deleted file mode 100644
index 9730100..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/check_docs.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/check_elif.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/check_elif.cpython-37.pyc
deleted file mode 100644
index 030378b..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/check_elif.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/comparetozero.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/comparetozero.cpython-37.pyc
deleted file mode 100644
index 83eaae3..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/comparetozero.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/docparams.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/docparams.cpython-37.pyc
deleted file mode 100644
index 3d447e1..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/docparams.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/docstyle.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/docstyle.cpython-37.pyc
deleted file mode 100644
index e6d0d7d..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/docstyle.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/emptystring.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/emptystring.cpython-37.pyc
deleted file mode 100644
index f5f4892..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/emptystring.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/mccabe.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/mccabe.cpython-37.pyc
deleted file mode 100644
index cb64a4d..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/mccabe.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/overlapping_exceptions.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/overlapping_exceptions.cpython-37.pyc
deleted file mode 100644
index f099683..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/overlapping_exceptions.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/__pycache__/redefined_variable_type.cpython-37.pyc b/venv/Lib/site-packages/pylint/extensions/__pycache__/redefined_variable_type.cpython-37.pyc
deleted file mode 100644
index eb897a3..0000000
--- a/venv/Lib/site-packages/pylint/extensions/__pycache__/redefined_variable_type.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/extensions/_check_docs_utils.py b/venv/Lib/site-packages/pylint/extensions/_check_docs_utils.py
deleted file mode 100644
index fe1603f..0000000
--- a/venv/Lib/site-packages/pylint/extensions/_check_docs_utils.py
+++ /dev/null
@@ -1,792 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2016-2018 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016 Yuri Bochkarev <baltazar.bz@gmail.com>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Mitar <mitar.github@tnode.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2018 Mitchell T.H. Young <mitchelly@gmail.com>
-# Copyright (c) 2018 Adrian Chirieac <chirieacam@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Utility methods for docstring checking."""
-
-import re
-
-import astroid
-
-from pylint.checkers import utils
-
-
-def space_indentation(s):
- """The number of leading spaces in a string
-
- :param str s: input string
-
- :rtype: int
- :return: number of leading spaces
- """
- return len(s) - len(s.lstrip(" "))
-
-
-def get_setters_property_name(node):
- """Get the name of the property that the given node is a setter for.
-
- :param node: The node to get the property name for.
- :type node: str
-
- :rtype: str or None
- :returns: The name of the property that the node is a setter for,
- or None if one could not be found.
- """
- decorators = node.decorators.nodes if node.decorators else []
- for decorator in decorators:
- if (
- isinstance(decorator, astroid.Attribute)
- and decorator.attrname == "setter"
- and isinstance(decorator.expr, astroid.Name)
- ):
- return decorator.expr.name
- return None
-
-
-def get_setters_property(node):
- """Get the property node for the given setter node.
-
- :param node: The node to get the property for.
- :type node: astroid.FunctionDef
-
- :rtype: astroid.FunctionDef or None
- :returns: The node relating to the property of the given setter node,
- or None if one could not be found.
- """
- property_ = None
-
- property_name = get_setters_property_name(node)
- class_node = utils.node_frame_class(node)
- if property_name and class_node:
- class_attrs = class_node.getattr(node.name)
- for attr in class_attrs:
- if utils.decorated_with_property(attr):
- property_ = attr
- break
-
- return property_
-
-
-def returns_something(return_node):
- """Check if a return node returns a value other than None.
-
- :param return_node: The return node to check.
- :type return_node: astroid.Return
-
- :rtype: bool
- :return: True if the return node returns a value other than None,
- False otherwise.
- """
- returns = return_node.value
-
- if returns is None:
- return False
-
- return not (isinstance(returns, astroid.Const) and returns.value is None)
-
-
-def _get_raise_target(node):
- if isinstance(node.exc, astroid.Call):
- func = node.exc.func
- if isinstance(func, (astroid.Name, astroid.Attribute)):
- return utils.safe_infer(func)
- return None
-
-
-def possible_exc_types(node):
- """
- Gets all of the possible raised exception types for the given raise node.
-
- .. note::
-
- Caught exception types are ignored.
-
-
- :param node: The raise node to find exception types for.
- :type node: astroid.node_classes.NodeNG
-
- :returns: A list of exception types possibly raised by :param:`node`.
- :rtype: set(str)
- """
- excs = []
- if isinstance(node.exc, astroid.Name):
- inferred = utils.safe_infer(node.exc)
- if inferred:
- excs = [inferred.name]
- elif node.exc is None:
- handler = node.parent
- while handler and not isinstance(handler, astroid.ExceptHandler):
- handler = handler.parent
-
- if handler and handler.type:
- inferred_excs = astroid.unpack_infer(handler.type)
- excs = (exc.name for exc in inferred_excs if exc is not astroid.Uninferable)
- else:
- target = _get_raise_target(node)
- if isinstance(target, astroid.ClassDef):
- excs = [target.name]
- elif isinstance(target, astroid.FunctionDef):
- for ret in target.nodes_of_class(astroid.Return):
- if ret.frame() != target:
- # return from inner function - ignore it
- continue
-
- val = utils.safe_infer(ret.value)
- if (
- val
- and isinstance(val, (astroid.Instance, astroid.ClassDef))
- and utils.inherit_from_std_ex(val)
- ):
- excs.append(val.name)
-
- try:
- return {exc for exc in excs if not utils.node_ignores_exception(node, exc)}
- except astroid.InferenceError:
- return set()
-
-
-def docstringify(docstring, default_type="default"):
- for docstring_type in [
- SphinxDocstring,
- EpytextDocstring,
- GoogleDocstring,
- NumpyDocstring,
- ]:
- instance = docstring_type(docstring)
- if instance.is_valid():
- return instance
-
- docstring_type = DOCSTRING_TYPES.get(default_type, Docstring)
- return docstring_type(docstring)
-
-
-class Docstring:
- re_for_parameters_see = re.compile(
- r"""
- For\s+the\s+(other)?\s*parameters\s*,\s+see
- """,
- re.X | re.S,
- )
-
- supports_yields = None
- """True if the docstring supports a "yield" section.
-
- False if the docstring uses the returns section to document generators.
- """
-
- # These methods are designed to be overridden
- # pylint: disable=no-self-use
- def __init__(self, doc):
- doc = doc or ""
- self.doc = doc.expandtabs()
-
- def is_valid(self):
- return False
-
- def exceptions(self):
- return set()
-
- def has_params(self):
- return False
-
- def has_returns(self):
- return False
-
- def has_rtype(self):
- return False
-
- def has_property_returns(self):
- return False
-
- def has_property_type(self):
- return False
-
- def has_yields(self):
- return False
-
- def has_yields_type(self):
- return False
-
- def match_param_docs(self):
- return set(), set()
-
- def params_documented_elsewhere(self):
- return self.re_for_parameters_see.search(self.doc) is not None
-
-
-class SphinxDocstring(Docstring):
- re_type = r"""
- [~!.]? # Optional link style prefix
- \w(?:\w|\.[^\.])* # Valid python name
- """
-
- re_simple_container_type = r"""
- {type} # a container type
- [\(\[] [^\n\s]+ [\)\]] # with the contents of the container
- """.format(
- type=re_type
- )
-
- re_xref = r"""
- (?::\w+:)? # optional tag
- `{}` # what to reference
- """.format(
- re_type
- )
-
- re_param_raw = r"""
- : # initial colon
- (?: # Sphinx keywords
- param|parameter|
- arg|argument|
- key|keyword
- )
- \s+ # whitespace
-
- (?: # optional type declaration
- ({type}|{container_type})
- \s+
- )?
-
- (\w+) # Parameter name
- \s* # whitespace
- : # final colon
- """.format(
- type=re_type, container_type=re_simple_container_type
- )
- re_param_in_docstring = re.compile(re_param_raw, re.X | re.S)
-
- re_type_raw = r"""
- :type # Sphinx keyword
- \s+ # whitespace
- ({type}) # Parameter name
- \s* # whitespace
- : # final colon
- """.format(
- type=re_type
- )
- re_type_in_docstring = re.compile(re_type_raw, re.X | re.S)
-
- re_property_type_raw = r"""
- :type: # Sphinx keyword
- \s+ # whitespace
- {type} # type declaration
- """.format(
- type=re_type
- )
- re_property_type_in_docstring = re.compile(re_property_type_raw, re.X | re.S)
-
- re_raise_raw = r"""
- : # initial colon
- (?: # Sphinx keyword
- raises?|
- except|exception
- )
- \s+ # whitespace
- ({type}) # exception type
- \s* # whitespace
- : # final colon
- """.format(
- type=re_type
- )
- re_raise_in_docstring = re.compile(re_raise_raw, re.X | re.S)
-
- re_rtype_in_docstring = re.compile(r":rtype:")
-
- re_returns_in_docstring = re.compile(r":returns?:")
-
- supports_yields = False
-
- def is_valid(self):
- return bool(
- self.re_param_in_docstring.search(self.doc)
- or self.re_raise_in_docstring.search(self.doc)
- or self.re_rtype_in_docstring.search(self.doc)
- or self.re_returns_in_docstring.search(self.doc)
- or self.re_property_type_in_docstring.search(self.doc)
- )
-
- def exceptions(self):
- types = set()
-
- for match in re.finditer(self.re_raise_in_docstring, self.doc):
- raise_type = match.group(1)
- types.add(raise_type)
-
- return types
-
- def has_params(self):
- if not self.doc:
- return False
-
- return self.re_param_in_docstring.search(self.doc) is not None
-
- def has_returns(self):
- if not self.doc:
- return False
-
- return bool(self.re_returns_in_docstring.search(self.doc))
-
- def has_rtype(self):
- if not self.doc:
- return False
-
- return bool(self.re_rtype_in_docstring.search(self.doc))
-
- def has_property_returns(self):
- if not self.doc:
- return False
-
- # The summary line is the return doc,
- # so the first line must not be a known directive.
- return not self.doc.lstrip().startswith(":")
-
- def has_property_type(self):
- if not self.doc:
- return False
-
- return bool(self.re_property_type_in_docstring.search(self.doc))
-
- def match_param_docs(self):
- params_with_doc = set()
- params_with_type = set()
-
- for match in re.finditer(self.re_param_in_docstring, self.doc):
- name = match.group(2)
- params_with_doc.add(name)
- param_type = match.group(1)
- if param_type is not None:
- params_with_type.add(name)
-
- params_with_type.update(re.findall(self.re_type_in_docstring, self.doc))
- return params_with_doc, params_with_type
-
-
-class EpytextDocstring(SphinxDocstring):
- """
- Epytext is similar to Sphinx. See the docs:
- http://epydoc.sourceforge.net/epytext.html
- http://epydoc.sourceforge.net/fields.html#fields
-
- It's used in PyCharm:
- https://www.jetbrains.com/help/pycharm/2016.1/creating-documentation-comments.html#d848203e314
- https://www.jetbrains.com/help/pycharm/2016.1/using-docstrings-to-specify-types.html
- """
-
- re_param_in_docstring = re.compile(
- SphinxDocstring.re_param_raw.replace(":", "@", 1), re.X | re.S
- )
-
- re_type_in_docstring = re.compile(
- SphinxDocstring.re_type_raw.replace(":", "@", 1), re.X | re.S
- )
-
- re_property_type_in_docstring = re.compile(
- SphinxDocstring.re_property_type_raw.replace(":", "@", 1), re.X | re.S
- )
-
- re_raise_in_docstring = re.compile(
- SphinxDocstring.re_raise_raw.replace(":", "@", 1), re.X | re.S
- )
-
- re_rtype_in_docstring = re.compile(
- r"""
- @ # initial "at" symbol
- (?: # Epytext keyword
- rtype|returntype
- )
- : # final colon
- """,
- re.X | re.S,
- )
-
- re_returns_in_docstring = re.compile(r"@returns?:")
-
- def has_property_returns(self):
- if not self.doc:
- return False
-
- # If this is a property docstring, the summary is the return doc.
- if self.has_property_type():
- # The summary line is the return doc,
- # so the first line must not be a known directive.
- return not self.doc.lstrip().startswith("@")
-
- return False
-
-
-class GoogleDocstring(Docstring):
- re_type = SphinxDocstring.re_type
-
- re_xref = SphinxDocstring.re_xref
-
- re_container_type = r"""
- (?:{type}|{xref}) # a container type
- [\(\[] [^\n]+ [\)\]] # with the contents of the container
- """.format(
- type=re_type, xref=re_xref
- )
-
- re_multiple_type = r"""
- (?:{container_type}|{type}|{xref})
- (?:\s+(?:of|or)\s+(?:{container_type}|{type}|{xref}))*
- """.format(
- type=re_type, xref=re_xref, container_type=re_container_type
- )
-
- _re_section_template = r"""
- ^([ ]*) {0} \s*: \s*$ # Google parameter header
- ( .* ) # section
- """
-
- re_param_section = re.compile(
- _re_section_template.format(r"(?:Args|Arguments|Parameters)"),
- re.X | re.S | re.M,
- )
-
- re_keyword_param_section = re.compile(
- _re_section_template.format(r"Keyword\s(?:Args|Arguments|Parameters)"),
- re.X | re.S | re.M,
- )
-
- re_param_line = re.compile(
- r"""
- \s* \*{{0,2}}(\w+) # identifier potentially with asterisks
- \s* ( [(]
- {type}
- (?:,\s+optional)?
- [)] )? \s* : # optional type declaration
- \s* (.*) # beginning of optional description
- """.format(
- type=re_multiple_type
- ),
- re.X | re.S | re.M,
- )
-
- re_raise_section = re.compile(
- _re_section_template.format(r"Raises"), re.X | re.S | re.M
- )
-
- re_raise_line = re.compile(
- r"""
- \s* ({type}) \s* : # identifier
- \s* (.*) # beginning of optional description
- """.format(
- type=re_type
- ),
- re.X | re.S | re.M,
- )
-
- re_returns_section = re.compile(
- _re_section_template.format(r"Returns?"), re.X | re.S | re.M
- )
-
- re_returns_line = re.compile(
- r"""
- \s* ({type}:)? # identifier
- \s* (.*) # beginning of description
- """.format(
- type=re_multiple_type
- ),
- re.X | re.S | re.M,
- )
-
- re_property_returns_line = re.compile(
- r"""
- ^{type}: # indentifier
- \s* (.*) # Summary line / description
- """.format(
- type=re_multiple_type
- ),
- re.X | re.S | re.M,
- )
-
- re_yields_section = re.compile(
- _re_section_template.format(r"Yields?"), re.X | re.S | re.M
- )
-
- re_yields_line = re_returns_line
-
- supports_yields = True
-
- def is_valid(self):
- return bool(
- self.re_param_section.search(self.doc)
- or self.re_raise_section.search(self.doc)
- or self.re_returns_section.search(self.doc)
- or self.re_yields_section.search(self.doc)
- or self.re_property_returns_line.search(self._first_line())
- )
-
- def has_params(self):
- if not self.doc:
- return False
-
- return self.re_param_section.search(self.doc) is not None
-
- def has_returns(self):
- if not self.doc:
- return False
-
- entries = self._parse_section(self.re_returns_section)
- for entry in entries:
- match = self.re_returns_line.match(entry)
- if not match:
- continue
-
- return_desc = match.group(2)
- if return_desc:
- return True
-
- return False
-
- def has_rtype(self):
- if not self.doc:
- return False
-
- entries = self._parse_section(self.re_returns_section)
- for entry in entries:
- match = self.re_returns_line.match(entry)
- if not match:
- continue
-
- return_type = match.group(1)
- if return_type:
- return True
-
- return False
-
- def has_property_returns(self):
- # The summary line is the return doc,
- # so the first line must not be a known directive.
- first_line = self._first_line()
- return not bool(
- self.re_param_section.search(first_line)
- or self.re_raise_section.search(first_line)
- or self.re_returns_section.search(first_line)
- or self.re_yields_section.search(first_line)
- )
-
- def has_property_type(self):
- if not self.doc:
- return False
-
- return bool(self.re_property_returns_line.match(self._first_line()))
-
- def has_yields(self):
- if not self.doc:
- return False
-
- entries = self._parse_section(self.re_yields_section)
- for entry in entries:
- match = self.re_yields_line.match(entry)
- if not match:
- continue
-
- yield_desc = match.group(2)
- if yield_desc:
- return True
-
- return False
-
- def has_yields_type(self):
- if not self.doc:
- return False
-
- entries = self._parse_section(self.re_yields_section)
- for entry in entries:
- match = self.re_yields_line.match(entry)
- if not match:
- continue
-
- yield_type = match.group(1)
- if yield_type:
- return True
-
- return False
-
- def exceptions(self):
- types = set()
-
- entries = self._parse_section(self.re_raise_section)
- for entry in entries:
- match = self.re_raise_line.match(entry)
- if not match:
- continue
-
- exc_type = match.group(1)
- exc_desc = match.group(2)
- if exc_desc:
- types.add(exc_type)
-
- return types
-
- def match_param_docs(self):
- params_with_doc = set()
- params_with_type = set()
-
- entries = self._parse_section(self.re_param_section)
- entries.extend(self._parse_section(self.re_keyword_param_section))
- for entry in entries:
- match = self.re_param_line.match(entry)
- if not match:
- continue
-
- param_name = match.group(1)
- param_type = match.group(2)
- param_desc = match.group(3)
- if param_type:
- params_with_type.add(param_name)
-
- if param_desc:
- params_with_doc.add(param_name)
-
- return params_with_doc, params_with_type
-
- def _first_line(self):
- return self.doc.lstrip().split("\n", 1)[0]
-
- @staticmethod
- def min_section_indent(section_match):
- return len(section_match.group(1)) + 1
-
- @staticmethod
- def _is_section_header(_):
- # Google parsing does not need to detect section headers,
- # because it works off of indentation level only
- return False
-
- def _parse_section(self, section_re):
- section_match = section_re.search(self.doc)
- if section_match is None:
- return []
-
- min_indentation = self.min_section_indent(section_match)
-
- entries = []
- entry = []
- is_first = True
- for line in section_match.group(2).splitlines():
- if not line.strip():
- continue
- indentation = space_indentation(line)
- if indentation < min_indentation:
- break
-
- # The first line after the header defines the minimum
- # indentation.
- if is_first:
- min_indentation = indentation
- is_first = False
-
- if indentation == min_indentation:
- if self._is_section_header(line):
- break
- # Lines with minimum indentation must contain the beginning
- # of a new parameter documentation.
- if entry:
- entries.append("\n".join(entry))
- entry = []
-
- entry.append(line)
-
- if entry:
- entries.append("\n".join(entry))
-
- return entries
-
-
-class NumpyDocstring(GoogleDocstring):
- _re_section_template = r"""
- ^([ ]*) {0} \s*?$ # Numpy parameters header
- \s* [-=]+ \s*?$ # underline
- ( .* ) # section
- """
-
- re_param_section = re.compile(
- _re_section_template.format(r"(?:Args|Arguments|Parameters)"),
- re.X | re.S | re.M,
- )
-
- re_param_line = re.compile(
- r"""
- \s* (\w+) # identifier
- \s* :
- \s* (?:({type})(?:,\s+optional)?)? # optional type declaration
- \n # description starts on a new line
- \s* (.*) # description
- """.format(
- type=GoogleDocstring.re_multiple_type
- ),
- re.X | re.S,
- )
-
- re_raise_section = re.compile(
- _re_section_template.format(r"Raises"), re.X | re.S | re.M
- )
-
- re_raise_line = re.compile(
- r"""
- \s* ({type})$ # type declaration
- \s* (.*) # optional description
- """.format(
- type=GoogleDocstring.re_type
- ),
- re.X | re.S | re.M,
- )
-
- re_returns_section = re.compile(
- _re_section_template.format(r"Returns?"), re.X | re.S | re.M
- )
-
- re_returns_line = re.compile(
- r"""
- \s* (?:\w+\s+:\s+)? # optional name
- ({type})$ # type declaration
- \s* (.*) # optional description
- """.format(
- type=GoogleDocstring.re_multiple_type
- ),
- re.X | re.S | re.M,
- )
-
- re_yields_section = re.compile(
- _re_section_template.format(r"Yields?"), re.X | re.S | re.M
- )
-
- re_yields_line = re_returns_line
-
- supports_yields = True
-
- @staticmethod
- def min_section_indent(section_match):
- return len(section_match.group(1))
-
- @staticmethod
- def _is_section_header(line):
- return bool(re.match(r"\s*-+$", line))
-
-
-DOCSTRING_TYPES = {
- "sphinx": SphinxDocstring,
- "epytext": EpytextDocstring,
- "google": GoogleDocstring,
- "numpy": NumpyDocstring,
- "default": Docstring,
-}
-"""A map of the name of the docstring type to its class.
-
-:type: dict(str, type)
-"""
diff --git a/venv/Lib/site-packages/pylint/extensions/bad_builtin.py b/venv/Lib/site-packages/pylint/extensions/bad_builtin.py
deleted file mode 100644
index 754c409..0000000
--- a/venv/Lib/site-packages/pylint/extensions/bad_builtin.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright (c) 2016 Claudiu Popa <pcmanticore@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Checker for deprecated builtins."""
-import astroid
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker
-
-BAD_FUNCTIONS = ["map", "filter"]
-# Some hints regarding the use of bad builtins.
-BUILTIN_HINTS = {"map": "Using a list comprehension can be clearer."}
-BUILTIN_HINTS["filter"] = BUILTIN_HINTS["map"]
-
-
-class BadBuiltinChecker(BaseChecker):
-
- __implements__ = (IAstroidChecker,)
- name = "deprecated_builtins"
- msgs = {
- "W0141": (
- "Used builtin function %s",
- "bad-builtin",
- "Used when a black listed builtin function is used (see the "
- "bad-function option). Usual black listed functions are the ones "
- "like map, or filter , where Python offers now some cleaner "
- "alternative like list comprehension.",
- )
- }
-
- options = (
- (
- "bad-functions",
- {
- "default": BAD_FUNCTIONS,
- "type": "csv",
- "metavar": "<builtin function names>",
- "help": "List of builtins function names that should not be "
- "used, separated by a comma",
- },
- ),
- )
-
- @check_messages("bad-builtin")
- def visit_call(self, node):
- if isinstance(node.func, astroid.Name):
- name = node.func.name
- # ignore the name if it's not a builtin (i.e. not defined in the
- # locals nor globals scope)
- if not (name in node.frame() or name in node.root()):
- if name in self.config.bad_functions:
- hint = BUILTIN_HINTS.get(name)
- if hint:
- args = "%r. %s" % (name, hint)
- else:
- args = repr(name)
- self.add_message("bad-builtin", node=node, args=args)
-
-
-def register(linter):
- """Required method to auto register this checker.
-
- :param linter: Main interface object for Pylint plugins
- :type linter: Pylint object
- """
- linter.register_checker(BadBuiltinChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/broad_try_clause.py b/venv/Lib/site-packages/pylint/extensions/broad_try_clause.py
deleted file mode 100644
index 9a61fb6..0000000
--- a/venv/Lib/site-packages/pylint/extensions/broad_try_clause.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2019 Tyler N. Thieding <python@thieding.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Looks for try/except statements with too much code in the try clause."""
-
-from pylint import checkers, interfaces
-
-
-class BroadTryClauseChecker(checkers.BaseChecker):
- """Checks for try clauses with too many lines.
-
- According to PEP 8, ``try`` clauses shall contain the absolute minimum
- amount of code. This checker enforces a maximum number of statements within
- ``try`` clauses.
-
- """
-
- __implements__ = interfaces.IAstroidChecker
-
- # configuration section name
- name = "broad_try_clause"
- msgs = {
- "W0717": (
- "%s",
- "too-many-try-statements",
- "Try clause contains too many statements.",
- )
- }
-
- priority = -2
- options = (
- (
- "max-try-statements",
- {
- "default": 1,
- "type": "int",
- "metavar": "<int>",
- "help": "Maximum number of statements allowed in a try clause",
- },
- ),
- )
-
- def visit_tryexcept(self, node):
- try_clause_statements = len(node.body)
- if try_clause_statements > self.config.max_try_statements:
- msg = "try clause contains {0} statements, expected at most {1}".format(
- try_clause_statements, self.config.max_try_statements
- )
- self.add_message(
- "too-many-try-statements", node.lineno, node=node, args=msg
- )
-
-
-def register(linter):
- """Required method to auto register this checker."""
- linter.register_checker(BroadTryClauseChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/check_docs.py b/venv/Lib/site-packages/pylint/extensions/check_docs.py
deleted file mode 100644
index 7f7f643..0000000
--- a/venv/Lib/site-packages/pylint/extensions/check_docs.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (c) 2014-2015 Bruno Daniel <bruno.daniel@blue-yonder.com>
-# Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import warnings
-
-from pylint.extensions import docparams
-
-
-def register(linter):
- """Required method to auto register this checker.
-
- :param linter: Main interface object for Pylint plugins
- :type linter: Pylint object
- """
- warnings.warn(
- "This plugin is deprecated, use pylint.extensions.docparams instead.",
- DeprecationWarning,
- )
- linter.register_checker(docparams.DocstringParameterChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/check_elif.py b/venv/Lib/site-packages/pylint/extensions/check_elif.py
deleted file mode 100644
index 67555b1..0000000
--- a/venv/Lib/site-packages/pylint/extensions/check_elif.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016 Glenn Matthews <glmatthe@cisco.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import astroid
-
-from pylint.checkers import BaseTokenChecker
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker, ITokenChecker
-
-
-class ElseifUsedChecker(BaseTokenChecker):
- """Checks for use of "else if" when an "elif" could be used
- """
-
- __implements__ = (ITokenChecker, IAstroidChecker)
- name = "else_if_used"
- msgs = {
- "R5501": (
- 'Consider using "elif" instead of "else if"',
- "else-if-used",
- "Used when an else statement is immediately followed by "
- "an if statement and does not contain statements that "
- "would be unrelated to it.",
- )
- }
-
- def __init__(self, linter=None):
- BaseTokenChecker.__init__(self, linter)
- self._init()
-
- def _init(self):
- self._elifs = []
- self._if_counter = 0
-
- def process_tokens(self, tokens):
- # Process tokens and look for 'if' or 'elif'
- for _, token, _, _, _ in tokens:
- if token == "elif":
- self._elifs.append(True)
- elif token == "if":
- self._elifs.append(False)
-
- def leave_module(self, _):
- self._init()
-
- def visit_ifexp(self, node):
- if isinstance(node.parent, astroid.FormattedValue):
- return
- self._if_counter += 1
-
- def visit_comprehension(self, node):
- self._if_counter += len(node.ifs)
-
- @check_messages("else-if-used")
- def visit_if(self, node):
- if isinstance(node.parent, astroid.If):
- orelse = node.parent.orelse
- # current if node must directly follow an "else"
- if orelse and orelse == [node]:
- if not self._elifs[self._if_counter]:
- self.add_message("else-if-used", node=node)
- self._if_counter += 1
-
-
-def register(linter):
- """Required method to auto register this checker.
-
- :param linter: Main interface object for Pylint plugins
- :type linter: Pylint object
- """
- linter.register_checker(ElseifUsedChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/comparetozero.py b/venv/Lib/site-packages/pylint/extensions/comparetozero.py
deleted file mode 100644
index e31f488..0000000
--- a/venv/Lib/site-packages/pylint/extensions/comparetozero.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2017 Claudiu Popa <pcmanticore@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Looks for comparisons to empty string."""
-
-import itertools
-
-import astroid
-
-from pylint import checkers, interfaces
-from pylint.checkers import utils
-
-
-def _is_constant_zero(node):
- return isinstance(node, astroid.Const) and node.value == 0
-
-
-class CompareToZeroChecker(checkers.BaseChecker):
- """Checks for comparisons to zero.
- Most of the times you should use the fact that integers with a value of 0 are false.
- An exception to this rule is when 0 is allowed in the program and has a
- different meaning than None!
- """
-
- __implements__ = (interfaces.IAstroidChecker,)
-
- # configuration section name
- name = "compare-to-zero"
- msgs = {
- "C2001": (
- "Avoid comparisons to zero",
- "compare-to-zero",
- "Used when Pylint detects comparison to a 0 constant.",
- )
- }
-
- priority = -2
- options = ()
-
- @utils.check_messages("compare-to-zero")
- def visit_compare(self, node):
- _operators = ["!=", "==", "is not", "is"]
- # note: astroid.Compare has the left most operand in node.left
- # while the rest are a list of tuples in node.ops
- # the format of the tuple is ('compare operator sign', node)
- # here we squash everything into `ops` to make it easier for processing later
- ops = [("", node.left)]
- ops.extend(node.ops)
- ops = list(itertools.chain(*ops))
-
- for ops_idx in range(len(ops) - 2):
- op_1 = ops[ops_idx]
- op_2 = ops[ops_idx + 1]
- op_3 = ops[ops_idx + 2]
- error_detected = False
-
- # 0 ?? X
- if _is_constant_zero(op_1) and op_2 in _operators:
- error_detected = True
- # X ?? 0
- elif op_2 in _operators and _is_constant_zero(op_3):
- error_detected = True
-
- if error_detected:
- self.add_message("compare-to-zero", node=node)
-
-
-def register(linter):
- """Required method to auto register this checker."""
- linter.register_checker(CompareToZeroChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/docparams.py b/venv/Lib/site-packages/pylint/extensions/docparams.py
deleted file mode 100644
index d5a15a4..0000000
--- a/venv/Lib/site-packages/pylint/extensions/docparams.py
+++ /dev/null
@@ -1,536 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014-2015 Bruno Daniel <bruno.daniel@blue-yonder.com>
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016-2018 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-# Copyright (c) 2016 Glenn Matthews <glmatthe@cisco.com>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2017 John Paraskevopoulos <io.paraskev@gmail.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Adam Dangoor <adamdangoor@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Pylint plugin for checking in Sphinx, Google, or Numpy style docstrings
-"""
-import astroid
-
-import pylint.extensions._check_docs_utils as utils
-from pylint.checkers import BaseChecker
-from pylint.checkers import utils as checker_utils
-from pylint.interfaces import IAstroidChecker
-
-
-class DocstringParameterChecker(BaseChecker):
- """Checker for Sphinx, Google, or Numpy style docstrings
-
- * Check that all function, method and constructor parameters are mentioned
- in the params and types part of the docstring. Constructor parameters
- can be documented in either the class docstring or ``__init__`` docstring,
- but not both.
- * Check that there are no naming inconsistencies between the signature and
- the documentation, i.e. also report documented parameters that are missing
- in the signature. This is important to find cases where parameters are
- renamed only in the code, not in the documentation.
- * Check that all explicitly raised exceptions in a function are documented
- in the function docstring. Caught exceptions are ignored.
-
- Activate this checker by adding the line::
-
- load-plugins=pylint.extensions.docparams
-
- to the ``MASTER`` section of your ``.pylintrc``.
-
- :param linter: linter object
- :type linter: :class:`pylint.lint.PyLinter`
- """
-
- __implements__ = IAstroidChecker
-
- name = "parameter_documentation"
- msgs = {
- "W9005": (
- '"%s" has constructor parameters documented in class and __init__',
- "multiple-constructor-doc",
- "Please remove parameter declarations in the class or constructor.",
- ),
- "W9006": (
- '"%s" not documented as being raised',
- "missing-raises-doc",
- "Please document exceptions for all raised exception types.",
- ),
- "W9008": (
- "Redundant returns documentation",
- "redundant-returns-doc",
- "Please remove the return/rtype documentation from this method.",
- ),
- "W9010": (
- "Redundant yields documentation",
- "redundant-yields-doc",
- "Please remove the yields documentation from this method.",
- ),
- "W9011": (
- "Missing return documentation",
- "missing-return-doc",
- "Please add documentation about what this method returns.",
- {"old_names": [("W9007", "old-missing-returns-doc")]},
- ),
- "W9012": (
- "Missing return type documentation",
- "missing-return-type-doc",
- "Please document the type returned by this method.",
- # we can't use the same old_name for two different warnings
- # {'old_names': [('W9007', 'missing-returns-doc')]},
- ),
- "W9013": (
- "Missing yield documentation",
- "missing-yield-doc",
- "Please add documentation about what this generator yields.",
- {"old_names": [("W9009", "old-missing-yields-doc")]},
- ),
- "W9014": (
- "Missing yield type documentation",
- "missing-yield-type-doc",
- "Please document the type yielded by this method.",
- # we can't use the same old_name for two different warnings
- # {'old_names': [('W9009', 'missing-yields-doc')]},
- ),
- "W9015": (
- '"%s" missing in parameter documentation',
- "missing-param-doc",
- "Please add parameter declarations for all parameters.",
- {"old_names": [("W9003", "old-missing-param-doc")]},
- ),
- "W9016": (
- '"%s" missing in parameter type documentation',
- "missing-type-doc",
- "Please add parameter type declarations for all parameters.",
- {"old_names": [("W9004", "old-missing-type-doc")]},
- ),
- "W9017": (
- '"%s" differing in parameter documentation',
- "differing-param-doc",
- "Please check parameter names in declarations.",
- ),
- "W9018": (
- '"%s" differing in parameter type documentation',
- "differing-type-doc",
- "Please check parameter names in type declarations.",
- ),
- }
-
- options = (
- (
- "accept-no-param-doc",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y or n>",
- "help": "Whether to accept totally missing parameter "
- "documentation in the docstring of a function that has "
- "parameters.",
- },
- ),
- (
- "accept-no-raise-doc",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y or n>",
- "help": "Whether to accept totally missing raises "
- "documentation in the docstring of a function that "
- "raises an exception.",
- },
- ),
- (
- "accept-no-return-doc",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y or n>",
- "help": "Whether to accept totally missing return "
- "documentation in the docstring of a function that "
- "returns a statement.",
- },
- ),
- (
- "accept-no-yields-doc",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y or n>",
- "help": "Whether to accept totally missing yields "
- "documentation in the docstring of a generator.",
- },
- ),
- (
- "default-docstring-type",
- {
- "type": "choice",
- "default": "default",
- "choices": list(utils.DOCSTRING_TYPES),
- "help": "If the docstring type cannot be guessed "
- "the specified docstring type will be used.",
- },
- ),
- )
-
- priority = -2
-
- constructor_names = {"__init__", "__new__"}
- not_needed_param_in_docstring = {"self", "cls"}
-
- def visit_functiondef(self, node):
- """Called for function and method definitions (def).
-
- :param node: Node for a function or method definition in the AST
- :type node: :class:`astroid.scoped_nodes.Function`
- """
- node_doc = utils.docstringify(node.doc, self.config.default_docstring_type)
- self.check_functiondef_params(node, node_doc)
- self.check_functiondef_returns(node, node_doc)
- self.check_functiondef_yields(node, node_doc)
-
- def check_functiondef_params(self, node, node_doc):
- node_allow_no_param = None
- if node.name in self.constructor_names:
- class_node = checker_utils.node_frame_class(node)
- if class_node is not None:
- class_doc = utils.docstringify(
- class_node.doc, self.config.default_docstring_type
- )
- self.check_single_constructor_params(class_doc, node_doc, class_node)
-
- # __init__ or class docstrings can have no parameters documented
- # as long as the other documents them.
- node_allow_no_param = (
- class_doc.has_params()
- or class_doc.params_documented_elsewhere()
- or None
- )
- class_allow_no_param = (
- node_doc.has_params()
- or node_doc.params_documented_elsewhere()
- or None
- )
-
- self.check_arguments_in_docstring(
- class_doc, node.args, class_node, class_allow_no_param
- )
-
- self.check_arguments_in_docstring(
- node_doc, node.args, node, node_allow_no_param
- )
-
- def check_functiondef_returns(self, node, node_doc):
- if (not node_doc.supports_yields and node.is_generator()) or node.is_abstract():
- return
-
- return_nodes = node.nodes_of_class(astroid.Return)
- if (node_doc.has_returns() or node_doc.has_rtype()) and not any(
- utils.returns_something(ret_node) for ret_node in return_nodes
- ):
- self.add_message("redundant-returns-doc", node=node)
-
- def check_functiondef_yields(self, node, node_doc):
- if not node_doc.supports_yields or node.is_abstract():
- return
-
- if (
- node_doc.has_yields() or node_doc.has_yields_type()
- ) and not node.is_generator():
- self.add_message("redundant-yields-doc", node=node)
-
- def visit_raise(self, node):
- func_node = node.frame()
- if not isinstance(func_node, astroid.FunctionDef):
- return
-
- expected_excs = utils.possible_exc_types(node)
-
- if not expected_excs:
- return
-
- if not func_node.doc:
- # If this is a property setter,
- # the property should have the docstring instead.
- property_ = utils.get_setters_property(func_node)
- if property_:
- func_node = property_
-
- doc = utils.docstringify(func_node.doc, self.config.default_docstring_type)
- if not doc.is_valid():
- if doc.doc:
- self._handle_no_raise_doc(expected_excs, func_node)
- return
-
- found_excs_full_names = doc.exceptions()
-
- # Extract just the class name, e.g. "error" from "re.error"
- found_excs_class_names = {exc.split(".")[-1] for exc in found_excs_full_names}
- missing_excs = expected_excs - found_excs_class_names
- self._add_raise_message(missing_excs, func_node)
-
- def visit_return(self, node):
- if not utils.returns_something(node):
- return
-
- func_node = node.frame()
- if not isinstance(func_node, astroid.FunctionDef):
- return
-
- doc = utils.docstringify(func_node.doc, self.config.default_docstring_type)
- if not doc.is_valid() and self.config.accept_no_return_doc:
- return
-
- is_property = checker_utils.decorated_with_property(func_node)
-
- if not (doc.has_returns() or (doc.has_property_returns() and is_property)):
- self.add_message("missing-return-doc", node=func_node)
-
- if func_node.returns:
- return
-
- if not (doc.has_rtype() or (doc.has_property_type() and is_property)):
- self.add_message("missing-return-type-doc", node=func_node)
-
- def visit_yield(self, node):
- func_node = node.frame()
- if not isinstance(func_node, astroid.FunctionDef):
- return
-
- doc = utils.docstringify(func_node.doc, self.config.default_docstring_type)
- if not doc.is_valid() and self.config.accept_no_yields_doc:
- return
-
- if doc.supports_yields:
- doc_has_yields = doc.has_yields()
- doc_has_yields_type = doc.has_yields_type()
- else:
- doc_has_yields = doc.has_returns()
- doc_has_yields_type = doc.has_rtype()
-
- if not doc_has_yields:
- self.add_message("missing-yield-doc", node=func_node)
-
- if not (doc_has_yields_type or func_node.returns):
- self.add_message("missing-yield-type-doc", node=func_node)
-
- def visit_yieldfrom(self, node):
- self.visit_yield(node)
-
- def _compare_missing_args(
- self,
- found_argument_names,
- message_id,
- not_needed_names,
- expected_argument_names,
- warning_node,
- ):
- """Compare the found argument names with the expected ones and
- generate a message if there are arguments missing.
-
- :param set found_argument_names: argument names found in the
- docstring
-
- :param str message_id: pylint message id
-
- :param not_needed_names: names that may be omitted
- :type not_needed_names: set of str
-
- :param set expected_argument_names: Expected argument names
- :param NodeNG warning_node: The node to be analyzed
- """
- missing_argument_names = (
- expected_argument_names - found_argument_names
- ) - not_needed_names
- if missing_argument_names:
- self.add_message(
- message_id,
- args=(", ".join(sorted(missing_argument_names)),),
- node=warning_node,
- )
-
- def _compare_different_args(
- self,
- found_argument_names,
- message_id,
- not_needed_names,
- expected_argument_names,
- warning_node,
- ):
- """Compare the found argument names with the expected ones and
- generate a message if there are extra arguments found.
-
- :param set found_argument_names: argument names found in the
- docstring
-
- :param str message_id: pylint message id
-
- :param not_needed_names: names that may be omitted
- :type not_needed_names: set of str
-
- :param set expected_argument_names: Expected argument names
- :param NodeNG warning_node: The node to be analyzed
- """
- differing_argument_names = (
- (expected_argument_names ^ found_argument_names)
- - not_needed_names
- - expected_argument_names
- )
-
- if differing_argument_names:
- self.add_message(
- message_id,
- args=(", ".join(sorted(differing_argument_names)),),
- node=warning_node,
- )
-
- def check_arguments_in_docstring(
- self, doc, arguments_node, warning_node, accept_no_param_doc=None
- ):
- """Check that all parameters in a function, method or class constructor
- on the one hand and the parameters mentioned in the parameter
- documentation (e.g. the Sphinx tags 'param' and 'type') on the other
- hand are consistent with each other.
-
- * Undocumented parameters except 'self' are noticed.
- * Undocumented parameter types except for 'self' and the ``*<args>``
- and ``**<kwargs>`` parameters are noticed.
- * Parameters mentioned in the parameter documentation that don't or no
- longer exist in the function parameter list are noticed.
- * If the text "For the parameters, see" or "For the other parameters,
- see" (ignoring additional whitespace) is mentioned in the docstring,
- missing parameter documentation is tolerated.
- * If there's no Sphinx style, Google style or NumPy style parameter
- documentation at all, i.e. ``:param`` is never mentioned etc., the
- checker assumes that the parameters are documented in another format
- and the absence is tolerated.
-
- :param doc: Docstring for the function, method or class.
- :type doc: :class:`Docstring`
-
- :param arguments_node: Arguments node for the function, method or
- class constructor.
- :type arguments_node: :class:`astroid.scoped_nodes.Arguments`
-
- :param warning_node: The node to assign the warnings to
- :type warning_node: :class:`astroid.scoped_nodes.Node`
-
- :param accept_no_param_doc: Whether or not to allow no parameters
- to be documented.
- If None then this value is read from the configuration.
- :type accept_no_param_doc: bool or None
- """
- # Tolerate missing param or type declarations if there is a link to
- # another method carrying the same name.
- if not doc.doc:
- return
-
- if accept_no_param_doc is None:
- accept_no_param_doc = self.config.accept_no_param_doc
- tolerate_missing_params = doc.params_documented_elsewhere()
-
- # Collect the function arguments.
- expected_argument_names = {arg.name for arg in arguments_node.args}
- expected_argument_names.update(arg.name for arg in arguments_node.kwonlyargs)
- not_needed_type_in_docstring = self.not_needed_param_in_docstring.copy()
-
- if arguments_node.vararg is not None:
- expected_argument_names.add(arguments_node.vararg)
- not_needed_type_in_docstring.add(arguments_node.vararg)
- if arguments_node.kwarg is not None:
- expected_argument_names.add(arguments_node.kwarg)
- not_needed_type_in_docstring.add(arguments_node.kwarg)
- params_with_doc, params_with_type = doc.match_param_docs()
-
- # Tolerate no parameter documentation at all.
- if not params_with_doc and not params_with_type and accept_no_param_doc:
- tolerate_missing_params = True
-
- if not tolerate_missing_params:
- self._compare_missing_args(
- params_with_doc,
- "missing-param-doc",
- self.not_needed_param_in_docstring,
- expected_argument_names,
- warning_node,
- )
-
- for index, arg_name in enumerate(arguments_node.args):
- if arguments_node.annotations[index]:
- params_with_type.add(arg_name.name)
- for index, arg_name in enumerate(arguments_node.kwonlyargs):
- if arguments_node.kwonlyargs_annotations[index]:
- params_with_type.add(arg_name.name)
-
- if not tolerate_missing_params:
- self._compare_missing_args(
- params_with_type,
- "missing-type-doc",
- not_needed_type_in_docstring,
- expected_argument_names,
- warning_node,
- )
-
- self._compare_different_args(
- params_with_doc,
- "differing-param-doc",
- self.not_needed_param_in_docstring,
- expected_argument_names,
- warning_node,
- )
- self._compare_different_args(
- params_with_type,
- "differing-type-doc",
- not_needed_type_in_docstring,
- expected_argument_names,
- warning_node,
- )
-
- def check_single_constructor_params(self, class_doc, init_doc, class_node):
- if class_doc.has_params() and init_doc.has_params():
- self.add_message(
- "multiple-constructor-doc", args=(class_node.name,), node=class_node
- )
-
- def _handle_no_raise_doc(self, excs, node):
- if self.config.accept_no_raise_doc:
- return
-
- self._add_raise_message(excs, node)
-
- def _add_raise_message(self, missing_excs, node):
- """
- Adds a message on :param:`node` for the missing exception type.
-
- :param missing_excs: A list of missing exception types.
- :type missing_excs: set(str)
-
- :param node: The node show the message on.
- :type node: astroid.node_classes.NodeNG
- """
- if node.is_abstract():
- try:
- missing_excs.remove("NotImplementedError")
- except KeyError:
- pass
-
- if not missing_excs:
- return
-
- self.add_message(
- "missing-raises-doc", args=(", ".join(sorted(missing_excs)),), node=node
- )
-
-
-def register(linter):
- """Required method to auto register this checker.
-
- :param linter: Main interface object for Pylint plugins
- :type linter: Pylint object
- """
- linter.register_checker(DocstringParameterChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/docstyle.py b/venv/Lib/site-packages/pylint/extensions/docstyle.py
deleted file mode 100644
index 36f506f..0000000
--- a/venv/Lib/site-packages/pylint/extensions/docstyle.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Luis Escobar <lescobar@vauxoo.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import linecache
-
-from pylint import checkers
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import HIGH, IAstroidChecker
-
-
-class DocStringStyleChecker(checkers.BaseChecker):
- """Checks format of docstrings based on PEP 0257"""
-
- __implements__ = IAstroidChecker
- name = "docstyle"
-
- msgs = {
- "C0198": (
- 'Bad docstring quotes in %s, expected """, given %s',
- "bad-docstring-quotes",
- "Used when a docstring does not have triple double quotes.",
- ),
- "C0199": (
- "First line empty in %s docstring",
- "docstring-first-line-empty",
- "Used when a blank line is found at the beginning of a docstring.",
- ),
- }
-
- @check_messages("docstring-first-line-empty", "bad-docstring-quotes")
- def visit_module(self, node):
- self._check_docstring("module", node)
-
- def visit_classdef(self, node):
- self._check_docstring("class", node)
-
- def visit_functiondef(self, node):
- ftype = "method" if node.is_method() else "function"
- self._check_docstring(ftype, node)
-
- visit_asyncfunctiondef = visit_functiondef
-
- def _check_docstring(self, node_type, node):
- docstring = node.doc
- if docstring and docstring[0] == "\n":
- self.add_message(
- "docstring-first-line-empty",
- node=node,
- args=(node_type,),
- confidence=HIGH,
- )
-
- # Use "linecache", instead of node.as_string(), because the latter
- # looses the original form of the docstrings.
-
- if docstring:
- lineno = node.fromlineno + 1
- line = linecache.getline(node.root().file, lineno).lstrip()
- if line and line.find('"""') == 0:
- return
- if line and "'''" in line:
- quotes = "'''"
- elif line and line[0] == '"':
- quotes = '"'
- elif line and line[0] == "'":
- quotes = "'"
- else:
- quotes = False
- if quotes:
- self.add_message(
- "bad-docstring-quotes",
- node=node,
- args=(node_type, quotes),
- confidence=HIGH,
- )
-
-
-def register(linter):
- """Required method to auto register this checker.
-
- :param linter: Main interface object for Pylint plugins
- :type linter: Pylint object
- """
- linter.register_checker(DocStringStyleChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/emptystring.py b/venv/Lib/site-packages/pylint/extensions/emptystring.py
deleted file mode 100644
index 04021d5..0000000
--- a/venv/Lib/site-packages/pylint/extensions/emptystring.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2017 Claudiu Popa <pcmanticore@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Looks for comparisons to empty string."""
-
-import itertools
-
-import astroid
-
-from pylint import checkers, interfaces
-from pylint.checkers import utils
-
-
-def _is_constant_empty_str(node):
- return isinstance(node, astroid.Const) and node.value == ""
-
-
-class CompareToEmptyStringChecker(checkers.BaseChecker):
- """Checks for comparisons to empty string.
- Most of the times you should use the fact that empty strings are false.
- An exception to this rule is when an empty string value is allowed in the program
- and has a different meaning than None!
- """
-
- __implements__ = (interfaces.IAstroidChecker,)
-
- # configuration section name
- name = "compare-to-empty-string"
- msgs = {
- "C1901": (
- "Avoid comparisons to empty string",
- "compare-to-empty-string",
- "Used when Pylint detects comparison to an empty string constant.",
- )
- }
-
- priority = -2
- options = ()
-
- @utils.check_messages("compare-to-empty-string")
- def visit_compare(self, node):
- _operators = ["!=", "==", "is not", "is"]
- # note: astroid.Compare has the left most operand in node.left
- # while the rest are a list of tuples in node.ops
- # the format of the tuple is ('compare operator sign', node)
- # here we squash everything into `ops` to make it easier for processing later
- ops = [("", node.left)]
- ops.extend(node.ops)
- ops = list(itertools.chain(*ops))
-
- for ops_idx in range(len(ops) - 2):
- op_1 = ops[ops_idx]
- op_2 = ops[ops_idx + 1]
- op_3 = ops[ops_idx + 2]
- error_detected = False
-
- # x ?? ""
- if _is_constant_empty_str(op_1) and op_2 in _operators:
- error_detected = True
- # '' ?? X
- elif op_2 in _operators and _is_constant_empty_str(op_3):
- error_detected = True
-
- if error_detected:
- self.add_message("compare-to-empty-string", node=node)
-
-
-def register(linter):
- """Required method to auto register this checker."""
- linter.register_checker(CompareToEmptyStringChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/mccabe.py b/venv/Lib/site-packages/pylint/extensions/mccabe.py
deleted file mode 100644
index cafac97..0000000
--- a/venv/Lib/site-packages/pylint/extensions/mccabe.py
+++ /dev/null
@@ -1,196 +0,0 @@
-# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Module to add McCabe checker class for pylint. """
-
-from mccabe import PathGraph as Mccabe_PathGraph
-from mccabe import PathGraphingAstVisitor as Mccabe_PathGraphingAstVisitor
-
-from pylint import checkers
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import HIGH, IAstroidChecker
-
-
-class PathGraph(Mccabe_PathGraph):
- def __init__(self, node):
- super(PathGraph, self).__init__(name="", entity="", lineno=1)
- self.root = node
-
-
-class PathGraphingAstVisitor(Mccabe_PathGraphingAstVisitor):
- def __init__(self):
- super(PathGraphingAstVisitor, self).__init__()
- self._bottom_counter = 0
-
- def default(self, node, *args):
- for child in node.get_children():
- self.dispatch(child, *args)
-
- def dispatch(self, node, *args):
- self.node = node
- klass = node.__class__
- meth = self._cache.get(klass)
- if meth is None:
- class_name = klass.__name__
- meth = getattr(self.visitor, "visit" + class_name, self.default)
- self._cache[klass] = meth
- return meth(node, *args)
-
- def visitFunctionDef(self, node):
- if self.graph is not None:
- # closure
- pathnode = self._append_node(node)
- self.tail = pathnode
- self.dispatch_list(node.body)
- bottom = "%s" % self._bottom_counter
- self._bottom_counter += 1
- self.graph.connect(self.tail, bottom)
- self.graph.connect(node, bottom)
- self.tail = bottom
- else:
- self.graph = PathGraph(node)
- self.tail = node
- self.dispatch_list(node.body)
- self.graphs["%s%s" % (self.classname, node.name)] = self.graph
- self.reset()
-
- visitAsyncFunctionDef = visitFunctionDef
-
- def visitSimpleStatement(self, node):
- self._append_node(node)
-
- visitAssert = (
- visitAssign
- ) = (
- visitAugAssign
- ) = (
- visitDelete
- ) = (
- visitPrint
- ) = (
- visitRaise
- ) = (
- visitYield
- ) = (
- visitImport
- ) = (
- visitCall
- ) = (
- visitSubscript
- ) = (
- visitPass
- ) = (
- visitContinue
- ) = (
- visitBreak
- ) = visitGlobal = visitReturn = visitExpr = visitAwait = visitSimpleStatement
-
- def visitWith(self, node):
- self._append_node(node)
- self.dispatch_list(node.body)
-
- visitAsyncWith = visitWith
-
- def _append_node(self, node):
- if not self.tail:
- return None
- self.graph.connect(self.tail, node)
- self.tail = node
- return node
-
- def _subgraph(self, node, name, extra_blocks=()):
- """create the subgraphs representing any `if` and `for` statements"""
- if self.graph is None:
- # global loop
- self.graph = PathGraph(node)
- self._subgraph_parse(node, node, extra_blocks)
- self.graphs["%s%s" % (self.classname, name)] = self.graph
- self.reset()
- else:
- self._append_node(node)
- self._subgraph_parse(node, node, extra_blocks)
-
- def _subgraph_parse(self, node, pathnode, extra_blocks):
- """parse the body and any `else` block of `if` and `for` statements"""
- loose_ends = []
- self.tail = node
- self.dispatch_list(node.body)
- loose_ends.append(self.tail)
- for extra in extra_blocks:
- self.tail = node
- self.dispatch_list(extra.body)
- loose_ends.append(self.tail)
- if node.orelse:
- self.tail = node
- self.dispatch_list(node.orelse)
- loose_ends.append(self.tail)
- else:
- loose_ends.append(node)
- if node:
- bottom = "%s" % self._bottom_counter
- self._bottom_counter += 1
- for end in loose_ends:
- self.graph.connect(end, bottom)
- self.tail = bottom
-
-
-class McCabeMethodChecker(checkers.BaseChecker):
- """Checks McCabe complexity cyclomatic threshold in methods and functions
- to validate a too complex code.
- """
-
- __implements__ = IAstroidChecker
- name = "design"
-
- msgs = {
- "R1260": (
- "%s is too complex. The McCabe rating is %d",
- "too-complex",
- "Used when a method or function is too complex based on "
- "McCabe Complexity Cyclomatic",
- )
- }
- options = (
- (
- "max-complexity",
- {
- "default": 10,
- "type": "int",
- "metavar": "<int>",
- "help": "McCabe complexity cyclomatic threshold",
- },
- ),
- )
-
- @check_messages("too-complex")
- def visit_module(self, node):
- """visit an astroid.Module node to check too complex rating and
- add message if is greather than max_complexity stored from options"""
- visitor = PathGraphingAstVisitor()
- for child in node.body:
- visitor.preorder(child, visitor)
- for graph in visitor.graphs.values():
- complexity = graph.complexity()
- node = graph.root
- if hasattr(node, "name"):
- node_name = "'%s'" % node.name
- else:
- node_name = "This '%s'" % node.__class__.__name__.lower()
- if complexity <= self.config.max_complexity:
- continue
- self.add_message(
- "too-complex", node=node, confidence=HIGH, args=(node_name, complexity)
- )
-
-
-def register(linter):
- """Required method to auto register this checker.
-
- :param linter: Main interface object for Pylint plugins
- :type linter: Pylint object
- """
- linter.register_checker(McCabeMethodChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/overlapping_exceptions.py b/venv/Lib/site-packages/pylint/extensions/overlapping_exceptions.py
deleted file mode 100644
index be2208c..0000000
--- a/venv/Lib/site-packages/pylint/extensions/overlapping_exceptions.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Looks for overlapping exceptions."""
-
-import astroid
-
-from pylint import checkers, interfaces
-from pylint.checkers import utils
-from pylint.checkers.exceptions import _annotated_unpack_infer
-
-
-class OverlappingExceptionsChecker(checkers.BaseChecker):
- """Checks for two or more exceptions in the same exception handler
- clause that are identical or parts of the same inheritance hierarchy
- (i.e. overlapping)."""
-
- __implements__ = interfaces.IAstroidChecker
-
- name = "overlap-except"
- msgs = {
- "W0714": (
- "Overlapping exceptions (%s)",
- "overlapping-except",
- "Used when exceptions in handler overlap or are identical",
- )
- }
- priority = -2
- options = ()
-
- @utils.check_messages("overlapping-except")
- def visit_tryexcept(self, node):
- """check for empty except"""
- for handler in node.handlers:
- if handler.type is None:
- continue
- if isinstance(handler.type, astroid.BoolOp):
- continue
- try:
- excs = list(_annotated_unpack_infer(handler.type))
- except astroid.InferenceError:
- continue
-
- handled_in_clause = []
- for part, exc in excs:
- if exc is astroid.Uninferable:
- continue
- if isinstance(exc, astroid.Instance) and utils.inherit_from_std_ex(exc):
- # pylint: disable=protected-access
- exc = exc._proxied
-
- if not isinstance(exc, astroid.ClassDef):
- continue
-
- exc_ancestors = [
- anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef)
- ]
-
- for prev_part, prev_exc in handled_in_clause:
- prev_exc_ancestors = [
- anc
- for anc in prev_exc.ancestors()
- if isinstance(anc, astroid.ClassDef)
- ]
- if exc == prev_exc:
- self.add_message(
- "overlapping-except",
- node=handler.type,
- args="%s and %s are the same"
- % (prev_part.as_string(), part.as_string()),
- )
- elif prev_exc in exc_ancestors or exc in prev_exc_ancestors:
- ancestor = part if exc in prev_exc_ancestors else prev_part
- descendant = part if prev_exc in exc_ancestors else prev_part
- self.add_message(
- "overlapping-except",
- node=handler.type,
- args="%s is an ancestor class of %s"
- % (ancestor.as_string(), descendant.as_string()),
- )
- handled_in_clause += [(part, exc)]
-
-
-def register(linter):
- """Required method to auto register this checker."""
- linter.register_checker(OverlappingExceptionsChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/extensions/redefined_variable_type.py b/venv/Lib/site-packages/pylint/extensions/redefined_variable_type.py
deleted file mode 100644
index cfe4754..0000000
--- a/venv/Lib/site-packages/pylint/extensions/redefined_variable_type.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2016 Glenn Matthews <glmatthe@cisco.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import astroid
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import check_messages, is_none, node_type
-from pylint.interfaces import IAstroidChecker
-
-BUILTINS = "builtins"
-
-
-class MultipleTypesChecker(BaseChecker):
- """Checks for variable type redefinitions (NoneType excepted)
-
- At a function, method, class or module scope
-
- This rule could be improved:
-
- - Currently, if an attribute is set to different types in 2 methods of a
- same class, it won't be detected (see functional test)
- - One could improve the support for inference on assignment with tuples,
- ifexpr, etc. Also it would be great to have support for inference on
- str.split()
- """
-
- __implements__ = IAstroidChecker
-
- name = "multiple_types"
- msgs = {
- "R0204": (
- "Redefinition of %s type from %s to %s",
- "redefined-variable-type",
- "Used when the type of a variable changes inside a "
- "method or a function.",
- )
- }
-
- def visit_classdef(self, _):
- self._assigns.append({})
-
- @check_messages("redefined-variable-type")
- def leave_classdef(self, _):
- self._check_and_add_messages()
-
- visit_functiondef = visit_classdef
- leave_functiondef = leave_module = leave_classdef
-
- def visit_module(self, _):
- self._assigns = [{}]
-
- def _check_and_add_messages(self):
- assigns = self._assigns.pop()
- for name, args in assigns.items():
- if len(args) <= 1:
- continue
- orig_node, orig_type = args[0]
- # Check if there is a type in the following nodes that would be
- # different from orig_type.
- for redef_node, redef_type in args[1:]:
- if redef_type == orig_type:
- continue
- # if a variable is defined to several types in an if node,
- # this is not actually redefining.
- orig_parent = orig_node.parent
- redef_parent = redef_node.parent
- if isinstance(orig_parent, astroid.If):
- if orig_parent == redef_parent:
- if (
- redef_node in orig_parent.orelse
- and orig_node not in orig_parent.orelse
- ):
- orig_node, orig_type = redef_node, redef_type
- continue
- elif isinstance(
- redef_parent, astroid.If
- ) and redef_parent in orig_parent.nodes_of_class(astroid.If):
- orig_node, orig_type = redef_node, redef_type
- continue
- orig_type = orig_type.replace(BUILTINS + ".", "")
- redef_type = redef_type.replace(BUILTINS + ".", "")
- self.add_message(
- "redefined-variable-type",
- node=redef_node,
- args=(name, orig_type, redef_type),
- )
- break
-
- def visit_assign(self, node):
- # we don't handle multiple assignment nor slice assignment
- target = node.targets[0]
- if isinstance(target, (astroid.Tuple, astroid.Subscript)):
- return
- # ignore NoneType
- if is_none(node):
- return
- _type = node_type(node.value)
- if _type:
- self._assigns[-1].setdefault(target.as_string(), []).append(
- (node, _type.pytype())
- )
-
-
-def register(linter):
- """Required method to auto register this checker.
-
- :param linter: Main interface object for Pylint plugins
- :type linter: Pylint object
- """
- linter.register_checker(MultipleTypesChecker(linter))
diff --git a/venv/Lib/site-packages/pylint/graph.py b/venv/Lib/site-packages/pylint/graph.py
deleted file mode 100644
index 0dc7a14..0000000
--- a/venv/Lib/site-packages/pylint/graph.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Graph manipulation utilities.
-
-(dot generation adapted from pypy/translator/tool/make_dot.py)
-"""
-
-import codecs
-import os
-import os.path as osp
-import subprocess
-import sys
-import tempfile
-
-
-def target_info_from_filename(filename):
- """Transforms /some/path/foo.png into ('/some/path', 'foo.png', 'png')."""
- basename = osp.basename(filename)
- storedir = osp.dirname(osp.abspath(filename))
- target = filename.split(".")[-1]
- return storedir, basename, target
-
-
-class DotBackend:
- """Dot File backend."""
-
- def __init__(
- self,
- graphname,
- rankdir=None,
- size=None,
- ratio=None,
- charset="utf-8",
- renderer="dot",
- additional_param=None,
- ):
- if additional_param is None:
- additional_param = {}
- self.graphname = graphname
- self.renderer = renderer
- self.lines = []
- self._source = None
- self.emit("digraph %s {" % normalize_node_id(graphname))
- if rankdir:
- self.emit("rankdir=%s" % rankdir)
- if ratio:
- self.emit("ratio=%s" % ratio)
- if size:
- self.emit('size="%s"' % size)
- if charset:
- assert charset.lower() in ("utf-8", "iso-8859-1", "latin1"), (
- "unsupported charset %s" % charset
- )
- self.emit('charset="%s"' % charset)
- for param in additional_param.items():
- self.emit("=".join(param))
-
- def get_source(self):
- """returns self._source"""
- if self._source is None:
- self.emit("}\n")
- self._source = "\n".join(self.lines)
- del self.lines
- return self._source
-
- source = property(get_source)
-
- def generate(self, outputfile=None, dotfile=None, mapfile=None):
- """Generates a graph file.
-
- :param str outputfile: filename and path [defaults to graphname.png]
- :param str dotfile: filename and path [defaults to graphname.dot]
- :param str mapfile: filename and path
-
- :rtype: str
- :return: a path to the generated file
- """
- name = self.graphname
- if not dotfile:
- # if 'outputfile' is a dot file use it as 'dotfile'
- if outputfile and outputfile.endswith(".dot"):
- dotfile = outputfile
- else:
- dotfile = "%s.dot" % name
- if outputfile is not None:
- storedir, _, target = target_info_from_filename(outputfile)
- if target != "dot":
- pdot, dot_sourcepath = tempfile.mkstemp(".dot", name)
- os.close(pdot)
- else:
- dot_sourcepath = osp.join(storedir, dotfile)
- else:
- target = "png"
- pdot, dot_sourcepath = tempfile.mkstemp(".dot", name)
- ppng, outputfile = tempfile.mkstemp(".png", name)
- os.close(pdot)
- os.close(ppng)
- pdot = codecs.open(dot_sourcepath, "w", encoding="utf8")
- pdot.write(self.source)
- pdot.close()
- if target != "dot":
- use_shell = sys.platform == "win32"
- if mapfile:
- subprocess.call(
- [
- self.renderer,
- "-Tcmapx",
- "-o",
- mapfile,
- "-T",
- target,
- dot_sourcepath,
- "-o",
- outputfile,
- ],
- shell=use_shell,
- )
- else:
- subprocess.call(
- [self.renderer, "-T", target, dot_sourcepath, "-o", outputfile],
- shell=use_shell,
- )
- os.unlink(dot_sourcepath)
- return outputfile
-
- def emit(self, line):
- """Adds <line> to final output."""
- self.lines.append(line)
-
- def emit_edge(self, name1, name2, **props):
- """emit an edge from <name1> to <name2>.
- edge properties: see http://www.graphviz.org/doc/info/attrs.html
- """
- attrs = ['%s="%s"' % (prop, value) for prop, value in props.items()]
- n_from, n_to = normalize_node_id(name1), normalize_node_id(name2)
- self.emit("%s -> %s [%s];" % (n_from, n_to, ", ".join(sorted(attrs))))
-
- def emit_node(self, name, **props):
- """emit a node with given properties.
- node properties: see http://www.graphviz.org/doc/info/attrs.html
- """
- attrs = ['%s="%s"' % (prop, value) for prop, value in props.items()]
- self.emit("%s [%s];" % (normalize_node_id(name), ", ".join(sorted(attrs))))
-
-
-def normalize_node_id(nid):
- """Returns a suitable DOT node id for `nid`."""
- return '"%s"' % nid
-
-
-def get_cycles(graph_dict, vertices=None):
- """given a dictionary representing an ordered graph (i.e. key are vertices
- and values is a list of destination vertices representing edges), return a
- list of detected cycles
- """
- if not graph_dict:
- return ()
- result = []
- if vertices is None:
- vertices = graph_dict.keys()
- for vertice in vertices:
- _get_cycles(graph_dict, [], set(), result, vertice)
- return result
-
-
-def _get_cycles(graph_dict, path, visited, result, vertice):
- """recursive function doing the real work for get_cycles"""
- if vertice in path:
- cycle = [vertice]
- for node in path[::-1]:
- if node == vertice:
- break
- cycle.insert(0, node)
- # make a canonical representation
- start_from = min(cycle)
- index = cycle.index(start_from)
- cycle = cycle[index:] + cycle[0:index]
- # append it to result if not already in
- if cycle not in result:
- result.append(cycle)
- return
- path.append(vertice)
- try:
- for node in graph_dict[vertice]:
- # don't check already visited nodes again
- if node not in visited:
- _get_cycles(graph_dict, path, visited, result, node)
- visited.add(node)
- except KeyError:
- pass
- path.pop()
diff --git a/venv/Lib/site-packages/pylint/interfaces.py b/venv/Lib/site-packages/pylint/interfaces.py
deleted file mode 100644
index 378585c..0000000
--- a/venv/Lib/site-packages/pylint/interfaces.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2009-2010, 2012-2013 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2013-2014 Google, Inc.
-# Copyright (c) 2014 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Interfaces for Pylint objects"""
-from collections import namedtuple
-
-Confidence = namedtuple("Confidence", ["name", "description"])
-# Warning Certainties
-HIGH = Confidence("HIGH", "No false positive possible.")
-INFERENCE = Confidence("INFERENCE", "Warning based on inference result.")
-INFERENCE_FAILURE = Confidence(
- "INFERENCE_FAILURE", "Warning based on inference with failures."
-)
-UNDEFINED = Confidence("UNDEFINED", "Warning without any associated confidence level.")
-
-CONFIDENCE_LEVELS = [HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED]
-
-
-class Interface:
- """Base class for interfaces."""
-
- @classmethod
- def is_implemented_by(cls, instance):
- return implements(instance, cls)
-
-
-def implements(obj, interface):
- """Return true if the give object (maybe an instance or class) implements
- the interface.
- """
- kimplements = getattr(obj, "__implements__", ())
- if not isinstance(kimplements, (list, tuple)):
- kimplements = (kimplements,)
- for implementedinterface in kimplements:
- if issubclass(implementedinterface, interface):
- return True
- return False
-
-
-class IChecker(Interface):
- """This is a base interface, not designed to be used elsewhere than for
- sub interfaces definition.
- """
-
- def open(self):
- """called before visiting project (i.e set of modules)"""
-
- def close(self):
- """called after visiting project (i.e set of modules)"""
-
-
-class IRawChecker(IChecker):
- """interface for checker which need to parse the raw file
- """
-
- def process_module(self, astroid):
- """ process a module
-
- the module's content is accessible via astroid.stream
- """
-
-
-class ITokenChecker(IChecker):
- """Interface for checkers that need access to the token list."""
-
- def process_tokens(self, tokens):
- """Process a module.
-
- tokens is a list of all source code tokens in the file.
- """
-
-
-class IAstroidChecker(IChecker):
- """ interface for checker which prefers receive events according to
- statement type
- """
-
-
-class IReporter(Interface):
- """ reporter collect messages and display results encapsulated in a layout
- """
-
- def handle_message(self, msg):
- """Handle the given message object."""
-
- def display_reports(self, layout):
- """display results encapsulated in the layout tree
- """
-
-
-__all__ = ("IRawChecker", "IAstroidChecker", "ITokenChecker", "IReporter")
diff --git a/venv/Lib/site-packages/pylint/lint.py b/venv/Lib/site-packages/pylint/lint.py
deleted file mode 100644
index a98970b..0000000
--- a/venv/Lib/site-packages/pylint/lint.py
+++ /dev/null
@@ -1,1817 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2008 Fabrice Douchant <Fabrice.Douchant@logilab.fr>
-# Copyright (c) 2009 Vincent
-# Copyright (c) 2009 Mads Kiilerich <mads@kiilerich.com>
-# Copyright (c) 2011-2014 Google, Inc.
-# Copyright (c) 2012 David Pursehouse <david.pursehouse@sonymobile.com>
-# Copyright (c) 2012 Kevin Jing Qiu <kevin.jing.qiu@gmail.com>
-# Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com>
-# Copyright (c) 2012 JT Olds <jtolds@xnet5.com>
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014-2015 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Alexandru Coman <fcoman@bitdefender.com>
-# Copyright (c) 2014 Daniel Harding <dharding@living180.net>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2014 Dan Goldsmith <djgoldsmith@googlemail.com>
-# Copyright (c) 2015-2016 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Aru Sahni <arusahni@gmail.com>
-# Copyright (c) 2015 Steven Myint <hg@stevenmyint.com>
-# Copyright (c) 2015 Simu Toni <simutoni@gmail.com>
-# Copyright (c) 2015 Mihai Balint <balint.mihai@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016-2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-# Copyright (c) 2016 Alan Evangelista <alanoe@linux.vnet.ibm.com>
-# Copyright (c) 2017-2018 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Daniel Miller <millerdev@gmail.com>
-# Copyright (c) 2017 Roman Ivanov <me@roivanov.com>
-# Copyright (c) 2017 Ned Batchelder <ned@nedbatchelder.com>
-# Copyright (c) 2018 Randall Leeds <randall@bleeds.info>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2018 Jason Owen <jason.a.owen@gmail.com>
-# Copyright (c) 2018 Gary Tyler McLeod <mail@garytyler.com>
-# Copyright (c) 2018 Yuval Langer <yuvallanger@mail.tau.ac.il>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-# Copyright (c) 2018 kapsh <kapsh@kap.sh>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-# pylint: disable=broad-except
-
-""" pylint [options] modules_or_packages
-
- Check that module(s) satisfy a coding standard (and more !).
-
- pylint --help
-
- Display this help message and exit.
-
- pylint --help-msg <msg-id>[,<msg-id>]
-
- Display help messages about given message identifiers and exit.
-"""
-import collections
-import contextlib
-import operator
-import os
-import sys
-import tokenize
-import traceback
-import warnings
-from io import TextIOWrapper
-
-import astroid
-from astroid import modutils
-from astroid.__pkginfo__ import version as astroid_version
-from astroid.builder import AstroidBuilder
-
-from pylint import __pkginfo__, checkers, config, exceptions, interfaces, reporters
-from pylint.__pkginfo__ import version
-from pylint.constants import MAIN_CHECKER_NAME, MSG_TYPES, OPTION_RGX
-from pylint.message import Message, MessageDefinitionStore, MessagesHandlerMixIn
-from pylint.reporters.ureports import nodes as report_nodes
-from pylint.utils import ASTWalker, FileState, utils
-
-try:
- import multiprocessing
-except ImportError:
- multiprocessing = None # type: ignore
-
-
-MANAGER = astroid.MANAGER
-
-
-def _ast_from_string(data, filepath, modname):
- cached = MANAGER.astroid_cache.get(modname)
- if cached and cached.file == filepath:
- return cached
-
- return AstroidBuilder(MANAGER).string_build(data, modname, filepath)
-
-
-def _read_stdin():
- # https://mail.python.org/pipermail/python-list/2012-November/634424.html
- sys.stdin = TextIOWrapper(sys.stdin.detach(), encoding="utf-8")
- return sys.stdin.read()
-
-
-def _get_new_args(message):
- location = (
- message.abspath,
- message.path,
- message.module,
- message.obj,
- message.line,
- message.column,
- )
- return (message.msg_id, message.symbol, location, message.msg, message.confidence)
-
-
-def _get_python_path(filepath):
- dirname = os.path.realpath(os.path.expanduser(filepath))
- if not os.path.isdir(dirname):
- dirname = os.path.dirname(dirname)
- while True:
- if not os.path.exists(os.path.join(dirname, "__init__.py")):
- return dirname
- old_dirname = dirname
- dirname = os.path.dirname(dirname)
- if old_dirname == dirname:
- return os.getcwd()
- return None
-
-
-def _merge_stats(stats):
- merged = {}
- by_msg = collections.Counter()
- for stat in stats:
- message_stats = stat.pop("by_msg", {})
- by_msg.update(message_stats)
-
- for key, item in stat.items():
- if key not in merged:
- merged[key] = item
- else:
- if isinstance(item, dict):
- merged[key].update(item)
- else:
- merged[key] = merged[key] + item
-
- merged["by_msg"] = by_msg
- return merged
-
-
-# Python Linter class #########################################################
-
-MSGS = {
- "F0001": (
- "%s",
- "fatal",
- "Used when an error occurred preventing the analysis of a \
- module (unable to find it for instance).",
- ),
- "F0002": (
- "%s: %s",
- "astroid-error",
- "Used when an unexpected error occurred while building the "
- "Astroid representation. This is usually accompanied by a "
- "traceback. Please report such errors !",
- ),
- "F0010": (
- "error while code parsing: %s",
- "parse-error",
- "Used when an exception occurred while building the Astroid "
- "representation which could be handled by astroid.",
- ),
- "I0001": (
- "Unable to run raw checkers on built-in module %s",
- "raw-checker-failed",
- "Used to inform that a built-in module has not been checked "
- "using the raw checkers.",
- ),
- "I0010": (
- "Unable to consider inline option %r",
- "bad-inline-option",
- "Used when an inline option is either badly formatted or can't "
- "be used inside modules.",
- ),
- "I0011": (
- "Locally disabling %s (%s)",
- "locally-disabled",
- "Used when an inline option disables a message or a messages category.",
- ),
- "I0013": (
- "Ignoring entire file",
- "file-ignored",
- "Used to inform that the file will not be checked",
- ),
- "I0020": (
- "Suppressed %s (from line %d)",
- "suppressed-message",
- "A message was triggered on a line, but suppressed explicitly "
- "by a disable= comment in the file. This message is not "
- "generated for messages that are ignored due to configuration "
- "settings.",
- ),
- "I0021": (
- "Useless suppression of %s",
- "useless-suppression",
- "Reported when a message is explicitly disabled for a line or "
- "a block of code, but never triggered.",
- ),
- "I0022": (
- 'Pragma "%s" is deprecated, use "%s" instead',
- "deprecated-pragma",
- "Some inline pylint options have been renamed or reworked, "
- "only the most recent form should be used. "
- "NOTE:skip-all is only available with pylint >= 0.26",
- {"old_names": [("I0014", "deprecated-disable-all")]},
- ),
- "E0001": ("%s", "syntax-error", "Used when a syntax error is raised for a module."),
- "E0011": (
- "Unrecognized file option %r",
- "unrecognized-inline-option",
- "Used when an unknown inline option is encountered.",
- ),
- "E0012": (
- "Bad option value %r",
- "bad-option-value",
- "Used when a bad value for an inline option is encountered.",
- ),
-}
-
-
-def _cpu_count() -> int:
- """Use sched_affinity if available for virtualized or containerized environments."""
- sched_getaffinity = getattr(os, "sched_getaffinity", None)
- # pylint: disable=not-callable,using-constant-test
- if sched_getaffinity:
- return len(sched_getaffinity(0))
- if multiprocessing:
- return multiprocessing.cpu_count()
- return 1
-
-
-if multiprocessing is not None:
-
- class ChildLinter(multiprocessing.Process):
- def run(self):
- # pylint: disable=no-member, unbalanced-tuple-unpacking
- tasks_queue, results_queue, self._config = self._args
-
- self._config["jobs"] = 1 # Child does not parallelize any further.
- self._python3_porting_mode = self._config.pop("python3_porting_mode", None)
- self._plugins = self._config.pop("plugins", None)
-
- # Run linter for received files/modules.
- for file_or_module in iter(tasks_queue.get, "STOP"):
- try:
- result = self._run_linter(file_or_module[0])
- results_queue.put(result)
- except Exception as ex:
- print(
- "internal error with sending report for module %s"
- % file_or_module,
- file=sys.stderr,
- )
- print(ex, file=sys.stderr)
- results_queue.put({})
-
- def _run_linter(self, file_or_module):
- linter = PyLinter()
-
- # Register standard checkers.
- linter.load_default_plugins()
- # Load command line plugins.
- if self._plugins:
- linter.load_plugin_modules(self._plugins)
-
- linter.load_configuration_from_config(self._config)
-
- # Load plugin specific configuration
- linter.load_plugin_configuration()
-
- linter.set_reporter(reporters.CollectingReporter())
-
- # Enable the Python 3 checker mode. This option is
- # passed down from the parent linter up to here, since
- # the Python 3 porting flag belongs to the Run class,
- # instead of the Linter class.
- if self._python3_porting_mode:
- linter.python3_porting_mode()
-
- # Run the checks.
- linter.check(file_or_module)
-
- msgs = [_get_new_args(m) for m in linter.reporter.messages]
- return (
- file_or_module,
- linter.file_state.base_name,
- linter.current_name,
- msgs,
- linter.stats,
- linter.msg_status,
- )
-
-
-# pylint: disable=too-many-instance-attributes,too-many-public-methods
-class PyLinter(
- config.OptionsManagerMixIn,
- MessagesHandlerMixIn,
- reporters.ReportsHandlerMixIn,
- checkers.BaseTokenChecker,
-):
- """lint Python modules using external checkers.
-
- This is the main checker controlling the other ones and the reports
- generation. It is itself both a raw checker and an astroid checker in order
- to:
- * handle message activation / deactivation at the module level
- * handle some basic but necessary stats'data (number of classes, methods...)
-
- IDE plugin developers: you may have to call
- `astroid.builder.MANAGER.astroid_cache.clear()` across runs if you want
- to ensure the latest code version is actually checked.
- """
-
- __implements__ = (interfaces.ITokenChecker,)
-
- name = MAIN_CHECKER_NAME
- priority = 0
- level = 0
- msgs = MSGS
-
- @staticmethod
- def make_options():
- return (
- (
- "ignore",
- {
- "type": "csv",
- "metavar": "<file>[,<file>...]",
- "dest": "black_list",
- "default": ("CVS",),
- "help": "Add files or directories to the blacklist. "
- "They should be base names, not paths.",
- },
- ),
- (
- "ignore-patterns",
- {
- "type": "regexp_csv",
- "metavar": "<pattern>[,<pattern>...]",
- "dest": "black_list_re",
- "default": (),
- "help": "Add files or directories matching the regex patterns to the"
- " blacklist. The regex matches against base names, not paths.",
- },
- ),
- (
- "persistent",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y_or_n>",
- "level": 1,
- "help": "Pickle collected data for later comparisons.",
- },
- ),
- (
- "load-plugins",
- {
- "type": "csv",
- "metavar": "<modules>",
- "default": (),
- "level": 1,
- "help": "List of plugins (as comma separated values of "
- "python module names) to load, usually to register "
- "additional checkers.",
- },
- ),
- (
- "output-format",
- {
- "default": "text",
- "type": "string",
- "metavar": "<format>",
- "short": "f",
- "group": "Reports",
- "help": "Set the output format. Available formats are text,"
- " parseable, colorized, json and msvs (visual studio)."
- " You can also give a reporter class, e.g. mypackage.mymodule."
- "MyReporterClass.",
- },
- ),
- (
- "reports",
- {
- "default": False,
- "type": "yn",
- "metavar": "<y_or_n>",
- "short": "r",
- "group": "Reports",
- "help": "Tells whether to display a full report or only the "
- "messages.",
- },
- ),
- (
- "evaluation",
- {
- "type": "string",
- "metavar": "<python_expression>",
- "group": "Reports",
- "level": 1,
- "default": "10.0 - ((float(5 * error + warning + refactor + "
- "convention) / statement) * 10)",
- "help": "Python expression which should return a score less "
- "than or equal to 10. You have access to the variables "
- "'error', 'warning', 'refactor', and 'convention' which "
- "contain the number of messages in each category, as well as "
- "'statement' which is the total number of statements "
- "analyzed. This score is used by the global "
- "evaluation report (RP0004).",
- },
- ),
- (
- "score",
- {
- "default": True,
- "type": "yn",
- "metavar": "<y_or_n>",
- "short": "s",
- "group": "Reports",
- "help": "Activate the evaluation score.",
- },
- ),
- (
- "confidence",
- {
- "type": "multiple_choice",
- "metavar": "<levels>",
- "default": "",
- "choices": [c.name for c in interfaces.CONFIDENCE_LEVELS],
- "group": "Messages control",
- "help": "Only show warnings with the listed confidence levels."
- " Leave empty to show all. Valid levels: %s."
- % (", ".join(c.name for c in interfaces.CONFIDENCE_LEVELS),),
- },
- ),
- (
- "enable",
- {
- "type": "csv",
- "metavar": "<msg ids>",
- "short": "e",
- "group": "Messages control",
- "help": "Enable the message, report, category or checker with the "
- "given id(s). You can either give multiple identifier "
- "separated by comma (,) or put this option multiple time "
- "(only on the command line, not in the configuration file "
- "where it should appear only once). "
- 'See also the "--disable" option for examples.',
- },
- ),
- (
- "disable",
- {
- "type": "csv",
- "metavar": "<msg ids>",
- "short": "d",
- "group": "Messages control",
- "help": "Disable the message, report, category or checker "
- "with the given id(s). You can either give multiple identifiers "
- "separated by comma (,) or put this option multiple times "
- "(only on the command line, not in the configuration file "
- "where it should appear only once). "
- 'You can also use "--disable=all" to disable everything first '
- "and then reenable specific checks. For example, if you want "
- "to run only the similarities checker, you can use "
- '"--disable=all --enable=similarities". '
- "If you want to run only the classes checker, but have no "
- "Warning level messages displayed, use "
- '"--disable=all --enable=classes --disable=W".',
- },
- ),
- (
- "msg-template",
- {
- "type": "string",
- "metavar": "<template>",
- "group": "Reports",
- "help": (
- "Template used to display messages. "
- "This is a python new-style format string "
- "used to format the message information. "
- "See doc for all details."
- ),
- },
- ),
- (
- "jobs",
- {
- "type": "int",
- "metavar": "<n-processes>",
- "short": "j",
- "default": 1,
- "help": "Use multiple processes to speed up Pylint. Specifying 0 will "
- "auto-detect the number of processors available to use.",
- },
- ),
- (
- "unsafe-load-any-extension",
- {
- "type": "yn",
- "metavar": "<yn>",
- "default": False,
- "hide": True,
- "help": (
- "Allow loading of arbitrary C extensions. Extensions"
- " are imported into the active Python interpreter and"
- " may run arbitrary code."
- ),
- },
- ),
- (
- "limit-inference-results",
- {
- "type": "int",
- "metavar": "<number-of-results>",
- "default": 100,
- "help": (
- "Control the amount of potential inferred values when inferring "
- "a single object. This can help the performance when dealing with "
- "large functions or complex, nested conditions. "
- ),
- },
- ),
- (
- "extension-pkg-whitelist",
- {
- "type": "csv",
- "metavar": "<pkg[,pkg]>",
- "default": [],
- "help": (
- "A comma-separated list of package or module names"
- " from where C extensions may be loaded. Extensions are"
- " loading into the active Python interpreter and may run"
- " arbitrary code."
- ),
- },
- ),
- (
- "suggestion-mode",
- {
- "type": "yn",
- "metavar": "<yn>",
- "default": True,
- "help": (
- "When enabled, pylint would attempt to guess common "
- "misconfiguration and emit user-friendly hints instead "
- "of false-positive error messages."
- ),
- },
- ),
- (
- "exit-zero",
- {
- "action": "store_true",
- "help": (
- "Always return a 0 (non-error) status code, even if "
- "lint errors are found. This is primarily useful in "
- "continuous integration scripts."
- ),
- },
- ),
- (
- "from-stdin",
- {
- "action": "store_true",
- "help": (
- "Interpret the stdin as a python script, whose filename "
- "needs to be passed as the module_or_package argument."
- ),
- },
- ),
- )
-
- option_groups = (
- ("Messages control", "Options controlling analysis messages"),
- ("Reports", "Options related to output formatting and reporting"),
- )
-
- def __init__(self, options=(), reporter=None, option_groups=(), pylintrc=None):
- # some stuff has to be done before ancestors initialization...
- #
- # messages store / checkers / reporter / astroid manager
- self.msgs_store = MessageDefinitionStore()
- self.reporter = None
- self._reporter_name = None
- self._reporters = {}
- self._checkers = collections.defaultdict(list)
- self._pragma_lineno = {}
- self._ignore_file = False
- # visit variables
- self.file_state = FileState()
- self.current_name = None
- self.current_file = None
- self.stats = None
- # init options
- self._external_opts = options
- self.options = options + PyLinter.make_options()
- self.option_groups = option_groups + PyLinter.option_groups
- self._options_methods = {"enable": self.enable, "disable": self.disable}
- self._bw_options_methods = {
- "disable-msg": self.disable,
- "enable-msg": self.enable,
- }
- full_version = "pylint %s\nastroid %s\nPython %s" % (
- version,
- astroid_version,
- sys.version,
- )
- MessagesHandlerMixIn.__init__(self)
- reporters.ReportsHandlerMixIn.__init__(self)
- super(PyLinter, self).__init__(
- usage=__doc__, version=full_version, config_file=pylintrc or config.PYLINTRC
- )
- checkers.BaseTokenChecker.__init__(self)
- # provided reports
- self.reports = (
- ("RP0001", "Messages by category", report_total_messages_stats),
- (
- "RP0002",
- "% errors / warnings by module",
- report_messages_by_module_stats,
- ),
- ("RP0003", "Messages", report_messages_stats),
- )
- self.register_checker(self)
- self._dynamic_plugins = set()
- self._python3_porting_mode = False
- self._error_mode = False
- self.load_provider_defaults()
- if reporter:
- self.set_reporter(reporter)
-
- def load_default_plugins(self):
- checkers.initialize(self)
- reporters.initialize(self)
- # Make sure to load the default reporter, because
- # the option has been set before the plugins had been loaded.
- if not self.reporter:
- self._load_reporter()
-
- def load_plugin_modules(self, modnames):
- """take a list of module names which are pylint plugins and load
- and register them
- """
- for modname in modnames:
- if modname in self._dynamic_plugins:
- continue
- self._dynamic_plugins.add(modname)
- module = modutils.load_module_from_name(modname)
- module.register(self)
-
- def load_plugin_configuration(self):
- """Call the configuration hook for plugins
-
- This walks through the list of plugins, grabs the "load_configuration"
- hook, if exposed, and calls it to allow plugins to configure specific
- settings.
- """
- for modname in self._dynamic_plugins:
- module = modutils.load_module_from_name(modname)
- if hasattr(module, "load_configuration"):
- module.load_configuration(self)
-
- def _load_reporter(self):
- name = self._reporter_name.lower()
- if name in self._reporters:
- self.set_reporter(self._reporters[name]())
- else:
- try:
- reporter_class = self._load_reporter_class()
- except (ImportError, AttributeError):
- raise exceptions.InvalidReporterError(name)
- else:
- self.set_reporter(reporter_class())
-
- def _load_reporter_class(self):
- qname = self._reporter_name
- module = modutils.load_module_from_name(modutils.get_module_part(qname))
- class_name = qname.split(".")[-1]
- reporter_class = getattr(module, class_name)
- return reporter_class
-
- def set_reporter(self, reporter):
- """set the reporter used to display messages and reports"""
- self.reporter = reporter
- reporter.linter = self
-
- def set_option(self, optname, value, action=None, optdict=None):
- """overridden from config.OptionsProviderMixin to handle some
- special options
- """
- if optname in self._options_methods or optname in self._bw_options_methods:
- if value:
- try:
- meth = self._options_methods[optname]
- except KeyError:
- meth = self._bw_options_methods[optname]
- warnings.warn(
- "%s is deprecated, replace it by %s"
- % (optname, optname.split("-")[0]),
- DeprecationWarning,
- )
- value = utils._check_csv(value)
- if isinstance(value, (list, tuple)):
- for _id in value:
- meth(_id, ignore_unknown=True)
- else:
- meth(value)
- return # no need to call set_option, disable/enable methods do it
- elif optname == "output-format":
- self._reporter_name = value
- # If the reporters are already available, load
- # the reporter class.
- if self._reporters:
- self._load_reporter()
-
- try:
- checkers.BaseTokenChecker.set_option(self, optname, value, action, optdict)
- except config.UnsupportedAction:
- print("option %s can't be read from config file" % optname, file=sys.stderr)
-
- def register_reporter(self, reporter_class):
- self._reporters[reporter_class.name] = reporter_class
-
- def report_order(self):
- reports = sorted(self._reports, key=lambda x: getattr(x, "name", ""))
- try:
- # Remove the current reporter and add it
- # at the end of the list.
- reports.pop(reports.index(self))
- except ValueError:
- pass
- else:
- reports.append(self)
- return reports
-
- # checkers manipulation methods ############################################
-
- def register_checker(self, checker):
- """register a new checker
-
- checker is an object implementing IRawChecker or / and IAstroidChecker
- """
- assert checker.priority <= 0, "checker priority can't be >= 0"
- self._checkers[checker.name].append(checker)
- for r_id, r_title, r_cb in checker.reports:
- self.register_report(r_id, r_title, r_cb, checker)
- self.register_options_provider(checker)
- if hasattr(checker, "msgs"):
- self.msgs_store.register_messages_from_checker(checker)
- checker.load_defaults()
-
- # Register the checker, but disable all of its messages.
- if not getattr(checker, "enabled", True):
- self.disable(checker.name)
-
- def disable_noerror_messages(self):
- for msgcat, msgids in self.msgs_store._msgs_by_category.items():
- # enable only messages with 'error' severity and above ('fatal')
- if msgcat in ["E", "F"]:
- for msgid in msgids:
- self.enable(msgid)
- else:
- for msgid in msgids:
- self.disable(msgid)
-
- def disable_reporters(self):
- """disable all reporters"""
- for _reporters in self._reports.values():
- for report_id, _, _ in _reporters:
- self.disable_report(report_id)
-
- def error_mode(self):
- """error mode: enable only errors; no reports, no persistent"""
- self._error_mode = True
- self.disable_noerror_messages()
- self.disable("miscellaneous")
- if self._python3_porting_mode:
- self.disable("all")
- for msg_id in self._checker_messages("python3"):
- if msg_id.startswith("E"):
- self.enable(msg_id)
- config_parser = self.cfgfile_parser
- if config_parser.has_option("MESSAGES CONTROL", "disable"):
- value = config_parser.get("MESSAGES CONTROL", "disable")
- self.global_set_option("disable", value)
- else:
- self.disable("python3")
- self.set_option("reports", False)
- self.set_option("persistent", False)
- self.set_option("score", False)
-
- def python3_porting_mode(self):
- """Disable all other checkers and enable Python 3 warnings."""
- self.disable("all")
- self.enable("python3")
- if self._error_mode:
- # The error mode was activated, using the -E flag.
- # So we'll need to enable only the errors from the
- # Python 3 porting checker.
- for msg_id in self._checker_messages("python3"):
- if msg_id.startswith("E"):
- self.enable(msg_id)
- else:
- self.disable(msg_id)
- config_parser = self.cfgfile_parser
- if config_parser.has_option("MESSAGES CONTROL", "disable"):
- value = config_parser.get("MESSAGES CONTROL", "disable")
- self.global_set_option("disable", value)
- self._python3_porting_mode = True
-
- def list_messages_enabled(self):
- enabled = [
- " %s (%s)" % (message.symbol, message.msgid)
- for message in self.msgs_store.messages
- if self.is_message_enabled(message.msgid)
- ]
- disabled = [
- " %s (%s)" % (message.symbol, message.msgid)
- for message in self.msgs_store.messages
- if not self.is_message_enabled(message.msgid)
- ]
- print("Enabled messages:")
- for msg in sorted(enabled):
- print(msg)
- print("\nDisabled messages:")
- for msg in sorted(disabled):
- print(msg)
- print("")
-
- # block level option handling #############################################
- #
- # see func_block_disable_msg.py test case for expected behaviour
-
- def process_tokens(self, tokens):
- """process tokens from the current module to search for module/block
- level options
- """
- control_pragmas = {"disable", "enable"}
- prev_line = None
- saw_newline = True
- seen_newline = True
- for (tok_type, content, start, _, _) in tokens:
- if prev_line and prev_line != start[0]:
- saw_newline = seen_newline
- seen_newline = False
-
- prev_line = start[0]
- if tok_type in (tokenize.NL, tokenize.NEWLINE):
- seen_newline = True
-
- if tok_type != tokenize.COMMENT:
- continue
- match = OPTION_RGX.search(content)
- if match is None:
- continue
-
- first_group = match.group(1)
- if (
- first_group.strip() == "disable-all"
- or first_group.strip() == "skip-file"
- ):
- if first_group.strip() == "disable-all":
- self.add_message(
- "deprecated-pragma",
- line=start[0],
- args=("disable-all", "skip-file"),
- )
- self.add_message("file-ignored", line=start[0])
- self._ignore_file = True
- return
- try:
- opt, value = first_group.split("=", 1)
- except ValueError:
- self.add_message(
- "bad-inline-option", args=first_group.strip(), line=start[0]
- )
- continue
- opt = opt.strip()
- if opt in self._options_methods or opt in self._bw_options_methods:
- try:
- meth = self._options_methods[opt]
- except KeyError:
- meth = self._bw_options_methods[opt]
- # found a "(dis|en)able-msg" pragma deprecated suppression
- self.add_message(
- "deprecated-pragma",
- line=start[0],
- args=(opt, opt.replace("-msg", "")),
- )
- for msgid in utils._splitstrip(value):
- # Add the line where a control pragma was encountered.
- if opt in control_pragmas:
- self._pragma_lineno[msgid] = start[0]
-
- try:
- if (opt, msgid) == ("disable", "all"):
- self.add_message(
- "deprecated-pragma",
- line=start[0],
- args=("disable=all", "skip-file"),
- )
- self.add_message("file-ignored", line=start[0])
- self._ignore_file = True
- return
- # If we did not see a newline between the previous line and now,
- # we saw a backslash so treat the two lines as one.
- if not saw_newline:
- meth(msgid, "module", start[0] - 1)
- meth(msgid, "module", start[0])
- except exceptions.UnknownMessageError:
- self.add_message("bad-option-value", args=msgid, line=start[0])
- else:
- self.add_message("unrecognized-inline-option", args=opt, line=start[0])
-
- # code checking methods ###################################################
-
- def get_checkers(self):
- """return all available checkers as a list"""
- return [self] + [
- c
- for _checkers in self._checkers.values()
- for c in _checkers
- if c is not self
- ]
-
- def get_checker_names(self):
- """Get all the checker names that this linter knows about."""
- current_checkers = self.get_checkers()
- return sorted(
- {
- checker.name
- for checker in current_checkers
- if checker.name != MAIN_CHECKER_NAME
- }
- )
-
- def prepare_checkers(self):
- """return checkers needed for activated messages and reports"""
- if not self.config.reports:
- self.disable_reporters()
- # get needed checkers
- needed_checkers = [self]
- for checker in self.get_checkers()[1:]:
- messages = {msg for msg in checker.msgs if self.is_message_enabled(msg)}
- if messages or any(self.report_is_enabled(r[0]) for r in checker.reports):
- needed_checkers.append(checker)
- # Sort checkers by priority
- needed_checkers = sorted(
- needed_checkers, key=operator.attrgetter("priority"), reverse=True
- )
- return needed_checkers
-
- # pylint: disable=unused-argument
- @staticmethod
- def should_analyze_file(modname, path, is_argument=False):
- """Returns whether or not a module should be checked.
-
- This implementation returns True for all python source file, indicating
- that all files should be linted.
-
- Subclasses may override this method to indicate that modules satisfying
- certain conditions should not be linted.
-
- :param str modname: The name of the module to be checked.
- :param str path: The full path to the source code of the module.
- :param bool is_argument: Whetter the file is an argument to pylint or not.
- Files which respect this property are always
- checked, since the user requested it explicitly.
- :returns: True if the module should be checked.
- :rtype: bool
- """
- if is_argument:
- return True
- return path.endswith(".py")
-
- # pylint: enable=unused-argument
-
- def check(self, files_or_modules):
- """main checking entry: check a list of files or modules from their
- name.
- """
- # initialize msgs_state now that all messages have been registered into
- # the store
- for msg in self.msgs_store.messages:
- if not msg.may_be_emitted():
- self._msgs_state[msg.msgid] = False
-
- if not isinstance(files_or_modules, (list, tuple)):
- files_or_modules = (files_or_modules,)
-
- if self.config.jobs == 1:
- self._do_check(files_or_modules)
- else:
- self._parallel_check(files_or_modules)
-
- def _get_jobs_config(self):
- child_config = collections.OrderedDict()
- filter_options = {"long-help"}
- filter_options.update((opt_name for opt_name, _ in self._external_opts))
- for opt_providers in self._all_options.values():
- for optname, optdict, val in opt_providers.options_and_values():
- if optdict.get("deprecated"):
- continue
-
- if optname not in filter_options:
- child_config[optname] = utils._format_option_value(optdict, val)
- child_config["python3_porting_mode"] = self._python3_porting_mode
- child_config["plugins"] = self._dynamic_plugins
- return child_config
-
- def _parallel_task(self, files_or_modules):
- # Prepare configuration for child linters.
- child_config = self._get_jobs_config()
-
- children = []
- manager = multiprocessing.Manager()
- tasks_queue = manager.Queue()
- results_queue = manager.Queue()
-
- # Send files to child linters.
- expanded_files = []
- for descr in self.expand_files(files_or_modules):
- modname, filepath, is_arg = descr["name"], descr["path"], descr["isarg"]
- if self.should_analyze_file(modname, filepath, is_argument=is_arg):
- expanded_files.append(descr)
-
- # do not start more jobs than needed
- for _ in range(min(self.config.jobs, len(expanded_files))):
- child_linter = ChildLinter(args=(tasks_queue, results_queue, child_config))
- child_linter.start()
- children.append(child_linter)
-
- for files_or_module in expanded_files:
- path = files_or_module["path"]
- tasks_queue.put([path])
-
- # collect results from child linters
- failed = False
- for _ in expanded_files:
- try:
- result = results_queue.get()
- except Exception as ex:
- print(
- "internal error while receiving results from child linter",
- file=sys.stderr,
- )
- print(ex, file=sys.stderr)
- failed = True
- break
- yield result
-
- # Stop child linters and wait for their completion.
- for _ in range(self.config.jobs):
- tasks_queue.put("STOP")
- for child in children:
- child.join()
-
- if failed:
- print("Error occurred, stopping the linter.", file=sys.stderr)
- sys.exit(32)
-
- def _parallel_check(self, files_or_modules):
- # Reset stats.
- self.open()
-
- all_stats = []
- module = None
- for result in self._parallel_task(files_or_modules):
- if not result:
- continue
- (_, self.file_state.base_name, module, messages, stats, msg_status) = result
-
- for msg in messages:
- msg = Message(*msg)
- self.set_current_module(module)
- self.reporter.handle_message(msg)
-
- all_stats.append(stats)
- self.msg_status |= msg_status
-
- self.stats = _merge_stats(all_stats)
- self.current_name = module
-
- # Insert stats data to local checkers.
- for checker in self.get_checkers():
- if checker is not self:
- checker.stats = self.stats
-
- def _do_check(self, files_or_modules):
- walker = ASTWalker(self)
- _checkers = self.prepare_checkers()
- tokencheckers = [
- c
- for c in _checkers
- if interfaces.implements(c, interfaces.ITokenChecker) and c is not self
- ]
- rawcheckers = [
- c for c in _checkers if interfaces.implements(c, interfaces.IRawChecker)
- ]
- # notify global begin
- for checker in _checkers:
- checker.open()
- if interfaces.implements(checker, interfaces.IAstroidChecker):
- walker.add_checker(checker)
- # build ast and check modules or packages
- if self.config.from_stdin:
- if len(files_or_modules) != 1:
- raise exceptions.InvalidArgsError(
- "Missing filename required for --from-stdin"
- )
-
- filepath = files_or_modules[0]
- try:
- # Note that this function does not really perform an
- # __import__ but may raise an ImportError exception, which
- # we want to catch here.
- modname = ".".join(modutils.modpath_from_file(filepath))
- except ImportError:
- modname = os.path.splitext(os.path.basename(filepath))[0]
-
- self.set_current_module(modname, filepath)
-
- # get the module representation
- ast_node = _ast_from_string(_read_stdin(), filepath, modname)
-
- if ast_node is not None:
- self.file_state = FileState(filepath)
- self.check_astroid_module(ast_node, walker, rawcheckers, tokencheckers)
- # warn about spurious inline messages handling
- spurious_messages = self.file_state.iter_spurious_suppression_messages(
- self.msgs_store
- )
- for msgid, line, args in spurious_messages:
- self.add_message(msgid, line, None, args)
- else:
- for descr in self.expand_files(files_or_modules):
- modname, filepath, is_arg = descr["name"], descr["path"], descr["isarg"]
- if not self.should_analyze_file(modname, filepath, is_argument=is_arg):
- continue
-
- self.set_current_module(modname, filepath)
- # get the module representation
- ast_node = self.get_ast(filepath, modname)
- if ast_node is None:
- continue
-
- self.file_state = FileState(descr["basename"])
- self._ignore_file = False
- # fix the current file (if the source file was not available or
- # if it's actually a c extension)
- self.current_file = ast_node.file # pylint: disable=maybe-no-member
- before_check_statements = walker.nbstatements
- self.check_astroid_module(ast_node, walker, rawcheckers, tokencheckers)
- self.stats["by_module"][modname]["statement"] = (
- walker.nbstatements - before_check_statements
- )
- # warn about spurious inline messages handling
- spurious_messages = self.file_state.iter_spurious_suppression_messages(
- self.msgs_store
- )
- for msgid, line, args in spurious_messages:
- self.add_message(msgid, line, None, args)
- # notify global end
- self.stats["statement"] = walker.nbstatements
- for checker in reversed(_checkers):
- checker.close()
-
- def expand_files(self, modules):
- """get modules and errors from a list of modules and handle errors
- """
- result, errors = utils.expand_modules(
- modules, self.config.black_list, self.config.black_list_re
- )
- for error in errors:
- message = modname = error["mod"]
- key = error["key"]
- self.set_current_module(modname)
- if key == "fatal":
- message = str(error["ex"]).replace(os.getcwd() + os.sep, "")
- self.add_message(key, args=message)
- return result
-
- def set_current_module(self, modname, filepath=None):
- """set the name of the currently analyzed module and
- init statistics for it
- """
- if not modname and filepath is None:
- return
- self.reporter.on_set_current_module(modname, filepath)
- self.current_name = modname
- self.current_file = filepath or modname
- self.stats["by_module"][modname] = {}
- self.stats["by_module"][modname]["statement"] = 0
- for msg_cat in MSG_TYPES.values():
- self.stats["by_module"][modname][msg_cat] = 0
-
- def get_ast(self, filepath, modname):
- """return an ast(roid) representation for a module"""
- try:
- return MANAGER.ast_from_file(filepath, modname, source=True)
- except astroid.AstroidSyntaxError as ex:
- # pylint: disable=no-member
- self.add_message(
- "syntax-error",
- line=getattr(ex.error, "lineno", 0),
- col_offset=getattr(ex.error, "offset", None),
- args=str(ex.error),
- )
- except astroid.AstroidBuildingException as ex:
- self.add_message("parse-error", args=ex)
- except Exception as ex:
- traceback.print_exc()
- self.add_message("astroid-error", args=(ex.__class__, ex))
-
- def check_astroid_module(self, ast_node, walker, rawcheckers, tokencheckers):
- """Check a module from its astroid representation."""
- try:
- tokens = utils.tokenize_module(ast_node)
- except tokenize.TokenError as ex:
- self.add_message("syntax-error", line=ex.args[1][0], args=ex.args[0])
- return None
-
- if not ast_node.pure_python:
- self.add_message("raw-checker-failed", args=ast_node.name)
- else:
- # assert astroid.file.endswith('.py')
- # invoke ITokenChecker interface on self to fetch module/block
- # level options
- self.process_tokens(tokens)
- if self._ignore_file:
- return False
- # walk ast to collect line numbers
- self.file_state.collect_block_lines(self.msgs_store, ast_node)
- # run raw and tokens checkers
- for checker in rawcheckers:
- checker.process_module(ast_node)
- for checker in tokencheckers:
- checker.process_tokens(tokens)
- # generate events to astroid checkers
- walker.walk(ast_node)
- return True
-
- # IAstroidChecker interface #################################################
-
- def open(self):
- """initialize counters"""
- self.stats = {"by_module": {}, "by_msg": {}}
- MANAGER.always_load_extensions = self.config.unsafe_load_any_extension
- MANAGER.max_inferable_values = self.config.limit_inference_results
- MANAGER.extension_package_whitelist.update(self.config.extension_pkg_whitelist)
- for msg_cat in MSG_TYPES.values():
- self.stats[msg_cat] = 0
-
- def generate_reports(self):
- """close the whole package /module, it's time to make reports !
-
- if persistent run, pickle results for later comparison
- """
- # Display whatever messages are left on the reporter.
- self.reporter.display_messages(report_nodes.Section())
-
- if self.file_state.base_name is not None:
- # load previous results if any
- previous_stats = config.load_results(self.file_state.base_name)
- self.reporter.on_close(self.stats, previous_stats)
- if self.config.reports:
- sect = self.make_reports(self.stats, previous_stats)
- else:
- sect = report_nodes.Section()
-
- if self.config.reports:
- self.reporter.display_reports(sect)
- self._report_evaluation()
- # save results if persistent run
- if self.config.persistent:
- config.save_results(self.stats, self.file_state.base_name)
- else:
- self.reporter.on_close(self.stats, {})
-
- def _report_evaluation(self):
- """make the global evaluation report"""
- # check with at least check 1 statements (usually 0 when there is a
- # syntax error preventing pylint from further processing)
- previous_stats = config.load_results(self.file_state.base_name)
- if self.stats["statement"] == 0:
- return
-
- # get a global note for the code
- evaluation = self.config.evaluation
- try:
- note = eval(evaluation, {}, self.stats) # pylint: disable=eval-used
- except Exception as ex:
- msg = "An exception occurred while rating: %s" % ex
- else:
- self.stats["global_note"] = note
- msg = "Your code has been rated at %.2f/10" % note
- pnote = previous_stats.get("global_note")
- if pnote is not None:
- msg += " (previous run: %.2f/10, %+.2f)" % (pnote, note - pnote)
-
- if self.config.score:
- sect = report_nodes.EvaluationSection(msg)
- self.reporter.display_reports(sect)
-
-
-# some reporting functions ####################################################
-
-
-def report_total_messages_stats(sect, stats, previous_stats):
- """make total errors / warnings report"""
- lines = ["type", "number", "previous", "difference"]
- lines += checkers.table_lines_from_stats(
- stats, previous_stats, ("convention", "refactor", "warning", "error")
- )
- sect.append(report_nodes.Table(children=lines, cols=4, rheaders=1))
-
-
-def report_messages_stats(sect, stats, _):
- """make messages type report"""
- if not stats["by_msg"]:
- # don't print this report when we didn't detected any errors
- raise exceptions.EmptyReportError()
- in_order = sorted(
- [
- (value, msg_id)
- for msg_id, value in stats["by_msg"].items()
- if not msg_id.startswith("I")
- ]
- )
- in_order.reverse()
- lines = ("message id", "occurrences")
- for value, msg_id in in_order:
- lines += (msg_id, str(value))
- sect.append(report_nodes.Table(children=lines, cols=2, rheaders=1))
-
-
-def report_messages_by_module_stats(sect, stats, _):
- """make errors / warnings by modules report"""
- if len(stats["by_module"]) == 1:
- # don't print this report when we are analysing a single module
- raise exceptions.EmptyReportError()
- by_mod = collections.defaultdict(dict)
- for m_type in ("fatal", "error", "warning", "refactor", "convention"):
- total = stats[m_type]
- for module in stats["by_module"].keys():
- mod_total = stats["by_module"][module][m_type]
- if total == 0:
- percent = 0
- else:
- percent = float((mod_total) * 100) / total
- by_mod[module][m_type] = percent
- sorted_result = []
- for module, mod_info in by_mod.items():
- sorted_result.append(
- (
- mod_info["error"],
- mod_info["warning"],
- mod_info["refactor"],
- mod_info["convention"],
- module,
- )
- )
- sorted_result.sort()
- sorted_result.reverse()
- lines = ["module", "error", "warning", "refactor", "convention"]
- for line in sorted_result:
- # Don't report clean modules.
- if all(entry == 0 for entry in line[:-1]):
- continue
- lines.append(line[-1])
- for val in line[:-1]:
- lines.append("%.2f" % val)
- if len(lines) == 5:
- raise exceptions.EmptyReportError()
- sect.append(report_nodes.Table(children=lines, cols=5, rheaders=1))
-
-
-# utilities ###################################################################
-
-
-class ArgumentPreprocessingError(Exception):
- """Raised if an error occurs during argument preprocessing."""
-
-
-def preprocess_options(args, search_for):
- """look for some options (keys of <search_for>) which have to be processed
- before others
-
- values of <search_for> are callback functions to call when the option is
- found
- """
- i = 0
- while i < len(args):
- arg = args[i]
- if arg.startswith("--"):
- try:
- option, val = arg[2:].split("=", 1)
- except ValueError:
- option, val = arg[2:], None
- try:
- cb, takearg = search_for[option]
- except KeyError:
- i += 1
- else:
- del args[i]
- if takearg and val is None:
- if i >= len(args) or args[i].startswith("-"):
- msg = "Option %s expects a value" % option
- raise ArgumentPreprocessingError(msg)
- val = args[i]
- del args[i]
- elif not takearg and val is not None:
- msg = "Option %s doesn't expects a value" % option
- raise ArgumentPreprocessingError(msg)
- cb(option, val)
- else:
- i += 1
-
-
-@contextlib.contextmanager
-def fix_import_path(args):
- """Prepare sys.path for running the linter checks.
-
- Within this context, each of the given arguments is importable.
- Paths are added to sys.path in corresponding order to the arguments.
- We avoid adding duplicate directories to sys.path.
- `sys.path` is reset to its original value upon exiting this context.
- """
- orig = list(sys.path)
- changes = []
- for arg in args:
- path = _get_python_path(arg)
- if path not in changes:
- changes.append(path)
- sys.path[:] = changes + ["."] + sys.path
- try:
- yield
- finally:
- sys.path[:] = orig
-
-
-class Run:
- """helper class to use as main for pylint :
-
- run(*sys.argv[1:])
- """
-
- LinterClass = PyLinter
- option_groups = (
- (
- "Commands",
- "Options which are actually commands. Options in this \
-group are mutually exclusive.",
- ),
- )
-
- def __init__(self, args, reporter=None, do_exit=True):
- self._rcfile = None
- self._plugins = []
- self.verbose = None
- try:
- preprocess_options(
- args,
- {
- # option: (callback, takearg)
- "init-hook": (cb_init_hook, True),
- "rcfile": (self.cb_set_rcfile, True),
- "load-plugins": (self.cb_add_plugins, True),
- "verbose": (self.cb_verbose_mode, False),
- },
- )
- except ArgumentPreprocessingError as ex:
- print(ex, file=sys.stderr)
- sys.exit(32)
-
- self.linter = linter = self.LinterClass(
- (
- (
- "rcfile",
- {
- "action": "callback",
- "callback": lambda *args: 1,
- "type": "string",
- "metavar": "<file>",
- "help": "Specify a configuration file.",
- },
- ),
- (
- "init-hook",
- {
- "action": "callback",
- "callback": lambda *args: 1,
- "type": "string",
- "metavar": "<code>",
- "level": 1,
- "help": "Python code to execute, usually for sys.path "
- "manipulation such as pygtk.require().",
- },
- ),
- (
- "help-msg",
- {
- "action": "callback",
- "type": "string",
- "metavar": "<msg-id>",
- "callback": self.cb_help_message,
- "group": "Commands",
- "help": "Display a help message for the given message id and "
- "exit. The value may be a comma separated list of message ids.",
- },
- ),
- (
- "list-msgs",
- {
- "action": "callback",
- "metavar": "<msg-id>",
- "callback": self.cb_list_messages,
- "group": "Commands",
- "level": 1,
- "help": "Generate pylint's messages.",
- },
- ),
- (
- "list-msgs-enabled",
- {
- "action": "callback",
- "metavar": "<msg-id>",
- "callback": self.cb_list_messages_enabled,
- "group": "Commands",
- "level": 1,
- "help": "Display a list of what messages are enabled "
- "and disabled with the given configuration.",
- },
- ),
- (
- "list-groups",
- {
- "action": "callback",
- "metavar": "<msg-id>",
- "callback": self.cb_list_groups,
- "group": "Commands",
- "level": 1,
- "help": "List pylint's message groups.",
- },
- ),
- (
- "list-conf-levels",
- {
- "action": "callback",
- "callback": cb_list_confidence_levels,
- "group": "Commands",
- "level": 1,
- "help": "Generate pylint's confidence levels.",
- },
- ),
- (
- "full-documentation",
- {
- "action": "callback",
- "metavar": "<msg-id>",
- "callback": self.cb_full_documentation,
- "group": "Commands",
- "level": 1,
- "help": "Generate pylint's full documentation.",
- },
- ),
- (
- "generate-rcfile",
- {
- "action": "callback",
- "callback": self.cb_generate_config,
- "group": "Commands",
- "help": "Generate a sample configuration file according to "
- "the current configuration. You can put other options "
- "before this one to get them in the generated "
- "configuration.",
- },
- ),
- (
- "generate-man",
- {
- "action": "callback",
- "callback": self.cb_generate_manpage,
- "group": "Commands",
- "help": "Generate pylint's man page.",
- "hide": True,
- },
- ),
- (
- "errors-only",
- {
- "action": "callback",
- "callback": self.cb_error_mode,
- "short": "E",
- "help": "In error mode, checkers without error messages are "
- "disabled and for others, only the ERROR messages are "
- "displayed, and no reports are done by default.",
- },
- ),
- (
- "py3k",
- {
- "action": "callback",
- "callback": self.cb_python3_porting_mode,
- "help": "In Python 3 porting mode, all checkers will be "
- "disabled and only messages emitted by the porting "
- "checker will be displayed.",
- },
- ),
- (
- "verbose",
- {
- "action": "callback",
- "callback": self.cb_verbose_mode,
- "short": "v",
- "help": "In verbose mode, extra non-checker-related info "
- "will be displayed.",
- },
- ),
- ),
- option_groups=self.option_groups,
- pylintrc=self._rcfile,
- )
- # register standard checkers
- linter.load_default_plugins()
- # load command line plugins
- linter.load_plugin_modules(self._plugins)
- # add some help section
- linter.add_help_section("Environment variables", config.ENV_HELP, level=1)
- # pylint: disable=bad-continuation
- linter.add_help_section(
- "Output",
- "Using the default text output, the message format is : \n"
- " \n"
- " MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE \n"
- " \n"
- "There are 5 kind of message types : \n"
- " * (C) convention, for programming standard violation \n"
- " * (R) refactor, for bad code smell \n"
- " * (W) warning, for python specific problems \n"
- " * (E) error, for probable bugs in the code \n"
- " * (F) fatal, if an error occurred which prevented pylint from doing further\n"
- "processing.\n",
- level=1,
- )
- linter.add_help_section(
- "Output status code",
- "Pylint should leave with following status code: \n"
- " * 0 if everything went fine \n"
- " * 1 if a fatal message was issued \n"
- " * 2 if an error message was issued \n"
- " * 4 if a warning message was issued \n"
- " * 8 if a refactor message was issued \n"
- " * 16 if a convention message was issued \n"
- " * 32 on usage error \n"
- " \n"
- "status 1 to 16 will be bit-ORed so you can know which different categories has\n"
- "been issued by analysing pylint output status code\n",
- level=1,
- )
- # read configuration
- linter.disable("I")
- linter.enable("c-extension-no-member")
- linter.read_config_file(verbose=self.verbose)
- config_parser = linter.cfgfile_parser
- # run init hook, if present, before loading plugins
- if config_parser.has_option("MASTER", "init-hook"):
- cb_init_hook(
- "init-hook", utils._unquote(config_parser.get("MASTER", "init-hook"))
- )
- # is there some additional plugins in the file configuration, in
- if config_parser.has_option("MASTER", "load-plugins"):
- plugins = utils._splitstrip(config_parser.get("MASTER", "load-plugins"))
- linter.load_plugin_modules(plugins)
- # now we can load file config and command line, plugins (which can
- # provide options) have been registered
- linter.load_config_file()
-
- if reporter:
- # if a custom reporter is provided as argument, it may be overridden
- # by file parameters, so re-set it here, but before command line
- # parsing so it's still overrideable by command line option
- linter.set_reporter(reporter)
- try:
- args = linter.load_command_line_configuration(args)
- except SystemExit as exc:
- if exc.code == 2: # bad options
- exc.code = 32
- raise
- if not args:
- print(linter.help())
- sys.exit(32)
-
- if linter.config.jobs < 0:
- print(
- "Jobs number (%d) should be greater than or equal to 0"
- % linter.config.jobs,
- file=sys.stderr,
- )
- sys.exit(32)
- if linter.config.jobs > 1 or linter.config.jobs == 0:
- if multiprocessing is None:
- print(
- "Multiprocessing library is missing, " "fallback to single process",
- file=sys.stderr,
- )
- linter.set_option("jobs", 1)
- else:
- if linter.config.jobs == 0:
- linter.config.jobs = _cpu_count()
-
- # We have loaded configuration from config file and command line. Now, we can
- # load plugin specific configuration.
- linter.load_plugin_configuration()
-
- # insert current working directory to the python path to have a correct
- # behaviour
- with fix_import_path(args):
- linter.check(args)
- linter.generate_reports()
- if do_exit:
- if linter.config.exit_zero:
- sys.exit(0)
- else:
- sys.exit(self.linter.msg_status)
-
- def cb_set_rcfile(self, name, value):
- """callback for option preprocessing (i.e. before option parsing)"""
- self._rcfile = value
-
- def cb_add_plugins(self, name, value):
- """callback for option preprocessing (i.e. before option parsing)"""
- self._plugins.extend(utils._splitstrip(value))
-
- def cb_error_mode(self, *args, **kwargs):
- """error mode:
- * disable all but error messages
- * disable the 'miscellaneous' checker which can be safely deactivated in
- debug
- * disable reports
- * do not save execution information
- """
- self.linter.error_mode()
-
- def cb_generate_config(self, *args, **kwargs):
- """optik callback for sample config file generation"""
- self.linter.generate_config(skipsections=("COMMANDS",))
- sys.exit(0)
-
- def cb_generate_manpage(self, *args, **kwargs):
- """optik callback for sample config file generation"""
- self.linter.generate_manpage(__pkginfo__)
- sys.exit(0)
-
- def cb_help_message(self, option, optname, value, parser):
- """optik callback for printing some help about a particular message"""
- self.linter.msgs_store.help_message(utils._splitstrip(value))
- sys.exit(0)
-
- def cb_full_documentation(self, option, optname, value, parser):
- """optik callback for printing full documentation"""
- self.linter.print_full_documentation()
- sys.exit(0)
-
- def cb_list_messages(self, option, optname, value, parser):
- """optik callback for printing available messages"""
- self.linter.msgs_store.list_messages()
- sys.exit(0)
-
- def cb_list_messages_enabled(self, option, optname, value, parser):
- """optik callback for printing available messages"""
- self.linter.list_messages_enabled()
- sys.exit(0)
-
- def cb_list_groups(self, *args, **kwargs):
- """List all the check groups that pylint knows about
-
- These should be useful to know what check groups someone can disable
- or enable.
- """
- for check in self.linter.get_checker_names():
- print(check)
- sys.exit(0)
-
- def cb_python3_porting_mode(self, *args, **kwargs):
- """Activate only the python3 porting checker."""
- self.linter.python3_porting_mode()
-
- def cb_verbose_mode(self, *args, **kwargs):
- self.verbose = True
-
-
-def cb_list_confidence_levels(option, optname, value, parser):
- for level in interfaces.CONFIDENCE_LEVELS:
- print("%-18s: %s" % level)
- sys.exit(0)
-
-
-def cb_init_hook(optname, value):
- """exec arbitrary code to set sys.path for instance"""
- exec(value) # pylint: disable=exec-used
-
-
-if __name__ == "__main__":
- Run(sys.argv[1:])
diff --git a/venv/Lib/site-packages/pylint/message/__init__.py b/venv/Lib/site-packages/pylint/message/__init__.py
deleted file mode 100644
index 5ac8411..0000000
--- a/venv/Lib/site-packages/pylint/message/__init__.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2009 Vincent
-# Copyright (c) 2009 Mads Kiilerich <mads@kiilerich.com>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014-2015 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 LCD 47 <lcd047@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2014 Damien Nozay <damien.nozay@gmail.com>
-# Copyright (c) 2015 Aru Sahni <arusahni@gmail.com>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Simu Toni <simutoni@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-# Copyright (c) 2016 Glenn Matthews <glmatthe@cisco.com>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2016 xmo-odoo <xmo-odoo@users.noreply.github.com>
-# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Pierre Sassoulas <pierre.sassoulas@cea.fr>
-# Copyright (c) 2017 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2017 Chris Lamb <chris@chris-lamb.co.uk>
-# Copyright (c) 2017 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2017 Thomas Hisch <t.hisch@gmail.com>
-# Copyright (c) 2017 Mikhail Fesenko <proggga@gmail.com>
-# Copyright (c) 2017 Craig Citro <craigcitro@gmail.com>
-# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Pierre Sassoulas <pierre.sassoulas@wisebim.fr>
-# Copyright (c) 2018 Reverb C <reverbc@users.noreply.github.com>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""All the classes related to Message handling."""
-
-from pylint.message.message import Message
-from pylint.message.message_definition import MessageDefinition
-from pylint.message.message_definition_store import MessageDefinitionStore
-from pylint.message.message_handler_mix_in import MessagesHandlerMixIn
-from pylint.message.message_id_store import MessageIdStore
-
-__all__ = [
- "Message",
- "MessageDefinition",
- "MessageDefinitionStore",
- "MessagesHandlerMixIn",
- "MessageIdStore",
-]
diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index f3462f1..0000000
--- a/venv/Lib/site-packages/pylint/message/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message.cpython-37.pyc
deleted file mode 100644
index 6c89577..0000000
--- a/venv/Lib/site-packages/pylint/message/__pycache__/message.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message_definition.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message_definition.cpython-37.pyc
deleted file mode 100644
index 952803b..0000000
--- a/venv/Lib/site-packages/pylint/message/__pycache__/message_definition.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message_definition_store.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message_definition_store.cpython-37.pyc
deleted file mode 100644
index ce6f867..0000000
--- a/venv/Lib/site-packages/pylint/message/__pycache__/message_definition_store.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message_handler_mix_in.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message_handler_mix_in.cpython-37.pyc
deleted file mode 100644
index 23cc65a..0000000
--- a/venv/Lib/site-packages/pylint/message/__pycache__/message_handler_mix_in.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message_id_store.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message_id_store.cpython-37.pyc
deleted file mode 100644
index f132b88..0000000
--- a/venv/Lib/site-packages/pylint/message/__pycache__/message_id_store.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/message/message.py b/venv/Lib/site-packages/pylint/message/message.py
deleted file mode 100644
index e2b0320..0000000
--- a/venv/Lib/site-packages/pylint/message/message.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-
-import collections
-
-from pylint.constants import MSG_TYPES
-
-_MsgBase = collections.namedtuple(
- "_MsgBase",
- [
- "msg_id",
- "symbol",
- "msg",
- "C",
- "category",
- "confidence",
- "abspath",
- "path",
- "module",
- "obj",
- "line",
- "column",
- ],
-)
-
-
-class Message(_MsgBase):
- """This class represent a message to be issued by the reporters"""
-
- def __new__(cls, msg_id, symbol, location, msg, confidence):
- return _MsgBase.__new__(
- cls,
- msg_id,
- symbol,
- msg,
- msg_id[0],
- MSG_TYPES[msg_id[0]],
- confidence,
- *location
- )
-
- def format(self, template):
- """Format the message according to the given template.
-
- The template format is the one of the format method :
- cf. http://docs.python.org/2/library/string.html#formatstrings
- """
- # For some reason, _asdict on derived namedtuples does not work with
- # Python 3.4. Needs some investigation.
- return template.format(**dict(zip(self._fields, self)))
diff --git a/venv/Lib/site-packages/pylint/message/message_definition.py b/venv/Lib/site-packages/pylint/message/message_definition.py
deleted file mode 100644
index e54c15a..0000000
--- a/venv/Lib/site-packages/pylint/message/message_definition.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import sys
-
-from pylint.constants import MSG_TYPES
-from pylint.exceptions import InvalidMessageError
-from pylint.utils import normalize_text
-
-
-class MessageDefinition:
- def __init__(
- self,
- checker,
- msgid,
- msg,
- description,
- symbol,
- scope,
- minversion=None,
- maxversion=None,
- old_names=None,
- ):
- self.checker = checker
- self.check_msgid(msgid)
- self.msgid = msgid
- self.symbol = symbol
- self.msg = msg
- self.description = description
- self.scope = scope
- self.minversion = minversion
- self.maxversion = maxversion
- self.old_names = []
- if old_names:
- for old_msgid, old_symbol in old_names:
- self.check_msgid(old_msgid)
- self.old_names.append([old_msgid, old_symbol])
-
- @staticmethod
- def check_msgid(msgid: str) -> None:
- if len(msgid) != 5:
- raise InvalidMessageError("Invalid message id %r" % msgid)
- if msgid[0] not in MSG_TYPES:
- raise InvalidMessageError("Bad message type %s in %r" % (msgid[0], msgid))
-
- def __repr__(self):
- return "MessageDefinition:%s (%s)" % (self.symbol, self.msgid)
-
- def __str__(self):
- return "%s:\n%s %s" % (repr(self), self.msg, self.description)
-
- def may_be_emitted(self):
- """return True if message may be emitted using the current interpreter"""
- if self.minversion is not None and self.minversion > sys.version_info:
- return False
- if self.maxversion is not None and self.maxversion <= sys.version_info:
- return False
- return True
-
- def format_help(self, checkerref=False):
- """return the help string for the given message id"""
- desc = self.description
- if checkerref:
- desc += " This message belongs to the %s checker." % self.checker.name
- title = self.msg
- if self.minversion or self.maxversion:
- restr = []
- if self.minversion:
- restr.append("< %s" % ".".join([str(n) for n in self.minversion]))
- if self.maxversion:
- restr.append(">= %s" % ".".join([str(n) for n in self.maxversion]))
- restr = " or ".join(restr)
- if checkerref:
- desc += " It can't be emitted when using Python %s." % restr
- else:
- desc += " This message can't be emitted when using Python %s." % restr
- msg_help = normalize_text(" ".join(desc.split()), indent=" ")
- message_id = "%s (%s)" % (self.symbol, self.msgid)
- if title != "%s":
- title = title.splitlines()[0]
- return ":%s: *%s*\n%s" % (message_id, title.rstrip(" "), msg_help)
- return ":%s:\n%s" % (message_id, msg_help)
diff --git a/venv/Lib/site-packages/pylint/message/message_definition_store.py b/venv/Lib/site-packages/pylint/message/message_definition_store.py
deleted file mode 100644
index f7d87b6..0000000
--- a/venv/Lib/site-packages/pylint/message/message_definition_store.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import collections
-
-from pylint.exceptions import UnknownMessageError
-from pylint.message.message_id_store import MessageIdStore
-
-
-class MessageDefinitionStore:
-
- """The messages store knows information about every possible message definition but has
- no particular state during analysis.
- """
-
- def __init__(self):
- self.message_id_store = MessageIdStore()
- # Primary registry for all active messages definitions.
- # It contains the 1:1 mapping from msgid to MessageDefinition.
- # Keys are msgid, values are MessageDefinition
- self._messages_definitions = {}
- # MessageDefinition kept by category
- self._msgs_by_category = collections.defaultdict(list)
-
- @property
- def messages(self) -> list:
- """The list of all active messages."""
- return self._messages_definitions.values()
-
- def register_messages_from_checker(self, checker):
- """Register all messages definitions from a checker.
-
- :param BaseChecker checker:
- """
- checker.check_consistency()
- for message in checker.messages:
- self.register_message(message)
-
- def register_message(self, message):
- """Register a MessageDefinition with consistency in mind.
-
- :param MessageDefinition message: The message definition being added.
- """
- self.message_id_store.register_message_definition(message)
- self._messages_definitions[message.msgid] = message
- self._msgs_by_category[message.msgid[0]].append(message.msgid)
-
- def get_message_definitions(self, msgid_or_symbol: str) -> list:
- """Returns the Message object for this message.
- :param str msgid_or_symbol: msgid_or_symbol may be either a numeric or symbolic id.
- :raises UnknownMessageError: if the message id is not defined.
- :rtype: List of MessageDefinition
- :return: A message definition corresponding to msgid_or_symbol
- """
- return [
- self._messages_definitions[m]
- for m in self.message_id_store.get_active_msgids(msgid_or_symbol)
- ]
-
- def get_msg_display_string(self, msgid_or_symbol: str):
- """Generates a user-consumable representation of a message. """
- message_definitions = self.get_message_definitions(msgid_or_symbol)
- if len(message_definitions) == 1:
- return repr(message_definitions[0].symbol)
- return repr([md.symbol for md in message_definitions])
-
- def help_message(self, msgids_or_symbols: list):
- """Display help messages for the given message identifiers"""
- for msgids_or_symbol in msgids_or_symbols:
- try:
- for message_definition in self.get_message_definitions(
- msgids_or_symbol
- ):
- print(message_definition.format_help(checkerref=True))
- print("")
- except UnknownMessageError as ex:
- print(ex)
- print("")
- continue
-
- def list_messages(self):
- """Output full messages list documentation in ReST format. """
- messages = sorted(self._messages_definitions.values(), key=lambda m: m.msgid)
- for message in messages:
- if not message.may_be_emitted():
- continue
- print(message.format_help(checkerref=False))
- print("")
diff --git a/venv/Lib/site-packages/pylint/message/message_handler_mix_in.py b/venv/Lib/site-packages/pylint/message/message_handler_mix_in.py
deleted file mode 100644
index 813cdd7..0000000
--- a/venv/Lib/site-packages/pylint/message/message_handler_mix_in.py
+++ /dev/null
@@ -1,393 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import sys
-
-from pylint.constants import (
- _SCOPE_EXEMPT,
- MAIN_CHECKER_NAME,
- MSG_STATE_CONFIDENCE,
- MSG_STATE_SCOPE_CONFIG,
- MSG_STATE_SCOPE_MODULE,
- MSG_TYPES,
- MSG_TYPES_LONG,
- MSG_TYPES_STATUS,
- WarningScope,
-)
-from pylint.exceptions import InvalidMessageError, UnknownMessageError
-from pylint.interfaces import UNDEFINED
-from pylint.message.message import Message
-from pylint.utils import get_module_and_frameid, get_rst_section, get_rst_title
-
-
-class MessagesHandlerMixIn:
- """a mix-in class containing all the messages related methods for the main
- lint class
- """
-
- __by_id_managed_msgs = [] # type: ignore
-
- def __init__(self):
- self._msgs_state = {}
- self.msg_status = 0
-
- def _checker_messages(self, checker):
- for known_checker in self._checkers[checker.lower()]:
- for msgid in known_checker.msgs:
- yield msgid
-
- @classmethod
- def clear_by_id_managed_msgs(cls):
- cls.__by_id_managed_msgs.clear()
-
- @classmethod
- def get_by_id_managed_msgs(cls):
- return cls.__by_id_managed_msgs
-
- def _register_by_id_managed_msg(self, msgid, line, is_disabled=True):
- """If the msgid is a numeric one, then register it to inform the user
- it could furnish instead a symbolic msgid."""
- try:
- message_definitions = self.msgs_store.get_message_definitions(msgid)
- for message_definition in message_definitions:
- if msgid == message_definition.msgid:
- MessagesHandlerMixIn.__by_id_managed_msgs.append(
- (
- self.current_name,
- message_definition.msgid,
- message_definition.symbol,
- line,
- is_disabled,
- )
- )
- except UnknownMessageError:
- pass
-
- def disable(self, msgid, scope="package", line=None, ignore_unknown=False):
- """don't output message of the given id"""
- self._set_msg_status(
- msgid, enable=False, scope=scope, line=line, ignore_unknown=ignore_unknown
- )
- self._register_by_id_managed_msg(msgid, line)
-
- def enable(self, msgid, scope="package", line=None, ignore_unknown=False):
- """reenable message of the given id"""
- self._set_msg_status(
- msgid, enable=True, scope=scope, line=line, ignore_unknown=ignore_unknown
- )
- self._register_by_id_managed_msg(msgid, line, is_disabled=False)
-
- def _set_msg_status(
- self, msgid, enable, scope="package", line=None, ignore_unknown=False
- ):
- assert scope in ("package", "module")
-
- if msgid == "all":
- for _msgid in MSG_TYPES:
- self._set_msg_status(_msgid, enable, scope, line, ignore_unknown)
- if enable and not self._python3_porting_mode:
- # Don't activate the python 3 porting checker if it wasn't activated explicitly.
- self.disable("python3")
- return
-
- # msgid is a category?
- category_id = msgid.upper()
- if category_id not in MSG_TYPES:
- category_id = MSG_TYPES_LONG.get(category_id)
- if category_id is not None:
- for _msgid in self.msgs_store._msgs_by_category.get(category_id):
- self._set_msg_status(_msgid, enable, scope, line)
- return
-
- # msgid is a checker name?
- if msgid.lower() in self._checkers:
- for checker in self._checkers[msgid.lower()]:
- for _msgid in checker.msgs:
- self._set_msg_status(_msgid, enable, scope, line)
- return
-
- # msgid is report id?
- if msgid.lower().startswith("rp"):
- if enable:
- self.enable_report(msgid)
- else:
- self.disable_report(msgid)
- return
-
- try:
- # msgid is a symbolic or numeric msgid.
- message_definitions = self.msgs_store.get_message_definitions(msgid)
- except UnknownMessageError:
- if ignore_unknown:
- return
- raise
- for message_definition in message_definitions:
- self._set_one_msg_status(scope, message_definition, line, enable)
-
- def _set_one_msg_status(self, scope, msg, line, enable):
- if scope == "module":
- self.file_state.set_msg_status(msg, line, enable)
- if not enable and msg.symbol != "locally-disabled":
- self.add_message(
- "locally-disabled", line=line, args=(msg.symbol, msg.msgid)
- )
- else:
- msgs = self._msgs_state
- msgs[msg.msgid] = enable
- # sync configuration object
- self.config.enable = [
- self._message_symbol(mid) for mid, val in sorted(msgs.items()) if val
- ]
- self.config.disable = [
- self._message_symbol(mid)
- for mid, val in sorted(msgs.items())
- if not val
- ]
-
- def _message_symbol(self, msgid):
- """Get the message symbol of the given message id
-
- Return the original message id if the message does not
- exist.
- """
- try:
- return [md.symbol for md in self.msgs_store.get_message_definitions(msgid)]
- except UnknownMessageError:
- return msgid
-
- def get_message_state_scope(self, msgid, line=None, confidence=UNDEFINED):
- """Returns the scope at which a message was enabled/disabled."""
- if self.config.confidence and confidence.name not in self.config.confidence:
- return MSG_STATE_CONFIDENCE
- try:
- if line in self.file_state._module_msgs_state[msgid]:
- return MSG_STATE_SCOPE_MODULE
- except (KeyError, TypeError):
- return MSG_STATE_SCOPE_CONFIG
- return None
-
- def is_message_enabled(self, msg_descr, line=None, confidence=None):
- """return true if the message associated to the given message id is
- enabled
-
- msgid may be either a numeric or symbolic message id.
- """
- if self.config.confidence and confidence:
- if confidence.name not in self.config.confidence:
- return False
- try:
- message_definitions = self.msgs_store.get_message_definitions(msg_descr)
- msgids = [md.msgid for md in message_definitions]
- except UnknownMessageError:
- # The linter checks for messages that are not registered
- # due to version mismatch, just treat them as message IDs
- # for now.
- msgids = [msg_descr]
- for msgid in msgids:
- if self.is_one_message_enabled(msgid, line):
- return True
- return False
-
- def is_one_message_enabled(self, msgid, line):
- if line is None:
- return self._msgs_state.get(msgid, True)
- try:
- return self.file_state._module_msgs_state[msgid][line]
- except KeyError:
- # Check if the message's line is after the maximum line existing in ast tree.
- # This line won't appear in the ast tree and won't be referred in
- #  self.file_state._module_msgs_state
- # This happens for example with a commented line at the end of a module.
- max_line_number = self.file_state.get_effective_max_line_number()
- if max_line_number and line > max_line_number:
- fallback = True
- lines = self.file_state._raw_module_msgs_state.get(msgid, {})
-
- # Doesn't consider scopes, as a disable can be in a different scope
- # than that of the current line.
- closest_lines = reversed(
- [
- (message_line, enable)
- for message_line, enable in lines.items()
- if message_line <= line
- ]
- )
- last_line, is_enabled = next(closest_lines, (None, None))
- if last_line is not None:
- fallback = is_enabled
-
- return self._msgs_state.get(msgid, fallback)
- return self._msgs_state.get(msgid, True)
-
- def add_message(
- self, msgid, line=None, node=None, args=None, confidence=None, col_offset=None
- ):
- """Adds a message given by ID or name.
-
- If provided, the message string is expanded using args.
-
- AST checkers must provide the node argument (but may optionally
- provide line if the line number is different), raw and token checkers
- must provide the line argument.
- """
- if confidence is None:
- confidence = UNDEFINED
- message_definitions = self.msgs_store.get_message_definitions(msgid)
- for message_definition in message_definitions:
- self.add_one_message(
- message_definition, line, node, args, confidence, col_offset
- )
-
- @staticmethod
- def check_message_definition(message_definition, line, node):
- if message_definition.msgid[0] not in _SCOPE_EXEMPT:
- # Fatal messages and reports are special, the node/scope distinction
- # does not apply to them.
- if message_definition.scope == WarningScope.LINE:
- if line is None:
- raise InvalidMessageError(
- "Message %s must provide line, got None"
- % message_definition.msgid
- )
- if node is not None:
- raise InvalidMessageError(
- "Message %s must only provide line, "
- "got line=%s, node=%s" % (message_definition.msgid, line, node)
- )
- elif message_definition.scope == WarningScope.NODE:
- # Node-based warnings may provide an override line.
- if node is None:
- raise InvalidMessageError(
- "Message %s must provide Node, got None"
- % message_definition.msgid
- )
-
- def add_one_message(
- self, message_definition, line, node, args, confidence, col_offset
- ):
- self.check_message_definition(message_definition, line, node)
- if line is None and node is not None:
- line = node.fromlineno
- if col_offset is None and hasattr(node, "col_offset"):
- col_offset = node.col_offset
-
- # should this message be displayed
- if not self.is_message_enabled(message_definition.msgid, line, confidence):
- self.file_state.handle_ignored_message(
- self.get_message_state_scope(
- message_definition.msgid, line, confidence
- ),
- message_definition.msgid,
- line,
- node,
- args,
- confidence,
- )
- return
- # update stats
- msg_cat = MSG_TYPES[message_definition.msgid[0]]
- self.msg_status |= MSG_TYPES_STATUS[message_definition.msgid[0]]
- self.stats[msg_cat] += 1
- self.stats["by_module"][self.current_name][msg_cat] += 1
- try:
- self.stats["by_msg"][message_definition.symbol] += 1
- except KeyError:
- self.stats["by_msg"][message_definition.symbol] = 1
- # expand message ?
- msg = message_definition.msg
- if args:
- msg %= args
- # get module and object
- if node is None:
- module, obj = self.current_name, ""
- abspath = self.current_file
- else:
- module, obj = get_module_and_frameid(node)
- abspath = node.root().file
- path = abspath.replace(self.reporter.path_strip_prefix, "", 1)
- # add the message
- self.reporter.handle_message(
- Message(
- message_definition.msgid,
- message_definition.symbol,
- (abspath, path, module, obj, line or 1, col_offset or 0),
- msg,
- confidence,
- )
- )
-
- def _get_checkers_infos(self):
- by_checker = {}
- for checker in self.get_checkers():
- name = checker.name
- if name != "master":
- try:
- by_checker[name]["checker"] = checker
- by_checker[name]["options"] += checker.options_and_values()
- by_checker[name]["msgs"].update(checker.msgs)
- by_checker[name]["reports"] += checker.reports
- except KeyError:
- by_checker[name] = {
- "checker": checker,
- "options": list(checker.options_and_values()),
- "msgs": dict(checker.msgs),
- "reports": list(checker.reports),
- }
- return by_checker
-
- def get_checkers_documentation(self):
- result = get_rst_title("Pylint global options and switches", "-")
- result += """
-Pylint provides global options and switches.
-
-"""
- for checker in self.get_checkers():
- name = checker.name
- if name == MAIN_CHECKER_NAME:
- if checker.options:
- for section, options in checker.options_by_section():
- if section is None:
- title = "General options"
- else:
- title = "%s options" % section.capitalize()
- result += get_rst_title(title, "~")
- result += "%s\n" % get_rst_section(None, options)
- result += get_rst_title("Pylint checkers' options and switches", "-")
- result += """\
-
-Pylint checkers can provide three set of features:
-
-* options that control their execution,
-* messages that they can raise,
-* reports that they can generate.
-
-Below is a list of all checkers and their features.
-
-"""
- by_checker = self._get_checkers_infos()
- for checker in sorted(by_checker):
- information = by_checker[checker]
- checker = information["checker"]
- del information["checker"]
- result += checker.get_full_documentation(**information)
- return result
-
- def print_full_documentation(self, stream=None):
- """output a full documentation in ReST format"""
- if not stream:
- stream = sys.stdout
- print(self.get_checkers_documentation()[:-1], file=stream)
-
- @staticmethod
- def _print_checker_doc(information, stream=None):
- """Helper method for print_full_documentation.
-
- Also used by doc/exts/pylint_extensions.py.
- """
- if not stream:
- stream = sys.stdout
- checker = information["checker"]
- del information["checker"]
- print(checker.get_full_documentation(**information)[:-1], file=stream)
diff --git a/venv/Lib/site-packages/pylint/message/message_id_store.py b/venv/Lib/site-packages/pylint/message/message_id_store.py
deleted file mode 100644
index 756888a..0000000
--- a/venv/Lib/site-packages/pylint/message/message_id_store.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-from typing import List
-
-from pylint.exceptions import InvalidMessageError, UnknownMessageError
-
-
-class MessageIdStore:
-
- """The MessageIdStore store MessageId and make sure that there is a 1-1 relation between msgid and symbol."""
-
- def __init__(self):
- self.__msgid_to_symbol = {}
- self.__symbol_to_msgid = {}
- self.__old_names = {}
-
- def __len__(self):
- return len(self.__msgid_to_symbol)
-
- def __repr__(self):
- result = "MessageIdStore: [\n"
- for msgid, symbol in self.__msgid_to_symbol.items():
- result += " - {msgid} ({symbol})\n".format(msgid=msgid, symbol=symbol)
- result += "]"
- return result
-
- def get_symbol(self, msgid: str) -> str:
- return self.__msgid_to_symbol[msgid]
-
- def get_msgid(self, symbol: str) -> str:
- return self.__symbol_to_msgid[symbol]
-
- def register_message_definition(self, message_definition):
- self.check_msgid_and_symbol(message_definition.msgid, message_definition.symbol)
- self.add_msgid_and_symbol(message_definition.msgid, message_definition.symbol)
- for old_msgid, old_symbol in message_definition.old_names:
- self.check_msgid_and_symbol(old_msgid, old_symbol)
- self.add_legacy_msgid_and_symbol(
- old_msgid, old_symbol, message_definition.msgid
- )
-
- def add_msgid_and_symbol(self, msgid: str, symbol: str) -> None:
- """Add valid message id.
-
- There is a little duplication with add_legacy_msgid_and_symbol to avoid a function call,
- this is called a lot at initialization."""
- self.__msgid_to_symbol[msgid] = symbol
- self.__symbol_to_msgid[symbol] = msgid
-
- def add_legacy_msgid_and_symbol(self, msgid: str, symbol: str, new_msgid: str):
- """Add valid legacy message id.
-
- There is a little duplication with add_msgid_and_symbol to avoid a function call,
- this is called a lot at initialization."""
- self.__msgid_to_symbol[msgid] = symbol
- self.__symbol_to_msgid[symbol] = msgid
- existing_old_names = self.__old_names.get(msgid, [])
- existing_old_names.append(new_msgid)
- self.__old_names[msgid] = existing_old_names
-
- def check_msgid_and_symbol(self, msgid: str, symbol: str) -> None:
- existing_msgid = self.__symbol_to_msgid.get(symbol)
- existing_symbol = self.__msgid_to_symbol.get(msgid)
- if existing_symbol is None and existing_msgid is None:
- return
- if existing_msgid is not None:
- if existing_msgid != msgid:
- self._raise_duplicate_msgid(symbol, msgid, existing_msgid)
- if existing_symbol != symbol:
- self._raise_duplicate_symbol(msgid, symbol, existing_symbol)
-
- @staticmethod
- def _raise_duplicate_symbol(msgid, symbol, other_symbol):
- """Raise an error when a symbol is duplicated.
-
- :param str msgid: The msgid corresponding to the symbols
- :param str symbol: Offending symbol
- :param str other_symbol: Other offending symbol
- :raises InvalidMessageError:"""
- symbols = [symbol, other_symbol]
- symbols.sort()
- error_message = "Message id '{msgid}' cannot have both ".format(msgid=msgid)
- error_message += "'{other_symbol}' and '{symbol}' as symbolic name.".format(
- other_symbol=symbols[0], symbol=symbols[1]
- )
- raise InvalidMessageError(error_message)
-
- @staticmethod
- def _raise_duplicate_msgid(symbol, msgid, other_msgid):
- """Raise an error when a msgid is duplicated.
-
- :param str symbol: The symbol corresponding to the msgids
- :param str msgid: Offending msgid
- :param str other_msgid: Other offending msgid
- :raises InvalidMessageError:"""
- msgids = [msgid, other_msgid]
- msgids.sort()
- error_message = (
- "Message symbol '{symbol}' cannot be used for "
- "'{other_msgid}' and '{msgid}' at the same time."
- " If you're creating an 'old_names' use 'old-{symbol}' as the old symbol."
- ).format(symbol=symbol, other_msgid=msgids[0], msgid=msgids[1])
- raise InvalidMessageError(error_message)
-
- def get_active_msgids(self, msgid_or_symbol: str) -> List[str]:
- """Return msgids but the input can be a symbol."""
- # Only msgid can have a digit as second letter
- is_msgid = msgid_or_symbol[1:].isdigit()
- if is_msgid:
- msgid = msgid_or_symbol.upper()
- symbol = self.__msgid_to_symbol.get(msgid)
- else:
- msgid = self.__symbol_to_msgid.get(msgid_or_symbol)
- symbol = msgid_or_symbol
- if not msgid or not symbol:
- error_msg = "No such message id or symbol '{msgid_or_symbol}'.".format(
- msgid_or_symbol=msgid_or_symbol
- )
- raise UnknownMessageError(error_msg)
- # logging.debug(
- # "Return for {} and msgid {} is {}".format(
- # msgid_or_symbol, msgid, self.__old_names.get(msgid, [msgid])
- # )
- # )
- return self.__old_names.get(msgid, [msgid])
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__init__.py b/venv/Lib/site-packages/pylint/pyreverse/__init__.py
deleted file mode 100644
index 9ca1da5..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""
-pyreverse.extensions
-"""
-
-__revision__ = "$Id $"
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 6054dd9..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diadefslib.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diadefslib.cpython-37.pyc
deleted file mode 100644
index 64bdd6b..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diadefslib.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diagrams.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diagrams.cpython-37.pyc
deleted file mode 100644
index cd5a663..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/diagrams.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/inspector.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/inspector.cpython-37.pyc
deleted file mode 100644
index 0bcfb4d..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/inspector.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/main.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/main.cpython-37.pyc
deleted file mode 100644
index c8f9398..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/main.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/utils.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/utils.cpython-37.pyc
deleted file mode 100644
index 1711f15..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/utils.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/vcgutils.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/vcgutils.cpython-37.pyc
deleted file mode 100644
index f1a93f5..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/vcgutils.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/writer.cpython-37.pyc b/venv/Lib/site-packages/pylint/pyreverse/__pycache__/writer.cpython-37.pyc
deleted file mode 100644
index a0ac15c..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/__pycache__/writer.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/pyreverse/diadefslib.py b/venv/Lib/site-packages/pylint/pyreverse/diadefslib.py
deleted file mode 100644
index de4e9fd..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/diadefslib.py
+++ /dev/null
@@ -1,238 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006, 2008-2010, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""handle diagram generation options for class diagram or default diagrams
-"""
-
-import astroid
-
-from pylint.pyreverse.diagrams import ClassDiagram, PackageDiagram
-from pylint.pyreverse.utils import LocalsVisitor
-
-BUILTINS_NAME = "builtins"
-
-# diagram generators ##########################################################
-
-
-class DiaDefGenerator:
- """handle diagram generation options"""
-
- def __init__(self, linker, handler):
- """common Diagram Handler initialization"""
- self.config = handler.config
- self._set_default_options()
- self.linker = linker
- self.classdiagram = None # defined by subclasses
-
- def get_title(self, node):
- """get title for objects"""
- title = node.name
- if self.module_names:
- title = "%s.%s" % (node.root().name, title)
- return title
-
- def _set_option(self, option):
- """activate some options if not explicitly deactivated"""
- # if we have a class diagram, we want more information by default;
- # so if the option is None, we return True
- if option is None:
- return bool(self.config.classes)
- return option
-
- def _set_default_options(self):
- """set different default options with _default dictionary"""
- self.module_names = self._set_option(self.config.module_names)
- all_ancestors = self._set_option(self.config.all_ancestors)
- all_associated = self._set_option(self.config.all_associated)
- anc_level, association_level = (0, 0)
- if all_ancestors:
- anc_level = -1
- if all_associated:
- association_level = -1
- if self.config.show_ancestors is not None:
- anc_level = self.config.show_ancestors
- if self.config.show_associated is not None:
- association_level = self.config.show_associated
- self.anc_level, self.association_level = anc_level, association_level
-
- def _get_levels(self):
- """help function for search levels"""
- return self.anc_level, self.association_level
-
- def show_node(self, node):
- """true if builtins and not show_builtins"""
- if self.config.show_builtin:
- return True
- return node.root().name != BUILTINS_NAME
-
- def add_class(self, node):
- """visit one class and add it to diagram"""
- self.linker.visit(node)
- self.classdiagram.add_object(self.get_title(node), node)
-
- def get_ancestors(self, node, level):
- """return ancestor nodes of a class node"""
- if level == 0:
- return
- for ancestor in node.ancestors(recurs=False):
- if not self.show_node(ancestor):
- continue
- yield ancestor
-
- def get_associated(self, klass_node, level):
- """return associated nodes of a class node"""
- if level == 0:
- return
- for association_nodes in list(klass_node.instance_attrs_type.values()) + list(
- klass_node.locals_type.values()
- ):
- for node in association_nodes:
- if isinstance(node, astroid.Instance):
- node = node._proxied
- if not (isinstance(node, astroid.ClassDef) and self.show_node(node)):
- continue
- yield node
-
- def extract_classes(self, klass_node, anc_level, association_level):
- """extract recursively classes related to klass_node"""
- if self.classdiagram.has_node(klass_node) or not self.show_node(klass_node):
- return
- self.add_class(klass_node)
-
- for ancestor in self.get_ancestors(klass_node, anc_level):
- self.extract_classes(ancestor, anc_level - 1, association_level)
-
- for node in self.get_associated(klass_node, association_level):
- self.extract_classes(node, anc_level, association_level - 1)
-
-
-class DefaultDiadefGenerator(LocalsVisitor, DiaDefGenerator):
- """generate minimum diagram definition for the project :
-
- * a package diagram including project's modules
- * a class diagram including project's classes
- """
-
- def __init__(self, linker, handler):
- DiaDefGenerator.__init__(self, linker, handler)
- LocalsVisitor.__init__(self)
-
- def visit_project(self, node):
- """visit a pyreverse.utils.Project node
-
- create a diagram definition for packages
- """
- mode = self.config.mode
- if len(node.modules) > 1:
- self.pkgdiagram = PackageDiagram("packages %s" % node.name, mode)
- else:
- self.pkgdiagram = None
- self.classdiagram = ClassDiagram("classes %s" % node.name, mode)
-
- def leave_project(self, node): # pylint: disable=unused-argument
- """leave the pyreverse.utils.Project node
-
- return the generated diagram definition
- """
- if self.pkgdiagram:
- return self.pkgdiagram, self.classdiagram
- return (self.classdiagram,)
-
- def visit_module(self, node):
- """visit an astroid.Module node
-
- add this class to the package diagram definition
- """
- if self.pkgdiagram:
- self.linker.visit(node)
- self.pkgdiagram.add_object(node.name, node)
-
- def visit_classdef(self, node):
- """visit an astroid.Class node
-
- add this class to the class diagram definition
- """
- anc_level, association_level = self._get_levels()
- self.extract_classes(node, anc_level, association_level)
-
- def visit_importfrom(self, node):
- """visit astroid.ImportFrom and catch modules for package diagram
- """
- if self.pkgdiagram:
- self.pkgdiagram.add_from_depend(node, node.modname)
-
-
-class ClassDiadefGenerator(DiaDefGenerator):
- """generate a class diagram definition including all classes related to a
- given class
- """
-
- def __init__(self, linker, handler):
- DiaDefGenerator.__init__(self, linker, handler)
-
- def class_diagram(self, project, klass):
- """return a class diagram definition for the given klass and its
- related klasses
- """
-
- self.classdiagram = ClassDiagram(klass, self.config.mode)
- if len(project.modules) > 1:
- module, klass = klass.rsplit(".", 1)
- module = project.get_module(module)
- else:
- module = project.modules[0]
- klass = klass.split(".")[-1]
- klass = next(module.ilookup(klass))
-
- anc_level, association_level = self._get_levels()
- self.extract_classes(klass, anc_level, association_level)
- return self.classdiagram
-
-
-# diagram handler #############################################################
-
-
-class DiadefsHandler:
- """handle diagram definitions :
-
- get it from user (i.e. xml files) or generate them
- """
-
- def __init__(self, config):
- self.config = config
-
- def get_diadefs(self, project, linker):
- """Get the diagrams configuration data
-
- :param project:The pyreverse project
- :type project: pyreverse.utils.Project
- :param linker: The linker
- :type linker: pyreverse.inspector.Linker(IdGeneratorMixIn, LocalsVisitor)
-
- :returns: The list of diagram definitions
- :rtype: list(:class:`pylint.pyreverse.diagrams.ClassDiagram`)
- """
-
- # read and interpret diagram definitions (Diadefs)
- diagrams = []
- generator = ClassDiadefGenerator(linker, self)
- for klass in self.config.classes:
- diagrams.append(generator.class_diagram(project, klass))
- if not diagrams:
- diagrams = DefaultDiadefGenerator(linker, self).visit(project)
- for diagram in diagrams:
- diagram.extract_relationships()
- return diagrams
diff --git a/venv/Lib/site-packages/pylint/pyreverse/diagrams.py b/venv/Lib/site-packages/pylint/pyreverse/diagrams.py
deleted file mode 100644
index b53b845..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/diagrams.py
+++ /dev/null
@@ -1,268 +0,0 @@
-# Copyright (c) 2006, 2008-2010, 2012-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""diagram objects
-"""
-
-import astroid
-
-from pylint.checkers.utils import decorated_with_property
-from pylint.pyreverse.utils import FilterMixIn, is_interface
-
-
-class Figure:
- """base class for counter handling"""
-
-
-class Relationship(Figure):
- """a relation ship from an object in the diagram to another
- """
-
- def __init__(self, from_object, to_object, relation_type, name=None):
- Figure.__init__(self)
- self.from_object = from_object
- self.to_object = to_object
- self.type = relation_type
- self.name = name
-
-
-class DiagramEntity(Figure):
- """a diagram object, i.e. a label associated to an astroid node
- """
-
- def __init__(self, title="No name", node=None):
- Figure.__init__(self)
- self.title = title
- self.node = node
-
-
-class ClassDiagram(Figure, FilterMixIn):
- """main class diagram handling
- """
-
- TYPE = "class"
-
- def __init__(self, title, mode):
- FilterMixIn.__init__(self, mode)
- Figure.__init__(self)
- self.title = title
- self.objects = []
- self.relationships = {}
- self._nodes = {}
- self.depends = []
-
- def get_relationships(self, role):
- # sorted to get predictable (hence testable) results
- return sorted(
- self.relationships.get(role, ()),
- key=lambda x: (x.from_object.fig_id, x.to_object.fig_id),
- )
-
- def add_relationship(self, from_object, to_object, relation_type, name=None):
- """create a relation ship
- """
- rel = Relationship(from_object, to_object, relation_type, name)
- self.relationships.setdefault(relation_type, []).append(rel)
-
- def get_relationship(self, from_object, relation_type):
- """return a relation ship or None
- """
- for rel in self.relationships.get(relation_type, ()):
- if rel.from_object is from_object:
- return rel
- raise KeyError(relation_type)
-
- def get_attrs(self, node):
- """return visible attributes, possibly with class name"""
- attrs = []
- properties = [
- (n, m)
- for n, m in node.items()
- if isinstance(m, astroid.FunctionDef) and decorated_with_property(m)
- ]
- for node_name, associated_nodes in (
- list(node.instance_attrs_type.items())
- + list(node.locals_type.items())
- + properties
- ):
- if not self.show_attr(node_name):
- continue
- names = self.class_names(associated_nodes)
- if names:
- node_name = "%s : %s" % (node_name, ", ".join(names))
- attrs.append(node_name)
- return sorted(attrs)
-
- def get_methods(self, node):
- """return visible methods"""
- methods = [
- m
- for m in node.values()
- if isinstance(m, astroid.FunctionDef)
- and not decorated_with_property(m)
- and self.show_attr(m.name)
- ]
- return sorted(methods, key=lambda n: n.name)
-
- def add_object(self, title, node):
- """create a diagram object
- """
- assert node not in self._nodes
- ent = DiagramEntity(title, node)
- self._nodes[node] = ent
- self.objects.append(ent)
-
- def class_names(self, nodes):
- """return class names if needed in diagram"""
- names = []
- for node in nodes:
- if isinstance(node, astroid.Instance):
- node = node._proxied
- if (
- isinstance(node, astroid.ClassDef)
- and hasattr(node, "name")
- and not self.has_node(node)
- ):
- if node.name not in names:
- node_name = node.name
- names.append(node_name)
- return names
-
- def nodes(self):
- """return the list of underlying nodes
- """
- return self._nodes.keys()
-
- def has_node(self, node):
- """return true if the given node is included in the diagram
- """
- return node in self._nodes
-
- def object_from_node(self, node):
- """return the diagram object mapped to node
- """
- return self._nodes[node]
-
- def classes(self):
- """return all class nodes in the diagram"""
- return [o for o in self.objects if isinstance(o.node, astroid.ClassDef)]
-
- def classe(self, name):
- """return a class by its name, raise KeyError if not found
- """
- for klass in self.classes():
- if klass.node.name == name:
- return klass
- raise KeyError(name)
-
- def extract_relationships(self):
- """extract relation ships between nodes in the diagram
- """
- for obj in self.classes():
- node = obj.node
- obj.attrs = self.get_attrs(node)
- obj.methods = self.get_methods(node)
- # shape
- if is_interface(node):
- obj.shape = "interface"
- else:
- obj.shape = "class"
- # inheritance link
- for par_node in node.ancestors(recurs=False):
- try:
- par_obj = self.object_from_node(par_node)
- self.add_relationship(obj, par_obj, "specialization")
- except KeyError:
- continue
- # implements link
- for impl_node in node.implements:
- try:
- impl_obj = self.object_from_node(impl_node)
- self.add_relationship(obj, impl_obj, "implements")
- except KeyError:
- continue
- # associations link
- for name, values in list(node.instance_attrs_type.items()) + list(
- node.locals_type.items()
- ):
- for value in values:
- if value is astroid.Uninferable:
- continue
- if isinstance(value, astroid.Instance):
- value = value._proxied
- try:
- associated_obj = self.object_from_node(value)
- self.add_relationship(associated_obj, obj, "association", name)
- except KeyError:
- continue
-
-
-class PackageDiagram(ClassDiagram):
- """package diagram handling
- """
-
- TYPE = "package"
-
- def modules(self):
- """return all module nodes in the diagram"""
- return [o for o in self.objects if isinstance(o.node, astroid.Module)]
-
- def module(self, name):
- """return a module by its name, raise KeyError if not found
- """
- for mod in self.modules():
- if mod.node.name == name:
- return mod
- raise KeyError(name)
-
- def get_module(self, name, node):
- """return a module by its name, looking also for relative imports;
- raise KeyError if not found
- """
- for mod in self.modules():
- mod_name = mod.node.name
- if mod_name == name:
- return mod
- # search for fullname of relative import modules
- package = node.root().name
- if mod_name == "%s.%s" % (package, name):
- return mod
- if mod_name == "%s.%s" % (package.rsplit(".", 1)[0], name):
- return mod
- raise KeyError(name)
-
- def add_from_depend(self, node, from_module):
- """add dependencies created by from-imports
- """
- mod_name = node.root().name
- obj = self.module(mod_name)
- if from_module not in obj.node.depends:
- obj.node.depends.append(from_module)
-
- def extract_relationships(self):
- """extract relation ships between nodes in the diagram
- """
- ClassDiagram.extract_relationships(self)
- for obj in self.classes():
- # ownership
- try:
- mod = self.object_from_node(obj.node.root())
- self.add_relationship(obj, mod, "ownership")
- except KeyError:
- continue
- for obj in self.modules():
- obj.shape = "package"
- # dependencies
- for dep_name in obj.node.depends:
- try:
- dep = self.get_module(dep_name, obj.node)
- except KeyError:
- continue
- self.add_relationship(obj, dep, "depends")
diff --git a/venv/Lib/site-packages/pylint/pyreverse/inspector.py b/venv/Lib/site-packages/pylint/pyreverse/inspector.py
deleted file mode 100644
index 702b108..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/inspector.py
+++ /dev/null
@@ -1,357 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""
-Visitor doing some postprocessing on the astroid tree.
-Try to resolve definitions (namespace) dictionary, relationship...
-"""
-import collections
-import os
-import traceback
-
-import astroid
-from astroid import bases, exceptions, manager, modutils, node_classes
-
-from pylint.pyreverse import utils
-
-
-def _iface_hdlr(_):
- """Handler used by interfaces to handle suspicious interface nodes."""
- return True
-
-
-def _astroid_wrapper(func, modname):
- print("parsing %s..." % modname)
- try:
- return func(modname)
- except exceptions.AstroidBuildingException as exc:
- print(exc)
- except Exception as exc: # pylint: disable=broad-except
- traceback.print_exc()
-
-
-def interfaces(node, herited=True, handler_func=_iface_hdlr):
- """Return an iterator on interfaces implemented by the given class node."""
- try:
- implements = bases.Instance(node).getattr("__implements__")[0]
- except exceptions.NotFoundError:
- return
- if not herited and implements.frame() is not node:
- return
- found = set()
- missing = False
- for iface in node_classes.unpack_infer(implements):
- if iface is astroid.Uninferable:
- missing = True
- continue
- if iface not in found and handler_func(iface):
- found.add(iface)
- yield iface
- if missing:
- raise exceptions.InferenceError()
-
-
-class IdGeneratorMixIn:
- """Mixin adding the ability to generate integer uid."""
-
- def __init__(self, start_value=0):
- self.id_count = start_value
-
- def init_counter(self, start_value=0):
- """init the id counter
- """
- self.id_count = start_value
-
- def generate_id(self):
- """generate a new identifier
- """
- self.id_count += 1
- return self.id_count
-
-
-class Linker(IdGeneratorMixIn, utils.LocalsVisitor):
- """Walk on the project tree and resolve relationships.
-
- According to options the following attributes may be
- added to visited nodes:
-
- * uid,
- a unique identifier for the node (on astroid.Project, astroid.Module,
- astroid.Class and astroid.locals_type). Only if the linker
- has been instantiated with tag=True parameter (False by default).
-
- * Function
- a mapping from locals names to their bounded value, which may be a
- constant like a string or an integer, or an astroid node
- (on astroid.Module, astroid.Class and astroid.Function).
-
- * instance_attrs_type
- as locals_type but for klass member attributes (only on astroid.Class)
-
- * implements,
- list of implemented interface _objects_ (only on astroid.Class nodes)
- """
-
- def __init__(self, project, inherited_interfaces=0, tag=False):
- IdGeneratorMixIn.__init__(self)
- utils.LocalsVisitor.__init__(self)
- # take inherited interface in consideration or not
- self.inherited_interfaces = inherited_interfaces
- # tag nodes or not
- self.tag = tag
- # visited project
- self.project = project
-
- def visit_project(self, node):
- """visit a pyreverse.utils.Project node
-
- * optionally tag the node with a unique id
- """
- if self.tag:
- node.uid = self.generate_id()
- for module in node.modules:
- self.visit(module)
-
- def visit_package(self, node):
- """visit an astroid.Package node
-
- * optionally tag the node with a unique id
- """
- if self.tag:
- node.uid = self.generate_id()
- for subelmt in node.values():
- self.visit(subelmt)
-
- def visit_module(self, node):
- """visit an astroid.Module node
-
- * set the locals_type mapping
- * set the depends mapping
- * optionally tag the node with a unique id
- """
- if hasattr(node, "locals_type"):
- return
- node.locals_type = collections.defaultdict(list)
- node.depends = []
- if self.tag:
- node.uid = self.generate_id()
-
- def visit_classdef(self, node):
- """visit an astroid.Class node
-
- * set the locals_type and instance_attrs_type mappings
- * set the implements list and build it
- * optionally tag the node with a unique id
- """
- if hasattr(node, "locals_type"):
- return
- node.locals_type = collections.defaultdict(list)
- if self.tag:
- node.uid = self.generate_id()
- # resolve ancestors
- for baseobj in node.ancestors(recurs=False):
- specializations = getattr(baseobj, "specializations", [])
- specializations.append(node)
- baseobj.specializations = specializations
- # resolve instance attributes
- node.instance_attrs_type = collections.defaultdict(list)
- for assignattrs in node.instance_attrs.values():
- for assignattr in assignattrs:
- self.handle_assignattr_type(assignattr, node)
- # resolve implemented interface
- try:
- node.implements = list(interfaces(node, self.inherited_interfaces))
- except astroid.InferenceError:
- node.implements = ()
-
- def visit_functiondef(self, node):
- """visit an astroid.Function node
-
- * set the locals_type mapping
- * optionally tag the node with a unique id
- """
- if hasattr(node, "locals_type"):
- return
- node.locals_type = collections.defaultdict(list)
- if self.tag:
- node.uid = self.generate_id()
-
- link_project = visit_project
- link_module = visit_module
- link_class = visit_classdef
- link_function = visit_functiondef
-
- def visit_assignname(self, node):
- """visit an astroid.AssignName node
-
- handle locals_type
- """
- # avoid double parsing done by different Linkers.visit
- # running over the same project:
- if hasattr(node, "_handled"):
- return
- node._handled = True
- if node.name in node.frame():
- frame = node.frame()
- else:
- # the name has been defined as 'global' in the frame and belongs
- # there.
- frame = node.root()
- try:
- if not hasattr(frame, "locals_type"):
- # If the frame doesn't have a locals_type yet,
- # it means it wasn't yet visited. Visit it now
- # to add what's missing from it.
- if isinstance(frame, astroid.ClassDef):
- self.visit_classdef(frame)
- elif isinstance(frame, astroid.FunctionDef):
- self.visit_functiondef(frame)
- else:
- self.visit_module(frame)
-
- current = frame.locals_type[node.name]
- values = set(node.infer())
- frame.locals_type[node.name] = list(set(current) | values)
- except astroid.InferenceError:
- pass
-
- @staticmethod
- def handle_assignattr_type(node, parent):
- """handle an astroid.assignattr node
-
- handle instance_attrs_type
- """
- try:
- values = set(node.infer())
- current = set(parent.instance_attrs_type[node.attrname])
- parent.instance_attrs_type[node.attrname] = list(current | values)
- except astroid.InferenceError:
- pass
-
- def visit_import(self, node):
- """visit an astroid.Import node
-
- resolve module dependencies
- """
- context_file = node.root().file
- for name in node.names:
- relative = modutils.is_relative(name[0], context_file)
- self._imported_module(node, name[0], relative)
-
- def visit_importfrom(self, node):
- """visit an astroid.ImportFrom node
-
- resolve module dependencies
- """
- basename = node.modname
- context_file = node.root().file
- if context_file is not None:
- relative = modutils.is_relative(basename, context_file)
- else:
- relative = False
- for name in node.names:
- if name[0] == "*":
- continue
- # analyze dependencies
- fullname = "%s.%s" % (basename, name[0])
- if fullname.find(".") > -1:
- try:
- fullname = modutils.get_module_part(fullname, context_file)
- except ImportError:
- continue
- if fullname != basename:
- self._imported_module(node, fullname, relative)
-
- def compute_module(self, context_name, mod_path):
- """return true if the module should be added to dependencies"""
- package_dir = os.path.dirname(self.project.path)
- if context_name == mod_path:
- return 0
- if modutils.is_standard_module(mod_path, (package_dir,)):
- return 1
- return 0
-
- def _imported_module(self, node, mod_path, relative):
- """Notify an imported module, used to analyze dependencies"""
- module = node.root()
- context_name = module.name
- if relative:
- mod_path = "%s.%s" % (".".join(context_name.split(".")[:-1]), mod_path)
- if self.compute_module(context_name, mod_path):
- # handle dependencies
- if not hasattr(module, "depends"):
- module.depends = []
- mod_paths = module.depends
- if mod_path not in mod_paths:
- mod_paths.append(mod_path)
-
-
-class Project:
- """a project handle a set of modules / packages"""
-
- def __init__(self, name=""):
- self.name = name
- self.path = None
- self.modules = []
- self.locals = {}
- self.__getitem__ = self.locals.__getitem__
- self.__iter__ = self.locals.__iter__
- self.values = self.locals.values
- self.keys = self.locals.keys
- self.items = self.locals.items
-
- def add_module(self, node):
- self.locals[node.name] = node
- self.modules.append(node)
-
- def get_module(self, name):
- return self.locals[name]
-
- def get_children(self):
- return self.modules
-
- def __repr__(self):
- return "<Project %r at %s (%s modules)>" % (
- self.name,
- id(self),
- len(self.modules),
- )
-
-
-def project_from_files(
- files, func_wrapper=_astroid_wrapper, project_name="no name", black_list=("CVS",)
-):
- """return a Project from a list of files or modules"""
- # build the project representation
- astroid_manager = manager.AstroidManager()
- project = Project(project_name)
- for something in files:
- if not os.path.exists(something):
- fpath = modutils.file_from_modpath(something.split("."))
- elif os.path.isdir(something):
- fpath = os.path.join(something, "__init__.py")
- else:
- fpath = something
- ast = func_wrapper(astroid_manager.ast_from_file, fpath)
- if ast is None:
- continue
- project.path = project.path or ast.file
- project.add_module(ast)
- base_name = ast.name
- # recurse in package except if __init__ was explicitly given
- if ast.package and something.find("__init__") == -1:
- # recurse on others packages / modules if this is a package
- for fpath in modutils.get_module_files(
- os.path.dirname(ast.file), black_list
- ):
- ast = func_wrapper(astroid_manager.ast_from_file, fpath)
- if ast is None or ast.name == base_name:
- continue
- project.add_module(ast)
- return project
diff --git a/venv/Lib/site-packages/pylint/pyreverse/main.py b/venv/Lib/site-packages/pylint/pyreverse/main.py
deleted file mode 100644
index 652b954..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/main.py
+++ /dev/null
@@ -1,214 +0,0 @@
-# Copyright (c) 2008-2010, 2012-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Alexander Pervakov <frost.nzcr4@jagmort.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""
- %prog [options] <packages>
-
- create UML diagrams for classes and modules in <packages>
-"""
-import os
-import subprocess
-import sys
-
-from pylint.config import ConfigurationMixIn
-from pylint.pyreverse import writer
-from pylint.pyreverse.diadefslib import DiadefsHandler
-from pylint.pyreverse.inspector import Linker, project_from_files
-from pylint.pyreverse.utils import insert_default_options
-
-OPTIONS = (
- (
- "filter-mode",
- dict(
- short="f",
- default="PUB_ONLY",
- dest="mode",
- type="string",
- action="store",
- metavar="<mode>",
- help="""filter attributes and functions according to
- <mode>. Correct modes are :
- 'PUB_ONLY' filter all non public attributes
- [DEFAULT], equivalent to PRIVATE+SPECIAL_A
- 'ALL' no filter
- 'SPECIAL' filter Python special functions
- except constructor
- 'OTHER' filter protected and private
- attributes""",
- ),
- ),
- (
- "class",
- dict(
- short="c",
- action="append",
- metavar="<class>",
- dest="classes",
- default=[],
- help="create a class diagram with all classes related to <class>;\
- this uses by default the options -ASmy",
- ),
- ),
- (
- "show-ancestors",
- dict(
- short="a",
- action="store",
- metavar="<ancestor>",
- type="int",
- help="show <ancestor> generations of ancestor classes not in <projects>",
- ),
- ),
- (
- "all-ancestors",
- dict(
- short="A",
- default=None,
- help="show all ancestors off all classes in <projects>",
- ),
- ),
- (
- "show-associated",
- dict(
- short="s",
- action="store",
- metavar="<association_level>",
- type="int",
- help="show <association_level> levels of associated classes not in <projects>",
- ),
- ),
- (
- "all-associated",
- dict(
- short="S",
- default=None,
- help="show recursively all associated off all associated classes",
- ),
- ),
- (
- "show-builtin",
- dict(
- short="b",
- action="store_true",
- default=False,
- help="include builtin objects in representation of classes",
- ),
- ),
- (
- "module-names",
- dict(
- short="m",
- default=None,
- type="yn",
- metavar="[yn]",
- help="include module name in representation of classes",
- ),
- ),
- (
- "only-classnames",
- dict(
- short="k",
- action="store_true",
- default=False,
- help="don't show attributes and methods in the class boxes; \
-this disables -f values",
- ),
- ),
- (
- "output",
- dict(
- short="o",
- dest="output_format",
- action="store",
- default="dot",
- metavar="<format>",
- help="create a *.<format> output file if format available.",
- ),
- ),
- (
- "ignore",
- {
- "type": "csv",
- "metavar": "<file[,file...]>",
- "dest": "black_list",
- "default": ("CVS",),
- "help": "Add files or directories to the blacklist. They "
- "should be base names, not paths.",
- },
- ),
- (
- "project",
- {
- "default": "",
- "type": "string",
- "short": "p",
- "metavar": "<project name>",
- "help": "set the project name.",
- },
- ),
-)
-
-
-def _check_graphviz_available(output_format):
- """check if we need graphviz for different output format"""
- try:
- subprocess.call(["dot", "-V"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- except OSError:
- print(
- "The output format '%s' is currently not available.\n"
- "Please install 'Graphviz' to have other output formats "
- "than 'dot' or 'vcg'." % output_format
- )
- sys.exit(32)
-
-
-class Run(ConfigurationMixIn):
- """base class providing common behaviour for pyreverse commands"""
-
- options = OPTIONS # type: ignore
-
- def __init__(self, args):
- ConfigurationMixIn.__init__(self, usage=__doc__)
- insert_default_options()
- args = self.load_command_line_configuration()
- if self.config.output_format not in ("dot", "vcg"):
- _check_graphviz_available(self.config.output_format)
-
- sys.exit(self.run(args))
-
- def run(self, args):
- """checking arguments and run project"""
- if not args:
- print(self.help())
- return 1
- # insert current working directory to the python path to recognize
- # dependencies to local modules even if cwd is not in the PYTHONPATH
- sys.path.insert(0, os.getcwd())
- try:
- project = project_from_files(
- args,
- project_name=self.config.project,
- black_list=self.config.black_list,
- )
- linker = Linker(project, tag=True)
- handler = DiadefsHandler(self.config)
- diadefs = handler.get_diadefs(project, linker)
- finally:
- sys.path.pop(0)
-
- if self.config.output_format == "vcg":
- writer.VCGWriter(self.config).write(diadefs)
- else:
- writer.DotWriter(self.config).write(diadefs)
- return 0
-
-
-if __name__ == "__main__":
- Run(sys.argv[1:])
diff --git a/venv/Lib/site-packages/pylint/pyreverse/utils.py b/venv/Lib/site-packages/pylint/pyreverse/utils.py
deleted file mode 100644
index 5a1e7e2..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/utils.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# Copyright (c) 2006, 2008, 2010, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""
-generic classes/functions for pyreverse core/extensions
-"""
-import os
-import re
-import sys
-
-########### pyreverse option utils ##############################
-
-
-RCFILE = ".pyreverserc"
-
-
-def get_default_options():
- """
- Read config file and return list of options
- """
- options = []
- home = os.environ.get("HOME", "")
- if home:
- rcfile = os.path.join(home, RCFILE)
- try:
- options = open(rcfile).read().split()
- except IOError:
- pass # ignore if no config file found
- return options
-
-
-def insert_default_options():
- """insert default options to sys.argv
- """
- options = get_default_options()
- options.reverse()
- for arg in options:
- sys.argv.insert(1, arg)
-
-
-# astroid utilities ###########################################################
-
-SPECIAL = re.compile("^__[A-Za-z0-9]+[A-Za-z0-9_]*__$")
-PRIVATE = re.compile("^__[_A-Za-z0-9]*[A-Za-z0-9]+_?$")
-PROTECTED = re.compile("^_[_A-Za-z0-9]*$")
-
-
-def get_visibility(name):
- """return the visibility from a name: public, protected, private or special
- """
- if SPECIAL.match(name):
- visibility = "special"
- elif PRIVATE.match(name):
- visibility = "private"
- elif PROTECTED.match(name):
- visibility = "protected"
-
- else:
- visibility = "public"
- return visibility
-
-
-ABSTRACT = re.compile("^.*Abstract.*")
-FINAL = re.compile("^[A-Z_]*$")
-
-
-def is_abstract(node):
- """return true if the given class node correspond to an abstract class
- definition
- """
- return ABSTRACT.match(node.name)
-
-
-def is_final(node):
- """return true if the given class/function node correspond to final
- definition
- """
- return FINAL.match(node.name)
-
-
-def is_interface(node):
- # bw compat
- return node.type == "interface"
-
-
-def is_exception(node):
- # bw compat
- return node.type == "exception"
-
-
-# Helpers #####################################################################
-
-_CONSTRUCTOR = 1
-_SPECIAL = 2
-_PROTECTED = 4
-_PRIVATE = 8
-MODES = {
- "ALL": 0,
- "PUB_ONLY": _SPECIAL + _PROTECTED + _PRIVATE,
- "SPECIAL": _SPECIAL,
- "OTHER": _PROTECTED + _PRIVATE,
-}
-VIS_MOD = {
- "special": _SPECIAL,
- "protected": _PROTECTED,
- "private": _PRIVATE,
- "public": 0,
-}
-
-
-class FilterMixIn:
- """filter nodes according to a mode and nodes' visibility
- """
-
- def __init__(self, mode):
- "init filter modes"
- __mode = 0
- for nummod in mode.split("+"):
- try:
- __mode += MODES[nummod]
- except KeyError as ex:
- print("Unknown filter mode %s" % ex, file=sys.stderr)
- self.__mode = __mode
-
- def show_attr(self, node):
- """return true if the node should be treated
- """
- visibility = get_visibility(getattr(node, "name", node))
- return not self.__mode & VIS_MOD[visibility]
-
-
-class ASTWalker:
- """a walker visiting a tree in preorder, calling on the handler:
-
- * visit_<class name> on entering a node, where class name is the class of
- the node in lower case
-
- * leave_<class name> on leaving a node, where class name is the class of
- the node in lower case
- """
-
- def __init__(self, handler):
- self.handler = handler
- self._cache = {}
-
- def walk(self, node, _done=None):
- """walk on the tree from <node>, getting callbacks from handler"""
- if _done is None:
- _done = set()
- if node in _done:
- raise AssertionError((id(node), node, node.parent))
- _done.add(node)
- self.visit(node)
- for child_node in node.get_children():
- assert child_node is not node
- self.walk(child_node, _done)
- self.leave(node)
- assert node.parent is not node
-
- def get_callbacks(self, node):
- """get callbacks from handler for the visited node"""
- klass = node.__class__
- methods = self._cache.get(klass)
- if methods is None:
- handler = self.handler
- kid = klass.__name__.lower()
- e_method = getattr(
- handler, "visit_%s" % kid, getattr(handler, "visit_default", None)
- )
- l_method = getattr(
- handler, "leave_%s" % kid, getattr(handler, "leave_default", None)
- )
- self._cache[klass] = (e_method, l_method)
- else:
- e_method, l_method = methods
- return e_method, l_method
-
- def visit(self, node):
- """walk on the tree from <node>, getting callbacks from handler"""
- method = self.get_callbacks(node)[0]
- if method is not None:
- method(node)
-
- def leave(self, node):
- """walk on the tree from <node>, getting callbacks from handler"""
- method = self.get_callbacks(node)[1]
- if method is not None:
- method(node)
-
-
-class LocalsVisitor(ASTWalker):
- """visit a project by traversing the locals dictionary"""
-
- def __init__(self):
- ASTWalker.__init__(self, self)
- self._visited = set()
-
- def visit(self, node):
- """launch the visit starting from the given node"""
- if node in self._visited:
- return None
-
- self._visited.add(node)
- methods = self.get_callbacks(node)
- if methods[0] is not None:
- methods[0](node)
- if hasattr(node, "locals"): # skip Instance and other proxy
- for local_node in node.values():
- self.visit(local_node)
- if methods[1] is not None:
- return methods[1](node)
- return None
diff --git a/venv/Lib/site-packages/pylint/pyreverse/vcgutils.py b/venv/Lib/site-packages/pylint/pyreverse/vcgutils.py
deleted file mode 100644
index 89c6911..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/vcgutils.py
+++ /dev/null
@@ -1,229 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Functions to generate files readable with Georg Sander's vcg
-(Visualization of Compiler Graphs).
-
-You can download vcg at http://rw4.cs.uni-sb.de/~sander/html/gshome.html
-Note that vcg exists as a debian package.
-
-See vcg's documentation for explanation about the different values that
-maybe used for the functions parameters.
-"""
-
-ATTRS_VAL = {
- "algos": (
- "dfs",
- "tree",
- "minbackward",
- "left_to_right",
- "right_to_left",
- "top_to_bottom",
- "bottom_to_top",
- "maxdepth",
- "maxdepthslow",
- "mindepth",
- "mindepthslow",
- "mindegree",
- "minindegree",
- "minoutdegree",
- "maxdegree",
- "maxindegree",
- "maxoutdegree",
- ),
- "booleans": ("yes", "no"),
- "colors": (
- "black",
- "white",
- "blue",
- "red",
- "green",
- "yellow",
- "magenta",
- "lightgrey",
- "cyan",
- "darkgrey",
- "darkblue",
- "darkred",
- "darkgreen",
- "darkyellow",
- "darkmagenta",
- "darkcyan",
- "gold",
- "lightblue",
- "lightred",
- "lightgreen",
- "lightyellow",
- "lightmagenta",
- "lightcyan",
- "lilac",
- "turquoise",
- "aquamarine",
- "khaki",
- "purple",
- "yellowgreen",
- "pink",
- "orange",
- "orchid",
- ),
- "shapes": ("box", "ellipse", "rhomb", "triangle"),
- "textmodes": ("center", "left_justify", "right_justify"),
- "arrowstyles": ("solid", "line", "none"),
- "linestyles": ("continuous", "dashed", "dotted", "invisible"),
-}
-
-# meaning of possible values:
-# O -> string
-# 1 -> int
-# list -> value in list
-GRAPH_ATTRS = {
- "title": 0,
- "label": 0,
- "color": ATTRS_VAL["colors"],
- "textcolor": ATTRS_VAL["colors"],
- "bordercolor": ATTRS_VAL["colors"],
- "width": 1,
- "height": 1,
- "borderwidth": 1,
- "textmode": ATTRS_VAL["textmodes"],
- "shape": ATTRS_VAL["shapes"],
- "shrink": 1,
- "stretch": 1,
- "orientation": ATTRS_VAL["algos"],
- "vertical_order": 1,
- "horizontal_order": 1,
- "xspace": 1,
- "yspace": 1,
- "layoutalgorithm": ATTRS_VAL["algos"],
- "late_edge_labels": ATTRS_VAL["booleans"],
- "display_edge_labels": ATTRS_VAL["booleans"],
- "dirty_edge_labels": ATTRS_VAL["booleans"],
- "finetuning": ATTRS_VAL["booleans"],
- "manhattan_edges": ATTRS_VAL["booleans"],
- "smanhattan_edges": ATTRS_VAL["booleans"],
- "port_sharing": ATTRS_VAL["booleans"],
- "edges": ATTRS_VAL["booleans"],
- "nodes": ATTRS_VAL["booleans"],
- "splines": ATTRS_VAL["booleans"],
-}
-NODE_ATTRS = {
- "title": 0,
- "label": 0,
- "color": ATTRS_VAL["colors"],
- "textcolor": ATTRS_VAL["colors"],
- "bordercolor": ATTRS_VAL["colors"],
- "width": 1,
- "height": 1,
- "borderwidth": 1,
- "textmode": ATTRS_VAL["textmodes"],
- "shape": ATTRS_VAL["shapes"],
- "shrink": 1,
- "stretch": 1,
- "vertical_order": 1,
- "horizontal_order": 1,
-}
-EDGE_ATTRS = {
- "sourcename": 0,
- "targetname": 0,
- "label": 0,
- "linestyle": ATTRS_VAL["linestyles"],
- "class": 1,
- "thickness": 0,
- "color": ATTRS_VAL["colors"],
- "textcolor": ATTRS_VAL["colors"],
- "arrowcolor": ATTRS_VAL["colors"],
- "backarrowcolor": ATTRS_VAL["colors"],
- "arrowsize": 1,
- "backarrowsize": 1,
- "arrowstyle": ATTRS_VAL["arrowstyles"],
- "backarrowstyle": ATTRS_VAL["arrowstyles"],
- "textmode": ATTRS_VAL["textmodes"],
- "priority": 1,
- "anchor": 1,
- "horizontal_order": 1,
-}
-
-
-# Misc utilities ###############################################################
-
-
-class VCGPrinter:
- """A vcg graph writer.
- """
-
- def __init__(self, output_stream):
- self._stream = output_stream
- self._indent = ""
-
- def open_graph(self, **args):
- """open a vcg graph
- """
- self._stream.write("%sgraph:{\n" % self._indent)
- self._inc_indent()
- self._write_attributes(GRAPH_ATTRS, **args)
-
- def close_graph(self):
- """close a vcg graph
- """
- self._dec_indent()
- self._stream.write("%s}\n" % self._indent)
-
- def node(self, title, **args):
- """draw a node
- """
- self._stream.write('%snode: {title:"%s"' % (self._indent, title))
- self._write_attributes(NODE_ATTRS, **args)
- self._stream.write("}\n")
-
- def edge(self, from_node, to_node, edge_type="", **args):
- """draw an edge from a node to another.
- """
- self._stream.write(
- '%s%sedge: {sourcename:"%s" targetname:"%s"'
- % (self._indent, edge_type, from_node, to_node)
- )
- self._write_attributes(EDGE_ATTRS, **args)
- self._stream.write("}\n")
-
- # private ##################################################################
-
- def _write_attributes(self, attributes_dict, **args):
- """write graph, node or edge attributes
- """
- for key, value in args.items():
- try:
- _type = attributes_dict[key]
- except KeyError:
- raise Exception(
- """no such attribute %s
-possible attributes are %s"""
- % (key, attributes_dict.keys())
- )
-
- if not _type:
- self._stream.write('%s%s:"%s"\n' % (self._indent, key, value))
- elif _type == 1:
- self._stream.write("%s%s:%s\n" % (self._indent, key, int(value)))
- elif value in _type:
- self._stream.write("%s%s:%s\n" % (self._indent, key, value))
- else:
- raise Exception(
- """value %s isn\'t correct for attribute %s
-correct values are %s"""
- % (value, key, _type)
- )
-
- def _inc_indent(self):
- """increment indentation
- """
- self._indent = " %s" % self._indent
-
- def _dec_indent(self):
- """decrement indentation
- """
- self._indent = self._indent[:-2]
diff --git a/venv/Lib/site-packages/pylint/pyreverse/writer.py b/venv/Lib/site-packages/pylint/pyreverse/writer.py
deleted file mode 100644
index 609b1ef..0000000
--- a/venv/Lib/site-packages/pylint/pyreverse/writer.py
+++ /dev/null
@@ -1,213 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2008-2010, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Mike Frysinger <vapier@gentoo.org>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Utilities for creating VCG and Dot diagrams"""
-
-from pylint.graph import DotBackend
-from pylint.pyreverse.utils import is_exception
-from pylint.pyreverse.vcgutils import VCGPrinter
-
-
-class DiagramWriter:
- """base class for writing project diagrams
- """
-
- def __init__(self, config, styles):
- self.config = config
- self.pkg_edges, self.inh_edges, self.imp_edges, self.association_edges = styles
- self.printer = None # defined in set_printer
-
- def write(self, diadefs):
- """write files for <project> according to <diadefs>
- """
- for diagram in diadefs:
- basename = diagram.title.strip().replace(" ", "_")
- file_name = "%s.%s" % (basename, self.config.output_format)
- self.set_printer(file_name, basename)
- if diagram.TYPE == "class":
- self.write_classes(diagram)
- else:
- self.write_packages(diagram)
- self.close_graph()
-
- def write_packages(self, diagram):
- """write a package diagram"""
- # sorted to get predictable (hence testable) results
- for i, obj in enumerate(sorted(diagram.modules(), key=lambda x: x.title)):
- self.printer.emit_node(i, label=self.get_title(obj), shape="box")
- obj.fig_id = i
- # package dependencies
- for rel in diagram.get_relationships("depends"):
- self.printer.emit_edge(
- rel.from_object.fig_id, rel.to_object.fig_id, **self.pkg_edges
- )
-
- def write_classes(self, diagram):
- """write a class diagram"""
- # sorted to get predictable (hence testable) results
- for i, obj in enumerate(sorted(diagram.objects, key=lambda x: x.title)):
- self.printer.emit_node(i, **self.get_values(obj))
- obj.fig_id = i
- # inheritance links
- for rel in diagram.get_relationships("specialization"):
- self.printer.emit_edge(
- rel.from_object.fig_id, rel.to_object.fig_id, **self.inh_edges
- )
- # implementation links
- for rel in diagram.get_relationships("implements"):
- self.printer.emit_edge(
- rel.from_object.fig_id, rel.to_object.fig_id, **self.imp_edges
- )
- # generate associations
- for rel in diagram.get_relationships("association"):
- self.printer.emit_edge(
- rel.from_object.fig_id,
- rel.to_object.fig_id,
- label=rel.name,
- **self.association_edges
- )
-
- def set_printer(self, file_name, basename):
- """set printer"""
- raise NotImplementedError
-
- def get_title(self, obj):
- """get project title"""
- raise NotImplementedError
-
- def get_values(self, obj):
- """get label and shape for classes."""
- raise NotImplementedError
-
- def close_graph(self):
- """finalize the graph"""
- raise NotImplementedError
-
-
-class DotWriter(DiagramWriter):
- """write dot graphs from a diagram definition and a project
- """
-
- def __init__(self, config):
- styles = [
- dict(arrowtail="none", arrowhead="open"),
- dict(arrowtail="none", arrowhead="empty"),
- dict(arrowtail="node", arrowhead="empty", style="dashed"),
- dict(
- fontcolor="green", arrowtail="none", arrowhead="diamond", style="solid"
- ),
- ]
- DiagramWriter.__init__(self, config, styles)
-
- def set_printer(self, file_name, basename):
- """initialize DotWriter and add options for layout.
- """
- layout = dict(rankdir="BT")
- self.printer = DotBackend(basename, additional_param=layout)
- self.file_name = file_name
-
- def get_title(self, obj):
- """get project title"""
- return obj.title
-
- def get_values(self, obj):
- """get label and shape for classes.
-
- The label contains all attributes and methods
- """
- label = obj.title
- if obj.shape == "interface":
- label = "«interface»\\n%s" % label
- if not self.config.only_classnames:
- label = r"%s|%s\l|" % (label, r"\l".join(obj.attrs))
- for func in obj.methods:
- args = [arg.name for arg in func.args.args if arg.name != "self"]
- label = r"%s%s(%s)\l" % (label, func.name, ", ".join(args))
- label = "{%s}" % label
- if is_exception(obj.node):
- return dict(fontcolor="red", label=label, shape="record")
- return dict(label=label, shape="record")
-
- def close_graph(self):
- """print the dot graph into <file_name>"""
- self.printer.generate(self.file_name)
-
-
-class VCGWriter(DiagramWriter):
- """write vcg graphs from a diagram definition and a project
- """
-
- def __init__(self, config):
- styles = [
- dict(arrowstyle="solid", backarrowstyle="none", backarrowsize=0),
- dict(arrowstyle="solid", backarrowstyle="none", backarrowsize=10),
- dict(
- arrowstyle="solid",
- backarrowstyle="none",
- linestyle="dotted",
- backarrowsize=10,
- ),
- dict(arrowstyle="solid", backarrowstyle="none", textcolor="green"),
- ]
- DiagramWriter.__init__(self, config, styles)
-
- def set_printer(self, file_name, basename):
- """initialize VCGWriter for a UML graph"""
- self.graph_file = open(file_name, "w+")
- self.printer = VCGPrinter(self.graph_file)
- self.printer.open_graph(
- title=basename,
- layoutalgorithm="dfs",
- late_edge_labels="yes",
- port_sharing="no",
- manhattan_edges="yes",
- )
- self.printer.emit_node = self.printer.node
- self.printer.emit_edge = self.printer.edge
-
- def get_title(self, obj):
- """get project title in vcg format"""
- return r"\fb%s\fn" % obj.title
-
- def get_values(self, obj):
- """get label and shape for classes.
-
- The label contains all attributes and methods
- """
- if is_exception(obj.node):
- label = r"\fb\f09%s\fn" % obj.title
- else:
- label = r"\fb%s\fn" % obj.title
- if obj.shape == "interface":
- shape = "ellipse"
- else:
- shape = "box"
- if not self.config.only_classnames:
- attrs = obj.attrs
- methods = [func.name for func in obj.methods]
- # box width for UML like diagram
- maxlen = max(len(name) for name in [obj.title] + methods + attrs)
- line = "_" * (maxlen + 2)
- label = r"%s\n\f%s" % (label, line)
- for attr in attrs:
- label = r"%s\n\f08%s" % (label, attr)
- if attrs:
- label = r"%s\n\f%s" % (label, line)
- for func in methods:
- label = r"%s\n\f10%s()" % (label, func)
- return dict(label=label, shape=shape)
-
- def close_graph(self):
- """close graph and file"""
- self.printer.close_graph()
- self.graph_file.close()
diff --git a/venv/Lib/site-packages/pylint/reporters/__init__.py b/venv/Lib/site-packages/pylint/reporters/__init__.py
deleted file mode 100644
index f01629b..0000000
--- a/venv/Lib/site-packages/pylint/reporters/__init__.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006, 2010, 2012-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com>
-# Copyright (c) 2014-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Ricardo Gemignani <ricardo.gemignani@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Simu Toni <simutoni@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2017 Kári Tristan Helgason <kthelgason@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""utilities methods and classes for reporters"""
-
-
-from pylint import utils
-from pylint.reporters.base_reporter import BaseReporter
-from pylint.reporters.collecting_reporter import CollectingReporter
-from pylint.reporters.json_reporter import JSONReporter
-from pylint.reporters.reports_handler_mix_in import ReportsHandlerMixIn
-
-
-def initialize(linter):
- """initialize linter with reporters in this package """
- utils.register_plugins(linter, __path__[0])
-
-
-__all__ = ["BaseReporter", "ReportsHandlerMixIn", "JSONReporter", "CollectingReporter"]
diff --git a/venv/Lib/site-packages/pylint/reporters/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index a1b55a7..0000000
--- a/venv/Lib/site-packages/pylint/reporters/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/__pycache__/base_reporter.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/__pycache__/base_reporter.cpython-37.pyc
deleted file mode 100644
index 5f35295..0000000
--- a/venv/Lib/site-packages/pylint/reporters/__pycache__/base_reporter.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/__pycache__/collecting_reporter.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/__pycache__/collecting_reporter.cpython-37.pyc
deleted file mode 100644
index 066140c..0000000
--- a/venv/Lib/site-packages/pylint/reporters/__pycache__/collecting_reporter.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/__pycache__/json_reporter.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/__pycache__/json_reporter.cpython-37.pyc
deleted file mode 100644
index ca871c3..0000000
--- a/venv/Lib/site-packages/pylint/reporters/__pycache__/json_reporter.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/__pycache__/reports_handler_mix_in.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/__pycache__/reports_handler_mix_in.cpython-37.pyc
deleted file mode 100644
index 8269f35..0000000
--- a/venv/Lib/site-packages/pylint/reporters/__pycache__/reports_handler_mix_in.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/__pycache__/text.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/__pycache__/text.cpython-37.pyc
deleted file mode 100644
index f40cc5e..0000000
--- a/venv/Lib/site-packages/pylint/reporters/__pycache__/text.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/base_reporter.py b/venv/Lib/site-packages/pylint/reporters/base_reporter.py
deleted file mode 100644
index 1003eeb..0000000
--- a/venv/Lib/site-packages/pylint/reporters/base_reporter.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import os
-import sys
-
-
-class BaseReporter:
- """base class for reporters
-
- symbols: show short symbolic names for messages.
- """
-
- extension = ""
-
- def __init__(self, output=None):
- self.linter = None
- self.section = 0
- self.out = None
- self.out_encoding = None
- self.set_output(output)
- # Build the path prefix to strip to get relative paths
- self.path_strip_prefix = os.getcwd() + os.sep
-
- def handle_message(self, msg):
- """Handle a new message triggered on the current file."""
-
- def set_output(self, output=None):
- """set output stream"""
- self.out = output or sys.stdout
-
- def writeln(self, string=""):
- """write a line in the output buffer"""
- print(string, file=self.out)
-
- def display_reports(self, layout):
- """display results encapsulated in the layout tree"""
- self.section = 0
- if hasattr(layout, "report_id"):
- layout.children[0].children[0].data += " (%s)" % layout.report_id
- self._display(layout)
-
- def _display(self, layout):
- """display the layout"""
- raise NotImplementedError()
-
- def display_messages(self, layout):
- """Hook for displaying the messages of the reporter
-
- This will be called whenever the underlying messages
- needs to be displayed. For some reporters, it probably
- doesn't make sense to display messages as soon as they
- are available, so some mechanism of storing them could be used.
- This method can be implemented to display them after they've
- been aggregated.
- """
-
- # Event callbacks
-
- def on_set_current_module(self, module, filepath):
- """Hook called when a module starts to be analysed."""
-
- def on_close(self, stats, previous_stats):
- """Hook called when a module finished analyzing."""
diff --git a/venv/Lib/site-packages/pylint/reporters/collecting_reporter.py b/venv/Lib/site-packages/pylint/reporters/collecting_reporter.py
deleted file mode 100644
index 7798d83..0000000
--- a/venv/Lib/site-packages/pylint/reporters/collecting_reporter.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-from pylint.reporters.base_reporter import BaseReporter
-
-
-class CollectingReporter(BaseReporter):
- """collects messages"""
-
- name = "collector"
-
- def __init__(self):
- BaseReporter.__init__(self)
- self.messages = []
-
- def handle_message(self, msg):
- self.messages.append(msg)
-
- _display = None
diff --git a/venv/Lib/site-packages/pylint/reporters/json_reporter.py b/venv/Lib/site-packages/pylint/reporters/json_reporter.py
deleted file mode 100644
index fa6a0f8..0000000
--- a/venv/Lib/site-packages/pylint/reporters/json_reporter.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (c) 2014 Vlad Temian <vladtemian@gmail.com>
-# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2017 guillaume2 <guillaume.peillex@gmail.col>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""JSON reporter"""
-import html
-import json
-import sys
-
-from pylint.interfaces import IReporter
-from pylint.reporters.base_reporter import BaseReporter
-
-
-class JSONReporter(BaseReporter):
- """Report messages and layouts in JSON."""
-
- __implements__ = IReporter
- name = "json"
- extension = "json"
-
- def __init__(self, output=sys.stdout):
- BaseReporter.__init__(self, output)
- self.messages = []
-
- def handle_message(self, msg):
- """Manage message of different type and in the context of path."""
- self.messages.append(
- {
- "type": msg.category,
- "module": msg.module,
- "obj": msg.obj,
- "line": msg.line,
- "column": msg.column,
- "path": msg.path,
- "symbol": msg.symbol,
- "message": html.escape(msg.msg or "", quote=False),
- "message-id": msg.msg_id,
- }
- )
-
- def display_messages(self, layout):
- """Launch layouts display"""
- print(json.dumps(self.messages, indent=4), file=self.out)
-
- def display_reports(self, layout):
- """Don't do nothing in this reporter."""
-
- def _display(self, layout):
- """Do nothing."""
-
-
-def register(linter):
- """Register the reporter classes with the linter."""
- linter.register_reporter(JSONReporter)
diff --git a/venv/Lib/site-packages/pylint/reporters/reports_handler_mix_in.py b/venv/Lib/site-packages/pylint/reporters/reports_handler_mix_in.py
deleted file mode 100644
index 6f91a97..0000000
--- a/venv/Lib/site-packages/pylint/reporters/reports_handler_mix_in.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import collections
-
-from pylint.exceptions import EmptyReportError
-from pylint.reporters.ureports.nodes import Section
-
-
-class ReportsHandlerMixIn:
- """a mix-in class containing all the reports and stats manipulation
- related methods for the main lint class
- """
-
- def __init__(self):
- self._reports = collections.defaultdict(list)
- self._reports_state = {}
-
- def report_order(self):
- """ Return a list of reports, sorted in the order
- in which they must be called.
- """
- return list(self._reports)
-
- def register_report(self, reportid, r_title, r_cb, checker):
- """register a report
-
- reportid is the unique identifier for the report
- r_title the report's title
- r_cb the method to call to make the report
- checker is the checker defining the report
- """
- reportid = reportid.upper()
- self._reports[checker].append((reportid, r_title, r_cb))
-
- def enable_report(self, reportid):
- """disable the report of the given id"""
- reportid = reportid.upper()
- self._reports_state[reportid] = True
-
- def disable_report(self, reportid):
- """disable the report of the given id"""
- reportid = reportid.upper()
- self._reports_state[reportid] = False
-
- def report_is_enabled(self, reportid):
- """return true if the report associated to the given identifier is
- enabled
- """
- return self._reports_state.get(reportid, True)
-
- def make_reports(self, stats, old_stats):
- """render registered reports"""
- sect = Section("Report", "%s statements analysed." % (self.stats["statement"]))
- for checker in self.report_order():
- for reportid, r_title, r_cb in self._reports[checker]:
- if not self.report_is_enabled(reportid):
- continue
- report_sect = Section(r_title)
- try:
- r_cb(report_sect, stats, old_stats)
- except EmptyReportError:
- continue
- report_sect.report_id = reportid
- sect.append(report_sect)
- return sect
-
- def add_stats(self, **kwargs):
- """add some stats entries to the statistic dictionary
- raise an AssertionError if there is a key conflict
- """
- for key, value in kwargs.items():
- if key[-1] == "_":
- key = key[:-1]
- assert key not in self.stats
- self.stats[key] = value
- return self.stats
diff --git a/venv/Lib/site-packages/pylint/reporters/text.py b/venv/Lib/site-packages/pylint/reporters/text.py
deleted file mode 100644
index ce74174..0000000
--- a/venv/Lib/site-packages/pylint/reporters/text.py
+++ /dev/null
@@ -1,247 +0,0 @@
-# Copyright (c) 2006-2007, 2010-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 y2kbugger <y2kbugger@users.noreply.github.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Jace Browning <jacebrowning@gmail.com>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Plain text reporters:
-
-:text: the default one grouping messages by module
-:colorized: an ANSI colorized text reporter
-"""
-import os
-import sys
-import warnings
-
-from pylint import utils
-from pylint.interfaces import IReporter
-from pylint.reporters import BaseReporter
-from pylint.reporters.ureports.text_writer import TextWriter
-
-TITLE_UNDERLINES = ["", "=", "-", "."]
-
-ANSI_PREFIX = "\033["
-ANSI_END = "m"
-ANSI_RESET = "\033[0m"
-ANSI_STYLES = {
- "reset": "0",
- "bold": "1",
- "italic": "3",
- "underline": "4",
- "blink": "5",
- "inverse": "7",
- "strike": "9",
-}
-ANSI_COLORS = {
- "reset": "0",
- "black": "30",
- "red": "31",
- "green": "32",
- "yellow": "33",
- "blue": "34",
- "magenta": "35",
- "cyan": "36",
- "white": "37",
-}
-
-
-def _get_ansi_code(color=None, style=None):
- """return ansi escape code corresponding to color and style
-
- :type color: str or None
- :param color:
- the color name (see `ANSI_COLORS` for available values)
- or the color number when 256 colors are available
-
- :type style: str or None
- :param style:
- style string (see `ANSI_COLORS` for available values). To get
- several style effects at the same time, use a coma as separator.
-
- :raise KeyError: if an unexistent color or style identifier is given
-
- :rtype: str
- :return: the built escape code
- """
- ansi_code = []
- if style:
- style_attrs = utils._splitstrip(style)
- for effect in style_attrs:
- ansi_code.append(ANSI_STYLES[effect])
- if color:
- if color.isdigit():
- ansi_code.extend(["38", "5"])
- ansi_code.append(color)
- else:
- ansi_code.append(ANSI_COLORS[color])
- if ansi_code:
- return ANSI_PREFIX + ";".join(ansi_code) + ANSI_END
- return ""
-
-
-def colorize_ansi(msg, color=None, style=None):
- """colorize message by wrapping it with ansi escape codes
-
- :type msg: str or unicode
- :param msg: the message string to colorize
-
- :type color: str or None
- :param color:
- the color identifier (see `ANSI_COLORS` for available values)
-
- :type style: str or None
- :param style:
- style string (see `ANSI_COLORS` for available values). To get
- several style effects at the same time, use a coma as separator.
-
- :raise KeyError: if an unexistent color or style identifier is given
-
- :rtype: str or unicode
- :return: the ansi escaped string
- """
- # If both color and style are not defined, then leave the text as is
- if color is None and style is None:
- return msg
- escape_code = _get_ansi_code(color, style)
- # If invalid (or unknown) color, don't wrap msg with ansi codes
- if escape_code:
- return "%s%s%s" % (escape_code, msg, ANSI_RESET)
- return msg
-
-
-class TextReporter(BaseReporter):
- """reports messages and layouts in plain text"""
-
- __implements__ = IReporter
- name = "text"
- extension = "txt"
- line_format = "{path}:{line}:{column}: {msg_id}: {msg} ({symbol})"
-
- def __init__(self, output=None):
- BaseReporter.__init__(self, output)
- self._modules = set()
- self._template = None
-
- def on_set_current_module(self, module, filepath):
- self._template = str(self.linter.config.msg_template or self.line_format)
-
- def write_message(self, msg):
- """Convenience method to write a formated message with class default template"""
- self.writeln(msg.format(self._template))
-
- def handle_message(self, msg):
- """manage message of different type and in the context of path"""
- if msg.module not in self._modules:
- if msg.module:
- self.writeln("************* Module %s" % msg.module)
- self._modules.add(msg.module)
- else:
- self.writeln("************* ")
- self.write_message(msg)
-
- def _display(self, layout):
- """launch layouts display"""
- print(file=self.out)
- TextWriter().format(layout, self.out)
-
-
-class ParseableTextReporter(TextReporter):
- """a reporter very similar to TextReporter, but display messages in a form
- recognized by most text editors :
-
- <filename>:<linenum>:<msg>
- """
-
- name = "parseable"
- line_format = "{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}"
-
- def __init__(self, output=None):
- warnings.warn(
- "%s output format is deprecated. This is equivalent "
- "to --msg-template=%s" % (self.name, self.line_format),
- DeprecationWarning,
- )
- TextReporter.__init__(self, output)
-
-
-class VSTextReporter(ParseableTextReporter):
- """Visual studio text reporter"""
-
- name = "msvs"
- line_format = "{path}({line}): [{msg_id}({symbol}){obj}] {msg}"
-
-
-class ColorizedTextReporter(TextReporter):
- """Simple TextReporter that colorizes text output"""
-
- name = "colorized"
- COLOR_MAPPING = {
- "I": ("green", None),
- "C": (None, "bold"),
- "R": ("magenta", "bold, italic"),
- "W": ("magenta", None),
- "E": ("red", "bold"),
- "F": ("red", "bold, underline"),
- "S": ("yellow", "inverse"), # S stands for module Separator
- }
-
- def __init__(self, output=None, color_mapping=None):
- TextReporter.__init__(self, output)
- self.color_mapping = color_mapping or dict(ColorizedTextReporter.COLOR_MAPPING)
- ansi_terms = ["xterm-16color", "xterm-256color"]
- if os.environ.get("TERM") not in ansi_terms:
- if sys.platform == "win32":
- # pylint: disable=import-error,import-outside-toplevel
- import colorama
-
- self.out = colorama.AnsiToWin32(self.out)
-
- def _get_decoration(self, msg_id):
- """Returns the tuple color, style associated with msg_id as defined
- in self.color_mapping
- """
- try:
- return self.color_mapping[msg_id[0]]
- except KeyError:
- return None, None
-
- def handle_message(self, msg):
- """manage message of different types, and colorize output
- using ansi escape codes
- """
- if msg.module not in self._modules:
- color, style = self._get_decoration("S")
- if msg.module:
- modsep = colorize_ansi(
- "************* Module %s" % msg.module, color, style
- )
- else:
- modsep = colorize_ansi("************* %s" % msg.module, color, style)
- self.writeln(modsep)
- self._modules.add(msg.module)
- color, style = self._get_decoration(msg.C)
-
- msg = msg._replace(
- **{
- attr: colorize_ansi(getattr(msg, attr), color, style)
- for attr in ("msg", "symbol", "category", "C")
- }
- )
- self.write_message(msg)
-
-
-def register(linter):
- """Register the reporter classes with the linter."""
- linter.register_reporter(TextReporter)
- linter.register_reporter(ParseableTextReporter)
- linter.register_reporter(VSTextReporter)
- linter.register_reporter(ColorizedTextReporter)
diff --git a/venv/Lib/site-packages/pylint/reporters/ureports/__init__.py b/venv/Lib/site-packages/pylint/reporters/ureports/__init__.py
deleted file mode 100644
index 361552b..0000000
--- a/venv/Lib/site-packages/pylint/reporters/ureports/__init__.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Universal report objects and some formatting drivers.
-
-A way to create simple reports using python objects, primarily designed to be
-formatted as text and html.
-"""
-import os
-import sys
-from io import StringIO
-
-
-class BaseWriter:
- """base class for ureport writers"""
-
- def format(self, layout, stream=None, encoding=None):
- """format and write the given layout into the stream object
-
- unicode policy: unicode strings may be found in the layout;
- try to call stream.write with it, but give it back encoded using
- the given encoding if it fails
- """
- if stream is None:
- stream = sys.stdout
- if not encoding:
- encoding = getattr(stream, "encoding", "UTF-8")
- self.encoding = encoding or "UTF-8"
- self.out = stream
- self.begin_format()
- layout.accept(self)
- self.end_format()
-
- def format_children(self, layout):
- """recurse on the layout children and call their accept method
- (see the Visitor pattern)
- """
- for child in getattr(layout, "children", ()):
- child.accept(self)
-
- def writeln(self, string=""):
- """write a line in the output buffer"""
- self.write(string + os.linesep)
-
- def write(self, string):
- """write a string in the output buffer"""
- self.out.write(string)
-
- def begin_format(self):
- """begin to format a layout"""
- self.section = 0
-
- def end_format(self):
- """finished to format a layout"""
-
- def get_table_content(self, table):
- """trick to get table content without actually writing it
-
- return an aligned list of lists containing table cells values as string
- """
- result = [[]]
- cols = table.cols
- for cell in self.compute_content(table):
- if cols == 0:
- result.append([])
- cols = table.cols
- cols -= 1
- result[-1].append(cell)
- # fill missing cells
- while len(result[-1]) < cols:
- result[-1].append("")
- return result
-
- def compute_content(self, layout):
- """trick to compute the formatting of children layout before actually
- writing it
-
- return an iterator on strings (one for each child element)
- """
- # Patch the underlying output stream with a fresh-generated stream,
- # which is used to store a temporary representation of a child
- # node.
- out = self.out
- try:
- for child in layout.children:
- stream = StringIO()
- self.out = stream
- child.accept(self)
- yield stream.getvalue()
- finally:
- self.out = out
diff --git a/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 408b51f..0000000
--- a/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/nodes.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/nodes.cpython-37.pyc
deleted file mode 100644
index 2640b32..0000000
--- a/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/nodes.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/text_writer.cpython-37.pyc b/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/text_writer.cpython-37.pyc
deleted file mode 100644
index 7222ed4..0000000
--- a/venv/Lib/site-packages/pylint/reporters/ureports/__pycache__/text_writer.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/reporters/ureports/nodes.py b/venv/Lib/site-packages/pylint/reporters/ureports/nodes.py
deleted file mode 100644
index 8fafb20..0000000
--- a/venv/Lib/site-packages/pylint/reporters/ureports/nodes.py
+++ /dev/null
@@ -1,188 +0,0 @@
-# Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Micro reports objects.
-
-A micro report is a tree of layout and content objects.
-"""
-
-
-class VNode:
- def __init__(self, nid=None):
- self.id = nid
- # navigation
- self.parent = None
- self.children = []
-
- def __iter__(self):
- return iter(self.children)
-
- def append(self, child):
- """add a node to children"""
- self.children.append(child)
- child.parent = self
-
- def insert(self, index, child):
- """insert a child node"""
- self.children.insert(index, child)
- child.parent = self
-
- def _get_visit_name(self):
- """
- return the visit name for the mixed class. When calling 'accept', the
- method <'visit_' + name returned by this method> will be called on the
- visitor
- """
- try:
- # pylint: disable=no-member
- return self.TYPE.replace("-", "_")
- # pylint: disable=broad-except
- except Exception:
- return self.__class__.__name__.lower()
-
- def accept(self, visitor, *args, **kwargs):
- func = getattr(visitor, "visit_%s" % self._get_visit_name())
- return func(self, *args, **kwargs)
-
- def leave(self, visitor, *args, **kwargs):
- func = getattr(visitor, "leave_%s" % self._get_visit_name())
- return func(self, *args, **kwargs)
-
-
-class BaseLayout(VNode):
- """base container node
-
- attributes
- * children : components in this table (i.e. the table's cells)
- """
-
- def __init__(self, children=(), **kwargs):
- super(BaseLayout, self).__init__(**kwargs)
- for child in children:
- if isinstance(child, VNode):
- self.append(child)
- else:
- self.add_text(child)
-
- def append(self, child):
- """overridden to detect problems easily"""
- assert child not in self.parents()
- VNode.append(self, child)
-
- def parents(self):
- """return the ancestor nodes"""
- assert self.parent is not self
- if self.parent is None:
- return []
- return [self.parent] + self.parent.parents()
-
- def add_text(self, text):
- """shortcut to add text data"""
- self.children.append(Text(text))
-
-
-# non container nodes #########################################################
-
-
-class Text(VNode):
- """a text portion
-
- attributes :
- * data : the text value as an encoded or unicode string
- """
-
- def __init__(self, data, escaped=True, **kwargs):
- super(Text, self).__init__(**kwargs)
- # if isinstance(data, unicode):
- # data = data.encode('ascii')
- assert isinstance(data, str), data.__class__
- self.escaped = escaped
- self.data = data
-
-
-class VerbatimText(Text):
- """a verbatim text, display the raw data
-
- attributes :
- * data : the text value as an encoded or unicode string
- """
-
-
-# container nodes #############################################################
-
-
-class Section(BaseLayout):
- """a section
-
- attributes :
- * BaseLayout attributes
-
- a title may also be given to the constructor, it'll be added
- as a first element
- a description may also be given to the constructor, it'll be added
- as a first paragraph
- """
-
- def __init__(self, title=None, description=None, **kwargs):
- super(Section, self).__init__(**kwargs)
- if description:
- self.insert(0, Paragraph([Text(description)]))
- if title:
- self.insert(0, Title(children=(title,)))
-
-
-class EvaluationSection(Section):
- def __init__(self, message, **kwargs):
- super(EvaluationSection, self).__init__(**kwargs)
- title = Paragraph()
- title.append(Text("-" * len(message)))
- self.append(title)
-
- message_body = Paragraph()
- message_body.append(Text(message))
- self.append(message_body)
-
-
-class Title(BaseLayout):
- """a title
-
- attributes :
- * BaseLayout attributes
-
- A title must not contains a section nor a paragraph!
- """
-
-
-class Paragraph(BaseLayout):
- """a simple text paragraph
-
- attributes :
- * BaseLayout attributes
-
- A paragraph must not contains a section !
- """
-
-
-class Table(BaseLayout):
- """some tabular data
-
- attributes :
- * BaseLayout attributes
- * cols : the number of columns of the table (REQUIRED)
- * rheaders : the first row's elements are table's header
- * cheaders : the first col's elements are table's header
- * title : the table's optional title
- """
-
- def __init__(self, cols, title=None, rheaders=0, cheaders=0, **kwargs):
- super(Table, self).__init__(**kwargs)
- assert isinstance(cols, int)
- self.cols = cols
- self.title = title
- self.rheaders = rheaders
- self.cheaders = cheaders
diff --git a/venv/Lib/site-packages/pylint/reporters/ureports/text_writer.py b/venv/Lib/site-packages/pylint/reporters/ureports/text_writer.py
deleted file mode 100644
index 8f6aea2..0000000
--- a/venv/Lib/site-packages/pylint/reporters/ureports/text_writer.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Text formatting drivers for ureports"""
-
-from pylint.reporters.ureports import BaseWriter
-
-TITLE_UNDERLINES = ["", "=", "-", "`", ".", "~", "^"]
-BULLETS = ["*", "-"]
-
-
-class TextWriter(BaseWriter):
- """format layouts as text
- (ReStructured inspiration but not totally handled yet)
- """
-
- def begin_format(self):
- super(TextWriter, self).begin_format()
- self.list_level = 0
-
- def visit_section(self, layout):
- """display a section as text
- """
- self.section += 1
- self.writeln()
- self.format_children(layout)
- self.section -= 1
- self.writeln()
-
- def visit_evaluationsection(self, layout):
- """Display an evaluation section as a text."""
- self.section += 1
- self.format_children(layout)
- self.section -= 1
- self.writeln()
-
- def visit_title(self, layout):
- title = "".join(list(self.compute_content(layout)))
- self.writeln(title)
- try:
- self.writeln(TITLE_UNDERLINES[self.section] * len(title))
- except IndexError:
- print("FIXME TITLE TOO DEEP. TURNING TITLE INTO TEXT")
-
- def visit_paragraph(self, layout):
- """enter a paragraph"""
- self.format_children(layout)
- self.writeln()
-
- def visit_table(self, layout):
- """display a table as text"""
- table_content = self.get_table_content(layout)
- # get columns width
- cols_width = [0] * len(table_content[0])
- for row in table_content:
- for index, col in enumerate(row):
- cols_width[index] = max(cols_width[index], len(col))
- self.default_table(layout, table_content, cols_width)
- self.writeln()
-
- def default_table(self, layout, table_content, cols_width):
- """format a table"""
- cols_width = [size + 1 for size in cols_width]
- format_strings = " ".join(["%%-%ss"] * len(cols_width))
- format_strings = format_strings % tuple(cols_width)
- format_strings = format_strings.split(" ")
- table_linesep = "\n+" + "+".join(["-" * w for w in cols_width]) + "+\n"
- headsep = "\n+" + "+".join(["=" * w for w in cols_width]) + "+\n"
-
- self.write(table_linesep)
- for index, line in enumerate(table_content):
- self.write("|")
- for line_index, at_index in enumerate(line):
- self.write(format_strings[line_index] % at_index)
- self.write("|")
- if index == 0 and layout.rheaders:
- self.write(headsep)
- else:
- self.write(table_linesep)
-
- def visit_verbatimtext(self, layout):
- """display a verbatim layout as text (so difficult ;)
- """
- self.writeln("::\n")
- for line in layout.data.splitlines():
- self.writeln(" " + line)
- self.writeln()
-
- def visit_text(self, layout):
- """add some text"""
- self.write("%s" % layout.data)
diff --git a/venv/Lib/site-packages/pylint/testutils.py b/venv/Lib/site-packages/pylint/testutils.py
deleted file mode 100644
index f214208..0000000
--- a/venv/Lib/site-packages/pylint/testutils.py
+++ /dev/null
@@ -1,298 +0,0 @@
-# Copyright (c) 2012-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com>
-# Copyright (c) 2013-2017 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2013-2014 Google, Inc.
-# Copyright (c) 2013 buck@yelp.com <buck@yelp.com>
-# Copyright (c) 2014 LCD 47 <lcd047@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Ricardo Gemignani <ricardo.gemignani@gmail.com>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Pavel Roskin <proski@gnu.org>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>
-# Copyright (c) 2016 Roy Williams <roy.williams.iii@gmail.com>
-# Copyright (c) 2016 xmo-odoo <xmo-odoo@users.noreply.github.com>
-# Copyright (c) 2017 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""functional/non regression tests for pylint"""
-import collections
-import contextlib
-import functools
-import sys
-import tempfile
-import tokenize
-from glob import glob
-from io import StringIO
-from os import close, getcwd, linesep, remove, sep, write
-from os.path import abspath, basename, dirname, join, splitext
-
-import astroid
-
-from pylint import checkers
-from pylint.interfaces import IReporter
-from pylint.lint import PyLinter
-from pylint.reporters import BaseReporter
-from pylint.utils import ASTWalker
-
-# Utils
-
-SYS_VERS_STR = "%d%d%d" % sys.version_info[:3]
-TITLE_UNDERLINES = ["", "=", "-", "."]
-PREFIX = abspath(dirname(__file__))
-
-
-def _get_tests_info(input_dir, msg_dir, prefix, suffix):
- """get python input examples and output messages
-
- We use following conventions for input files and messages:
- for different inputs:
- test for python >= x.y -> input = <name>_pyxy.py
- test for python < x.y -> input = <name>_py_xy.py
- for one input and different messages:
- message for python >= x.y -> message = <name>_pyxy.txt
- lower versions -> message with highest num
- """
- result = []
- for fname in glob(join(input_dir, prefix + "*" + suffix)):
- infile = basename(fname)
- fbase = splitext(infile)[0]
- # filter input files :
- pyrestr = fbase.rsplit("_py", 1)[-1] # like _26 or 26
- if pyrestr.isdigit(): # '24', '25'...
- if SYS_VERS_STR < pyrestr:
- continue
- if pyrestr.startswith("_") and pyrestr[1:].isdigit():
- # skip test for higher python versions
- if SYS_VERS_STR >= pyrestr[1:]:
- continue
- messages = glob(join(msg_dir, fbase + "*.txt"))
- # the last one will be without ext, i.e. for all or upper versions:
- if messages:
- for outfile in sorted(messages, reverse=True):
- py_rest = outfile.rsplit("_py", 1)[-1][:-4]
- if py_rest.isdigit() and SYS_VERS_STR >= py_rest:
- break
- else:
- # This will provide an error message indicating the missing filename.
- outfile = join(msg_dir, fbase + ".txt")
- result.append((infile, outfile))
- return result
-
-
-class TestReporter(BaseReporter):
- """reporter storing plain text messages"""
-
- __implements__ = IReporter
-
- def __init__(self): # pylint: disable=super-init-not-called
-
- self.message_ids = {}
- self.reset()
- self.path_strip_prefix = getcwd() + sep
-
- def reset(self):
- self.out = StringIO()
- self.messages = []
-
- def handle_message(self, msg):
- """manage message of different type and in the context of path """
- obj = msg.obj
- line = msg.line
- msg_id = msg.msg_id
- msg = msg.msg
- self.message_ids[msg_id] = 1
- if obj:
- obj = ":%s" % obj
- sigle = msg_id[0]
- if linesep != "\n":
- # 2to3 writes os.linesep instead of using
- # the previosly used line separators
- msg = msg.replace("\r\n", "\n")
- self.messages.append("%s:%3s%s: %s" % (sigle, line, obj, msg))
-
- def finalize(self):
- self.messages.sort()
- for msg in self.messages:
- print(msg, file=self.out)
- result = self.out.getvalue()
- self.reset()
- return result
-
- # pylint: disable=unused-argument
- def on_set_current_module(self, module, filepath):
- pass
-
- # pylint: enable=unused-argument
-
- def display_reports(self, layout):
- """ignore layouts"""
-
- _display = None
-
-
-class MinimalTestReporter(BaseReporter):
- def handle_message(self, msg):
- self.messages.append(msg)
-
- def on_set_current_module(self, module, filepath):
- self.messages = []
-
- _display = None
-
-
-class Message(
- collections.namedtuple("Message", ["msg_id", "line", "node", "args", "confidence"])
-):
- def __new__(cls, msg_id, line=None, node=None, args=None, confidence=None):
- return tuple.__new__(cls, (msg_id, line, node, args, confidence))
-
- def __eq__(self, other):
- if isinstance(other, Message):
- if self.confidence and other.confidence:
- return super(Message, self).__eq__(other)
- return self[:-1] == other[:-1]
- return NotImplemented # pragma: no cover
-
- __hash__ = None
-
-
-class UnittestLinter:
- """A fake linter class to capture checker messages."""
-
- # pylint: disable=unused-argument, no-self-use
-
- def __init__(self):
- self._messages = []
- self.stats = {}
-
- def release_messages(self):
- try:
- return self._messages
- finally:
- self._messages = []
-
- def add_message(
- self, msg_id, line=None, node=None, args=None, confidence=None, col_offset=None
- ):
- # Do not test col_offset for now since changing Message breaks everything
- self._messages.append(Message(msg_id, line, node, args, confidence))
-
- def is_message_enabled(self, *unused_args, **unused_kwargs):
- return True
-
- def add_stats(self, **kwargs):
- for name, value in kwargs.items():
- self.stats[name] = value
- return self.stats
-
- @property
- def options_providers(self):
- return linter.options_providers
-
-
-def set_config(**kwargs):
- """Decorator for setting config values on a checker."""
-
- def _wrapper(fun):
- @functools.wraps(fun)
- def _forward(self):
- for key, value in kwargs.items():
- setattr(self.checker.config, key, value)
- if isinstance(self, CheckerTestCase):
- # reopen checker in case, it may be interested in configuration change
- self.checker.open()
- fun(self)
-
- return _forward
-
- return _wrapper
-
-
-class CheckerTestCase:
- """A base testcase class for unit testing individual checker classes."""
-
- CHECKER_CLASS = None
- CONFIG = {}
-
- def setup_method(self):
- self.linter = UnittestLinter()
- self.checker = self.CHECKER_CLASS(self.linter) # pylint: disable=not-callable
- for key, value in self.CONFIG.items():
- setattr(self.checker.config, key, value)
- self.checker.open()
-
- @contextlib.contextmanager
- def assertNoMessages(self):
- """Assert that no messages are added by the given method."""
- with self.assertAddsMessages():
- yield
-
- @contextlib.contextmanager
- def assertAddsMessages(self, *messages):
- """Assert that exactly the given method adds the given messages.
-
- The list of messages must exactly match *all* the messages added by the
- method. Additionally, we check to see whether the args in each message can
- actually be substituted into the message string.
- """
- yield
- got = self.linter.release_messages()
- msg = "Expected messages did not match actual.\n" "Expected:\n%s\nGot:\n%s" % (
- "\n".join(repr(m) for m in messages),
- "\n".join(repr(m) for m in got),
- )
- assert list(messages) == got, msg
-
- def walk(self, node):
- """recursive walk on the given node"""
- walker = ASTWalker(linter)
- walker.add_checker(self.checker)
- walker.walk(node)
-
-
-# Init
-test_reporter = TestReporter()
-linter = PyLinter()
-linter.set_reporter(test_reporter)
-linter.config.persistent = 0
-checkers.initialize(linter)
-
-
-def _tokenize_str(code):
- return list(tokenize.generate_tokens(StringIO(code).readline))
-
-
-@contextlib.contextmanager
-def _create_tempfile(content=None):
- """Create a new temporary file.
-
- If *content* parameter is given, then it will be written
- in the temporary file, before passing it back.
- This is a context manager and should be used with a *with* statement.
- """
- # Can't use tempfile.NamedTemporaryFile here
- # because on Windows the file must be closed before writing to it,
- # see http://bugs.python.org/issue14243
- file_handle, tmp = tempfile.mkstemp()
- if content:
- # erff
- write(file_handle, bytes(content, "ascii"))
- try:
- yield tmp
- finally:
- close(file_handle)
- remove(tmp)
-
-
-@contextlib.contextmanager
-def _create_file_backed_module(code):
- """Create an astroid module for the given code, backed by a real file."""
- with _create_tempfile() as temp:
- module = astroid.parse(code)
- module.file = temp
- yield module
diff --git a/venv/Lib/site-packages/pylint/utils/__init__.py b/venv/Lib/site-packages/pylint/utils/__init__.py
deleted file mode 100644
index 8ee9e07..0000000
--- a/venv/Lib/site-packages/pylint/utils/__init__.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2009 Vincent
-# Copyright (c) 2009 Mads Kiilerich <mads@kiilerich.com>
-# Copyright (c) 2012-2014 Google, Inc.
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014-2015 Michal Nowikowski <godfryd@gmail.com>
-# Copyright (c) 2014 LCD 47 <lcd047@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2014 Damien Nozay <damien.nozay@gmail.com>
-# Copyright (c) 2015 Aru Sahni <arusahni@gmail.com>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Simu Toni <simutoni@gmail.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
-# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
-# Copyright (c) 2016 Glenn Matthews <glmatthe@cisco.com>
-# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2016 xmo-odoo <xmo-odoo@users.noreply.github.com>
-# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
-# Copyright (c) 2017 Pierre Sassoulas <pierre.sassoulas@cea.fr>
-# Copyright (c) 2017 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2017 Chris Lamb <chris@chris-lamb.co.uk>
-# Copyright (c) 2017 Anthony Sottile <asottile@umich.edu>
-# Copyright (c) 2017 Thomas Hisch <t.hisch@gmail.com>
-# Copyright (c) 2017 Mikhail Fesenko <proggga@gmail.com>
-# Copyright (c) 2017 Craig Citro <craigcitro@gmail.com>
-# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
-# Copyright (c) 2018 Pierre Sassoulas <pierre.sassoulas@wisebim.fr>
-# Copyright (c) 2018 Reverb C <reverbc@users.noreply.github.com>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""some various utilities and helper classes, most of them used in the
-main pylint class
-"""
-
-from pylint.utils.ast_walker import ASTWalker
-from pylint.utils.file_state import FileState
-from pylint.utils.utils import (
- _basename_in_blacklist_re,
- _check_csv,
- _format_option_value,
- _splitstrip,
- _unquote,
- decoding_stream,
- deprecated_option,
- expand_modules,
- format_section,
- get_global_option,
- get_module_and_frameid,
- get_rst_section,
- get_rst_title,
- normalize_text,
- register_plugins,
- safe_decode,
- tokenize_module,
-)
diff --git a/venv/Lib/site-packages/pylint/utils/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/utils/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 6f3569d..0000000
--- a/venv/Lib/site-packages/pylint/utils/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/utils/__pycache__/ast_walker.cpython-37.pyc b/venv/Lib/site-packages/pylint/utils/__pycache__/ast_walker.cpython-37.pyc
deleted file mode 100644
index af27609..0000000
--- a/venv/Lib/site-packages/pylint/utils/__pycache__/ast_walker.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/utils/__pycache__/file_state.cpython-37.pyc b/venv/Lib/site-packages/pylint/utils/__pycache__/file_state.cpython-37.pyc
deleted file mode 100644
index 4a43508..0000000
--- a/venv/Lib/site-packages/pylint/utils/__pycache__/file_state.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/utils/__pycache__/utils.cpython-37.pyc b/venv/Lib/site-packages/pylint/utils/__pycache__/utils.cpython-37.pyc
deleted file mode 100644
index 9049995..0000000
--- a/venv/Lib/site-packages/pylint/utils/__pycache__/utils.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/Lib/site-packages/pylint/utils/ast_walker.py b/venv/Lib/site-packages/pylint/utils/ast_walker.py
deleted file mode 100644
index 2e7a6da..0000000
--- a/venv/Lib/site-packages/pylint/utils/ast_walker.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import collections
-
-from astroid import nodes
-
-
-class ASTWalker:
- def __init__(self, linter):
- # callbacks per node types
- self.nbstatements = 0
- self.visit_events = collections.defaultdict(list)
- self.leave_events = collections.defaultdict(list)
- self.linter = linter
-
- def _is_method_enabled(self, method):
- if not hasattr(method, "checks_msgs"):
- return True
- for msg_desc in method.checks_msgs:
- if self.linter.is_message_enabled(msg_desc):
- return True
- return False
-
- def add_checker(self, checker):
- """walk to the checker's dir and collect visit and leave methods"""
- vcids = set()
- lcids = set()
- visits = self.visit_events
- leaves = self.leave_events
- for member in dir(checker):
- cid = member[6:]
- if cid == "default":
- continue
- if member.startswith("visit_"):
- v_meth = getattr(checker, member)
- # don't use visit_methods with no activated message:
- if self._is_method_enabled(v_meth):
- visits[cid].append(v_meth)
- vcids.add(cid)
- elif member.startswith("leave_"):
- l_meth = getattr(checker, member)
- # don't use leave_methods with no activated message:
- if self._is_method_enabled(l_meth):
- leaves[cid].append(l_meth)
- lcids.add(cid)
- visit_default = getattr(checker, "visit_default", None)
- if visit_default:
- for cls in nodes.ALL_NODE_CLASSES:
- cid = cls.__name__.lower()
- if cid not in vcids:
- visits[cid].append(visit_default)
- # for now we have no "leave_default" method in Pylint
-
- def walk(self, astroid):
- """call visit events of astroid checkers for the given node, recurse on
- its children, then leave events.
- """
- cid = astroid.__class__.__name__.lower()
-
- # Detect if the node is a new name for a deprecated alias.
- # In this case, favour the methods for the deprecated
- # alias if any, in order to maintain backwards
- # compatibility.
- visit_events = self.visit_events.get(cid, ())
- leave_events = self.leave_events.get(cid, ())
-
- if astroid.is_statement:
- self.nbstatements += 1
- # generate events for this node on each checker
- for callback in visit_events or ():
- callback(astroid)
- # recurse on children
- for child in astroid.get_children():
- self.walk(child)
- for callback in leave_events or ():
- callback(astroid)
diff --git a/venv/Lib/site-packages/pylint/utils/file_state.py b/venv/Lib/site-packages/pylint/utils/file_state.py
deleted file mode 100644
index 1a8dd4d..0000000
--- a/venv/Lib/site-packages/pylint/utils/file_state.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import collections
-
-from astroid import nodes
-
-from pylint.constants import MSG_STATE_SCOPE_MODULE, WarningScope
-
-
-class FileState:
- """Hold internal state specific to the currently analyzed file"""
-
- def __init__(self, modname=None):
- self.base_name = modname
- self._module_msgs_state = {}
- self._raw_module_msgs_state = {}
- self._ignored_msgs = collections.defaultdict(set)
- self._suppression_mapping = {}
- self._effective_max_line_number = None
-
- def collect_block_lines(self, msgs_store, module_node):
- """Walk the AST to collect block level options line numbers."""
- for msg, lines in self._module_msgs_state.items():
- self._raw_module_msgs_state[msg] = lines.copy()
- orig_state = self._module_msgs_state.copy()
- self._module_msgs_state = {}
- self._suppression_mapping = {}
- self._effective_max_line_number = module_node.tolineno
- self._collect_block_lines(msgs_store, module_node, orig_state)
-
- def _collect_block_lines(self, msgs_store, node, msg_state):
- """Recursively walk (depth first) AST to collect block level options
- line numbers.
- """
- for child in node.get_children():
- self._collect_block_lines(msgs_store, child, msg_state)
- first = node.fromlineno
- last = node.tolineno
- # first child line number used to distinguish between disable
- # which are the first child of scoped node with those defined later.
- # For instance in the code below:
- #
- # 1. def meth8(self):
- # 2. """test late disabling"""
- # 3. pylint: disable=not-callable
- # 4. print(self.blip)
- # 5. pylint: disable=no-member
- # 6. print(self.bla)
- #
- # E1102 should be disabled from line 1 to 6 while E1101 from line 5 to 6
- #
- # this is necessary to disable locally messages applying to class /
- # function using their fromlineno
- if (
- isinstance(node, (nodes.Module, nodes.ClassDef, nodes.FunctionDef))
- and node.body
- ):
- firstchildlineno = node.body[0].fromlineno
- else:
- firstchildlineno = last
- for msgid, lines in msg_state.items():
- for lineno, state in list(lines.items()):
- original_lineno = lineno
- if first > lineno or last < lineno:
- continue
- # Set state for all lines for this block, if the
- # warning is applied to nodes.
- message_definitions = msgs_store.get_message_definitions(msgid)
- for message_definition in message_definitions:
- if message_definition.scope == WarningScope.NODE:
- if lineno > firstchildlineno:
- state = True
- first_, last_ = node.block_range(lineno)
- else:
- first_ = lineno
- last_ = last
- for line in range(first_, last_ + 1):
- # do not override existing entries
- if line in self._module_msgs_state.get(msgid, ()):
- continue
- if line in lines: # state change in the same block
- state = lines[line]
- original_lineno = line
- if not state:
- self._suppression_mapping[(msgid, line)] = original_lineno
- try:
- self._module_msgs_state[msgid][line] = state
- except KeyError:
- self._module_msgs_state[msgid] = {line: state}
- del lines[lineno]
-
- def set_msg_status(self, msg, line, status):
- """Set status (enabled/disable) for a given message at a given line"""
- assert line > 0
- try:
- self._module_msgs_state[msg.msgid][line] = status
- except KeyError:
- self._module_msgs_state[msg.msgid] = {line: status}
-
- def handle_ignored_message(
- self, state_scope, msgid, line, node, args, confidence
- ): # pylint: disable=unused-argument
- """Report an ignored message.
-
- state_scope is either MSG_STATE_SCOPE_MODULE or MSG_STATE_SCOPE_CONFIG,
- depending on whether the message was disabled locally in the module,
- or globally. The other arguments are the same as for add_message.
- """
- if state_scope == MSG_STATE_SCOPE_MODULE:
- try:
- orig_line = self._suppression_mapping[(msgid, line)]
- self._ignored_msgs[(msgid, orig_line)].add(line)
- except KeyError:
- pass
-
- def iter_spurious_suppression_messages(self, msgs_store):
- for warning, lines in self._raw_module_msgs_state.items():
- for line, enable in lines.items():
- if not enable and (warning, line) not in self._ignored_msgs:
- # ignore cyclic-import check which can show false positives
- # here due to incomplete context
- if warning != "R0401":
- yield "useless-suppression", line, (
- msgs_store.get_msg_display_string(warning),
- )
- # don't use iteritems here, _ignored_msgs may be modified by add_message
- for (warning, from_), lines in list(self._ignored_msgs.items()):
- for line in lines:
- yield "suppressed-message", line, (
- msgs_store.get_msg_display_string(warning),
- from_,
- )
-
- def get_effective_max_line_number(self):
- return self._effective_max_line_number
diff --git a/venv/Lib/site-packages/pylint/utils/utils.py b/venv/Lib/site-packages/pylint/utils/utils.py
deleted file mode 100644
index 5605ecd..0000000
--- a/venv/Lib/site-packages/pylint/utils/utils.py
+++ /dev/null
@@ -1,371 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-import codecs
-import re
-import sys
-import textwrap
-import tokenize
-from os import linesep, listdir
-from os.path import basename, dirname, exists, isdir, join, normpath, splitext
-
-from astroid import Module, modutils
-
-from pylint.constants import PY_EXTS
-
-
-def normalize_text(text, line_len=80, indent=""):
- """Wrap the text on the given line length."""
- return "\n".join(
- textwrap.wrap(
- text, width=line_len, initial_indent=indent, subsequent_indent=indent
- )
- )
-
-
-def get_module_and_frameid(node):
- """return the module name and the frame id in the module"""
- frame = node.frame()
- module, obj = "", []
- while frame:
- if isinstance(frame, Module):
- module = frame.name
- else:
- obj.append(getattr(frame, "name", "<lambda>"))
- try:
- frame = frame.parent.frame()
- except AttributeError:
- frame = None
- obj.reverse()
- return module, ".".join(obj)
-
-
-def get_rst_title(title, character):
- """Permit to get a title formatted as ReStructuredText test (underlined with a chosen character)."""
- return "%s\n%s\n" % (title, character * len(title))
-
-
-def get_rst_section(section, options, doc=None):
- """format an options section using as a ReStructuredText formatted output"""
- result = ""
- if section:
- result += get_rst_title(section, "'")
- if doc:
- formatted_doc = normalize_text(doc, line_len=79, indent="")
- result += "%s\n\n" % formatted_doc
- for optname, optdict, value in options:
- help_opt = optdict.get("help")
- result += ":%s:\n" % optname
- if help_opt:
- formatted_help = normalize_text(help_opt, line_len=79, indent=" ")
- result += "%s\n" % formatted_help
- if value:
- value = str(_format_option_value(optdict, value))
- result += "\n Default: ``%s``\n" % value.replace("`` ", "```` ``")
- return result
-
-
-def safe_decode(line, encoding, *args, **kwargs):
- """return decoded line from encoding or decode with default encoding"""
- try:
- return line.decode(encoding or sys.getdefaultencoding(), *args, **kwargs)
- except LookupError:
- return line.decode(sys.getdefaultencoding(), *args, **kwargs)
-
-
-def decoding_stream(stream, encoding, errors="strict"):
- try:
- reader_cls = codecs.getreader(encoding or sys.getdefaultencoding())
- except LookupError:
- reader_cls = codecs.getreader(sys.getdefaultencoding())
- return reader_cls(stream, errors)
-
-
-def tokenize_module(module):
- with module.stream() as stream:
- readline = stream.readline
- return list(tokenize.tokenize(readline))
-
-
-def _basename_in_blacklist_re(base_name, black_list_re):
- """Determines if the basename is matched in a regex blacklist
-
- :param str base_name: The basename of the file
- :param list black_list_re: A collection of regex patterns to match against.
- Successful matches are blacklisted.
-
- :returns: `True` if the basename is blacklisted, `False` otherwise.
- :rtype: bool
- """
- for file_pattern in black_list_re:
- if file_pattern.match(base_name):
- return True
- return False
-
-
-def _modpath_from_file(filename, is_namespace):
- def _is_package_cb(path, parts):
- return modutils.check_modpath_has_init(path, parts) or is_namespace
-
- return modutils.modpath_from_file_with_callback(
- filename, is_package_cb=_is_package_cb
- )
-
-
-def expand_modules(files_or_modules, black_list, black_list_re):
- """take a list of files/modules/packages and return the list of tuple
- (file, module name) which have to be actually checked
- """
- result = []
- errors = []
- for something in files_or_modules:
- if basename(something) in black_list:
- continue
- if _basename_in_blacklist_re(basename(something), black_list_re):
- continue
- if exists(something):
- # this is a file or a directory
- try:
- modname = ".".join(modutils.modpath_from_file(something))
- except ImportError:
- modname = splitext(basename(something))[0]
- if isdir(something):
- filepath = join(something, "__init__.py")
- else:
- filepath = something
- else:
- # suppose it's a module or package
- modname = something
- try:
- filepath = modutils.file_from_modpath(modname.split("."))
- if filepath is None:
- continue
- except (ImportError, SyntaxError) as ex:
- # The SyntaxError is a Python bug and should be
- # removed once we move away from imp.find_module: http://bugs.python.org/issue10588
- errors.append({"key": "fatal", "mod": modname, "ex": ex})
- continue
-
- filepath = normpath(filepath)
- modparts = (modname or something).split(".")
-
- try:
- spec = modutils.file_info_from_modpath(modparts, path=sys.path)
- except ImportError:
- # Might not be acceptable, don't crash.
- is_namespace = False
- is_directory = isdir(something)
- else:
- is_namespace = modutils.is_namespace(spec)
- is_directory = modutils.is_directory(spec)
-
- if not is_namespace:
- result.append(
- {
- "path": filepath,
- "name": modname,
- "isarg": True,
- "basepath": filepath,
- "basename": modname,
- }
- )
-
- has_init = (
- not (modname.endswith(".__init__") or modname == "__init__")
- and basename(filepath) == "__init__.py"
- )
-
- if has_init or is_namespace or is_directory:
- for subfilepath in modutils.get_module_files(
- dirname(filepath), black_list, list_all=is_namespace
- ):
- if filepath == subfilepath:
- continue
- if _basename_in_blacklist_re(basename(subfilepath), black_list_re):
- continue
-
- modpath = _modpath_from_file(subfilepath, is_namespace)
- submodname = ".".join(modpath)
- result.append(
- {
- "path": subfilepath,
- "name": submodname,
- "isarg": False,
- "basepath": filepath,
- "basename": modname,
- }
- )
- return result, errors
-
-
-def register_plugins(linter, directory):
- """load all module and package in the given directory, looking for a
- 'register' function in each one, used to register pylint checkers
- """
- imported = {}
- for filename in listdir(directory):
- base, extension = splitext(filename)
- if base in imported or base == "__pycache__":
- continue
- if (
- extension in PY_EXTS
- and base != "__init__"
- or (not extension and isdir(join(directory, base)))
- ):
- try:
- module = modutils.load_module_from_file(join(directory, filename))
- except ValueError:
- # empty module name (usually emacs auto-save files)
- continue
- except ImportError as exc:
- print(
- "Problem importing module %s: %s" % (filename, exc), file=sys.stderr
- )
- else:
- if hasattr(module, "register"):
- module.register(linter)
- imported[base] = 1
-
-
-def get_global_option(checker, option, default=None):
- """ Retrieve an option defined by the given *checker* or
- by all known option providers.
-
- It will look in the list of all options providers
- until the given *option* will be found.
- If the option wasn't found, the *default* value will be returned.
- """
- # First, try in the given checker's config.
- # After that, look in the options providers.
-
- try:
- return getattr(checker.config, option.replace("-", "_"))
- except AttributeError:
- pass
- for provider in checker.linter.options_providers:
- for options in provider.options:
- if options[0] == option:
- return getattr(provider.config, option.replace("-", "_"))
- return default
-
-
-def deprecated_option(
- shortname=None, opt_type=None, help_msg=None, deprecation_msg=None
-):
- def _warn_deprecated(option, optname, *args): # pylint: disable=unused-argument
- if deprecation_msg:
- sys.stderr.write(deprecation_msg % (optname,))
-
- option = {
- "help": help_msg,
- "hide": True,
- "type": opt_type,
- "action": "callback",
- "callback": _warn_deprecated,
- "deprecated": True,
- }
- if shortname:
- option["shortname"] = shortname
- return option
-
-
-def _splitstrip(string, sep=","):
- """return a list of stripped string by splitting the string given as
- argument on `sep` (',' by default). Empty string are discarded.
-
- >>> _splitstrip('a, b, c , 4,,')
- ['a', 'b', 'c', '4']
- >>> _splitstrip('a')
- ['a']
- >>> _splitstrip('a,\nb,\nc,')
- ['a', 'b', 'c']
-
- :type string: str or unicode
- :param string: a csv line
-
- :type sep: str or unicode
- :param sep: field separator, default to the comma (',')
-
- :rtype: str or unicode
- :return: the unquoted string (or the input string if it wasn't quoted)
- """
- return [word.strip() for word in string.split(sep) if word.strip()]
-
-
-def _unquote(string):
- """remove optional quotes (simple or double) from the string
-
- :type string: str or unicode
- :param string: an optionally quoted string
-
- :rtype: str or unicode
- :return: the unquoted string (or the input string if it wasn't quoted)
- """
- if not string:
- return string
- if string[0] in "\"'":
- string = string[1:]
- if string[-1] in "\"'":
- string = string[:-1]
- return string
-
-
-def _check_csv(value):
- if isinstance(value, (list, tuple)):
- return value
- return _splitstrip(value)
-
-
-def _comment(string):
- """return string as a comment"""
- lines = [line.strip() for line in string.splitlines()]
- return "# " + ("%s# " % linesep).join(lines)
-
-
-def _format_option_value(optdict, value):
- """return the user input's value from a 'compiled' value"""
- if isinstance(value, (list, tuple)):
- value = ",".join(_format_option_value(optdict, item) for item in value)
- elif isinstance(value, dict):
- value = ",".join("%s:%s" % (k, v) for k, v in value.items())
- elif hasattr(value, "match"): # optdict.get('type') == 'regexp'
- # compiled regexp
- value = value.pattern
- elif optdict.get("type") == "yn":
- value = "yes" if value else "no"
- elif isinstance(value, str) and value.isspace():
- value = "'%s'" % value
- return value
-
-
-def format_section(stream, section, options, doc=None):
- """format an options section using the INI format"""
- if doc:
- print(_comment(doc), file=stream)
- print("[%s]" % section, file=stream)
- _ini_format(stream, options)
-
-
-def _ini_format(stream, options):
- """format options using the INI format"""
- for optname, optdict, value in options:
- value = _format_option_value(optdict, value)
- help_opt = optdict.get("help")
- if help_opt:
- help_opt = normalize_text(help_opt, line_len=79, indent="# ")
- print(file=stream)
- print(help_opt, file=stream)
- else:
- print(file=stream)
- if value is None:
- print("#%s=" % optname, file=stream)
- else:
- value = str(value).strip()
- if re.match(r"^([\w-]+,)+[\w-]+$", str(value)):
- separator = "\n " + " " * len(optname)
- value = separator.join(x + "," for x in str(value).split(","))
- # remove trailing ',' from last element of the list
- value = value[:-1]
- print("%s=%s" % (optname, value), file=stream)