diff options
Diffstat (limited to 'venv/Lib/site-packages/pylint/checkers/python3.py')
-rw-r--r-- | venv/Lib/site-packages/pylint/checkers/python3.py | 1398 |
1 files changed, 0 insertions, 1398 deletions
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)) |