diff options
Diffstat (limited to 'venv/Lib/site-packages/pylint/extensions')
26 files changed, 2193 insertions, 0 deletions
diff --git a/venv/Lib/site-packages/pylint/extensions/__init__.py b/venv/Lib/site-packages/pylint/extensions/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__init__.py 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 Binary files differnew file mode 100644 index 0000000..03323e7 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/__init__.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..271e216 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/_check_docs_utils.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..bb50903 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/bad_builtin.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..cd3cd71 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/broad_try_clause.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..9730100 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/check_docs.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..030378b --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/check_elif.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..83eaae3 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/comparetozero.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..3d447e1 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/docparams.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..e6d0d7d --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/docstyle.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..f5f4892 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/emptystring.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..cb64a4d --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/mccabe.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..f099683 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/overlapping_exceptions.cpython-37.pyc 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 Binary files differnew file mode 100644 index 0000000..eb897a3 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/__pycache__/redefined_variable_type.cpython-37.pyc diff --git a/venv/Lib/site-packages/pylint/extensions/_check_docs_utils.py b/venv/Lib/site-packages/pylint/extensions/_check_docs_utils.py new file mode 100644 index 0000000..fe1603f --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/_check_docs_utils.py @@ -0,0 +1,792 @@ +# -*- 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 new file mode 100644 index 0000000..754c409 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/bad_builtin.py @@ -0,0 +1,69 @@ +# 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 new file mode 100644 index 0000000..9a61fb6 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/broad_try_clause.py @@ -0,0 +1,59 @@ +# -*- 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 new file mode 100644 index 0000000..7f7f643 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/check_docs.py @@ -0,0 +1,23 @@ +# 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 new file mode 100644 index 0000000..67555b1 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/check_elif.py @@ -0,0 +1,77 @@ +# -*- 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 new file mode 100644 index 0000000..e31f488 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/comparetozero.py @@ -0,0 +1,74 @@ +# -*- 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 new file mode 100644 index 0000000..d5a15a4 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/docparams.py @@ -0,0 +1,536 @@ +# -*- 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 new file mode 100644 index 0000000..36f506f --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/docstyle.py @@ -0,0 +1,89 @@ +# -*- 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 new file mode 100644 index 0000000..04021d5 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/emptystring.py @@ -0,0 +1,74 @@ +# -*- 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 new file mode 100644 index 0000000..cafac97 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/mccabe.py @@ -0,0 +1,196 @@ +# 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 new file mode 100644 index 0000000..be2208c --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/overlapping_exceptions.py @@ -0,0 +1,88 @@ +# -*- 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 new file mode 100644 index 0000000..cfe4754 --- /dev/null +++ b/venv/Lib/site-packages/pylint/extensions/redefined_variable_type.py @@ -0,0 +1,116 @@ +# -*- 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)) |