Hello community, here is the log from the commit of package python-astroid for openSUSE:Factory checked in at 2018-07-21 10:07:38 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-astroid (Old) and /work/SRC/openSUSE:Factory/.python-astroid.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-astroid" Sat Jul 21 10:07:38 2018 rev:14 rq:623122 version:1.6.5 Changes: -------- --- /work/SRC/openSUSE:Factory/python-astroid/python-astroid.changes 2018-01-25 12:37:02.296473866 +0100 +++ /work/SRC/openSUSE:Factory/.python-astroid.new/python-astroid.changes 2018-07-21 10:07:40.779205686 +0200 @@ -1,0 +2,7 @@ +Mon Jul 16 11:53:57 UTC 2018 - tchva...@suse.com + +- Version update to 1.6.5: + * Many various bugfixes making the pylint tests pass + * For details see ChangeLog + +------------------------------------------------------------------- Old: ---- astroid-1.6.1.tar.gz New: ---- astroid-1.6.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-astroid.spec ++++++ --- /var/tmp/diff_new_pack.puZpj8/_old 2018-07-21 10:07:41.555205509 +0200 +++ /var/tmp/diff_new_pack.puZpj8/_new 2018-07-21 10:07:41.555205509 +0200 @@ -18,19 +18,18 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define oldpython python -# Disabled for now wrt issue https://github.com/PyCQA/astroid/issues/439 -%bcond_with test %bcond_without python2 Name: python-astroid -Version: 1.6.1 +Version: 1.6.5 Release: 0 Summary: Rebuild a new abstract syntax tree from Python's ast -License: LGPL-2.1+ +License: LGPL-2.1-or-later Group: Development/Libraries/Python -Url: https://github.com/pycqa/astroid +URL: https://github.com/pycqa/astroid Source: https://files.pythonhosted.org/packages/source/a/astroid/astroid-%{version}.tar.gz Source1: pytest.ini BuildRequires: %{python_module lazy-object-proxy} +BuildRequires: %{python_module pytest-runner} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} BuildRequires: %{python_module six} @@ -70,6 +69,9 @@ %prep %setup -q -n astroid-%{version} +# FIXME: with next release verify again +# The numpy checks are broken on py3 completely +rm -f astroid/tests/unittest_brain_numpy.py %build %python_build @@ -80,14 +82,13 @@ %python_expand rm -rf %{buildroot}%{$python_sitelib}/astroid/tests %python_expand %fdupes %{buildroot}%{$python_sitelib} -%if %{with test} %check cp %{SOURCE1} . %python_exec -m pytest -s -%endif %files %{python_files} -%doc COPYING COPYING.LESSER ChangeLog README.rst +%license COPYING COPYING.LESSER +%doc ChangeLog README.rst %{python_sitelib}/astroid/ %{python_sitelib}/astroid-*.egg-info ++++++ astroid-1.6.1.tar.gz -> astroid-1.6.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/ChangeLog new/astroid-1.6.5/ChangeLog --- old/astroid-1.6.1/ChangeLog 2018-01-23 10:32:09.000000000 +0100 +++ new/astroid-1.6.5/ChangeLog 2018-06-06 17:01:12.000000000 +0200 @@ -1,6 +1,70 @@ Change log for the astroid package (used to be astng) ===================================================== +2018-06-06 -- 1.6.5 + + * Don't propagate Uninferable objects when inferring BinOps + + Close PyCQA/pylint#2059 + + * Protect against passing lookup_class to non-class proxied objects + + In some cases the _proxied object points to another Instance, not to the + Class of an Instance node (usually this happens with enum and with our + hardcoded inference support for this library). Instead of getting a TypeError, + we check before if the _proxied matches what we expect. + + Found by #2080 + + +2018-05-15 -- 1.6.4 + + * Skip non-attrs specific attributes in attr wrapped classes. Close PyCQA/pylint#2055 + + * Add brain tip for numpy.sum. Close PyCQA/pylint#1558 + + * deque.rotate has a default parameter. Close PyCQA/pylint#2013 + +2018-04-05 -- 1.6.3 + + * Fixes nested namespace package import for old-style namespace packages + + * Use .path for inferring a module's __path__ attribute. Close #528 + + * Improve the six urllib functions for Python 2 by setting them as instance attributes + + Because they were at the class level, we were considering them BoundMethods, resulting + in a too-many-function-args error when calling these functions. + Close PyCQA/pylint#1965 + +2018-03-16 -- 1.6.2 + + * Fix submodule imports from six + + Close PYCQA/pylint#1640 + + * Enhancement of brain_numpy by adding different types from + numpy.core.numerictypes + + * Fix RecursionError for augmented assign + + Close #437, #447, #313, PyCQA/pylint#1642, PyCQA/pylint#1805, PyCQA/pylint#1854, PyCQA/pylint#1452 + + + * Stop most inference tip overwrites from happening by using + predicates on existing inference_tip transforms. + + Close #472 + + * Add missing attrs special attribute + + Close PyCQA/pylint#1884 + + * Fix ``contextlib.contextmanager`` inference for nested context managers + + Close #1699 + + 2018-01-23 -- 1.6.1 * Fix a crash when __annotations__ access a parent's __init__ that does not have arguments @@ -1384,6 +1448,3 @@ longer be maintained (this explains that this package is starting with the 0.13 version number, since the fork occurs with the version released in logilab-common 0.12). - - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/PKG-INFO new/astroid-1.6.5/PKG-INFO --- old/astroid-1.6.1/PKG-INFO 2018-01-23 10:32:42.000000000 +0100 +++ new/astroid-1.6.5/PKG-INFO 2018-06-06 17:07:55.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: astroid -Version: 1.6.1 +Version: 1.6.5 Summary: A abstract syntax tree for Python with inference support. Home-page: https://github.com/PyCQA/astroid Author: Python Code Quality Authority diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/__init__.py new/astroid-1.6.5/astroid/__init__.py --- old/astroid-1.6.1/astroid/__init__.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/__init__.py 2018-06-06 16:59:26.000000000 +0200 @@ -97,18 +97,37 @@ # pylint: disable=no-member; github.com/pycqa/astroid/126 return self.regexp.search(node.as_string()) -def inference_tip(infer_function): +def inference_tip(infer_function, raise_on_overwrite=False): """Given an instance specific inference function, return a function to be given to MANAGER.register_transform to set this inference function. + :param bool raise_on_overwrite: Raise an `InferenceOverwriteError` + if the inference tip will overwrite another. Used for debugging + Typical usage .. sourcecode:: python MANAGER.register_transform(Call, inference_tip(infer_named_tuple), predicate) + + .. Note:: + + Using an inference tip will override + any previously set inference tip for the given + node. Use a predicate in the transform to prevent + excess overwrites. """ def transform(node, infer_function=infer_function): + if (raise_on_overwrite + and node._explicit_inference is not None + and node._explicit_inference is not infer_function): + raise InferenceOverwriteError( + "Inference already set to {existing_inference}. " + "Trying to overwrite with {new_inference} for {node}" + .format(existing_inference=infer_function, + new_inference=node._explicit_inference, + node=node)) node._explicit_inference = infer_function return node return transform diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/__pkginfo__.py new/astroid-1.6.5/astroid/__pkginfo__.py --- old/astroid-1.6.1/astroid/__pkginfo__.py 2018-01-23 10:32:09.000000000 +0100 +++ new/astroid-1.6.5/astroid/__pkginfo__.py 2018-06-06 17:01:12.000000000 +0200 @@ -16,7 +16,7 @@ modname = 'astroid' -version = '1.6.1' +version = '1.6.5' numversion = tuple(map(int, version.split('.'))) extras_require = {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/bases.py new/astroid-1.6.5/astroid/bases.py --- old/astroid-1.6.1/astroid/bases.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/bases.py 2018-06-06 16:59:26.000000000 +0200 @@ -170,10 +170,13 @@ for stmt in _infer_stmts(self._wrap_attr(get_attr, context), context, frame=self): yield stmt - except exceptions.AttributeInferenceError: + except exceptions.AttributeInferenceError as error: try: # fallback to class.igetattr since it has some logic to handle # descriptors + # But only if the _proxied is the Class. + if self._proxied.__class__.__name__ != 'ClassDef': + util.reraise(exceptions.InferenceError(**vars(error))) attrs = self._proxied.igetattr(name, context, class_context=False) for stmt in self._wrap_attr(attrs, context): yield stmt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/brain/brain_attrs.py new/astroid-1.6.5/astroid/brain/brain_attrs.py --- old/astroid-1.6.1/astroid/brain/brain_attrs.py 2018-01-23 10:32:09.000000000 +0100 +++ new/astroid-1.6.5/astroid/brain/brain_attrs.py 2018-06-06 16:59:26.000000000 +0200 @@ -30,12 +30,18 @@ """Given that the ClassNode has an attr decorator, rewrite class attributes as instance attributes """ + # Astroid can't infer this attribute properly + # Prevents https://github.com/PyCQA/pylint/issues/1884 + node.locals["__attrs_attrs__"] = [astroid.Unknown(parent=node.body)] + for cdefbodynode in node.body: if not isinstance(cdefbodynode, astroid.Assign): continue if isinstance(cdefbodynode.value, astroid.Call): if cdefbodynode.value.func.as_string() != ATTR_IB: continue + else: + continue for target in cdefbodynode.targets: rhs_node = astroid.Unknown( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/brain/brain_builtin_inference.py new/astroid-1.6.5/astroid/brain/brain_builtin_inference.py --- old/astroid-1.6.1/astroid/brain/brain_builtin_inference.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/brain/brain_builtin_inference.py 2018-06-06 16:59:26.000000000 +0200 @@ -488,14 +488,24 @@ def _infer_object__new__decorator(node, context=None): + # Instantiate class immediately + # since that's what @object.__new__ does + return iter((node.instantiate_class(),)) + + +def _infer_object__new__decorator_check(node): + """Predicate before inference_tip + + Check if the given ClassDef has a @object.__new__ decorator + """ if not node.decorators: - raise UseInferenceDefault + return False for decorator in node.decorators.nodes: if isinstance(decorator, nodes.Attribute): if decorator.as_string() == OBJECT_DUNDER_NEW: - return iter((node.instantiate_class(),)) - raise UseInferenceDefault + return True + return False # Builtins inference @@ -515,5 +525,6 @@ # Infer object.__new__ calls MANAGER.register_transform( nodes.ClassDef, - inference_tip(_infer_object__new__decorator) + inference_tip(_infer_object__new__decorator), + _infer_object__new__decorator_check ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/brain/brain_collections.py new/astroid-1.6.5/astroid/brain/brain_collections.py --- old/astroid-1.6.1/astroid/brain/brain_collections.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/brain/brain_collections.py 2018-06-06 16:59:26.000000000 +0200 @@ -39,7 +39,7 @@ def popleft(self): pass def remove(self, value): pass def reverse(self): pass - def rotate(self, n): pass + def rotate(self, n=1): pass def __iter__(self): return self def __reversed__(self): return self.iterable[::-1] def __getitem__(self, index): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/brain/brain_numpy.py new/astroid-1.6.5/astroid/brain/brain_numpy.py --- old/astroid-1.6.1/astroid/brain/brain_numpy.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/brain/brain_numpy.py 2018-06-06 16:59:26.000000000 +0200 @@ -146,6 +146,48 @@ def true_divide(x1, x2, {opt_args:s}): pass '''.format(opt_args=ufunc_optional_keyword_arguments)) + +def numpy_core_numerictypes_transform(): + return astroid.parse(''' + # different types defined in numerictypes.py + uint16 = type('uint16') + uint32 = type('uint32') + uint64 = type('uint64') + int128 = type('int128') + uint128 = type('uint128') + float16 = type('float16') + float32 = type('float32') + float64 = type('float64') + float80 = type('float80') + float96 = type('float96') + float128 = type('float128') + float256 = type('float256') + complex32 = type('complex32') + complex64 = type('complex64') + complex128 = type('complex128') + complex160 = type('complex160') + complex192 = type('complex192') + complex256 = type('complex256') + complex512 = type('complex512') + timedelta64 = type('timedelta64') + datetime64 = type('datetime64') + unicode_ = type('unicode_') + string_ = type('string_') + object_ = type('object_') + ''') + + +def numpy_funcs(): + return astroid.parse(''' + import builtins + def sum(a, axis=None, dtype=None, out=None, keepdims=None): + return builtins.sum(a) + ''') + + astroid.register_module_extender(astroid.MANAGER, 'numpy.core.umath', numpy_core_umath_transform) astroid.register_module_extender(astroid.MANAGER, 'numpy.random.mtrand', numpy_random_mtrand_transform) +astroid.register_module_extender(astroid.MANAGER, 'numpy.core.numerictypes', + numpy_core_numerictypes_transform) +astroid.register_module_extender(astroid.MANAGER, 'numpy', numpy_funcs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/brain/brain_six.py new/astroid-1.6.5/astroid/brain/brain_six.py --- old/astroid-1.6.1/astroid/brain/brain_six.py 2018-01-23 10:32:09.000000000 +0100 +++ new/astroid-1.6.5/astroid/brain/brain_six.py 2018-06-06 16:59:26.000000000 +0200 @@ -11,7 +11,7 @@ from astroid import MANAGER, register_module_extender from astroid.builder import AstroidBuilder -from astroid.exceptions import AstroidBuildingError, InferenceError +from astroid.exceptions import AstroidBuildingError, InferenceError, AttributeInferenceError from astroid import nodes @@ -81,31 +81,33 @@ reload_module = reload class UrllibParse(object): - import urlparse as _urlparse - import urllib as _urllib - ParseResult = _urlparse.ParseResult - SplitResult = _urlparse.SplitResult - parse_qs = _urlparse.parse_qs - parse_qsl = _urlparse.parse_qsl - urldefrag = _urlparse.urldefrag - urljoin = _urlparse.urljoin - urlparse = _urlparse.urlparse - urlsplit = _urlparse.urlsplit - urlunparse = _urlparse.urlunparse - urlunsplit = _urlparse.urlunsplit - quote = _urllib.quote - quote_plus = _urllib.quote_plus - unquote = _urllib.unquote - unquote_plus = _urllib.unquote_plus - urlencode = _urllib.urlencode - splitquery = _urllib.splitquery - splittag = _urllib.splittag - splituser = _urllib.splituser - uses_fragment = _urlparse.uses_fragment - uses_netloc = _urlparse.uses_netloc - uses_params = _urlparse.uses_params - uses_query = _urlparse.uses_query - uses_relative = _urlparse.uses_relative + def __init__(self): + import urlparse as _urlparse + import urllib as _urllib + + self.ParseResult = _urlparse.ParseResult + self.SplitResult = _urlparse.SplitResult + self.parse_qs = _urlparse.parse_qs + self.parse_qsl = _urlparse.parse_qsl + self.urldefrag = _urlparse.urldefrag + self.urljoin = _urlparse.urljoin + self.urlparse = _urlparse.urlparse + self.urlsplit = _urlparse.urlsplit + self.urlunparse = _urlparse.urlunparse + self.urlunsplit = _urlparse.urlunsplit + self.quote = _urllib.quote + self.quote_plus = _urllib.quote_plus + self.unquote = _urllib.unquote + self.unquote_plus = _urllib.unquote_plus + self.urlencode = _urllib.urlencode + self.splitquery = _urllib.splitquery + self.splittag = _urllib.splittag + self.splituser = _urllib.splituser + self.uses_fragment = _urlparse.uses_fragment + self.uses_netloc = _urlparse.uses_netloc + self.uses_params = _urlparse.uses_params + self.uses_query = _urlparse.uses_query + self.uses_relative = _urlparse.uses_relative class UrllibError(object): import urllib2 as _urllib2 @@ -118,40 +120,41 @@ pass class UrllibRequest(object): - import urlparse as _urlparse - import urllib2 as _urllib2 - import urllib as _urllib - urlopen = _urllib2.urlopen - install_opener = _urllib2.install_opener - build_opener = _urllib2.build_opener - pathname2url = _urllib.pathname2url - url2pathname = _urllib.url2pathname - getproxies = _urllib.getproxies - Request = _urllib2.Request - OpenerDirector = _urllib2.OpenerDirector - HTTPDefaultErrorHandler = _urllib2.HTTPDefaultErrorHandler - HTTPRedirectHandler = _urllib2.HTTPRedirectHandler - HTTPCookieProcessor = _urllib2.HTTPCookieProcessor - ProxyHandler = _urllib2.ProxyHandler - BaseHandler = _urllib2.BaseHandler - HTTPPasswordMgr = _urllib2.HTTPPasswordMgr - HTTPPasswordMgrWithDefaultRealm = _urllib2.HTTPPasswordMgrWithDefaultRealm - AbstractBasicAuthHandler = _urllib2.AbstractBasicAuthHandler - HTTPBasicAuthHandler = _urllib2.HTTPBasicAuthHandler - ProxyBasicAuthHandler = _urllib2.ProxyBasicAuthHandler - AbstractDigestAuthHandler = _urllib2.AbstractDigestAuthHandler - HTTPDigestAuthHandler = _urllib2.HTTPDigestAuthHandler - ProxyDigestAuthHandler = _urllib2.ProxyDigestAuthHandler - HTTPHandler = _urllib2.HTTPHandler - HTTPSHandler = _urllib2.HTTPSHandler - FileHandler = _urllib2.FileHandler - FTPHandler = _urllib2.FTPHandler - CacheFTPHandler = _urllib2.CacheFTPHandler - UnknownHandler = _urllib2.UnknownHandler - HTTPErrorProcessor = _urllib2.HTTPErrorProcessor - urlretrieve = _urllib.urlretrieve - urlcleanup = _urllib.urlcleanup - proxy_bypass = _urllib.proxy_bypass + def __init__(self): + import urlparse as _urlparse + import urllib2 as _urllib2 + import urllib as _urllib + self.urlopen = _urllib2.urlopen + self.install_opener = _urllib2.install_opener + self.build_opener = _urllib2.build_opener + self.pathname2url = _urllib.pathname2url + self.url2pathname = _urllib.url2pathname + self.getproxies = _urllib.getproxies + self.Request = _urllib2.Request + self.OpenerDirector = _urllib2.OpenerDirector + self.HTTPDefaultErrorHandler = _urllib2.HTTPDefaultErrorHandler + self.HTTPRedirectHandler = _urllib2.HTTPRedirectHandler + self.HTTPCookieProcessor = _urllib2.HTTPCookieProcessor + self.ProxyHandler = _urllib2.ProxyHandler + self.BaseHandler = _urllib2.BaseHandler + self.HTTPPasswordMgr = _urllib2.HTTPPasswordMgr + self.HTTPPasswordMgrWithDefaultRealm = _urllib2.HTTPPasswordMgrWithDefaultRealm + self.AbstractBasicAuthHandler = _urllib2.AbstractBasicAuthHandler + self.HTTPBasicAuthHandler = _urllib2.HTTPBasicAuthHandler + self.ProxyBasicAuthHandler = _urllib2.ProxyBasicAuthHandler + self.AbstractDigestAuthHandler = _urllib2.AbstractDigestAuthHandler + self.HTTPDigestAuthHandler = _urllib2.HTTPDigestAuthHandler + self.ProxyDigestAuthHandler = _urllib2.ProxyDigestAuthHandler + self.HTTPHandler = _urllib2.HTTPHandler + self.HTTPSHandler = _urllib2.HTTPSHandler + self.FileHandler = _urllib2.FileHandler + self.FTPHandler = _urllib2.FTPHandler + self.CacheFTPHandler = _urllib2.CacheFTPHandler + self.UnknownHandler = _urllib2.UnknownHandler + self.HTTPErrorProcessor = _urllib2.HTTPErrorProcessor + self.urlretrieve = _urllib.urlretrieve + self.urlcleanup = _urllib.urlcleanup + self.proxy_bypass = _urllib.proxy_bypass urllib_parse = UrllibParse() urllib_error = UrllibError() @@ -187,7 +190,7 @@ import html.entities as html_entities import html.parser as html_parser import http.client as http_client - import http.server + import http.server as http_server BaseHTTPServer = CGIHTTPServer = SimpleHTTPServer = http.server import pickle as cPickle import queue @@ -218,7 +221,8 @@ import tkinter.filedialog as tkinter_tkfiledialog import tkinter.font as tkinter_font import tkinter.messagebox as tkinter_messagebox - import urllib.request + import urllib + import urllib.request as urllib_request import urllib.robotparser as urllib_robotparser import urllib.parse as urllib_parse import urllib.error as urllib_error @@ -241,10 +245,38 @@ def _six_fail_hook(modname): - if modname != 'six.moves': + """Fix six.moves imports due to the dynamic nature of this + class. + + Construct a psuedo-module which contains all the nessecary imports + for six + + :param modname: Name of failed module + :type modname: str + + :return: An astroid module + :rtype: nodes.Module + """ + + attribute_of = (modname != "six.moves" and + modname.startswith("six.moves")) + if modname != 'six.moves' and not attribute_of: raise AstroidBuildingError(modname=modname) module = AstroidBuilder(MANAGER).string_build(_IMPORTS) module.name = 'six.moves' + if attribute_of: + # Facilitate import of submodules in Moves + start_index = len(module.name) + attribute = modname[start_index:].lstrip(".").replace(".", "_") + try: + import_attr = module.getattr(attribute)[0] + except AttributeInferenceError: + raise AstroidBuildingError(modname=modname) + if isinstance(import_attr, nodes.Import): + submodule = MANAGER.ast_from_module_name(import_attr.names[0][0]) + return submodule + # Let dummy submodule imports pass through + # This will cause an Uninferable result, which is okay return module def transform_six_add_metaclass(node): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/brain/brain_typing.py new/astroid-1.6.5/astroid/brain/brain_typing.py --- old/astroid-1.6.1/astroid/brain/brain_typing.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/brain/brain_typing.py 2018-06-06 16:59:26.000000000 +0200 @@ -51,9 +51,6 @@ """Infer a subclass of typing.NamedTuple""" # Check if it has the corresponding bases - if not set(node.basenames) & TYPING_NAMEDTUPLE_BASENAMES: - raise UseInferenceDefault - annassigns_fields = [ annassign.target.name for annassign in node.body if isinstance(annassign, nodes.AnnAssign) @@ -69,6 +66,15 @@ return node.infer(context=context) +def has_namedtuple_base(node): + """Predicate for class inference tip + + :type node: ClassDef + :rtype: bool + """ + return set(node.basenames) & TYPING_NAMEDTUPLE_BASENAMES + + def looks_like_typing_namedtuple(node): func = node.func if isinstance(func, nodes.Attribute): @@ -83,7 +89,9 @@ inference_tip(infer_typing_namedtuple), looks_like_typing_namedtuple ) + MANAGER.register_transform( nodes.ClassDef, - inference_tip(infer_typing_namedtuple_class) + inference_tip(infer_typing_namedtuple_class), + has_namedtuple_base ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/context.py new/astroid-1.6.5/astroid/context.py --- old/astroid-1.6.1/astroid/context.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/context.py 2018-06-06 16:59:26.000000000 +0200 @@ -7,20 +7,43 @@ """Various context related utilities, including inference and call contexts.""" import contextlib +import copy import pprint class InferenceContext(object): + """Provide context for inference + + Store already inferred nodes to save time + Account for already visited nodes to infinite stop infinite recursion + """ + __slots__ = ('path', 'lookupname', 'callcontext', 'boundnode', 'inferred') def __init__(self, path=None, inferred=None): self.path = path or set() + """Path of visited nodes and their lookupname + :type: set(tuple(NodeNG, optional(str)))""" self.lookupname = None self.callcontext = None self.boundnode = None self.inferred = inferred or {} + """ + :type: dict(seq, seq) + + Inferred node contexts to their mapped results + Currently the key is (node, lookupname, callcontext, boundnode) + and the value is tuple of the inferred results + """ def push(self, node): + """Push node into inference path + + :return: True if node is already in context path else False + :rtype: bool + + Allows one to see if the given node has already + been looked at for this inference context""" name = self.lookupname if (node, name) in self.path: return True @@ -29,20 +52,27 @@ return False def clone(self): + """Clone inference path + + For example, each side of a binary operation (BinOp) + starts with the same context but diverge as each side is inferred + so the InferenceContext will need be cloned""" # XXX copy lookupname/callcontext ? - clone = InferenceContext(self.path, inferred=self.inferred) + clone = InferenceContext(copy.copy(self.path), inferred=self.inferred) clone.callcontext = self.callcontext clone.boundnode = self.boundnode return clone def cache_generator(self, key, generator): + """Cache result of generator into dictionary + + Used to cache inference results""" results = [] for result in generator: results.append(result) yield result self.inferred[key] = tuple(results) - return @contextlib.contextmanager def restore_path(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/decorators.py new/astroid-1.6.5/astroid/decorators.py --- old/astroid-1.6.1/astroid/decorators.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/decorators.py 2018-06-06 16:59:26.000000000 +0200 @@ -68,7 +68,11 @@ def path_wrapper(func): - """return the given infer function wrapped to handle the path""" + """return the given infer function wrapped to handle the path + + Used to stop inference if the node has already been looked + at for a given `InferenceContext` to prevent infinite recursion + """ # TODO: switch this to wrapt after the monkey-patching is fixed (ceridwen) @functools.wraps(func) def wrapped(node, context=None, _func=func, **kwargs): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/exceptions.py new/astroid-1.6.5/astroid/exceptions.py --- old/astroid-1.6.1/astroid/exceptions.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/exceptions.py 2018-06-06 16:59:26.000000000 +0200 @@ -198,6 +198,13 @@ """Raised when a TypeError would be expected in Python code.""" +class InferenceOverwriteError(AstroidError): + """Raised when an inference tip is overwritten + + Currently only used for debugging. + """ + + # Backwards-compatibility aliases OperationError = util.BadOperationMessage UnaryOperationError = util.BadUnaryOperationMessage diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/inference.py new/astroid-1.6.5/astroid/inference.py --- old/astroid-1.6.1/astroid/inference.py 2018-01-23 10:14:57.000000000 +0100 +++ new/astroid-1.6.5/astroid/inference.py 2018-06-06 16:59:26.000000000 +0200 @@ -496,6 +496,8 @@ methods = dunder_lookup.lookup(instance, method_name) method = methods[0] inferred = next(method.infer(context=context)) + if inferred is util.Uninferable: + raise exceptions.InferenceError return instance.infer_binary_op(opnode, op, other, context, inferred) @@ -713,12 +715,7 @@ yield util.Uninferable return - # TODO(cpopa): if we have A() * A(), trying to infer - # the rhs with the same context will result in an - # inference error, so we create another context for it. - # This is a bug which should be fixed in InferenceContext at some point. rhs_context = context.clone() - rhs_context.path = set() for rhs in self.value.infer(context=rhs_context): if rhs is util.Uninferable: # Don't know how to process this. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/interpreter/_import/spec.py new/astroid-1.6.5/astroid/interpreter/_import/spec.py --- old/astroid-1.6.1/astroid/interpreter/_import/spec.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/interpreter/_import/spec.py 2018-06-06 16:59:26.000000000 +0200 @@ -122,7 +122,7 @@ def find_module(self, modname, module_parts, processed, submodule_path): if processed: - return None + modname = '.'.join(processed + [modname]) if util.is_namespace(modname) and modname in sys.modules: submodule_path = sys.modules[modname].__path__ return ModuleSpec(name=modname, location='', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/interpreter/objectmodel.py new/astroid-1.6.5/astroid/interpreter/objectmodel.py --- old/astroid-1.6.1/astroid/interpreter/objectmodel.py 2018-01-23 10:31:11.000000000 +0100 +++ new/astroid-1.6.5/astroid/interpreter/objectmodel.py 2018-06-06 16:59:26.000000000 +0200 @@ -138,11 +138,17 @@ raise exceptions.AttributeInferenceError(target=self._instance, attribute='__path__') - path = os.path.dirname(self._instance.file) - path_obj = node_classes.Const(value=path, parent=self._instance) + if isinstance(self._instance.path, list): + path_objs = [ + node_classes.Const(value=path, parent=self._instance) + for path in self._instance.path + ] + else: + path = os.path.dirname(self._instance.path) + path_objs = [node_classes.Const(value=path, parent=self._instance)] container = node_classes.List(parent=self._instance) - container.postinit([path_obj]) + container.postinit(path_objs) return container diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/node_classes.py new/astroid-1.6.5/astroid/node_classes.py --- old/astroid-1.6.1/astroid/node_classes.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/node_classes.py 2018-06-06 16:59:26.000000000 +0200 @@ -636,7 +636,7 @@ for matching in child_node.nodes_of_class(klass, skip_klass): yield matching - def _infer_name(self, frame, name): + def _infer_name(self, frame, name): #pylint: disable=useless-return # overridden for ImportFrom, Import, Global, TryExcept and Arguments return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/protocols.py new/astroid-1.6.5/astroid/protocols.py --- old/astroid-1.6.1/astroid/protocols.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/protocols.py 2018-06-06 16:59:26.000000000 +0200 @@ -445,7 +445,10 @@ # Get the first yield point. If it has multiple yields, # then a RuntimeError will be raised. # TODO(cpopa): Handle flows. - yield_point = next(func.nodes_of_class(nodes.Yield), None) + possible_yield_points = func.nodes_of_class(nodes.Yield) + # Ignore yields in nested functions + yield_point = next((node for node in possible_yield_points + if node.scope() == func), None) if yield_point: if not yield_point.value: # TODO(cpopa): an empty yield. Should be wrapped to Const. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/scoped_nodes.py new/astroid-1.6.5/astroid/scoped_nodes.py --- old/astroid-1.6.1/astroid/scoped_nodes.py 2018-01-23 10:32:09.000000000 +0100 +++ new/astroid-1.6.5/astroid/scoped_nodes.py 2018-06-06 16:59:26.000000000 +0200 @@ -536,7 +536,7 @@ """ return self - def previous_sibling(self): + def previous_sibling(self): #pylint: disable=useless-return """The previous sibling statement. :returns: The previous sibling statement node. @@ -544,7 +544,7 @@ """ return - def next_sibling(self): + def next_sibling(self): #pylint: disable=useless-return """The next sibling statement node. :returns: The next sibling statement node. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/tests/testdata/python2/data/foogle_fax-0.12.5-py2.7-nspkg.pth new/astroid-1.6.5/astroid/tests/testdata/python2/data/foogle_fax-0.12.5-py2.7-nspkg.pth --- old/astroid-1.6.1/astroid/tests/testdata/python2/data/foogle_fax-0.12.5-py2.7-nspkg.pth 1970-01-01 01:00:00.000000000 +0100 +++ new/astroid-1.6.5/astroid/tests/testdata/python2/data/foogle_fax-0.12.5-py2.7-nspkg.pth 2018-06-03 10:47:15.000000000 +0200 @@ -0,0 +1,2 @@ +import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('foogle',));ie = os.path.exists(os.path.join(p,'__init__.py'));m = not ie and sys.modules.setdefault('foogle', types.ModuleType('foogle'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p) +import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('foogle','crank'));ie = os.path.exists(os.path.join(p,'__init__.py'));m = not ie and sys.modules.setdefault('foogle.crank', types.ModuleType('foogle.crank'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/tests/testdata/python3/data/foogle_fax-0.12.5-py2.7-nspkg.pth new/astroid-1.6.5/astroid/tests/testdata/python3/data/foogle_fax-0.12.5-py2.7-nspkg.pth --- old/astroid-1.6.1/astroid/tests/testdata/python3/data/foogle_fax-0.12.5-py2.7-nspkg.pth 1970-01-01 01:00:00.000000000 +0100 +++ new/astroid-1.6.5/astroid/tests/testdata/python3/data/foogle_fax-0.12.5-py2.7-nspkg.pth 2018-06-03 10:47:15.000000000 +0200 @@ -0,0 +1,2 @@ +import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('foogle',));ie = os.path.exists(os.path.join(p,'__init__.py'));m = not ie and sys.modules.setdefault('foogle', types.ModuleType('foogle'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p) +import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('foogle','crank'));ie = os.path.exists(os.path.join(p,'__init__.py'));m = not ie and sys.modules.setdefault('foogle.crank', types.ModuleType('foogle.crank'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/tests/unittest_brain.py new/astroid-1.6.5/astroid/tests/unittest_brain.py --- old/astroid-1.6.1/astroid/tests/unittest_brain.py 2018-01-23 10:32:09.000000000 +0100 +++ new/astroid-1.6.5/astroid/tests/unittest_brain.py 2018-06-06 16:59:26.000000000 +0200 @@ -316,9 +316,9 @@ if six.PY2: # In reality it's a function, but our implementations # transforms it into a method. - self.assertIsInstance(urljoin, astroid.BoundMethod) + self.assertIsInstance(urljoin, astroid.FunctionDef) self.assertEqual(urljoin.qname(), 'urlparse.urljoin') - self.assertIsInstance(urlencode, astroid.BoundMethod) + self.assertIsInstance(urlencode, astroid.FunctionDef) self.assertEqual(urlencode.qname(), 'urllib.urlencode') else: self.assertIsInstance(urljoin, nodes.FunctionDef) @@ -350,9 +350,9 @@ if six.PY2: # In reality it's a function, but our implementations # transforms it into a method. - self.assertIsInstance(urlopen, astroid.BoundMethod) + self.assertIsInstance(urlopen, astroid.FunctionDef) self.assertEqual(urlopen.qname(), 'urllib2.urlopen') - self.assertIsInstance(urlretrieve, astroid.BoundMethod) + self.assertIsInstance(urlretrieve, astroid.FunctionDef) self.assertEqual(urlretrieve.qname(), 'urllib.urlretrieve') else: self.assertIsInstance(urlopen, nodes.FunctionDef) @@ -373,6 +373,20 @@ qname = 'httplib.HTTPSConnection' self.assertEqual(inferred.qname(), qname) + @unittest.skipIf(six.PY2, + "The python 2 six brain uses dummy classes") + def test_from_submodule_imports(self): + """Make sure ulrlib submodules can be imported from + + See PyCQA/pylint#1640 for relevant issue + """ + ast_node = builder.extract_node(''' + from six.moves.urllib.parse import urlparse + urlparse #@ + ''') + inferred = next(ast_node.infer()) + self.assertIsInstance(inferred, nodes.FunctionDef) + @unittest.skipUnless(HAS_MULTIPROCESSING, 'multiprocesing is required for this test, but ' @@ -645,9 +659,26 @@ self.assertIn(attr, module) -class IOBrainTest(unittest.TestCase): +def streams_are_fine(): + """Check if streams are being overwritten, + for example, by pytest + + stream inference will not work if they are overwritten + + PY3 only + """ + import io + for stream in (sys.stdout, sys.stderr, sys.stdin): + if not isinstance(stream, io.IOBase): + return False + return True + - @unittest.skipUnless(six.PY3, 'Needs Python 3 io model') +class IOBrainTest(unittest.TestCase): + @unittest.skipUnless( + six.PY3 and streams_are_fine(), + "Needs Python 3 io model / doesn't work with plain pytest." + "use pytest -s for this test to work") def test_sys_streams(self): for name in {'stdout', 'stderr', 'stdin'}: node = astroid.extract_node(''' @@ -824,6 +855,36 @@ should_be_attribute = next(module.getattr('f')[0].infer()).getattr('d')[0] self.assertIsInstance(should_be_attribute, astroid.Unknown) + def test_special_attributes(self): + """Make sure special attrs attributes exist""" + + code = """ + import attr + + @attr.s + class Foo: + pass + Foo() + """ + foo_inst = next(astroid.extract_node(code).infer()) + [attr_node] = foo_inst.getattr("__attrs_attrs__") + # Prevents https://github.com/PyCQA/pylint/issues/1884 + assert isinstance(attr_node, nodes.Unknown) + + def test_dont_consider_assignments_but_without_attrs(self): + code = ''' + import attr + + class Cls: pass + @attr.s + class Foo: + temp = Cls() + temp.prop = 5 + bar_thing = attr.ib(default=temp) + Foo() + ''' + next(astroid.extract_node(code).infer()) + if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/tests/unittest_brain_numpy.py new/astroid-1.6.5/astroid/tests/unittest_brain_numpy.py --- old/astroid-1.6.1/astroid/tests/unittest_brain_numpy.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/tests/unittest_brain_numpy.py 2018-06-06 16:59:26.000000000 +0200 @@ -238,5 +238,32 @@ self.assertEqual(default_args_values, exact_kwargs_default_values) +@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") +class NumpyBrainCoreNumericTypesTest(SubTestWrapper): + """ + Test of all the missing types defined in numerictypes module. + """ + all_types = ['uint16', 'uint32', 'uint64', 'int128', 'uint128', + 'float16', 'float32', 'float64', 'float80', 'float96', + 'float128', 'float256', 'complex32', 'complex64', 'complex128', + 'complex160', 'complex192', 'complex256', 'complex512', + 'timedelta64', 'datetime64', 'unicode_', 'string_', 'object_'] + + def _inferred_numpy_attribute(self, attrib): + node = builder.extract_node(""" + import numpy.core.numerictypes as tested_module + missing_type = tested_module.{:s}""".format(attrib)) + return next(node.value.infer()) + + def test_numpy_core_types(self): + """ + Test that all defined types have ClassDef type. + """ + for typ in self.all_types: + with self.subTest(typ=typ): + inferred = self._inferred_numpy_attribute(typ) + self.assertIsInstance(inferred, nodes.ClassDef) + + if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/tests/unittest_inference.py new/astroid-1.6.5/astroid/tests/unittest_inference.py --- old/astroid-1.6.1/astroid/tests/unittest_inference.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/tests/unittest_inference.py 2018-06-06 16:59:26.000000000 +0200 @@ -2154,6 +2154,36 @@ self.assertRaises(InferenceError, next, module['other_decorators'].infer()) self.assertRaises(InferenceError, next, module['no_yield'].infer()) + def test_nested_contextmanager(self): + """Make sure contextmanager works with nested functions + + Previously contextmanager would retrieve + the first yield instead of the yield in the + proper scope + + Fixes https://github.com/PyCQA/pylint/issues/1746 + """ + code = """ + from contextlib import contextmanager + + @contextmanager + def outer(): + @contextmanager + def inner(): + yield 2 + yield inner + + with outer() as ctx: + ctx #@ + with ctx() as val: + val #@ + """ + context_node, value_node = extract_node(code) + value = next(value_node.infer()) + context = next(context_node.infer()) + assert isinstance(context, nodes.FunctionDef) + assert isinstance(value, nodes.Const) + def test_unary_op_leaks_stop_iteration(self): node = extract_node('+[] #@') self.assertEqual(util.Uninferable, next(node.infer())) @@ -4273,9 +4303,7 @@ self.assertIn('f', site.duplicated_keywords) -@unittest.expectedFailure class ObjectDunderNewTest(unittest.TestCase): - def test_object_dunder_new_is_inferred_if_decorator(self): node = extract_node(''' @object.__new__ @@ -4286,5 +4314,24 @@ self.assertIsInstance(inferred, Instance) +def test_augassign_recursion(): + """Make sure inference doesn't throw a RecursionError + + Regression test for augmented assign dropping context.path + causing recursion errors + + """ + # infinitely recurses in python + code = """ + def rec(): + a = 0 + a += rec() + return a + rec() + """ + cls_node = extract_node(code) + assert next(cls_node.infer()) is util.Uninferable + + if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid/tests/unittest_manager.py new/astroid-1.6.5/astroid/tests/unittest_manager.py --- old/astroid-1.6.1/astroid/tests/unittest_manager.py 2018-01-07 11:53:49.000000000 +0100 +++ new/astroid-1.6.5/astroid/tests/unittest_manager.py 2018-06-06 16:59:26.000000000 +0200 @@ -138,6 +138,17 @@ del pkg_resources._namespace_packages['foogle'] # pylint: disable=no-member sys.modules.pop('foogle') + def test_nested_namespace_import(self): + pth = 'foogle_fax-0.12.5-py2.7-nspkg.pth' + site.addpackage(resources.RESOURCE_PATH, pth, []) + pkg_resources._namespace_packages['foogle'] = ['foogle.crank'] # pylint: disable=no-member + pkg_resources._namespace_packages['foogle.crank'] = [] # pylint: disable=no-member + try: + self.manager.ast_from_module_name('foogle.crank') + finally: + del pkg_resources._namespace_packages['foogle'] # pylint: disable=no-member + sys.modules.pop('foogle') + def test_namespace_and_file_mismatch(self): filepath = unittest.__file__ ast = self.manager.ast_from_file(filepath) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid.egg-info/PKG-INFO new/astroid-1.6.5/astroid.egg-info/PKG-INFO --- old/astroid-1.6.1/astroid.egg-info/PKG-INFO 2018-01-23 10:32:41.000000000 +0100 +++ new/astroid-1.6.5/astroid.egg-info/PKG-INFO 2018-06-06 17:07:54.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: astroid -Version: 1.6.1 +Version: 1.6.5 Summary: A abstract syntax tree for Python with inference support. Home-page: https://github.com/PyCQA/astroid Author: Python Code Quality Authority diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/astroid.egg-info/SOURCES.txt new/astroid-1.6.5/astroid.egg-info/SOURCES.txt --- old/astroid-1.6.1/astroid.egg-info/SOURCES.txt 2018-01-23 10:32:41.000000000 +0100 +++ new/astroid-1.6.5/astroid.egg-info/SOURCES.txt 2018-06-06 17:07:54.000000000 +0200 @@ -95,6 +95,7 @@ astroid/tests/testdata/python2/data/all.py astroid/tests/testdata/python2/data/descriptor_crash.py astroid/tests/testdata/python2/data/email.py +astroid/tests/testdata/python2/data/foogle_fax-0.12.5-py2.7-nspkg.pth astroid/tests/testdata/python2/data/format.py astroid/tests/testdata/python2/data/invalid_encoding.py astroid/tests/testdata/python2/data/joined_strings.py @@ -153,6 +154,7 @@ astroid/tests/testdata/python3/data/all.py astroid/tests/testdata/python3/data/descriptor_crash.py astroid/tests/testdata/python3/data/email.py +astroid/tests/testdata/python3/data/foogle_fax-0.12.5-py2.7-nspkg.pth astroid/tests/testdata/python3/data/format.py astroid/tests/testdata/python3/data/invalid_encoding.py astroid/tests/testdata/python3/data/joined_strings.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/setup.cfg new/astroid-1.6.5/setup.cfg --- old/astroid-1.6.1/setup.cfg 2018-01-23 10:32:42.000000000 +0100 +++ new/astroid-1.6.5/setup.cfg 2018-06-06 17:07:55.000000000 +0200 @@ -1,8 +1,11 @@ [wheel] universal = 1 +[tool:pytest] +python_files = unittest_* test_*.py +testpaths = astroid/tests + [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/astroid-1.6.1/tox.ini new/astroid-1.6.5/tox.ini --- old/astroid-1.6.1/tox.ini 2018-01-23 10:32:09.000000000 +0100 +++ new/astroid-1.6.5/tox.ini 2018-06-06 16:59:26.000000000 +0200 @@ -25,7 +25,11 @@ COVERAGE_FILE = {toxinidir}/.coverage.{envname} commands = - python -Wi -m coverage run -m unittest {posargs: discover -s astroid/tests -p "unittest*.py"} + ; --pyargs is needed so the directory astroid doesn't shadow the tox + ; installed astroid package + ; This is important for tests' test data which create files + ; inside the package + python -Wi {envsitepackagesdir}/coverage run -m pytest --pyargs astroid {posargs:} ; Transform absolute path to relative path ; for compatibility with coveralls.io and fix 'source not available' error. ; If you can find a cleaner way is welcome