From b0ad5a1c36354104d7d34627bc985f773fd89122 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Tue, 26 Feb 2019 15:08:48 +0100 Subject: [PATCH 01/40] Goes back to pass instead of return any for randint function. Declare zeros_like function (pass) and filter tuple for type inferred for a call to zeros_like --- astroid/brain/brain_numpy.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index b7d4df0a54..1d0e42f92d 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -43,7 +43,8 @@ def permutation(x): return any def poisson(lam=1.0, size=None): return any def power(a, size=None): return any def rand(*args): return any - def randint(low, high=None, size=None, dtype='l'): return any + def randint(low, high=None, size=None, dtype='l'): pass + def zeros_like(a, dtype=None, order='K', subok=True): pass def randn(*args): return any def random_integers(low, high=None, size=None): return any def random_sample(size=None): return any @@ -545,6 +546,12 @@ def _replace_numpy_function_infer_call_result(node, context=None): functools.partial(_looks_like_numpy_function, "array", "numpy.core.records"), ) +astroid.MANAGER.register_transform( + astroid.FunctionDef, + _replace_numpy_function_infer_call_result, + functools.partial(_looks_like_numpy_function, "zeros_like", "numpy.core.numeric"), +) + astroid.register_module_extender( astroid.MANAGER, "numpy.core.umath", numpy_core_umath_transform ) From 919f938df5ac1eb1e4f95322a585f1ff1cc72c3c Mon Sep 17 00:00:00 2001 From: hippo91 Date: Tue, 26 Feb 2019 15:26:20 +0100 Subject: [PATCH 02/40] Removing declaration of zeros_like (pass). Filtering tuple and list from types inferred by call to full_like and ones_like --- astroid/brain/brain_numpy.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index 1d0e42f92d..919c9607f1 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -44,7 +44,6 @@ def poisson(lam=1.0, size=None): return any def power(a, size=None): return any def rand(*args): return any def randint(low, high=None, size=None, dtype='l'): pass - def zeros_like(a, dtype=None, order='K', subok=True): pass def randn(*args): return any def random_integers(low, high=None, size=None): return any def random_sample(size=None): return any @@ -552,6 +551,18 @@ def _replace_numpy_function_infer_call_result(node, context=None): functools.partial(_looks_like_numpy_function, "zeros_like", "numpy.core.numeric"), ) +astroid.MANAGER.register_transform( + astroid.FunctionDef, + _replace_numpy_function_infer_call_result, + functools.partial(_looks_like_numpy_function, "full_like", "numpy.core.numeric"), +) + +astroid.MANAGER.register_transform( + astroid.FunctionDef, + _replace_numpy_function_infer_call_result, + functools.partial(_looks_like_numpy_function, "ones_like", "numpy.core.numeric"), +) + astroid.register_module_extender( astroid.MANAGER, "numpy.core.umath", numpy_core_umath_transform ) From 0e142fe1d782144e437ec9253cffc8a727ce3432 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Tue, 26 Feb 2019 21:13:07 +0100 Subject: [PATCH 03/40] Add transforms to define return type of numpy.zeros_like et numpy.linspace functions --- astroid/brain/brain_numpy.py | 37 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index 919c9607f1..b24326c80d 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -43,7 +43,7 @@ def permutation(x): return any def poisson(lam=1.0, size=None): return any def power(a, size=None): return any def rand(*args): return any - def randint(low, high=None, size=None, dtype='l'): pass + def randint(low, high=None, size=None, dtype='l'): return any def randn(*args): return any def random_integers(low, high=None, size=None): return any def random_sample(size=None): return any @@ -471,6 +471,23 @@ class int64(signedinteger): pass """ ) +def numpy_core_numeric_transform(): + return astroid.parse( + """ + # different functions defined in numeric.py + import numpy + def zeros_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) + """ + ) + +def numpy_core_function_base_transform(): + return astroid.parse( + """ + # different functions defined in numeric.py + import numpy + def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): return numpy.ndarray((0, 0)) + """ + ) def numpy_funcs(): return astroid.parse( @@ -551,18 +568,6 @@ def _replace_numpy_function_infer_call_result(node, context=None): functools.partial(_looks_like_numpy_function, "zeros_like", "numpy.core.numeric"), ) -astroid.MANAGER.register_transform( - astroid.FunctionDef, - _replace_numpy_function_infer_call_result, - functools.partial(_looks_like_numpy_function, "full_like", "numpy.core.numeric"), -) - -astroid.MANAGER.register_transform( - astroid.FunctionDef, - _replace_numpy_function_infer_call_result, - functools.partial(_looks_like_numpy_function, "ones_like", "numpy.core.numeric"), -) - astroid.register_module_extender( astroid.MANAGER, "numpy.core.umath", numpy_core_umath_transform ) @@ -572,4 +577,10 @@ def _replace_numpy_function_infer_call_result(node, context=None): astroid.register_module_extender( astroid.MANAGER, "numpy.core.numerictypes", numpy_core_numerictypes_transform ) +astroid.register_module_extender( + astroid.MANAGER, "numpy.core.numeric", numpy_core_numeric_transform +) +astroid.register_module_extender( + astroid.MANAGER, "numpy.core.function_base", numpy_core_function_base_transform +) astroid.register_module_extender(astroid.MANAGER, "numpy", numpy_funcs) From 0f7d210e5459504cbede3fb7d76cc1a510cc186f Mon Sep 17 00:00:00 2001 From: hippo91 Date: Tue, 26 Feb 2019 21:14:18 +0100 Subject: [PATCH 04/40] Add a test to ensure that numpy functions calls are infered as numpy arrays --- astroid/tests/unittest_brain_numpy.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index d3eae9cc09..e6650539ff 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -18,6 +18,7 @@ from astroid import builder from astroid import nodes from astroid import node_classes +from astroid import bases class SubTestWrapper(unittest.TestCase): @@ -624,6 +625,9 @@ class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): """ Test that calls to numpy functions returning arrays are correctly inferred """ + numpy_functions = (("array", "[1, 2]"), + ("linspace", "1, 100"), + ('zeros_like', "[1, 2]")) def _inferred_numpy_func_call(self, func_name, *func_args): node = builder.extract_node( @@ -637,11 +641,21 @@ def _inferred_numpy_func_call(self, func_name, *func_args): ) return node.infer() + def test_numpy_function_calls_inferred_as_ndarray(self): + """ + Test that some calls to numpy functions are inferred as numpy.ndarray + """ + licit_array_types = ('numpy.core.numerictypes.ndarray', 'numpy.core.records.recarray') + for func_ in self.numpy_functions: + with self.subTest(typ=func_): + self.assertTrue(any(isinstance(inferred, bases.Instance) and inferred.pytype() in licit_array_types + for inferred in self._inferred_numpy_func_call(*func_))) + def test_numpy_function_calls_not_inferred_as_list(self): """ Test that some calls to numpy functions are not inferred as list nor tuple """ - for func_ in (("array", "[1, 2]"),): + for func_ in self.numpy_functions: with self.subTest(typ=func_): for inferred in self._inferred_numpy_func_call(*func_): self.assertFalse(isinstance(inferred, node_classes.List)) @@ -650,7 +664,7 @@ def test_numpy_function_calls_not_inferred_as_tuple(self): """ Test that some calls to numpy functions are not inferred as list nor tuple """ - for func_ in (("array", "(1, 2)"), ("linspace", "1, 100")): + for func_ in self.numpy_functions: with self.subTest(typ=func_): for inferred in self._inferred_numpy_func_call(*func_): self.assertFalse(isinstance(inferred, node_classes.Tuple)) From effaf553234844f52630caef8732521489676912 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 23 Mar 2019 15:15:12 +0100 Subject: [PATCH 05/40] Add a definition for randint function. Move definition of class ndarray from numpy_core_numerictypes_transform function to infer_numpy_ndarray which is used a inference_tip. Add a _looks_like_numpy_ndarray function. Deletion of the register_transform for linspace function because it is correctly inferred with the inference_tip function for ndarray --- astroid/brain/brain_numpy.py | 189 ++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 94 deletions(-) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index a096e37b63..8ed6ac368e 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -43,7 +43,9 @@ def permutation(x): return uninferable def poisson(lam=1.0, size=None): return uninferable def power(a, size=None): return uninferable def rand(*args): return uninferable - def randint(low, high=None, size=None, dtype='l'): return uninferable + def randint(low, high=None, size=None, dtype='l'): + import numpy + return numpy.ndarray((1,1)) def randn(*args): return uninferable def random_integers(low, high=None, size=None): return uninferable def random_sample(size=None): return uninferable @@ -273,87 +275,6 @@ def __init__(self, obj, align=False, copy=False): def newbyteorder(self, new_order='S'): return uninferable def __neg__(self): return uninferable - - class ndarray(object): - def __init__(self, shape, dtype=float, buffer=None, offset=0, - strides=None, order=None): - self.T = None - self.base = None - self.ctypes = None - self.data = None - self.dtype = None - self.flags = None - self.flat = None - self.imag = None - self.itemsize = None - self.nbytes = None - self.ndim = None - self.real = None - self.shape = None - self.size = None - self.strides = None - - def __neg__(self): return uninferable - def __inv__(self): return uninferable - def __invert__(self): return uninferable - def all(self): return uninferable - def any(self): return uninferable - def argmax(self): return uninferable - def argmin(self): return uninferable - def argpartition(self): return uninferable - def argsort(self): return uninferable - def astype(self): return uninferable - def byteswap(self): return uninferable - def choose(self): return uninferable - def clip(self): return uninferable - def compress(self): return uninferable - def conj(self): return uninferable - def conjugate(self): return uninferable - def copy(self): return uninferable - def cumprod(self): return uninferable - def cumsum(self): return uninferable - def diagonal(self): return uninferable - def dot(self): return uninferable - def dump(self): return uninferable - def dumps(self): return uninferable - def fill(self): return uninferable - def flatten(self): return uninferable - def getfield(self): return uninferable - def item(self): return uninferable - def itemset(self): return uninferable - def max(self): return uninferable - def mean(self): return uninferable - def min(self): return uninferable - def newbyteorder(self): return uninferable - def nonzero(self): return uninferable - def partition(self): return uninferable - def prod(self): return uninferable - def ptp(self): return uninferable - def put(self): return uninferable - def ravel(self): return uninferable - def repeat(self): return uninferable - def reshape(self): return uninferable - def resize(self): return uninferable - def round(self): return uninferable - def searchsorted(self): return uninferable - def setfield(self): return uninferable - def setflags(self): return uninferable - def sort(self): return uninferable - def squeeze(self): return uninferable - def std(self): return uninferable - def sum(self): return uninferable - def swapaxes(self): return uninferable - def take(self): return uninferable - def tobytes(self): return uninferable - def tofile(self): return uninferable - def tolist(self): return uninferable - def tostring(self): return uninferable - def trace(self): return uninferable - def transpose(self): return uninferable - def var(self): return uninferable - def view(self): return uninferable - - class busdaycalendar(object): def __init__(self, weekmask='1111100', holidays=None): self.holidays = None @@ -547,25 +468,105 @@ def _replace_numpy_function_infer_call_result(node, context=None): node.infer_call_result = numpy_function_infer_call_result(node) return - -astroid.MANAGER.register_transform( - astroid.FunctionDef, - _replace_numpy_function_infer_call_result, - functools.partial( - _looks_like_numpy_function, "linspace", "numpy.core.function_base" - ), -) - astroid.MANAGER.register_transform( astroid.FunctionDef, _replace_numpy_function_infer_call_result, functools.partial(_looks_like_numpy_function, "array", "numpy.core.records"), ) +def infer_numpy_ndarray(node, context=None): + ndarray = """ + class ndarray(object): + def __init__(self, shape, dtype=float, buffer=None, offset=0, + strides=None, order=None): + self.T = None + self.base = None + self.ctypes = None + self.data = None + self.dtype = None + self.flags = None + self.flat = None + self.imag = None + self.itemsize = None + self.nbytes = None + self.ndim = None + self.real = None + self.shape = None + self.size = None + self.strides = None + + def __neg__(self): return uninferable + def __inv__(self): return uninferable + def __invert__(self): return uninferable + def all(self): return uninferable + def any(self): return uninferable + def argmax(self): return uninferable + def argmin(self): return uninferable + def argpartition(self): return uninferable + def argsort(self): return uninferable + def astype(self): return uninferable + def byteswap(self): return uninferable + def choose(self): return uninferable + def clip(self): return uninferable + def compress(self): return uninferable + def conj(self): return uninferable + def conjugate(self): return uninferable + def copy(self): return uninferable + def cumprod(self): return uninferable + def cumsum(self): return uninferable + def diagonal(self): return uninferable + def dot(self): return uninferable + def dump(self): return uninferable + def dumps(self): return uninferable + def fill(self): return uninferable + def flatten(self): return uninferable + def getfield(self): return uninferable + def item(self): return uninferable + def itemset(self): return uninferable + def max(self): return uninferable + def mean(self): return uninferable + def min(self): return uninferable + def newbyteorder(self): return uninferable + def nonzero(self): return uninferable + def partition(self): return uninferable + def prod(self): return uninferable + def ptp(self): return uninferable + def put(self): return uninferable + def ravel(self): return uninferable + def repeat(self): return uninferable + def reshape(self): return uninferable + def resize(self): return uninferable + def round(self): return uninferable + def searchsorted(self): return uninferable + def setfield(self): return uninferable + def setflags(self): return uninferable + def sort(self): return uninferable + def squeeze(self): return uninferable + def std(self): return uninferable + def sum(self): return uninferable + def swapaxes(self): return uninferable + def take(self): return uninferable + def tobytes(self): return uninferable + def tofile(self): return uninferable + def tolist(self): return uninferable + def tostring(self): return uninferable + def trace(self): return uninferable + def transpose(self): return uninferable + def var(self): return uninferable + def view(self): return uninferable + """ + node = astroid.extract_node(ndarray) + return node.infer(context=context) + +def _looks_like_numpy_ndarray(node): + if isinstance(node, astroid.Attribute) and node.attrname == 'ndarray': + return True + return False + astroid.MANAGER.register_transform( - astroid.FunctionDef, - _replace_numpy_function_infer_call_result, - functools.partial(_looks_like_numpy_function, "zeros_like", "numpy.core.numeric"), + astroid.Attribute, + astroid.inference_tip(infer_numpy_ndarray), + _looks_like_numpy_ndarray ) astroid.register_module_extender( From 83aa30f2be64c404cf8f445a8b0f6a6568c21904 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 23 Mar 2019 15:17:38 +0100 Subject: [PATCH 06/40] Correcting inference test. linspace and zeros_like are inferred as '.ndarray' and not 'numpy.core.numerictypes.ndarray' --- astroid/tests/unittest_brain_numpy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index e6650539ff..f2e05596f7 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -645,7 +645,7 @@ def test_numpy_function_calls_inferred_as_ndarray(self): """ Test that some calls to numpy functions are inferred as numpy.ndarray """ - licit_array_types = ('numpy.core.numerictypes.ndarray', 'numpy.core.records.recarray') + licit_array_types = ('.ndarray', 'numpy.core.records.recarray') for func_ in self.numpy_functions: with self.subTest(typ=func_): self.assertTrue(any(isinstance(inferred, bases.Instance) and inferred.pytype() in licit_array_types From d7c0373f83969119fe5697604eb185e0720066e0 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 30 Mar 2019 16:03:48 +0100 Subject: [PATCH 07/40] Add of __getitem__ and __setitem__ methods in ndarray. Correct signature of setitem method. Add of empty_like, ones_like function --- astroid/brain/brain_numpy.py | 6 +++++- astroid/tests/unittest_brain_numpy.py | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index 8ed6ac368e..1afc64834b 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -398,6 +398,8 @@ def numpy_core_numeric_transform(): # different functions defined in numeric.py import numpy def zeros_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) + def empty_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) + def ones_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) """ ) @@ -498,6 +500,8 @@ def __init__(self, shape, dtype=float, buffer=None, offset=0, def __neg__(self): return uninferable def __inv__(self): return uninferable def __invert__(self): return uninferable + def __getitem__(self, key): return uninferable + def __setitem__(self, key, value): return uninferable def all(self): return uninferable def any(self): return uninferable def argmax(self): return uninferable @@ -522,7 +526,7 @@ def fill(self): return uninferable def flatten(self): return uninferable def getfield(self): return uninferable def item(self): return uninferable - def itemset(self): return uninferable + def itemset(self, *args): return None def max(self): return uninferable def mean(self): return uninferable def min(self): return uninferable diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index f2e05596f7..0099ee3771 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -627,7 +627,11 @@ class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): """ numpy_functions = (("array", "[1, 2]"), ("linspace", "1, 100"), - ('zeros_like', "[1, 2]")) + ('zeros_like', "[1, 2]"), + ('full_like', "[1, 2]", '4'), + ('empty_like', "[1, 2]"), + ('ones_like', "[1, 2]"), + ) def _inferred_numpy_func_call(self, func_name, *func_args): node = builder.extract_node( From d6f1fe1b48deadf0b28bf014a8538035df66c90a Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 31 Mar 2019 20:47:25 +0200 Subject: [PATCH 08/40] Split the brain_numpy modules in smaller ones for clarity. --- astroid/brain/brain_numpy.py | 36 +----- .../brain/brain_numpy_core_function_base.py | 32 +++++ astroid/brain/brain_numpy_core_multiarray.py | 110 ++++++++++++++++++ astroid/brain/brain_numpy_core_numeric.py | 25 ++++ astroid/tests/unittest_brain_numpy.py | 29 ++++- 5 files changed, 195 insertions(+), 37 deletions(-) create mode 100644 astroid/brain/brain_numpy_core_function_base.py create mode 100644 astroid/brain/brain_numpy_core_multiarray.py create mode 100644 astroid/brain/brain_numpy_core_numeric.py diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index 1afc64834b..23c94a8919 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -142,9 +142,9 @@ def left_shift(x1, x2, {opt_args:s}): return uninferable def less(x1, x2, {opt_args:s}): return uninferable def logaddexp(x1, x2, {opt_args:s}): return uninferable def logaddexp2(x1, x2, {opt_args:s}): return uninferable - def logical_and(x1, x2, {opt_args:s}): return uninferable - def logical_or(x1, x2, {opt_args:s}): return uninferable - def logical_xor(x1, x2, {opt_args:s}): return uninferable + def logical_and(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) + def logical_or(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) + def logical_xor(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) def maximum(x1, x2, {opt_args:s}): return uninferable def minimum(x1, x2, {opt_args:s}): return uninferable def nextafter(x1, x2, {opt_args:s}): return uninferable @@ -392,26 +392,6 @@ class int64(signedinteger): pass """ ) -def numpy_core_numeric_transform(): - return astroid.parse( - """ - # different functions defined in numeric.py - import numpy - def zeros_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) - def empty_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) - def ones_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) - """ - ) - -def numpy_core_function_base_transform(): - return astroid.parse( - """ - # different functions defined in numeric.py - import numpy - def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): return numpy.ndarray((0, 0)) - """ - ) - def numpy_funcs(): return astroid.parse( """ @@ -563,9 +543,7 @@ def view(self): return uninferable return node.infer(context=context) def _looks_like_numpy_ndarray(node): - if isinstance(node, astroid.Attribute) and node.attrname == 'ndarray': - return True - return False + return isinstance(node, astroid.Attribute) and node.attrname == 'ndarray' astroid.MANAGER.register_transform( astroid.Attribute, @@ -582,10 +560,4 @@ def _looks_like_numpy_ndarray(node): astroid.register_module_extender( astroid.MANAGER, "numpy.core.numerictypes", numpy_core_numerictypes_transform ) -astroid.register_module_extender( - astroid.MANAGER, "numpy.core.numeric", numpy_core_numeric_transform -) -astroid.register_module_extender( - astroid.MANAGER, "numpy.core.function_base", numpy_core_function_base_transform -) astroid.register_module_extender(astroid.MANAGER, "numpy", numpy_funcs) diff --git a/astroid/brain/brain_numpy_core_function_base.py b/astroid/brain/brain_numpy_core_function_base.py new file mode 100644 index 0000000000..fd5f193d62 --- /dev/null +++ b/astroid/brain/brain_numpy_core_function_base.py @@ -0,0 +1,32 @@ +# Copyright (c) 2018-2019 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER + + +"""Astroid hooks for numpy.core.function_base module.""" + +import functools +import astroid + + +def infer_numpy_core_function_base_linspace(node, context=None): + src = """ + def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + + +def looks_like_numpy_core_function_base_member(member_name, node): + return (isinstance(node, astroid.Attribute) + and node.attrname == member_name + and node.expr.inferred()[-1].name == 'numpy') + + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_function_base_linspace), + functools.partial(looks_like_numpy_core_function_base_member, "linspace") +) \ No newline at end of file diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py new file mode 100644 index 0000000000..5b46d43748 --- /dev/null +++ b/astroid/brain/brain_numpy_core_multiarray.py @@ -0,0 +1,110 @@ +# Copyright (c) 2018-2019 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER + + +"""Astroid hooks for numpy.core.multiarray module.""" + +import functools +import astroid + + +def numpy_core_multiarray_transform(): + return astroid.parse( + """ + # different functions defined in multiarray.py + def inner(a, b): + return numpy.ndarray([0, 0]) + + def vdot(a, b): + return numpy.ndarray([0, 0]) + """ + ) + + +astroid.register_module_extender( + astroid.MANAGER, "numpy.core.multiarray", numpy_core_multiarray_transform +) + +def infer_numpy_core_multiarray_array(node, context=None): + src = """ + def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + + +def infer_numpy_core_multiarray_dot(node, context=None): + src = """ + def dot(a, b, out=None): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + + +def infer_numpy_core_multiarray_empty_like(node, context=None): + src = """ + def empty_like(a, dtype=None, order='K', subok=True): + return numpy.ndarray((0, 0)) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + + +def infer_numpy_core_multiarray_concatenate(node, context=None): + src = """ + def concatenate(arrays, axis=None, out=None): + return numpy.ndarray((0, 0)) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + + +def infer_numpy_core_multiarray_where(node, context=None): + src = """ + def where(condition, x=None, y=None): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + + +def looks_like_numpy_core_multiarray_member(member_name, node): + return (isinstance(node, astroid.Attribute) + and node.attrname == member_name + and node.expr.inferred()[-1].name == 'numpy') + + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_multiarray_array), + functools.partial(looks_like_numpy_core_multiarray_member, "array") +) + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_multiarray_dot), + functools.partial(looks_like_numpy_core_multiarray_member, "dot") +) + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_multiarray_empty_like), + functools.partial(looks_like_numpy_core_multiarray_member, "empty_like") +) + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_multiarray_concatenate), + functools.partial(looks_like_numpy_core_multiarray_member, "concatenate") +) + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_multiarray_where), + functools.partial(looks_like_numpy_core_multiarray_member, "where") +) + diff --git a/astroid/brain/brain_numpy_core_numeric.py b/astroid/brain/brain_numpy_core_numeric.py new file mode 100644 index 0000000000..0f2800740f --- /dev/null +++ b/astroid/brain/brain_numpy_core_numeric.py @@ -0,0 +1,25 @@ +# Copyright (c) 2018-2019 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER + + +"""Astroid hooks for numpy.core.numeric module.""" + +import astroid + + +def numpy_core_numeric_transform(): + return astroid.parse( + """ + # different functions defined in numeric.py + import numpy + def zeros_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) + def ones_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) + def full_like(a, fill_value, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) + """ + ) + +astroid.register_module_extender( + astroid.MANAGER, "numpy.core.numeric", numpy_core_numeric_transform +) \ No newline at end of file diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index 0099ee3771..6c886050d6 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -19,6 +19,7 @@ from astroid import nodes from astroid import node_classes from astroid import bases +from astroid import util class SubTestWrapper(unittest.TestCase): @@ -631,6 +632,14 @@ class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): ('full_like', "[1, 2]", '4'), ('empty_like', "[1, 2]"), ('ones_like', "[1, 2]"), + ('logical_or', "[1, 2]", "[1, 2]"), + ('logical_xor', "[1, 2]", "[1, 2]"), + ('logical_and', "[1, 2]", "[1, 2]"), + ('dot', "[1, 2]", "[1, 2]"), + ('vdot', "[1, 2]", "[1, 2]"), + ('concatenate', "([1, 2], [1, 2])"), + ('inner', "[1, 2]", "[1, 2]"), + ('where', '[True, False]', "[1, 2]", "[2, 1]") ) def _inferred_numpy_func_call(self, func_name, *func_args): @@ -653,25 +662,35 @@ def test_numpy_function_calls_inferred_as_ndarray(self): for func_ in self.numpy_functions: with self.subTest(typ=func_): self.assertTrue(any(isinstance(inferred, bases.Instance) and inferred.pytype() in licit_array_types - for inferred in self._inferred_numpy_func_call(*func_))) + for inferred in self._inferred_numpy_func_call(*func_)), + msg="subTest is : {:s}".format(func_[0])) def test_numpy_function_calls_not_inferred_as_list(self): """ - Test that some calls to numpy functions are not inferred as list nor tuple + Test that some calls to numpy functions are not inferred as list """ for func_ in self.numpy_functions: with self.subTest(typ=func_): for inferred in self._inferred_numpy_func_call(*func_): - self.assertFalse(isinstance(inferred, node_classes.List)) + self.assertFalse(isinstance(inferred, node_classes.List), msg="subTest is : {:s}".format(func_[0])) def test_numpy_function_calls_not_inferred_as_tuple(self): """ - Test that some calls to numpy functions are not inferred as list nor tuple + Test that some calls to numpy functions are not inferred as tuple """ for func_ in self.numpy_functions: with self.subTest(typ=func_): for inferred in self._inferred_numpy_func_call(*func_): - self.assertFalse(isinstance(inferred, node_classes.Tuple)) + self.assertFalse(isinstance(inferred, node_classes.Tuple), msg="subTest is : {:s}".format(func_[0])) + + def test_numpy_function_calls_not_inferred_as_uninferable(self): + """ + Test that some calls to numpy functions are not inferred as uninferable + """ + for func_ in self.numpy_functions: + with self.subTest(typ=func_): + for inferred in self._inferred_numpy_func_call(*func_): + self.assertNotEqual(inferred, util.Uninferable, msg="subTest is : {:s}".format(func_[0])) if __name__ == "__main__": From 81b70ed7191499658534ace02c00acf7d0a24657 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Tue, 2 Apr 2019 09:58:12 +0200 Subject: [PATCH 09/40] Test the unicity of inferred value for function returning ndarray. --- astroid/tests/unittest_brain_numpy.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index 6c886050d6..751f594cac 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -661,9 +661,11 @@ def test_numpy_function_calls_inferred_as_ndarray(self): licit_array_types = ('.ndarray', 'numpy.core.records.recarray') for func_ in self.numpy_functions: with self.subTest(typ=func_): - self.assertTrue(any(isinstance(inferred, bases.Instance) and inferred.pytype() in licit_array_types - for inferred in self._inferred_numpy_func_call(*func_)), - msg="subTest is : {:s}".format(func_[0])) + inferred_values = list(self._inferred_numpy_func_call(*func_)) + self.assertTrue(len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0])) + self.assertTrue(inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) def test_numpy_function_calls_not_inferred_as_list(self): """ From c5687bc0b493a2953b0e5e4b0e507e96e47856ed Mon Sep 17 00:00:00 2001 From: hippo91 Date: Tue, 2 Apr 2019 11:49:14 +0200 Subject: [PATCH 10/40] Remove test_numpy_function_calls_not_inferred_as_* methods because they are redondant with the one test only ndarray are inferred --- astroid/tests/unittest_brain_numpy.py | 28 --------------------------- 1 file changed, 28 deletions(-) diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index 751f594cac..655426e431 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -667,33 +667,5 @@ def test_numpy_function_calls_inferred_as_ndarray(self): self.assertTrue(inferred_values[-1].pytype() in licit_array_types, msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) - def test_numpy_function_calls_not_inferred_as_list(self): - """ - Test that some calls to numpy functions are not inferred as list - """ - for func_ in self.numpy_functions: - with self.subTest(typ=func_): - for inferred in self._inferred_numpy_func_call(*func_): - self.assertFalse(isinstance(inferred, node_classes.List), msg="subTest is : {:s}".format(func_[0])) - - def test_numpy_function_calls_not_inferred_as_tuple(self): - """ - Test that some calls to numpy functions are not inferred as tuple - """ - for func_ in self.numpy_functions: - with self.subTest(typ=func_): - for inferred in self._inferred_numpy_func_call(*func_): - self.assertFalse(isinstance(inferred, node_classes.Tuple), msg="subTest is : {:s}".format(func_[0])) - - def test_numpy_function_calls_not_inferred_as_uninferable(self): - """ - Test that some calls to numpy functions are not inferred as uninferable - """ - for func_ in self.numpy_functions: - with self.subTest(typ=func_): - for inferred in self._inferred_numpy_func_call(*func_): - self.assertNotEqual(inferred, util.Uninferable, msg="subTest is : {:s}".format(func_[0])) - - if __name__ == "__main__": unittest.main() From c5d9205887cb3d4ba4776eb545f72f875ac07836 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Tue, 2 Apr 2019 19:18:52 +0200 Subject: [PATCH 11/40] Finish the split of the numpy brain. Implements all the dunder methods for ndarray --- astroid/brain/brain_numpy.py | 507 ++---------------- astroid/brain/brain_numpy_core_fromnumeric.py | 21 + astroid/brain/brain_numpy_core_multiarray.py | 3 + .../brain/brain_numpy_core_numerictypes.py | 247 +++++++++ astroid/brain/brain_numpy_core_umath.py | 105 ++++ astroid/brain/brain_numpy_random_mtrand.py | 70 +++ astroid/tests/unittest_brain_numpy.py | 3 +- 7 files changed, 496 insertions(+), 460 deletions(-) create mode 100644 astroid/brain/brain_numpy_core_fromnumeric.py create mode 100644 astroid/brain/brain_numpy_core_numerictypes.py create mode 100644 astroid/brain/brain_numpy_core_umath.py create mode 100644 astroid/brain/brain_numpy_random_mtrand.py diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index 23c94a8919..1a5cd49dc4 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -12,450 +12,6 @@ import astroid -def numpy_random_mtrand_transform(): - return astroid.parse( - """ - def beta(a, b, size=None): return uninferable - def binomial(n, p, size=None): return uninferable - def bytes(length): return uninferable - def chisquare(df, size=None): return uninferable - def choice(a, size=None, replace=True, p=None): return uninferable - def dirichlet(alpha, size=None): return uninferable - def exponential(scale=1.0, size=None): return uninferable - def f(dfnum, dfden, size=None): return uninferable - def gamma(shape, scale=1.0, size=None): return uninferable - def geometric(p, size=None): return uninferable - def get_state(): return uninferable - def gumbel(loc=0.0, scale=1.0, size=None): return uninferable - def hypergeometric(ngood, nbad, nsample, size=None): return uninferable - def laplace(loc=0.0, scale=1.0, size=None): return uninferable - def logistic(loc=0.0, scale=1.0, size=None): return uninferable - def lognormal(mean=0.0, sigma=1.0, size=None): return uninferable - def logseries(p, size=None): return uninferable - def multinomial(n, pvals, size=None): return uninferable - def multivariate_normal(mean, cov, size=None): return uninferable - def negative_binomial(n, p, size=None): return uninferable - def noncentral_chisquare(df, nonc, size=None): return uninferable - def noncentral_f(dfnum, dfden, nonc, size=None): return uninferable - def normal(loc=0.0, scale=1.0, size=None): return uninferable - def pareto(a, size=None): return uninferable - def permutation(x): return uninferable - def poisson(lam=1.0, size=None): return uninferable - def power(a, size=None): return uninferable - def rand(*args): return uninferable - def randint(low, high=None, size=None, dtype='l'): - import numpy - return numpy.ndarray((1,1)) - def randn(*args): return uninferable - def random_integers(low, high=None, size=None): return uninferable - def random_sample(size=None): return uninferable - def rayleigh(scale=1.0, size=None): return uninferable - def seed(seed=None): return uninferable - def set_state(state): return uninferable - def shuffle(x): return uninferable - def standard_cauchy(size=None): return uninferable - def standard_exponential(size=None): return uninferable - def standard_gamma(shape, size=None): return uninferable - def standard_normal(size=None): return uninferable - def standard_t(df, size=None): return uninferable - def triangular(left, mode, right, size=None): return uninferable - def uniform(low=0.0, high=1.0, size=None): return uninferable - def vonmises(mu, kappa, size=None): return uninferable - def wald(mean, scale, size=None): return uninferable - def weibull(a, size=None): return uninferable - def zipf(a, size=None): return uninferable - """ - ) - - -def numpy_core_umath_transform(): - ufunc_optional_keyword_arguments = ( - """out=None, where=True, casting='same_kind', order='K', """ - """dtype=None, subok=True""" - ) - return astroid.parse( - """ - # Constants - e = 2.718281828459045 - euler_gamma = 0.5772156649015329 - - # No arg functions - def geterrobj(): return uninferable - - # One arg functions - def seterrobj(errobj): return uninferable - - # One arg functions with optional kwargs - def arccos(x, {opt_args:s}): return uninferable - def arccosh(x, {opt_args:s}): return uninferable - def arcsin(x, {opt_args:s}): return uninferable - def arcsinh(x, {opt_args:s}): return uninferable - def arctan(x, {opt_args:s}): return uninferable - def arctanh(x, {opt_args:s}): return uninferable - def cbrt(x, {opt_args:s}): return uninferable - def conj(x, {opt_args:s}): return uninferable - def conjugate(x, {opt_args:s}): return uninferable - def cosh(x, {opt_args:s}): return uninferable - def deg2rad(x, {opt_args:s}): return uninferable - def degrees(x, {opt_args:s}): return uninferable - def exp2(x, {opt_args:s}): return uninferable - def expm1(x, {opt_args:s}): return uninferable - def fabs(x, {opt_args:s}): return uninferable - def frexp(x, {opt_args:s}): return uninferable - def isfinite(x, {opt_args:s}): return uninferable - def isinf(x, {opt_args:s}): return uninferable - def log(x, {opt_args:s}): return uninferable - def log1p(x, {opt_args:s}): return uninferable - def log2(x, {opt_args:s}): return uninferable - def logical_not(x, {opt_args:s}): return uninferable - def modf(x, {opt_args:s}): return uninferable - def negative(x, {opt_args:s}): return uninferable - def rad2deg(x, {opt_args:s}): return uninferable - def radians(x, {opt_args:s}): return uninferable - def reciprocal(x, {opt_args:s}): return uninferable - def rint(x, {opt_args:s}): return uninferable - def sign(x, {opt_args:s}): return uninferable - def signbit(x, {opt_args:s}): return uninferable - def sinh(x, {opt_args:s}): return uninferable - def spacing(x, {opt_args:s}): return uninferable - def square(x, {opt_args:s}): return uninferable - def tan(x, {opt_args:s}): return uninferable - def tanh(x, {opt_args:s}): return uninferable - def trunc(x, {opt_args:s}): return uninferable - - # Two args functions with optional kwargs - def bitwise_and(x1, x2, {opt_args:s}): return uninferable - def bitwise_or(x1, x2, {opt_args:s}): return uninferable - def bitwise_xor(x1, x2, {opt_args:s}): return uninferable - def copysign(x1, x2, {opt_args:s}): return uninferable - def divide(x1, x2, {opt_args:s}): return uninferable - def equal(x1, x2, {opt_args:s}): return uninferable - def float_power(x1, x2, {opt_args:s}): return uninferable - def floor_divide(x1, x2, {opt_args:s}): return uninferable - def fmax(x1, x2, {opt_args:s}): return uninferable - def fmin(x1, x2, {opt_args:s}): return uninferable - def fmod(x1, x2, {opt_args:s}): return uninferable - def greater(x1, x2, {opt_args:s}): return uninferable - def hypot(x1, x2, {opt_args:s}): return uninferable - def ldexp(x1, x2, {opt_args:s}): return uninferable - def left_shift(x1, x2, {opt_args:s}): return uninferable - def less(x1, x2, {opt_args:s}): return uninferable - def logaddexp(x1, x2, {opt_args:s}): return uninferable - def logaddexp2(x1, x2, {opt_args:s}): return uninferable - def logical_and(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) - def logical_or(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) - def logical_xor(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) - def maximum(x1, x2, {opt_args:s}): return uninferable - def minimum(x1, x2, {opt_args:s}): return uninferable - def nextafter(x1, x2, {opt_args:s}): return uninferable - def not_equal(x1, x2, {opt_args:s}): return uninferable - def power(x1, x2, {opt_args:s}): return uninferable - def remainder(x1, x2, {opt_args:s}): return uninferable - def right_shift(x1, x2, {opt_args:s}): return uninferable - def subtract(x1, x2, {opt_args:s}): return uninferable - def true_divide(x1, x2, {opt_args:s}): return uninferable - """.format( - opt_args=ufunc_optional_keyword_arguments - ) - ) - - -def numpy_core_numerictypes_transform(): - return astroid.parse( - """ - # different types defined in numerictypes.py - class generic(object): - def __init__(self, value): - self.T = None - self.base = None - self.data = None - self.dtype = None - self.flags = None - self.flat = None - self.imag = None - self.itemsize = None - self.nbytes = None - self.ndim = None - self.real = None - self.size = None - self.strides = None - - def all(self): return uninferable - def any(self): return uninferable - def argmax(self): return uninferable - def argmin(self): return uninferable - def argsort(self): return uninferable - def astype(self): return uninferable - def base(self): return uninferable - def byteswap(self): return uninferable - def choose(self): return uninferable - def clip(self): return uninferable - def compress(self): return uninferable - def conj(self): return uninferable - def conjugate(self): return uninferable - def copy(self): return uninferable - def cumprod(self): return uninferable - def cumsum(self): return uninferable - def data(self): return uninferable - def diagonal(self): return uninferable - def dtype(self): return uninferable - def dump(self): return uninferable - def dumps(self): return uninferable - def fill(self): return uninferable - def flags(self): return uninferable - def flat(self): return uninferable - def flatten(self): return uninferable - def getfield(self): return uninferable - def imag(self): return uninferable - def item(self): return uninferable - def itemset(self): return uninferable - def itemsize(self): return uninferable - def max(self): return uninferable - def mean(self): return uninferable - def min(self): return uninferable - def nbytes(self): return uninferable - def ndim(self): return uninferable - def newbyteorder(self): return uninferable - def nonzero(self): return uninferable - def prod(self): return uninferable - def ptp(self): return uninferable - def put(self): return uninferable - def ravel(self): return uninferable - def real(self): return uninferable - def repeat(self): return uninferable - def reshape(self): return uninferable - def resize(self): return uninferable - def round(self): return uninferable - def searchsorted(self): return uninferable - def setfield(self): return uninferable - def setflags(self): return uninferable - def shape(self): return uninferable - def size(self): return uninferable - def sort(self): return uninferable - def squeeze(self): return uninferable - def std(self): return uninferable - def strides(self): return uninferable - def sum(self): return uninferable - def swapaxes(self): return uninferable - def take(self): return uninferable - def tobytes(self): return uninferable - def tofile(self): return uninferable - def tolist(self): return uninferable - def tostring(self): return uninferable - def trace(self): return uninferable - def transpose(self): return uninferable - def var(self): return uninferable - def view(self): return uninferable - - - class dtype(object): - def __init__(self, obj, align=False, copy=False): - self.alignment = None - self.base = None - self.byteorder = None - self.char = None - self.descr = None - self.fields = None - self.flags = None - self.hasobject = None - self.isalignedstruct = None - self.isbuiltin = None - self.isnative = None - self.itemsize = None - self.kind = None - self.metadata = None - self.name = None - self.names = None - self.num = None - self.shape = None - self.str = None - self.subdtype = None - self.type = None - - def newbyteorder(self, new_order='S'): return uninferable - def __neg__(self): return uninferable - - class busdaycalendar(object): - def __init__(self, weekmask='1111100', holidays=None): - self.holidays = None - self.weekmask = None - - class flexible(generic): pass - class bool_(generic): pass - class number(generic): - def __neg__(self): return uninferable - class datetime64(generic): pass - - - class void(flexible): - def __init__(self, *args, **kwargs): - self.base = None - self.dtype = None - self.flags = None - def getfield(self): return uninferable - def setfield(self): return uninferable - - - class character(flexible): pass - - - class integer(number): - def __init__(self, value): - self.denominator = None - self.numerator = None - - - class inexact(number): pass - - - class str_(str, character): - def maketrans(self, x, y=None, z=None): return uninferable - - - class bytes_(bytes, character): - def fromhex(self, string): return uninferable - def maketrans(self, frm, to): return uninferable - - - class signedinteger(integer): pass - - - class unsignedinteger(integer): pass - - - class complexfloating(inexact): pass - - - class floating(inexact): pass - - - class float64(floating, float): - def fromhex(self, string): return uninferable - - - class uint64(unsignedinteger): pass - class complex64(complexfloating): pass - class int16(signedinteger): pass - class float96(floating): pass - class int8(signedinteger): pass - class uint32(unsignedinteger): pass - class uint8(unsignedinteger): pass - class _typedict(dict): pass - class complex192(complexfloating): pass - class timedelta64(signedinteger): pass - class int32(signedinteger): pass - class uint16(unsignedinteger): pass - class float32(floating): pass - class complex128(complexfloating, complex): pass - class float16(floating): pass - class int64(signedinteger): pass - - buffer_type = memoryview - bool8 = bool_ - byte = int8 - bytes0 = bytes_ - cdouble = complex128 - cfloat = complex128 - clongdouble = complex192 - clongfloat = complex192 - complex_ = complex128 - csingle = complex64 - double = float64 - float_ = float64 - half = float16 - int0 = int32 - int_ = int32 - intc = int32 - intp = int32 - long = int32 - longcomplex = complex192 - longdouble = float96 - longfloat = float96 - longlong = int64 - object0 = object_ - object_ = object_ - short = int16 - single = float32 - singlecomplex = complex64 - str0 = str_ - string_ = bytes_ - ubyte = uint8 - uint = uint32 - uint0 = uint32 - uintc = uint32 - uintp = uint32 - ulonglong = uint64 - unicode = str_ - unicode_ = str_ - ushort = uint16 - void0 = void - """ - ) - -def numpy_funcs(): - return astroid.parse( - """ - import builtins - def sum(a, axis=None, dtype=None, out=None, keepdims=None): - return builtins.sum(a) - """ - ) - - -def _looks_like_numpy_function(func_name, numpy_module_name, node): - """ - Return True if the current node correspond to the function inside - the numpy module in parameters - - :param node: the current node - :type node: FunctionDef - :param func_name: name of the function - :type func_name: str - :param numpy_module_name: name of the numpy module - :type numpy_module_name: str - :return: True if the current node correspond to the function looked for - :rtype: bool - """ - return node.name == func_name and node.parent.name == numpy_module_name - - -def numpy_function_infer_call_result(node): - """ - A wrapper around infer_call_result method bounded to the node. - - :param node: the node which infer_call_result should be filtered - :type node: FunctionDef - :return: a function that filter the results of the call to node.infer_call_result - :rtype: function - """ - #  Put the origin infer_call_result method into the closure - origin_infer_call_result = node.infer_call_result - - def infer_call_result_wrapper(caller=None, context=None): - """ - Call the origin infer_call_result method bounded to the node instance and - filter the results to remove List and Tuple instances - """ - unfiltered_infer_call_result = origin_infer_call_result(caller, context) - return ( - x - for x in unfiltered_infer_call_result - if not isinstance(x, (astroid.List, astroid.Tuple)) - ) - - return infer_call_result_wrapper - - -def _replace_numpy_function_infer_call_result(node, context=None): - node.infer_call_result = numpy_function_infer_call_result(node) - return - -astroid.MANAGER.register_transform( - astroid.FunctionDef, - _replace_numpy_function_infer_call_result, - functools.partial(_looks_like_numpy_function, "array", "numpy.core.records"), -) - def infer_numpy_ndarray(node, context=None): ndarray = """ class ndarray(object): @@ -477,11 +33,55 @@ def __init__(self, shape, dtype=float, buffer=None, offset=0, self.size = None self.strides = None - def __neg__(self): return uninferable - def __inv__(self): return uninferable - def __invert__(self): return uninferable + def __abs__(self): return numpy.ndarray([0, 0]) + def __add__(self, value): return numpy.ndarray([0, 0]) + def __and__(self, value): return numpy.ndarray([0, 0]) + def __array__(dtype=None): return numpy.ndarray([0, 0]) + def __array_wrap__(obj): return numpy.ndarray([0, 0]) + def __contains__(self, key): return uninferable + def __copy__(self): return numpy.ndarray([0, 0]) + def __deepcopy__(self, memo): return numpy.ndarray([0, 0]) + def __divmod__(self, value): return (numpy.ndarray([0, 0]), numpy.ndarray([0, 0])) + def __eq__(self, value): return numpy.ndarray([0, 0]) + def __float__(self): return 0. + def __floordiv__(self): return numpy.ndarray([0, 0]) + def __ge__(self, value): return numpy.ndarray([0, 0]) def __getitem__(self, key): return uninferable + def __gt__(self, value): return numpy.ndarray([0, 0]) + def __iadd__(self, value): return numpy.ndarray([0, 0]) + def __iand__(self, value): return numpy.ndarray([0, 0]) + def __ifloordiv__(self, value): return numpy.ndarray([0, 0]) + def __ilshift__(self, value): return numpy.ndarray([0, 0]) + def __imod__(self, value): return numpy.ndarray([0, 0]) + def __imul__(self, value): return numpy.ndarray([0, 0]) + def __int__(self): return 0 + def __invert__(self): return numpy.ndarray([0, 0]) + def __ior__(self, value): return numpy.ndarray([0, 0]) + def __ipow__(self, value): return numpy.ndarray([0, 0]) + def __irshift__(self, value): return numpy.ndarray([0, 0]) + def __isub__(self, value): return numpy.ndarray([0, 0]) + def __itruediv__(self, value): return numpy.ndarray([0, 0]) + def __ixor__(self, value): return numpy.ndarray([0, 0]) + def __le__(self, value): return numpy.ndarray([0, 0]) + def __len__(self): return 1 + def __lshift__(self, value): return numpy.ndarray([0, 0]) + def __lt__(self, value): return numpy.ndarray([0, 0]) + def __matmul__(self, value): return numpy.ndarray([0, 0]) + def __mod__(self, value): return numpy.ndarray([0, 0]) + def __mul__(self, value): return numpy.ndarray([0, 0]) + def __ne__(self, value): return numpy.ndarray([0, 0]) + def __neg__(self): return numpy.ndarray([0, 0]) + def __or__(self): return numpy.ndarray([0, 0]) + def __pos__(self): return numpy.ndarray([0, 0]) + def __pow__(self): return numpy.ndarray([0, 0]) + def __repr__(self): return str() + def __rshift__(self): return numpy.ndarray([0, 0]) def __setitem__(self, key, value): return uninferable + def __str__(self): return str() + def __sub__(self, value): return numpy.ndarray([0, 0]) + def __truediv__(self, value): return numpy.ndarray([0, 0]) + def __xor__(self, value): return numpy.ndarray([0, 0]) + def __inv__(self): return uninferable def all(self): return uninferable def any(self): return uninferable def argmax(self): return uninferable @@ -549,15 +149,4 @@ def _looks_like_numpy_ndarray(node): astroid.Attribute, astroid.inference_tip(infer_numpy_ndarray), _looks_like_numpy_ndarray -) - -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) +) \ No newline at end of file diff --git a/astroid/brain/brain_numpy_core_fromnumeric.py b/astroid/brain/brain_numpy_core_fromnumeric.py new file mode 100644 index 0000000000..64b79adaa9 --- /dev/null +++ b/astroid/brain/brain_numpy_core_fromnumeric.py @@ -0,0 +1,21 @@ +# Copyright (c) 2018-2019 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER + + +"""Astroid hooks for numpy.core.umath module.""" + +import astroid + +def numpy_core_fromnumeric_transform(): + return astroid.parse( + """ + def sum(a, axis=None, dtype=None, out=None, keepdims=None, initial=None): + return numpy.ndarray([0, 0]) + """) + + +astroid.register_module_extender( + astroid.MANAGER, "numpy.core.fromnumeric", numpy_core_fromnumeric_transform +) \ No newline at end of file diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py index 5b46d43748..f4399cf51a 100644 --- a/astroid/brain/brain_numpy_core_multiarray.py +++ b/astroid/brain/brain_numpy_core_multiarray.py @@ -19,6 +19,9 @@ def inner(a, b): def vdot(a, b): return numpy.ndarray([0, 0]) + + def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): + return numpy.ndarray([0, 0]) """ ) diff --git a/astroid/brain/brain_numpy_core_numerictypes.py b/astroid/brain/brain_numpy_core_numerictypes.py new file mode 100644 index 0000000000..f8bd63a969 --- /dev/null +++ b/astroid/brain/brain_numpy_core_numerictypes.py @@ -0,0 +1,247 @@ +# Copyright (c) 2018-2019 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER + + +"""Astroid hooks for numpy.core.numerictypes module.""" + +import astroid + + +def numpy_core_numerictypes_transform(): + return astroid.parse( + """ + # different types defined in numerictypes.py + class generic(object): + def __init__(self, value): + self.T = None + self.base = None + self.data = None + self.dtype = None + self.flags = None + self.flat = None + self.imag = None + self.itemsize = None + self.nbytes = None + self.ndim = None + self.real = None + self.size = None + self.strides = None + + def all(self): return uninferable + def any(self): return uninferable + def argmax(self): return uninferable + def argmin(self): return uninferable + def argsort(self): return uninferable + def astype(self): return uninferable + def base(self): return uninferable + def byteswap(self): return uninferable + def choose(self): return uninferable + def clip(self): return uninferable + def compress(self): return uninferable + def conj(self): return uninferable + def conjugate(self): return uninferable + def copy(self): return uninferable + def cumprod(self): return uninferable + def cumsum(self): return uninferable + def data(self): return uninferable + def diagonal(self): return uninferable + def dtype(self): return uninferable + def dump(self): return uninferable + def dumps(self): return uninferable + def fill(self): return uninferable + def flags(self): return uninferable + def flat(self): return uninferable + def flatten(self): return uninferable + def getfield(self): return uninferable + def imag(self): return uninferable + def item(self): return uninferable + def itemset(self): return uninferable + def itemsize(self): return uninferable + def max(self): return uninferable + def mean(self): return uninferable + def min(self): return uninferable + def nbytes(self): return uninferable + def ndim(self): return uninferable + def newbyteorder(self): return uninferable + def nonzero(self): return uninferable + def prod(self): return uninferable + def ptp(self): return uninferable + def put(self): return uninferable + def ravel(self): return uninferable + def real(self): return uninferable + def repeat(self): return uninferable + def reshape(self): return uninferable + def resize(self): return uninferable + def round(self): return uninferable + def searchsorted(self): return uninferable + def setfield(self): return uninferable + def setflags(self): return uninferable + def shape(self): return uninferable + def size(self): return uninferable + def sort(self): return uninferable + def squeeze(self): return uninferable + def std(self): return uninferable + def strides(self): return uninferable + def sum(self): return uninferable + def swapaxes(self): return uninferable + def take(self): return uninferable + def tobytes(self): return uninferable + def tofile(self): return uninferable + def tolist(self): return uninferable + def tostring(self): return uninferable + def trace(self): return uninferable + def transpose(self): return uninferable + def var(self): return uninferable + def view(self): return uninferable + + + class dtype(object): + def __init__(self, obj, align=False, copy=False): + self.alignment = None + self.base = None + self.byteorder = None + self.char = None + self.descr = None + self.fields = None + self.flags = None + self.hasobject = None + self.isalignedstruct = None + self.isbuiltin = None + self.isnative = None + self.itemsize = None + self.kind = None + self.metadata = None + self.name = None + self.names = None + self.num = None + self.shape = None + self.str = None + self.subdtype = None + self.type = None + + def newbyteorder(self, new_order='S'): return uninferable + def __neg__(self): return uninferable + + class busdaycalendar(object): + def __init__(self, weekmask='1111100', holidays=None): + self.holidays = None + self.weekmask = None + + class flexible(generic): pass + class bool_(generic): pass + class number(generic): + def __neg__(self): return uninferable + class datetime64(generic): pass + + + class void(flexible): + def __init__(self, *args, **kwargs): + self.base = None + self.dtype = None + self.flags = None + def getfield(self): return uninferable + def setfield(self): return uninferable + + + class character(flexible): pass + + + class integer(number): + def __init__(self, value): + self.denominator = None + self.numerator = None + + + class inexact(number): pass + + + class str_(str, character): + def maketrans(self, x, y=None, z=None): return uninferable + + + class bytes_(bytes, character): + def fromhex(self, string): return uninferable + def maketrans(self, frm, to): return uninferable + + + class signedinteger(integer): pass + + + class unsignedinteger(integer): pass + + + class complexfloating(inexact): pass + + + class floating(inexact): pass + + + class float64(floating, float): + def fromhex(self, string): return uninferable + + + class uint64(unsignedinteger): pass + class complex64(complexfloating): pass + class int16(signedinteger): pass + class float96(floating): pass + class int8(signedinteger): pass + class uint32(unsignedinteger): pass + class uint8(unsignedinteger): pass + class _typedict(dict): pass + class complex192(complexfloating): pass + class timedelta64(signedinteger): pass + class int32(signedinteger): pass + class uint16(unsignedinteger): pass + class float32(floating): pass + class complex128(complexfloating, complex): pass + class float16(floating): pass + class int64(signedinteger): pass + + buffer_type = memoryview + bool8 = bool_ + byte = int8 + bytes0 = bytes_ + cdouble = complex128 + cfloat = complex128 + clongdouble = complex192 + clongfloat = complex192 + complex_ = complex128 + csingle = complex64 + double = float64 + float_ = float64 + half = float16 + int0 = int32 + int_ = int32 + intc = int32 + intp = int32 + long = int32 + longcomplex = complex192 + longdouble = float96 + longfloat = float96 + longlong = int64 + object0 = object_ + object_ = object_ + short = int16 + single = float32 + singlecomplex = complex64 + str0 = str_ + string_ = bytes_ + ubyte = uint8 + uint = uint32 + uint0 = uint32 + uintc = uint32 + uintp = uint32 + ulonglong = uint64 + unicode = str_ + unicode_ = str_ + ushort = uint16 + void0 = void + """ + ) + + +astroid.register_module_extender( + astroid.MANAGER, "numpy.core.numerictypes", numpy_core_numerictypes_transform +) \ No newline at end of file diff --git a/astroid/brain/brain_numpy_core_umath.py b/astroid/brain/brain_numpy_core_umath.py new file mode 100644 index 0000000000..a454d9538d --- /dev/null +++ b/astroid/brain/brain_numpy_core_umath.py @@ -0,0 +1,105 @@ +# Copyright (c) 2018-2019 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER + + +"""Astroid hooks for numpy.core.umath module.""" + +import astroid + +def numpy_core_umath_transform(): + ufunc_optional_keyword_arguments = ( + """out=None, where=True, casting='same_kind', order='K', """ + """dtype=None, subok=True""" + ) + return astroid.parse( + """ + # Constants + e = 2.718281828459045 + euler_gamma = 0.5772156649015329 + + # No arg functions + def geterrobj(): return uninferable + + # One arg functions + def seterrobj(errobj): return uninferable + + # One arg functions with optional kwargs + def arccos(x, {opt_args:s}): return uninferable + def arccosh(x, {opt_args:s}): return uninferable + def arcsin(x, {opt_args:s}): return uninferable + def arcsinh(x, {opt_args:s}): return uninferable + def arctan(x, {opt_args:s}): return uninferable + def arctanh(x, {opt_args:s}): return uninferable + def cbrt(x, {opt_args:s}): return uninferable + def conj(x, {opt_args:s}): return uninferable + def conjugate(x, {opt_args:s}): return uninferable + def cosh(x, {opt_args:s}): return uninferable + def deg2rad(x, {opt_args:s}): return uninferable + def degrees(x, {opt_args:s}): return uninferable + def exp2(x, {opt_args:s}): return uninferable + def expm1(x, {opt_args:s}): return uninferable + def fabs(x, {opt_args:s}): return uninferable + def frexp(x, {opt_args:s}): return uninferable + def isfinite(x, {opt_args:s}): return uninferable + def isinf(x, {opt_args:s}): return uninferable + def log(x, {opt_args:s}): return uninferable + def log1p(x, {opt_args:s}): return uninferable + def log2(x, {opt_args:s}): return uninferable + def logical_not(x, {opt_args:s}): return uninferable + def modf(x, {opt_args:s}): return uninferable + def negative(x, {opt_args:s}): return uninferable + def rad2deg(x, {opt_args:s}): return uninferable + def radians(x, {opt_args:s}): return uninferable + def reciprocal(x, {opt_args:s}): return uninferable + def rint(x, {opt_args:s}): return uninferable + def sign(x, {opt_args:s}): return uninferable + def signbit(x, {opt_args:s}): return uninferable + def sinh(x, {opt_args:s}): return uninferable + def spacing(x, {opt_args:s}): return uninferable + def square(x, {opt_args:s}): return uninferable + def tan(x, {opt_args:s}): return uninferable + def tanh(x, {opt_args:s}): return uninferable + def trunc(x, {opt_args:s}): return uninferable + + # Two args functions with optional kwargs + def bitwise_and(x1, x2, {opt_args:s}): return uninferable + def bitwise_or(x1, x2, {opt_args:s}): return uninferable + def bitwise_xor(x1, x2, {opt_args:s}): return uninferable + def copysign(x1, x2, {opt_args:s}): return uninferable + def divide(x1, x2, {opt_args:s}): return uninferable + def equal(x1, x2, {opt_args:s}): return uninferable + def float_power(x1, x2, {opt_args:s}): return uninferable + def floor_divide(x1, x2, {opt_args:s}): return uninferable + def fmax(x1, x2, {opt_args:s}): return uninferable + def fmin(x1, x2, {opt_args:s}): return uninferable + def fmod(x1, x2, {opt_args:s}): return uninferable + def greater(x1, x2, {opt_args:s}): return uninferable + def hypot(x1, x2, {opt_args:s}): return uninferable + def ldexp(x1, x2, {opt_args:s}): return uninferable + def left_shift(x1, x2, {opt_args:s}): return uninferable + def less(x1, x2, {opt_args:s}): return uninferable + def logaddexp(x1, x2, {opt_args:s}): return uninferable + def logaddexp2(x1, x2, {opt_args:s}): return uninferable + def logical_and(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) + def logical_or(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) + def logical_xor(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) + def maximum(x1, x2, {opt_args:s}): return uninferable + def minimum(x1, x2, {opt_args:s}): return uninferable + def nextafter(x1, x2, {opt_args:s}): return uninferable + def not_equal(x1, x2, {opt_args:s}): return uninferable + def power(x1, x2, {opt_args:s}): return uninferable + def remainder(x1, x2, {opt_args:s}): return uninferable + def right_shift(x1, x2, {opt_args:s}): return uninferable + def subtract(x1, x2, {opt_args:s}): return uninferable + def true_divide(x1, x2, {opt_args:s}): return uninferable + """.format( + opt_args=ufunc_optional_keyword_arguments + ) + ) + + +astroid.register_module_extender( + astroid.MANAGER, "numpy.core.umath", numpy_core_umath_transform +) \ No newline at end of file diff --git a/astroid/brain/brain_numpy_random_mtrand.py b/astroid/brain/brain_numpy_random_mtrand.py new file mode 100644 index 0000000000..2279494355 --- /dev/null +++ b/astroid/brain/brain_numpy_random_mtrand.py @@ -0,0 +1,70 @@ +# Copyright (c) 2018-2019 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER + + +"""Astroid hooks for numpy.random.mtrand module.""" + +import astroid + + +def numpy_random_mtrand_transform(): + return astroid.parse( + """ + def beta(a, b, size=None): return uninferable + def binomial(n, p, size=None): return uninferable + def bytes(length): return uninferable + def chisquare(df, size=None): return uninferable + def choice(a, size=None, replace=True, p=None): return uninferable + def dirichlet(alpha, size=None): return uninferable + def exponential(scale=1.0, size=None): return uninferable + def f(dfnum, dfden, size=None): return uninferable + def gamma(shape, scale=1.0, size=None): return uninferable + def geometric(p, size=None): return uninferable + def get_state(): return uninferable + def gumbel(loc=0.0, scale=1.0, size=None): return uninferable + def hypergeometric(ngood, nbad, nsample, size=None): return uninferable + def laplace(loc=0.0, scale=1.0, size=None): return uninferable + def logistic(loc=0.0, scale=1.0, size=None): return uninferable + def lognormal(mean=0.0, sigma=1.0, size=None): return uninferable + def logseries(p, size=None): return uninferable + def multinomial(n, pvals, size=None): return uninferable + def multivariate_normal(mean, cov, size=None): return uninferable + def negative_binomial(n, p, size=None): return uninferable + def noncentral_chisquare(df, nonc, size=None): return uninferable + def noncentral_f(dfnum, dfden, nonc, size=None): return uninferable + def normal(loc=0.0, scale=1.0, size=None): return uninferable + def pareto(a, size=None): return uninferable + def permutation(x): return uninferable + def poisson(lam=1.0, size=None): return uninferable + def power(a, size=None): return uninferable + def rand(*args): return uninferable + def randint(low, high=None, size=None, dtype='l'): + import numpy + return numpy.ndarray((1,1)) + def randn(*args): return uninferable + def random_integers(low, high=None, size=None): return uninferable + def random_sample(size=None): return uninferable + def rayleigh(scale=1.0, size=None): return uninferable + def seed(seed=None): return uninferable + def set_state(state): return uninferable + def shuffle(x): return uninferable + def standard_cauchy(size=None): return uninferable + def standard_exponential(size=None): return uninferable + def standard_gamma(shape, size=None): return uninferable + def standard_normal(size=None): return uninferable + def standard_t(df, size=None): return uninferable + def triangular(left, mode, right, size=None): return uninferable + def uniform(low=0.0, high=1.0, size=None): return uninferable + def vonmises(mu, kappa, size=None): return uninferable + def wald(mean, scale, size=None): return uninferable + def weibull(a, size=None): return uninferable + def zipf(a, size=None): return uninferable + """ + ) + + +astroid.register_module_extender( + astroid.MANAGER, "numpy.random.mtrand", numpy_random_mtrand_transform +) \ No newline at end of file diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index 655426e431..5e5f391d01 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -639,7 +639,8 @@ class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): ('vdot', "[1, 2]", "[1, 2]"), ('concatenate', "([1, 2], [1, 2])"), ('inner', "[1, 2]", "[1, 2]"), - ('where', '[True, False]', "[1, 2]", "[2, 1]") + ('where', '[True, False]', "[1, 2]", "[2, 1]"), + ('sum', '[[1, 2], [2, 1]]', "axis=0") ) def _inferred_numpy_func_call(self, func_name, *func_args): From 19f9f276c46ca35476591675a7b0eb0f4bf98413 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 6 Apr 2019 11:42:36 +0200 Subject: [PATCH 12/40] Finalizing description of numpy.ndarray --- astroid/brain/brain_numpy.py | 111 +++++++++++++++++------------------ 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index 1a5cd49dc4..69f25f9d35 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -81,63 +81,62 @@ def __str__(self): return str() def __sub__(self, value): return numpy.ndarray([0, 0]) def __truediv__(self, value): return numpy.ndarray([0, 0]) def __xor__(self, value): return numpy.ndarray([0, 0]) - def __inv__(self): return uninferable - def all(self): return uninferable - def any(self): return uninferable - def argmax(self): return uninferable - def argmin(self): return uninferable - def argpartition(self): return uninferable - def argsort(self): return uninferable - def astype(self): return uninferable - def byteswap(self): return uninferable - def choose(self): return uninferable - def clip(self): return uninferable - def compress(self): return uninferable - def conj(self): return uninferable - def conjugate(self): return uninferable - def copy(self): return uninferable - def cumprod(self): return uninferable - def cumsum(self): return uninferable - def diagonal(self): return uninferable - def dot(self): return uninferable - def dump(self): return uninferable - def dumps(self): return uninferable - def fill(self): return uninferable - def flatten(self): return uninferable - def getfield(self): return uninferable - def item(self): return uninferable + def all(self, axis=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def any(self, axis=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def argmax(self, axis=None, out=None): return np.ndarray([0, 0]) + def argmin(self, axis=None, out=None): return np.ndarray([0, 0]) + def argpartition(self, kth, axis=-1, kind='introselect', order=None): return np.ndarray([0, 0]) + def argsort(self, axis=-1, kind='quicksort', order=None): return np.ndarray([0, 0]) + def astype(self, dtype, order='K', casting='unsafe', subok=True, copy=True): return np.ndarray([0, 0]) + def byteswap(self, inplace=False): return np.ndarray([0, 0]) + def choose(self, choices, out=None, mode='raise'): return np.ndarray([0, 0]) + def clip(self, min=None, max=None, out=None): return np.ndarray([0, 0]) + def compress(self, condition, axis=None, out=None): return np.ndarray([0, 0]) + def conj(self): return np.ndarray([0, 0]) + def conjugate(self): return np.ndarray([0, 0]) + def copy(self, order='C'): return np.ndarray([0, 0]) + def cumprod(self, axis=None, dtype=None, out=None): return np.ndarray([0, 0]) + def cumsum(self, axis=None, dtype=None, out=None): return np.ndarray([0, 0]) + def diagonal(self, offset=0, axis1=0, axis2=1): return np.ndarray([0, 0]) + def dot(self, b, out=None): return np.ndarray([0, 0]) + def dump(self, file): return None + def dumps(self): return str() + def fill(self, value): return None + def flatten(self, order='C'): return np.ndarray([0, 0]) + def getfield(self, dtype, offset=0): return np.ndarray([0, 0]) + def item(self, *args): return uninferable def itemset(self, *args): return None - def max(self): return uninferable - def mean(self): return uninferable - def min(self): return uninferable - def newbyteorder(self): return uninferable - def nonzero(self): return uninferable - def partition(self): return uninferable - def prod(self): return uninferable - def ptp(self): return uninferable - def put(self): return uninferable - def ravel(self): return uninferable - def repeat(self): return uninferable - def reshape(self): return uninferable - def resize(self): return uninferable - def round(self): return uninferable - def searchsorted(self): return uninferable - def setfield(self): return uninferable - def setflags(self): return uninferable - def sort(self): return uninferable - def squeeze(self): return uninferable - def std(self): return uninferable - def sum(self): return uninferable - def swapaxes(self): return uninferable - def take(self): return uninferable - def tobytes(self): return uninferable - def tofile(self): return uninferable - def tolist(self): return uninferable - def tostring(self): return uninferable - def trace(self): return uninferable - def transpose(self): return uninferable - def var(self): return uninferable - def view(self): return uninferable + def max(self, axis=None, out=None): return np.ndarray([0, 0]) + def mean(self, axis=None, dtype=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def min(self, axis=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def newbyteorder(self, new_order='S'): return np.ndarray([0, 0]) + def nonzero(self): return (1,) + def partition(self, kth, axis=-1, kind='introselect', order=None): return None + def prod(self, axis=None, dtype, out=None, keepdims=False): return np.ndarray([0, 0]) + def ptp(self, axis=None, out=None): return np.ndarray([0, 0]) + def put(self, indices, values, mode='raise'): return None + def ravel(self, order='C'): return np.ndarray([0, 0]) + def repeat(self, repeats, axis=None): return np.ndarray([0, 0]) + def reshape(self, shape, order='C'): return np.ndarray([0, 0]) + def resize(self, new_shape, refcheck=True): return None + def round(self, decimals=0, out=None): return np.ndarray([0, 0]) + def searchsorted(self, v, side='left', sorter=None): return np.ndarray([0, 0]) + def setfield(self, val, dtype, offset=0): return None + def setflags(self, write=None, align=None, uic=None): return None + def sort(self, axis=-1, kind='quicksort', order=None): return None + def squeeze(self, axis=None): return np.ndarray([0, 0]) + def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False): return np.ndarray([0, 0]) + def sum(self, axis=None, dtype=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def swapaxes(self, axis1, axis2): return np.ndarray([0, 0]) + def take(self, indices, axis=None, out=None, mode='raise'): return np.ndarray([0, 0]) + def tobytes(self, order='C'): return b'' + def tofile(self, fid, sep="", format="%s"): return None + def tolist(self, ): return [] + def tostring(self, order='C'): return b'' + def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None): return np.ndarray([0, 0]) + def transpose(self, *axes): return np.ndarray([0, 0]) + def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False): return np.ndarray([0, 0]) + def view(self, dtype=None, type=None): return np.ndarray([0, 0]) """ node = astroid.extract_node(ndarray) return node.infer(context=context) From 86ffb90ab342a666cf73e84f900680a61aac2437 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 6 Apr 2019 13:25:49 +0200 Subject: [PATCH 13/40] Correctiong missing default value --- astroid/brain/brain_numpy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index 69f25f9d35..fec4e4d230 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -112,7 +112,7 @@ def min(self, axis=None, out=None, keepdims=False): return np.ndarray([0, 0]) def newbyteorder(self, new_order='S'): return np.ndarray([0, 0]) def nonzero(self): return (1,) def partition(self, kth, axis=-1, kind='introselect', order=None): return None - def prod(self, axis=None, dtype, out=None, keepdims=False): return np.ndarray([0, 0]) + def prod(self, axis=None, dtype=None, out=None, keepdims=False): return np.ndarray([0, 0]) def ptp(self, axis=None, out=None): return np.ndarray([0, 0]) def put(self, indices, values, mode='raise'): return None def ravel(self, order='C'): return np.ndarray([0, 0]) From be16e43e9d7759eab6cd3effb0b080b50c9ab97a Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 6 Apr 2019 13:26:29 +0200 Subject: [PATCH 14/40] Deleting test about __inv__ method which doesn't exists in ndarray --- astroid/tests/unittest_brain_numpy.py | 188 +------------------------- 1 file changed, 1 insertion(+), 187 deletions(-) diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index 5e5f391d01..0897dc1082 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -44,192 +44,6 @@ def subTestMock(msg=None): yield msg -@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class NumpyBrainCoreUmathTest(SubTestWrapper): - """ - Test of all members of numpy.core.umath module - """ - - no_arg_ufunc = ("geterrobj",) - - one_arg_ufunc_spec = ("seterrobj",) - - one_arg_ufunc = ( - "arccos", - "arccosh", - "arcsin", - "arcsinh", - "arctan", - "arctanh", - "cbrt", - "conj", - "conjugate", - "cosh", - "deg2rad", - "degrees", - "exp2", - "expm1", - "fabs", - "frexp", - "isfinite", - "isinf", - "log", - "log1p", - "log2", - "logical_not", - "modf", - "negative", - "rad2deg", - "radians", - "reciprocal", - "rint", - "sign", - "signbit", - "spacing", - "square", - "tan", - "tanh", - "trunc", - ) - - two_args_ufunc = ( - "bitwise_and", - "bitwise_or", - "bitwise_xor", - "copysign", - "divide", - "equal", - "float_power", - "floor_divide", - "fmax", - "fmin", - "fmod", - "greater", - "hypot", - "ldexp", - "left_shift", - "less", - "logaddexp", - "logaddexp2", - "logical_and", - "logical_or", - "logical_xor", - "maximum", - "minimum", - "nextafter", - "not_equal", - "power", - "remainder", - "right_shift", - "subtract", - "true_divide", - ) - - all_ufunc = no_arg_ufunc + one_arg_ufunc_spec + one_arg_ufunc + two_args_ufunc - - constants = ("e", "euler_gamma") - - def _inferred_numpy_attribute(self, func_name): - node = builder.extract_node( - """ - import numpy.core.umath as tested_module - func = tested_module.{:s} - func""".format( - func_name - ) - ) - return next(node.infer()) - - def test_numpy_core_umath_constants(self): - """ - Test that constants have Const type. - """ - for const in self.constants: - with self.subTest(const=const): - inferred = self._inferred_numpy_attribute(const) - self.assertIsInstance(inferred, nodes.Const) - - def test_numpy_core_umath_constants_values(self): - """ - Test the values of the constants. - """ - exact_values = {"e": 2.718281828459045, "euler_gamma": 0.5772156649015329} - for const in self.constants: - with self.subTest(const=const): - inferred = self._inferred_numpy_attribute(const) - self.assertEqual(inferred.value, exact_values[const]) - - def test_numpy_core_umath_functions(self): - """ - Test that functions have FunctionDef type. - """ - for func in self.all_ufunc: - with self.subTest(func=func): - inferred = self._inferred_numpy_attribute(func) - self.assertIsInstance(inferred, nodes.FunctionDef) - - def test_numpy_core_umath_functions_no_arg(self): - """ - Test that functions with no arguments have really no arguments. - """ - for func in self.no_arg_ufunc: - with self.subTest(func=func): - inferred = self._inferred_numpy_attribute(func) - self.assertFalse(inferred.argnames()) - - def test_numpy_core_umath_functions_one_arg_spec(self): - """ - Test the arguments names of functions. - """ - exact_arg_names = ["errobj"] - for func in self.one_arg_ufunc_spec: - with self.subTest(func=func): - inferred = self._inferred_numpy_attribute(func) - self.assertEqual(inferred.argnames(), exact_arg_names) - - def test_numpy_core_umath_functions_one_arg(self): - """ - Test the arguments names of functions. - """ - exact_arg_names = ["x", "out", "where", "casting", "order", "dtype", "subok"] - for func in self.one_arg_ufunc: - with self.subTest(func=func): - inferred = self._inferred_numpy_attribute(func) - self.assertEqual(inferred.argnames(), exact_arg_names) - - def test_numpy_core_umath_functions_two_args(self): - """ - Test the arguments names of functions. - """ - exact_arg_names = [ - "x1", - "x2", - "out", - "where", - "casting", - "order", - "dtype", - "subok", - ] - for func in self.two_args_ufunc: - with self.subTest(func=func): - inferred = self._inferred_numpy_attribute(func) - self.assertEqual(inferred.argnames(), exact_arg_names) - - def test_numpy_core_umath_functions_kwargs_default_values(self): - """ - Test the default values for keyword arguments. - """ - exact_kwargs_default_values = [None, True, "same_kind", "K", None, True] - for func in self.one_arg_ufunc + self.two_args_ufunc: - with self.subTest(func=func): - inferred = self._inferred_numpy_attribute(func) - default_args_values = [ - default.value for default in inferred.args.defaults - ] - self.assertEqual(default_args_values, exact_kwargs_default_values) - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") class NumpyBrainRandomMtrandTest(SubTestWrapper): """ @@ -611,7 +425,7 @@ def test_array_types_have_unary_operators(self): """ Test that array types have unary operators """ - unary_ops = ("__neg__", "__inv__", "__invert__") + unary_ops = ("__neg__", "__invert__") for type_ in ("ndarray",): with self.subTest(typ=type_): From 181c83ebe46f036975edc0117d828b79f9e29541 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 6 Apr 2019 15:49:31 +0200 Subject: [PATCH 15/40] Split the unittest_brain_numpy module in parts so that each brain_numpy_* module has its own unittest module --- astroid/tests/unittest_brain_numpy.py | 94 ------- .../tests/unittest_brain_numpy_core_umath.py | 229 ++++++++++++++++++ .../unittest_brain_numpy_random_mtrand.py | 139 +++++++++++ 3 files changed, 368 insertions(+), 94 deletions(-) create mode 100644 astroid/tests/unittest_brain_numpy_core_umath.py create mode 100644 astroid/tests/unittest_brain_numpy_random_mtrand.py diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index 0897dc1082..ee2e9372e6 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -44,100 +44,6 @@ def subTestMock(msg=None): yield msg -@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class NumpyBrainRandomMtrandTest(SubTestWrapper): - """ - Test of all the functions of numpy.random.mtrand module. - """ - - #  Map between functions names and arguments names and default values - all_mtrand = { - "beta": (["a", "b", "size"], [None]), - "binomial": (["n", "p", "size"], [None]), - "bytes": (["length"], []), - "chisquare": (["df", "size"], [None]), - "choice": (["a", "size", "replace", "p"], [None, True, None]), - "dirichlet": (["alpha", "size"], [None]), - "exponential": (["scale", "size"], [1.0, None]), - "f": (["dfnum", "dfden", "size"], [None]), - "gamma": (["shape", "scale", "size"], [1.0, None]), - "geometric": (["p", "size"], [None]), - "get_state": ([], []), - "gumbel": (["loc", "scale", "size"], [0.0, 1.0, None]), - "hypergeometric": (["ngood", "nbad", "nsample", "size"], [None]), - "laplace": (["loc", "scale", "size"], [0.0, 1.0, None]), - "logistic": (["loc", "scale", "size"], [0.0, 1.0, None]), - "lognormal": (["mean", "sigma", "size"], [0.0, 1.0, None]), - "logseries": (["p", "size"], [None]), - "multinomial": (["n", "pvals", "size"], [None]), - "multivariate_normal": (["mean", "cov", "size"], [None]), - "negative_binomial": (["n", "p", "size"], [None]), - "noncentral_chisquare": (["df", "nonc", "size"], [None]), - "noncentral_f": (["dfnum", "dfden", "nonc", "size"], [None]), - "normal": (["loc", "scale", "size"], [0.0, 1.0, None]), - "pareto": (["a", "size"], [None]), - "permutation": (["x"], []), - "poisson": (["lam", "size"], [1.0, None]), - "power": (["a", "size"], [None]), - "rand": (["args"], []), - "randint": (["low", "high", "size", "dtype"], [None, None, "l"]), - "randn": (["args"], []), - "random_integers": (["low", "high", "size"], [None, None]), - "random_sample": (["size"], [None]), - "rayleigh": (["scale", "size"], [1.0, None]), - "seed": (["seed"], [None]), - "set_state": (["state"], []), - "shuffle": (["x"], []), - "standard_cauchy": (["size"], [None]), - "standard_exponential": (["size"], [None]), - "standard_gamma": (["shape", "size"], [None]), - "standard_normal": (["size"], [None]), - "standard_t": (["df", "size"], [None]), - "triangular": (["left", "mode", "right", "size"], [None]), - "uniform": (["low", "high", "size"], [0.0, 1.0, None]), - "vonmises": (["mu", "kappa", "size"], [None]), - "wald": (["mean", "scale", "size"], [None]), - "weibull": (["a", "size"], [None]), - "zipf": (["a", "size"], [None]), - } - - def _inferred_numpy_attribute(self, func_name): - node = builder.extract_node( - """ - import numpy.random.mtrand as tested_module - func = tested_module.{:s} - func""".format( - func_name - ) - ) - return next(node.infer()) - - def test_numpy_random_mtrand_functions(self): - """ - Test that all functions have FunctionDef type. - """ - for func in self.all_mtrand: - with self.subTest(func=func): - inferred = self._inferred_numpy_attribute(func) - self.assertIsInstance(inferred, nodes.FunctionDef) - - def test_numpy_random_mtrand_functions_signature(self): - """ - Test the arguments names and default values. - """ - for ( - func, - (exact_arg_names, exact_kwargs_default_values), - ) in self.all_mtrand.items(): - with self.subTest(func=func): - inferred = self._inferred_numpy_attribute(func) - self.assertEqual(inferred.argnames(), exact_arg_names) - default_args_values = [ - default.value for default in inferred.args.defaults - ] - self.assertEqual(default_args_values, exact_kwargs_default_values) - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") class NumpyBrainCoreNumericTypesTest(SubTestWrapper): """ diff --git a/astroid/tests/unittest_brain_numpy_core_umath.py b/astroid/tests/unittest_brain_numpy_core_umath.py new file mode 100644 index 0000000000..5bd887139a --- /dev/null +++ b/astroid/tests/unittest_brain_numpy_core_umath.py @@ -0,0 +1,229 @@ +# -*- encoding=utf-8 -*- +# Copyright (c) 2017-2018 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER +import unittest +import contextlib + +try: + import numpy # pylint: disable=unused-import + + HAS_NUMPY = True +except ImportError: + HAS_NUMPY = False + +from astroid import builder +from astroid import nodes + + +class SubTestWrapper(unittest.TestCase): + """ + A class for supporting all unittest version wether or not subTest is available + """ + + def subTest(self, msg=None, **params): + try: + # For python versions above 3.5 this should be ok + return super(SubTestWrapper, self).subTest(msg, **params) + except AttributeError: + #  For python versions below 3.5 + return subTestMock(msg) + + +@contextlib.contextmanager +def subTestMock(msg=None): + """ + A mock for subTest which do nothing + """ + yield msg + + +@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") +class NumpyBrainCoreUmathTest(SubTestWrapper): + """ + Test of all members of numpy.core.umath module + """ + + no_arg_ufunc = ("geterrobj",) + + one_arg_ufunc_spec = ("seterrobj",) + + one_arg_ufunc = ( + "arccos", + "arccosh", + "arcsin", + "arcsinh", + "arctan", + "arctanh", + "cbrt", + "conj", + "conjugate", + "cosh", + "deg2rad", + "degrees", + "exp2", + "expm1", + "fabs", + "frexp", + "isfinite", + "isinf", + "log", + "log1p", + "log2", + "logical_not", + "modf", + "negative", + "rad2deg", + "radians", + "reciprocal", + "rint", + "sign", + "signbit", + "spacing", + "square", + "tan", + "tanh", + "trunc", + ) + + two_args_ufunc = ( + "bitwise_and", + "bitwise_or", + "bitwise_xor", + "copysign", + "divide", + "equal", + "float_power", + "floor_divide", + "fmax", + "fmin", + "fmod", + "greater", + "hypot", + "ldexp", + "left_shift", + "less", + "logaddexp", + "logaddexp2", + "logical_and", + "logical_or", + "logical_xor", + "maximum", + "minimum", + "nextafter", + "not_equal", + "power", + "remainder", + "right_shift", + "subtract", + "true_divide", + ) + + all_ufunc = no_arg_ufunc + one_arg_ufunc_spec + one_arg_ufunc + two_args_ufunc + + constants = ("e", "euler_gamma") + + def _inferred_numpy_attribute(self, func_name): + node = builder.extract_node( + """ + import numpy.core.umath as tested_module + func = tested_module.{:s} + func""".format( + func_name + ) + ) + return next(node.infer()) + + def test_numpy_core_umath_constants(self): + """ + Test that constants have Const type. + """ + for const in self.constants: + with self.subTest(const=const): + inferred = self._inferred_numpy_attribute(const) + self.assertIsInstance(inferred, nodes.Const) + + def test_numpy_core_umath_constants_values(self): + """ + Test the values of the constants. + """ + exact_values = {"e": 2.718281828459045, "euler_gamma": 0.5772156649015329} + for const in self.constants: + with self.subTest(const=const): + inferred = self._inferred_numpy_attribute(const) + self.assertEqual(inferred.value, exact_values[const]) + + def test_numpy_core_umath_functions(self): + """ + Test that functions have FunctionDef type. + """ + for func in self.all_ufunc: + with self.subTest(func=func): + inferred = self._inferred_numpy_attribute(func) + self.assertIsInstance(inferred, nodes.FunctionDef) + + def test_numpy_core_umath_functions_no_arg(self): + """ + Test that functions with no arguments have really no arguments. + """ + for func in self.no_arg_ufunc: + with self.subTest(func=func): + inferred = self._inferred_numpy_attribute(func) + self.assertFalse(inferred.argnames()) + + def test_numpy_core_umath_functions_one_arg_spec(self): + """ + Test the arguments names of functions. + """ + exact_arg_names = ["errobj"] + for func in self.one_arg_ufunc_spec: + with self.subTest(func=func): + inferred = self._inferred_numpy_attribute(func) + self.assertEqual(inferred.argnames(), exact_arg_names) + + def test_numpy_core_umath_functions_one_arg(self): + """ + Test the arguments names of functions. + """ + exact_arg_names = ["x", "out", "where", "casting", "order", "dtype", "subok"] + for func in self.one_arg_ufunc: + with self.subTest(func=func): + inferred = self._inferred_numpy_attribute(func) + self.assertEqual(inferred.argnames(), exact_arg_names) + + def test_numpy_core_umath_functions_two_args(self): + """ + Test the arguments names of functions. + """ + exact_arg_names = [ + "x1", + "x2", + "out", + "where", + "casting", + "order", + "dtype", + "subok", + ] + for func in self.two_args_ufunc: + with self.subTest(func=func): + inferred = self._inferred_numpy_attribute(func) + self.assertEqual(inferred.argnames(), exact_arg_names) + + def test_numpy_core_umath_functions_kwargs_default_values(self): + """ + Test the default values for keyword arguments. + """ + exact_kwargs_default_values = [None, True, "same_kind", "K", None, True] + for func in self.one_arg_ufunc + self.two_args_ufunc: + with self.subTest(func=func): + inferred = self._inferred_numpy_attribute(func) + default_args_values = [ + default.value for default in inferred.args.defaults + ] + self.assertEqual(default_args_values, exact_kwargs_default_values) + + +if __name__ == "__main__": + unittest.main() diff --git a/astroid/tests/unittest_brain_numpy_random_mtrand.py b/astroid/tests/unittest_brain_numpy_random_mtrand.py new file mode 100644 index 0000000000..71d7bd09c9 --- /dev/null +++ b/astroid/tests/unittest_brain_numpy_random_mtrand.py @@ -0,0 +1,139 @@ +# -*- encoding=utf-8 -*- +# Copyright (c) 2017-2018 hippo91 +# Copyright (c) 2017 Claudiu Popa +# Copyright (c) 2018 Bryce Guinta + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER +import unittest +import contextlib + +try: + import numpy # pylint: disable=unused-import + + HAS_NUMPY = True +except ImportError: + HAS_NUMPY = False + +from astroid import builder +from astroid import nodes + + +class SubTestWrapper(unittest.TestCase): + """ + A class for supporting all unittest version wether or not subTest is available + """ + + def subTest(self, msg=None, **params): + try: + # For python versions above 3.5 this should be ok + return super(SubTestWrapper, self).subTest(msg, **params) + except AttributeError: + #  For python versions below 3.5 + return subTestMock(msg) + + +@contextlib.contextmanager +def subTestMock(msg=None): + """ + A mock for subTest which do nothing + """ + yield msg + + +@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") +class NumpyBrainRandomMtrandTest(SubTestWrapper): + """ + Test of all the functions of numpy.random.mtrand module. + """ + + #  Map between functions names and arguments names and default values + all_mtrand = { + "beta": (["a", "b", "size"], [None]), + "binomial": (["n", "p", "size"], [None]), + "bytes": (["length"], []), + "chisquare": (["df", "size"], [None]), + "choice": (["a", "size", "replace", "p"], [None, True, None]), + "dirichlet": (["alpha", "size"], [None]), + "exponential": (["scale", "size"], [1.0, None]), + "f": (["dfnum", "dfden", "size"], [None]), + "gamma": (["shape", "scale", "size"], [1.0, None]), + "geometric": (["p", "size"], [None]), + "get_state": ([], []), + "gumbel": (["loc", "scale", "size"], [0.0, 1.0, None]), + "hypergeometric": (["ngood", "nbad", "nsample", "size"], [None]), + "laplace": (["loc", "scale", "size"], [0.0, 1.0, None]), + "logistic": (["loc", "scale", "size"], [0.0, 1.0, None]), + "lognormal": (["mean", "sigma", "size"], [0.0, 1.0, None]), + "logseries": (["p", "size"], [None]), + "multinomial": (["n", "pvals", "size"], [None]), + "multivariate_normal": (["mean", "cov", "size"], [None]), + "negative_binomial": (["n", "p", "size"], [None]), + "noncentral_chisquare": (["df", "nonc", "size"], [None]), + "noncentral_f": (["dfnum", "dfden", "nonc", "size"], [None]), + "normal": (["loc", "scale", "size"], [0.0, 1.0, None]), + "pareto": (["a", "size"], [None]), + "permutation": (["x"], []), + "poisson": (["lam", "size"], [1.0, None]), + "power": (["a", "size"], [None]), + "rand": (["args"], []), + "randint": (["low", "high", "size", "dtype"], [None, None, "l"]), + "randn": (["args"], []), + "random_integers": (["low", "high", "size"], [None, None]), + "random_sample": (["size"], [None]), + "rayleigh": (["scale", "size"], [1.0, None]), + "seed": (["seed"], [None]), + "set_state": (["state"], []), + "shuffle": (["x"], []), + "standard_cauchy": (["size"], [None]), + "standard_exponential": (["size"], [None]), + "standard_gamma": (["shape", "size"], [None]), + "standard_normal": (["size"], [None]), + "standard_t": (["df", "size"], [None]), + "triangular": (["left", "mode", "right", "size"], [None]), + "uniform": (["low", "high", "size"], [0.0, 1.0, None]), + "vonmises": (["mu", "kappa", "size"], [None]), + "wald": (["mean", "scale", "size"], [None]), + "weibull": (["a", "size"], [None]), + "zipf": (["a", "size"], [None]), + } + + def _inferred_numpy_attribute(self, func_name): + node = builder.extract_node( + """ + import numpy.random.mtrand as tested_module + func = tested_module.{:s} + func""".format( + func_name + ) + ) + return next(node.infer()) + + def test_numpy_random_mtrand_functions(self): + """ + Test that all functions have FunctionDef type. + """ + for func in self.all_mtrand: + with self.subTest(func=func): + inferred = self._inferred_numpy_attribute(func) + self.assertIsInstance(inferred, nodes.FunctionDef) + + def test_numpy_random_mtrand_functions_signature(self): + """ + Test the arguments names and default values. + """ + for ( + func, + (exact_arg_names, exact_kwargs_default_values), + ) in self.all_mtrand.items(): + with self.subTest(func=func): + inferred = self._inferred_numpy_attribute(func) + self.assertEqual(inferred.argnames(), exact_arg_names) + default_args_values = [ + default.value for default in inferred.args.defaults + ] + self.assertEqual(default_args_values, exact_kwargs_default_values) + + +if __name__ == "__main__": + unittest.main() From 6be0cda8e51cb7879aed2d9064c42692cd3fbe7b Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 7 Apr 2019 12:10:47 +0200 Subject: [PATCH 16/40] Changes uninferable return toward correct ones --- astroid/brain/brain_numpy_core_umath.py | 129 ++++++++++++------------ 1 file changed, 64 insertions(+), 65 deletions(-) diff --git a/astroid/brain/brain_numpy_core_umath.py b/astroid/brain/brain_numpy_core_umath.py index a454d9538d..8ad46ba906 100644 --- a/astroid/brain/brain_numpy_core_umath.py +++ b/astroid/brain/brain_numpy_core_umath.py @@ -20,80 +20,79 @@ def numpy_core_umath_transform(): euler_gamma = 0.5772156649015329 # No arg functions - def geterrobj(): return uninferable + def geterrobj(): return [] # One arg functions - def seterrobj(errobj): return uninferable + def seterrobj(errobj): return None # One arg functions with optional kwargs - def arccos(x, {opt_args:s}): return uninferable - def arccosh(x, {opt_args:s}): return uninferable - def arcsin(x, {opt_args:s}): return uninferable - def arcsinh(x, {opt_args:s}): return uninferable - def arctan(x, {opt_args:s}): return uninferable - def arctanh(x, {opt_args:s}): return uninferable - def cbrt(x, {opt_args:s}): return uninferable - def conj(x, {opt_args:s}): return uninferable - def conjugate(x, {opt_args:s}): return uninferable - def cosh(x, {opt_args:s}): return uninferable - def deg2rad(x, {opt_args:s}): return uninferable - def degrees(x, {opt_args:s}): return uninferable - def exp2(x, {opt_args:s}): return uninferable - def expm1(x, {opt_args:s}): return uninferable - def fabs(x, {opt_args:s}): return uninferable - def frexp(x, {opt_args:s}): return uninferable - def isfinite(x, {opt_args:s}): return uninferable - def isinf(x, {opt_args:s}): return uninferable - def log(x, {opt_args:s}): return uninferable - def log1p(x, {opt_args:s}): return uninferable - def log2(x, {opt_args:s}): return uninferable - def logical_not(x, {opt_args:s}): return uninferable - def modf(x, {opt_args:s}): return uninferable - def negative(x, {opt_args:s}): return uninferable - def rad2deg(x, {opt_args:s}): return uninferable - def radians(x, {opt_args:s}): return uninferable - def reciprocal(x, {opt_args:s}): return uninferable - def rint(x, {opt_args:s}): return uninferable - def sign(x, {opt_args:s}): return uninferable - def signbit(x, {opt_args:s}): return uninferable - def sinh(x, {opt_args:s}): return uninferable - def spacing(x, {opt_args:s}): return uninferable - def square(x, {opt_args:s}): return uninferable - def tan(x, {opt_args:s}): return uninferable - def tanh(x, {opt_args:s}): return uninferable - def trunc(x, {opt_args:s}): return uninferable + def arccos(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def arccosh(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def arcsin(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def arcsinh(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def arctan(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def arctanh(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def cbrt(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def conj(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def conjugate(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def cosh(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def deg2rad(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def degrees(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def exp2(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def expm1(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def fabs(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def frexp(x, {opt_args:s}): return (numpy.ndarray((0, 0)), numpy.ndarray((0, 0))) + def isfinite(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def isinf(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def log(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def log1p(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def log2(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def logical_not(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def modf(x, {opt_args:s}): return (numpy.ndarray((0, 0)), numpy.ndarray((0, 0))) + def negative(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def rad2deg(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def radians(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def reciprocal(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def rint(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def sign(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def signbit(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def sinh(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def spacing(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def square(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def tan(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def tanh(x, {opt_args:s}): return numpy.ndarray((0, 0)) + def trunc(x, {opt_args:s}): return numpy.ndarray((0, 0)) # Two args functions with optional kwargs - def bitwise_and(x1, x2, {opt_args:s}): return uninferable - def bitwise_or(x1, x2, {opt_args:s}): return uninferable - def bitwise_xor(x1, x2, {opt_args:s}): return uninferable - def copysign(x1, x2, {opt_args:s}): return uninferable - def divide(x1, x2, {opt_args:s}): return uninferable - def equal(x1, x2, {opt_args:s}): return uninferable - def float_power(x1, x2, {opt_args:s}): return uninferable - def floor_divide(x1, x2, {opt_args:s}): return uninferable - def fmax(x1, x2, {opt_args:s}): return uninferable - def fmin(x1, x2, {opt_args:s}): return uninferable - def fmod(x1, x2, {opt_args:s}): return uninferable - def greater(x1, x2, {opt_args:s}): return uninferable - def hypot(x1, x2, {opt_args:s}): return uninferable - def ldexp(x1, x2, {opt_args:s}): return uninferable - def left_shift(x1, x2, {opt_args:s}): return uninferable - def less(x1, x2, {opt_args:s}): return uninferable - def logaddexp(x1, x2, {opt_args:s}): return uninferable - def logaddexp2(x1, x2, {opt_args:s}): return uninferable + def bitwise_and(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def bitwise_or(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def bitwise_xor(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def copysign(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def divide(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def equal(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def floor_divide(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def fmax(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def fmin(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def fmod(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def greater(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def hypot(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def ldexp(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def left_shift(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def less(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def logaddexp(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def logaddexp2(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) def logical_and(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) def logical_or(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) def logical_xor(x1, x2, {opt_args:s}): return numpy.ndarray([0, 0]) - def maximum(x1, x2, {opt_args:s}): return uninferable - def minimum(x1, x2, {opt_args:s}): return uninferable - def nextafter(x1, x2, {opt_args:s}): return uninferable - def not_equal(x1, x2, {opt_args:s}): return uninferable - def power(x1, x2, {opt_args:s}): return uninferable - def remainder(x1, x2, {opt_args:s}): return uninferable - def right_shift(x1, x2, {opt_args:s}): return uninferable - def subtract(x1, x2, {opt_args:s}): return uninferable - def true_divide(x1, x2, {opt_args:s}): return uninferable + def maximum(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def minimum(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def nextafter(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def not_equal(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def power(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def remainder(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def right_shift(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def subtract(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) + def true_divide(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) """.format( opt_args=ufunc_optional_keyword_arguments ) From ecb4fbd04259e3f840fc0e067cd47326dfe30c75 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 7 Apr 2019 12:12:09 +0200 Subject: [PATCH 17/40] Split the unittest_brain_numpy --- astroid/tests/unittest_brain_numpy.py | 304 ---------------- .../unittest_brain_numpy_core_numeric.py | 79 ++++ .../unittest_brain_numpy_core_numerictypes.py | 342 ++++++++++++++++++ .../tests/unittest_brain_numpy_core_umath.py | 1 - 4 files changed, 421 insertions(+), 305 deletions(-) create mode 100644 astroid/tests/unittest_brain_numpy_core_numeric.py create mode 100644 astroid/tests/unittest_brain_numpy_core_numerictypes.py diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index ee2e9372e6..4797e64e6e 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -16,10 +16,6 @@ HAS_NUMPY = False from astroid import builder -from astroid import nodes -from astroid import node_classes -from astroid import bases -from astroid import util class SubTestWrapper(unittest.TestCase): @@ -44,303 +40,6 @@ def subTestMock(msg=None): yield msg -@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", - "float16", - "float32", - "float64", - "float96", - "complex64", - "complex128", - "complex192", - "timedelta64", - "datetime64", - "unicode_", - "str_", - "bool_", - "bool8", - "byte", - "int8", - "bytes0", - "bytes_", - "cdouble", - "cfloat", - "character", - "clongdouble", - "clongfloat", - "complexfloating", - "csingle", - "double", - "flexible", - "floating", - "half", - "inexact", - "int0", - "longcomplex", - "longdouble", - "longfloat", - "short", - "signedinteger", - "single", - "singlecomplex", - "str0", - "ubyte", - "uint", - "uint0", - "uintc", - "uintp", - "ulonglong", - "unsignedinteger", - "ushort", - "void0", - ] - - 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) - - def test_generic_types_have_methods(self): - """ - Test that all generic derived types have specified methods - """ - generic_methods = [ - "all", - "any", - "argmax", - "argmin", - "argsort", - "astype", - "base", - "byteswap", - "choose", - "clip", - "compress", - "conj", - "conjugate", - "copy", - "cumprod", - "cumsum", - "data", - "diagonal", - "dtype", - "dump", - "dumps", - "fill", - "flags", - "flat", - "flatten", - "getfield", - "imag", - "item", - "itemset", - "itemsize", - "max", - "mean", - "min", - "nbytes", - "ndim", - "newbyteorder", - "nonzero", - "prod", - "ptp", - "put", - "ravel", - "real", - "repeat", - "reshape", - "resize", - "round", - "searchsorted", - "setfield", - "setflags", - "shape", - "size", - "sort", - "squeeze", - "std", - "strides", - "sum", - "swapaxes", - "take", - "tobytes", - "tofile", - "tolist", - "tostring", - "trace", - "transpose", - "var", - "view", - ] - - for type_ in ( - "bool_", - "bytes_", - "character", - "complex128", - "complex192", - "complex64", - "complexfloating", - "datetime64", - "flexible", - "float16", - "float32", - "float64", - "float96", - "floating", - "generic", - "inexact", - "int16", - "int32", - "int32", - "int64", - "int8", - "integer", - "number", - "signedinteger", - "str_", - "timedelta64", - "uint16", - "uint32", - "uint32", - "uint64", - "uint8", - "unsignedinteger", - "void", - ): - with self.subTest(typ=type_): - inferred = self._inferred_numpy_attribute(type_) - for meth in generic_methods: - with self.subTest(meth=meth): - self.assertTrue(meth in {m.name for m in inferred.methods()}) - - def test_generic_types_have_attributes(self): - """ - Test that all generic derived types have specified attributes - """ - generic_attr = [ - "base", - "data", - "dtype", - "flags", - "flat", - "imag", - "itemsize", - "nbytes", - "ndim", - "real", - "size", - "strides", - ] - - for type_ in ( - "bool_", - "bytes_", - "character", - "complex128", - "complex192", - "complex64", - "complexfloating", - "datetime64", - "flexible", - "float16", - "float32", - "float64", - "float96", - "floating", - "generic", - "inexact", - "int16", - "int32", - "int32", - "int64", - "int8", - "integer", - "number", - "signedinteger", - "str_", - "timedelta64", - "uint16", - "uint32", - "uint32", - "uint64", - "uint8", - "unsignedinteger", - "void", - ): - with self.subTest(typ=type_): - inferred = self._inferred_numpy_attribute(type_) - for attr in generic_attr: - with self.subTest(attr=attr): - self.assertNotEqual(len(inferred.getattr(attr)), 0) - - def test_number_types_have_unary_operators(self): - """ - Test that number types have unary operators - """ - unary_ops = ("__neg__",) - - for type_ in ( - "float64", - "float96", - "floating", - "int16", - "int32", - "int32", - "int64", - "int8", - "integer", - "number", - "signedinteger", - "uint16", - "uint32", - "uint32", - "uint64", - "uint8", - "unsignedinteger", - ): - with self.subTest(typ=type_): - inferred = self._inferred_numpy_attribute(type_) - for attr in unary_ops: - with self.subTest(attr=attr): - self.assertNotEqual(len(inferred.getattr(attr)), 0) - - def test_array_types_have_unary_operators(self): - """ - Test that array types have unary operators - """ - unary_ops = ("__neg__", "__invert__") - - for type_ in ("ndarray",): - with self.subTest(typ=type_): - inferred = self._inferred_numpy_attribute(type_) - for attr in unary_ops: - with self.subTest(attr=attr): - self.assertNotEqual(len(inferred.getattr(attr)), 0) - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): """ @@ -348,10 +47,7 @@ class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): """ numpy_functions = (("array", "[1, 2]"), ("linspace", "1, 100"), - ('zeros_like', "[1, 2]"), - ('full_like', "[1, 2]", '4'), ('empty_like', "[1, 2]"), - ('ones_like', "[1, 2]"), ('logical_or', "[1, 2]", "[1, 2]"), ('logical_xor', "[1, 2]", "[1, 2]"), ('logical_and', "[1, 2]", "[1, 2]"), diff --git a/astroid/tests/unittest_brain_numpy_core_numeric.py b/astroid/tests/unittest_brain_numpy_core_numeric.py new file mode 100644 index 0000000000..f764d6d396 --- /dev/null +++ b/astroid/tests/unittest_brain_numpy_core_numeric.py @@ -0,0 +1,79 @@ +# -*- encoding=utf-8 -*- +# Copyright (c) 2017-2018 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER +import unittest +import contextlib + +try: + import numpy # pylint: disable=unused-import + + HAS_NUMPY = True +except ImportError: + HAS_NUMPY = False + +from astroid import builder + + +class SubTestWrapper(unittest.TestCase): + """ + A class for supporting all unittest version wether or not subTest is available + """ + + def subTest(self, msg=None, **params): + try: + # For python versions above 3.5 this should be ok + return super(SubTestWrapper, self).subTest(msg, **params) + except AttributeError: + #  For python versions below 3.5 + return subTestMock(msg) + + +@contextlib.contextmanager +def subTestMock(msg=None): + """ + A mock for subTest which do nothing + """ + yield msg + + +@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") +class BrainNumpyCoreNumericTest(SubTestWrapper): + """ + Test the numpy core numeric brain module + """ + numpy_functions = ( + ('zeros_like', "[1, 2]"), + ('full_like', "[1, 2]", '4'), + ('ones_like', "[1, 2]"), + ) + + def _inferred_numpy_func_call(self, func_name, *func_args): + node = builder.extract_node( + """ + import numpy as np + func = np.{:s} + func({:s}) + """.format( + func_name, ",".join(func_args) + ) + ) + return node.infer() + + def test_numpy_function_calls_inferred_as_ndarray(self): + """ + Test that calls to numpy functions are inferred as numpy.ndarray + """ + licit_array_types = ('.ndarray',) + for func_ in self.numpy_functions: + with self.subTest(typ=func_): + inferred_values = list(self._inferred_numpy_func_call(*func_)) + self.assertTrue(len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0])) + self.assertTrue(inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + + +if __name__ == "__main__": + unittest.main() diff --git a/astroid/tests/unittest_brain_numpy_core_numerictypes.py b/astroid/tests/unittest_brain_numpy_core_numerictypes.py new file mode 100644 index 0000000000..5e4ebbac2a --- /dev/null +++ b/astroid/tests/unittest_brain_numpy_core_numerictypes.py @@ -0,0 +1,342 @@ +# -*- encoding=utf-8 -*- +# Copyright (c) 2017-2018 hippo91 +# Copyright (c) 2017 Claudiu Popa +# Copyright (c) 2018 Bryce Guinta + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER +import unittest +import contextlib + +try: + import numpy # pylint: disable=unused-import + + HAS_NUMPY = True +except ImportError: + HAS_NUMPY = False + +from astroid import builder +from astroid import nodes + + +class SubTestWrapper(unittest.TestCase): + """ + A class for supporting all unittest version wether or not subTest is available + """ + + def subTest(self, msg=None, **params): + try: + # For python versions above 3.5 this should be ok + return super(SubTestWrapper, self).subTest(msg, **params) + except AttributeError: + #  For python versions below 3.5 + return subTestMock(msg) + + +@contextlib.contextmanager +def subTestMock(msg=None): + """ + A mock for subTest which do nothing + """ + yield msg + + +@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", + "float16", + "float32", + "float64", + "float96", + "complex64", + "complex128", + "complex192", + "timedelta64", + "datetime64", + "unicode_", + "str_", + "bool_", + "bool8", + "byte", + "int8", + "bytes0", + "bytes_", + "cdouble", + "cfloat", + "character", + "clongdouble", + "clongfloat", + "complexfloating", + "csingle", + "double", + "flexible", + "floating", + "half", + "inexact", + "int0", + "longcomplex", + "longdouble", + "longfloat", + "short", + "signedinteger", + "single", + "singlecomplex", + "str0", + "ubyte", + "uint", + "uint0", + "uintc", + "uintp", + "ulonglong", + "unsignedinteger", + "ushort", + "void0", + ] + + 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) + + def test_generic_types_have_methods(self): + """ + Test that all generic derived types have specified methods + """ + generic_methods = [ + "all", + "any", + "argmax", + "argmin", + "argsort", + "astype", + "base", + "byteswap", + "choose", + "clip", + "compress", + "conj", + "conjugate", + "copy", + "cumprod", + "cumsum", + "data", + "diagonal", + "dtype", + "dump", + "dumps", + "fill", + "flags", + "flat", + "flatten", + "getfield", + "imag", + "item", + "itemset", + "itemsize", + "max", + "mean", + "min", + "nbytes", + "ndim", + "newbyteorder", + "nonzero", + "prod", + "ptp", + "put", + "ravel", + "real", + "repeat", + "reshape", + "resize", + "round", + "searchsorted", + "setfield", + "setflags", + "shape", + "size", + "sort", + "squeeze", + "std", + "strides", + "sum", + "swapaxes", + "take", + "tobytes", + "tofile", + "tolist", + "tostring", + "trace", + "transpose", + "var", + "view", + ] + + for type_ in ( + "bool_", + "bytes_", + "character", + "complex128", + "complex192", + "complex64", + "complexfloating", + "datetime64", + "flexible", + "float16", + "float32", + "float64", + "float96", + "floating", + "generic", + "inexact", + "int16", + "int32", + "int32", + "int64", + "int8", + "integer", + "number", + "signedinteger", + "str_", + "timedelta64", + "uint16", + "uint32", + "uint32", + "uint64", + "uint8", + "unsignedinteger", + "void", + ): + with self.subTest(typ=type_): + inferred = self._inferred_numpy_attribute(type_) + for meth in generic_methods: + with self.subTest(meth=meth): + self.assertTrue(meth in {m.name for m in inferred.methods()}) + + def test_generic_types_have_attributes(self): + """ + Test that all generic derived types have specified attributes + """ + generic_attr = [ + "base", + "data", + "dtype", + "flags", + "flat", + "imag", + "itemsize", + "nbytes", + "ndim", + "real", + "size", + "strides", + ] + + for type_ in ( + "bool_", + "bytes_", + "character", + "complex128", + "complex192", + "complex64", + "complexfloating", + "datetime64", + "flexible", + "float16", + "float32", + "float64", + "float96", + "floating", + "generic", + "inexact", + "int16", + "int32", + "int32", + "int64", + "int8", + "integer", + "number", + "signedinteger", + "str_", + "timedelta64", + "uint16", + "uint32", + "uint32", + "uint64", + "uint8", + "unsignedinteger", + "void", + ): + with self.subTest(typ=type_): + inferred = self._inferred_numpy_attribute(type_) + for attr in generic_attr: + with self.subTest(attr=attr): + self.assertNotEqual(len(inferred.getattr(attr)), 0) + + def test_number_types_have_unary_operators(self): + """ + Test that number types have unary operators + """ + unary_ops = ("__neg__",) + + for type_ in ( + "float64", + "float96", + "floating", + "int16", + "int32", + "int32", + "int64", + "int8", + "integer", + "number", + "signedinteger", + "uint16", + "uint32", + "uint32", + "uint64", + "uint8", + "unsignedinteger", + ): + with self.subTest(typ=type_): + inferred = self._inferred_numpy_attribute(type_) + for attr in unary_ops: + with self.subTest(attr=attr): + self.assertNotEqual(len(inferred.getattr(attr)), 0) + + def test_array_types_have_unary_operators(self): + """ + Test that array types have unary operators + """ + unary_ops = ("__neg__", "__invert__") + + for type_ in ("ndarray",): + with self.subTest(typ=type_): + inferred = self._inferred_numpy_attribute(type_) + for attr in unary_ops: + with self.subTest(attr=attr): + self.assertNotEqual(len(inferred.getattr(attr)), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/astroid/tests/unittest_brain_numpy_core_umath.py b/astroid/tests/unittest_brain_numpy_core_umath.py index 5bd887139a..8385e526c4 100644 --- a/astroid/tests/unittest_brain_numpy_core_umath.py +++ b/astroid/tests/unittest_brain_numpy_core_umath.py @@ -94,7 +94,6 @@ class NumpyBrainCoreUmathTest(SubTestWrapper): "copysign", "divide", "equal", - "float_power", "floor_divide", "fmax", "fmin", From 0e0edeb6158c01eb53ae8c798e035a77a93b0065 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 7 Apr 2019 15:45:09 +0200 Subject: [PATCH 18/40] Check that functions return a ndarray --- .../tests/unittest_brain_numpy_core_umath.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/astroid/tests/unittest_brain_numpy_core_umath.py b/astroid/tests/unittest_brain_numpy_core_umath.py index 8385e526c4..cb0b87906d 100644 --- a/astroid/tests/unittest_brain_numpy_core_umath.py +++ b/astroid/tests/unittest_brain_numpy_core_umath.py @@ -223,6 +223,32 @@ def test_numpy_core_umath_functions_kwargs_default_values(self): ] self.assertEqual(default_args_values, exact_kwargs_default_values) + def _inferred_numpy_func_call(self, func_name, *func_args): + node = builder.extract_node( + """ + import numpy as np + func = np.{:s} + func() + """.format(func_name) + ) + return node.infer() + + def test_numpy_core_umath_functions_return_type(self): + """ + Test that functions which should return a ndarray do return it + """ + ndarray_returning_func = [f + for f in self.all_ufunc + if f not in ('geterrobj', 'seterrobj', 'frexp', 'modf') + ] + licit_array_types = ('.ndarray',) + for func_ in ndarray_returning_func: + with self.subTest(typ=func_): + inferred_values = list(self._inferred_numpy_func_call(func_)) + self.assertTrue(len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_)) + self.assertTrue(inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format(func_, inferred_values[-1].pytype())) if __name__ == "__main__": unittest.main() From 2aba1f90740d45c832c39bdc9b084177227c9491 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 7 Apr 2019 17:18:33 +0200 Subject: [PATCH 19/40] Split the unittest_brain_numpy module --- astroid/tests/unittest_brain_numpy.py | 14 +--- ...unittest_brain_numpy_core_function_base.py | 79 ++++++++++++++++++ .../unittest_brain_numpy_core_multiarray.py | 83 +++++++++++++++++++ 3 files changed, 164 insertions(+), 12 deletions(-) create mode 100644 astroid/tests/unittest_brain_numpy_core_function_base.py create mode 100644 astroid/tests/unittest_brain_numpy_core_multiarray.py diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index 4797e64e6e..5aa4293ee1 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -45,18 +45,8 @@ class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): """ Test that calls to numpy functions returning arrays are correctly inferred """ - numpy_functions = (("array", "[1, 2]"), - ("linspace", "1, 100"), - ('empty_like', "[1, 2]"), - ('logical_or', "[1, 2]", "[1, 2]"), - ('logical_xor', "[1, 2]", "[1, 2]"), - ('logical_and', "[1, 2]", "[1, 2]"), - ('dot', "[1, 2]", "[1, 2]"), - ('vdot', "[1, 2]", "[1, 2]"), - ('concatenate', "([1, 2], [1, 2])"), - ('inner', "[1, 2]", "[1, 2]"), - ('where', '[True, False]', "[1, 2]", "[2, 1]"), - ('sum', '[[1, 2], [2, 1]]', "axis=0") + numpy_functions = ( + ('sum', '[[1, 2], [2, 1]]', "axis=0"), ) def _inferred_numpy_func_call(self, func_name, *func_args): diff --git a/astroid/tests/unittest_brain_numpy_core_function_base.py b/astroid/tests/unittest_brain_numpy_core_function_base.py new file mode 100644 index 0000000000..7cf548c76b --- /dev/null +++ b/astroid/tests/unittest_brain_numpy_core_function_base.py @@ -0,0 +1,79 @@ +# -*- encoding=utf-8 -*- +# Copyright (c) 2017-2018 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER +import unittest +import contextlib + +try: + import numpy # pylint: disable=unused-import + + HAS_NUMPY = True +except ImportError: + HAS_NUMPY = False + +from astroid import builder + + +class SubTestWrapper(unittest.TestCase): + """ + A class for supporting all unittest version wether or not subTest is available + """ + + def subTest(self, msg=None, **params): + try: + # For python versions above 3.5 this should be ok + return super(SubTestWrapper, self).subTest(msg, **params) + except AttributeError: + #  For python versions below 3.5 + return subTestMock(msg) + + +@contextlib.contextmanager +def subTestMock(msg=None): + """ + A mock for subTest which do nothing + """ + yield msg + + +@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") +class BrainNumpyCoreFunctionBaseTest(SubTestWrapper): + """ + Test the numpy core numeric brain module + """ + numpy_functions = ( + ("linspace", "1, 100"), + ("logspace", "1, 100"), + ("geomspace", "1, 100"), + ) + + def _inferred_numpy_func_call(self, func_name, *func_args): + node = builder.extract_node( + """ + import numpy as np + func = np.{:s} + func({:s}) + """.format( + func_name, ",".join(func_args) + ) + ) + return node.infer() + + def test_numpy_function_calls_inferred_as_ndarray(self): + """ + Test that calls to numpy functions are inferred as numpy.ndarray + """ + licit_array_types = ('.ndarray',) + for func_ in self.numpy_functions: + with self.subTest(typ=func_): + inferred_values = list(self._inferred_numpy_func_call(*func_)) + self.assertTrue(len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0])) + self.assertTrue(inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + + +if __name__ == "__main__": + unittest.main() diff --git a/astroid/tests/unittest_brain_numpy_core_multiarray.py b/astroid/tests/unittest_brain_numpy_core_multiarray.py new file mode 100644 index 0000000000..cb7af0208a --- /dev/null +++ b/astroid/tests/unittest_brain_numpy_core_multiarray.py @@ -0,0 +1,83 @@ +# -*- encoding=utf-8 -*- +# Copyright (c) 2017-2018 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER +import unittest +import contextlib + +try: + import numpy # pylint: disable=unused-import + + HAS_NUMPY = True +except ImportError: + HAS_NUMPY = False + +from astroid import builder + + +class SubTestWrapper(unittest.TestCase): + """ + A class for supporting all unittest version wether or not subTest is available + """ + + def subTest(self, msg=None, **params): + try: + # For python versions above 3.5 this should be ok + return super(SubTestWrapper, self).subTest(msg, **params) + except AttributeError: + #  For python versions below 3.5 + return subTestMock(msg) + + +@contextlib.contextmanager +def subTestMock(msg=None): + """ + A mock for subTest which do nothing + """ + yield msg + + +@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") +class BrainNumpyCoreMultiarrayTest(SubTestWrapper): + """ + Test the numpy core numeric brain module + """ + numpy_functions = ( + ('array', "[1, 2]"), + ('inner', "[1, 2]", "[1, 2]"), + ('vdot', "[1, 2]", "[1, 2]"), + ('concatenate', "([1, 2], [1, 2])"), + ('dot', "[1, 2]", "[1, 2]"), + ('empty_like', "[1, 2]"), + ('where', '[True, False]', "[1, 2]", "[2, 1]"), + ) + + def _inferred_numpy_func_call(self, func_name, *func_args): + node = builder.extract_node( + """ + import numpy as np + func = np.{:s} + func({:s}) + """.format( + func_name, ",".join(func_args) + ) + ) + return node.infer() + + def test_numpy_function_calls_inferred_as_ndarray(self): + """ + Test that calls to numpy functions are inferred as numpy.ndarray + """ + licit_array_types = ('.ndarray',) + for func_ in self.numpy_functions: + with self.subTest(typ=func_): + inferred_values = list(self._inferred_numpy_func_call(*func_)) + self.assertTrue(len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0])) + self.assertTrue(inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + + +if __name__ == "__main__": + unittest.main() From 2308d930e8ec0195079750dbbef8d69031f5b9ce Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 7 Apr 2019 17:19:18 +0200 Subject: [PATCH 20/40] Reformat --- astroid/brain/brain_numpy_core_multiarray.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py index f4399cf51a..e23a4bdbb4 100644 --- a/astroid/brain/brain_numpy_core_multiarray.py +++ b/astroid/brain/brain_numpy_core_multiarray.py @@ -19,9 +19,6 @@ def inner(a, b): def vdot(a, b): return numpy.ndarray([0, 0]) - - def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): - return numpy.ndarray([0, 0]) """ ) @@ -39,27 +36,27 @@ def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): return node.infer(context=context) -def infer_numpy_core_multiarray_dot(node, context=None): +def infer_numpy_core_multiarray_concatenate(node, context=None): src = """ - def dot(a, b, out=None): - return numpy.ndarray([0, 0]) + def concatenate(arrays, axis=None, out=None): + return numpy.ndarray((0, 0)) """ node = astroid.extract_node(src) return node.infer(context=context) -def infer_numpy_core_multiarray_empty_like(node, context=None): +def infer_numpy_core_multiarray_dot(node, context=None): src = """ - def empty_like(a, dtype=None, order='K', subok=True): - return numpy.ndarray((0, 0)) + def dot(a, b, out=None): + return numpy.ndarray([0, 0]) """ node = astroid.extract_node(src) return node.infer(context=context) -def infer_numpy_core_multiarray_concatenate(node, context=None): +def infer_numpy_core_multiarray_empty_like(node, context=None): src = """ - def concatenate(arrays, axis=None, out=None): + def empty_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) """ node = astroid.extract_node(src) From 27a9d3308d3874b76b6dec9cf3030b15c40947ed Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 7 Apr 2019 17:19:34 +0200 Subject: [PATCH 21/40] Add logspace et geomspace functions --- .../brain/brain_numpy_core_function_base.py | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/astroid/brain/brain_numpy_core_function_base.py b/astroid/brain/brain_numpy_core_function_base.py index fd5f193d62..79cb743376 100644 --- a/astroid/brain/brain_numpy_core_function_base.py +++ b/astroid/brain/brain_numpy_core_function_base.py @@ -9,7 +9,6 @@ import functools import astroid - def infer_numpy_core_function_base_linspace(node, context=None): src = """ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): @@ -18,6 +17,21 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis node = astroid.extract_node(src) return node.infer(context=context) +def infer_numpy_core_function_base_logspace(node, context=None): + src = """ + def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + +def infer_numpy_core_function_base_geomspace(node, context=None): + src = """ + def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) def looks_like_numpy_core_function_base_member(member_name, node): return (isinstance(node, astroid.Attribute) @@ -29,4 +43,16 @@ def looks_like_numpy_core_function_base_member(member_name, node): astroid.Attribute, astroid.inference_tip(infer_numpy_core_function_base_linspace), functools.partial(looks_like_numpy_core_function_base_member, "linspace") +) + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_function_base_logspace), + functools.partial(looks_like_numpy_core_function_base_member, "logspace") +) + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_function_base_geomspace), + functools.partial(looks_like_numpy_core_function_base_member, "geomspace") ) \ No newline at end of file From ee0db7fe456823fb905a665a63cacd13d8994b06 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 7 Apr 2019 18:34:59 +0200 Subject: [PATCH 22/40] Typo. --- astroid/brain/brain_numpy_core_fromnumeric.py | 2 +- astroid/tests/unittest_brain_numpy_core_multiarray.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/astroid/brain/brain_numpy_core_fromnumeric.py b/astroid/brain/brain_numpy_core_fromnumeric.py index 64b79adaa9..4988fe953f 100644 --- a/astroid/brain/brain_numpy_core_fromnumeric.py +++ b/astroid/brain/brain_numpy_core_fromnumeric.py @@ -4,7 +4,7 @@ # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER -"""Astroid hooks for numpy.core.umath module.""" +"""Astroid hooks for numpy.core.fromnumeric module.""" import astroid diff --git a/astroid/tests/unittest_brain_numpy_core_multiarray.py b/astroid/tests/unittest_brain_numpy_core_multiarray.py index cb7af0208a..e534548250 100644 --- a/astroid/tests/unittest_brain_numpy_core_multiarray.py +++ b/astroid/tests/unittest_brain_numpy_core_multiarray.py @@ -41,7 +41,7 @@ def subTestMock(msg=None): @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") class BrainNumpyCoreMultiarrayTest(SubTestWrapper): """ - Test the numpy core numeric brain module + Test the numpy core multiarray brain module """ numpy_functions = ( ('array', "[1, 2]"), From 8718254272de33d77de03536b5fe26ad781b47b5 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 7 Apr 2019 18:36:01 +0200 Subject: [PATCH 23/40] Add a unittest dedicated to the numpy_core_fromnumeric brain --- .../unittest_brain_numpy_core_fromnumeric.py | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 astroid/tests/unittest_brain_numpy_core_fromnumeric.py diff --git a/astroid/tests/unittest_brain_numpy_core_fromnumeric.py b/astroid/tests/unittest_brain_numpy_core_fromnumeric.py new file mode 100644 index 0000000000..c6c2319d94 --- /dev/null +++ b/astroid/tests/unittest_brain_numpy_core_fromnumeric.py @@ -0,0 +1,77 @@ +# -*- encoding=utf-8 -*- +# Copyright (c) 2017-2018 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER +import unittest +import contextlib + +try: + import numpy # pylint: disable=unused-import + + HAS_NUMPY = True +except ImportError: + HAS_NUMPY = False + +from astroid import builder + + +class SubTestWrapper(unittest.TestCase): + """ + A class for supporting all unittest version wether or not subTest is available + """ + + def subTest(self, msg=None, **params): + try: + # For python versions above 3.5 this should be ok + return super(SubTestWrapper, self).subTest(msg, **params) + except AttributeError: + #  For python versions below 3.5 + return subTestMock(msg) + + +@contextlib.contextmanager +def subTestMock(msg=None): + """ + A mock for subTest which do nothing + """ + yield msg + + +@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") +class BrainNumpyCoreFromNumericTest(SubTestWrapper): + """ + Test the numpy core fromnumeric brain module + """ + numpy_functions = ( + ('sum', "[1, 2]"), + ) + + def _inferred_numpy_func_call(self, func_name, *func_args): + node = builder.extract_node( + """ + import numpy as np + func = np.{:s} + func({:s}) + """.format( + func_name, ",".join(func_args) + ) + ) + return node.infer() + + def test_numpy_function_calls_inferred_as_ndarray(self): + """ + Test that calls to numpy functions are inferred as numpy.ndarray + """ + licit_array_types = ('.ndarray',) + for func_ in self.numpy_functions: + with self.subTest(typ=func_): + inferred_values = list(self._inferred_numpy_func_call(*func_)) + self.assertTrue(len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0])) + self.assertTrue(inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + + +if __name__ == "__main__": + unittest.main() From 0401d819efd642c32ab544a1534d57b97532b502 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 10:00:31 +0200 Subject: [PATCH 24/40] Correct prototypes of 3 dunder methods. --- astroid/brain/brain_numpy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.py index fec4e4d230..157d4ab33e 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy.py @@ -36,9 +36,9 @@ def __init__(self, shape, dtype=float, buffer=None, offset=0, def __abs__(self): return numpy.ndarray([0, 0]) def __add__(self, value): return numpy.ndarray([0, 0]) def __and__(self, value): return numpy.ndarray([0, 0]) - def __array__(dtype=None): return numpy.ndarray([0, 0]) - def __array_wrap__(obj): return numpy.ndarray([0, 0]) - def __contains__(self, key): return uninferable + def __array__(self, dtype=None): return numpy.ndarray([0, 0]) + def __array_wrap__(self, obj): return numpy.ndarray([0, 0]) + def __contains__(self, key): return True def __copy__(self): return numpy.ndarray([0, 0]) def __deepcopy__(self, memo): return numpy.ndarray([0, 0]) def __divmod__(self, value): return (numpy.ndarray([0, 0]), numpy.ndarray([0, 0])) From cee901276307d76015c72b3be30998fc9e5c631a Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 10:01:44 +0200 Subject: [PATCH 25/40] Refactor in order to test the methods of ndarray --- astroid/tests/unittest_brain_numpy.py | 63 +++++++++++++++++++++------ 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy.py index 5aa4293ee1..720926c1d3 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy.py @@ -45,19 +45,54 @@ class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): """ Test that calls to numpy functions returning arrays are correctly inferred """ - numpy_functions = ( - ('sum', '[[1, 2], [2, 1]]', "axis=0"), - ) + ndarray_returning_ndarray_methods = ( + "__abs__", + "__add__", + "__and__", + "__array__", + "__array_wrap__", + "__copy__", + "__deepcopy__", + "__eq__", + "__floordiv__", + "__ge__", + "__gt__", + "__iadd__", + "__iand__", + "__ifloordiv__", + "__ilshift__", + "__imod__", + "__imul__", + "__invert__", + "__ior__", + "__ipow__", + "__irshift__", + "__isub__", + "__itruediv__", + "__ixor__", + "__le__", + "__lshift__", + "__lt__", + "__matmul__", + "__mod__", + "__mul__", + "__ne__", + "__neg__", + "__or__", + "__pos__", + "__pow__", + "__rshift__", + "__sub__", + "__truediv__", + "__xor__") - def _inferred_numpy_func_call(self, func_name, *func_args): + def _inferred_ndarray_method_call(self, func_name): node = builder.extract_node( """ import numpy as np - func = np.{:s} - func({:s}) - """.format( - func_name, ",".join(func_args) - ) + test_array = np.ndarray((2, 2)) + test_array.{:s}() + """.format(func_name) ) return node.infer() @@ -65,14 +100,14 @@ def test_numpy_function_calls_inferred_as_ndarray(self): """ Test that some calls to numpy functions are inferred as numpy.ndarray """ - licit_array_types = ('.ndarray', 'numpy.core.records.recarray') - for func_ in self.numpy_functions: + licit_array_types = ('.ndarray') + for func_ in self.ndarray_returning_ndarray_methods: with self.subTest(typ=func_): - inferred_values = list(self._inferred_numpy_func_call(*func_)) + inferred_values = list(self._inferred_ndarray_method_call(func_)) self.assertTrue(len(inferred_values) == 1, - msg="Too much inferred value for {:s}".format(func_[0])) + msg="Too much inferred value for {:s}".format(func_)) self.assertTrue(inferred_values[-1].pytype() in licit_array_types, - msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + msg="Illicit type for {:s} ({})".format(func_, inferred_values[-1].pytype())) if __name__ == "__main__": unittest.main() From 264a547e664b76add99fb72a939e762cf36d80cc Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 10:14:06 +0200 Subject: [PATCH 26/40] Rename brain_numpy module and associated unit test module --- astroid/brain/{brain_numpy.py => brain_numpy_ndarray.py} | 2 +- ...{unittest_brain_numpy.py => unittest_brain_numpy_ndarray.py} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename astroid/brain/{brain_numpy.py => brain_numpy_ndarray.py} (99%) rename astroid/tests/{unittest_brain_numpy.py => unittest_brain_numpy_ndarray.py} (98%) diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy_ndarray.py similarity index 99% rename from astroid/brain/brain_numpy.py rename to astroid/brain/brain_numpy_ndarray.py index 157d4ab33e..3ab190efb1 100644 --- a/astroid/brain/brain_numpy.py +++ b/astroid/brain/brain_numpy_ndarray.py @@ -6,7 +6,7 @@ # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER -"""Astroid hooks for numpy.""" +"""Astroid hooks for numpy ndarray class.""" import functools import astroid diff --git a/astroid/tests/unittest_brain_numpy.py b/astroid/tests/unittest_brain_numpy_ndarray.py similarity index 98% rename from astroid/tests/unittest_brain_numpy.py rename to astroid/tests/unittest_brain_numpy_ndarray.py index 720926c1d3..89f4ccefd3 100644 --- a/astroid/tests/unittest_brain_numpy.py +++ b/astroid/tests/unittest_brain_numpy_ndarray.py @@ -41,7 +41,7 @@ def subTestMock(msg=None): @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class NumpyBrainFunctionReturningArrayTest(SubTestWrapper): +class NumpyBrainNdarrayTest(SubTestWrapper): """ Test that calls to numpy functions returning arrays are correctly inferred """ From 257c78b4d7118313aa4e6e13397d41d6615e269a Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 10:38:09 +0200 Subject: [PATCH 27/40] Add the tests concerning ndarray classic methods --- astroid/tests/unittest_brain_numpy_ndarray.py | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/astroid/tests/unittest_brain_numpy_ndarray.py b/astroid/tests/unittest_brain_numpy_ndarray.py index 89f4ccefd3..88215dafec 100644 --- a/astroid/tests/unittest_brain_numpy_ndarray.py +++ b/astroid/tests/unittest_brain_numpy_ndarray.py @@ -84,7 +84,47 @@ class NumpyBrainNdarrayTest(SubTestWrapper): "__rshift__", "__sub__", "__truediv__", - "__xor__") + "__xor__", + "all", + "any", + "argmax", + "argmin", + "argpartition", + "argsort", + "astype", + "byteswap", + "choose", + "clip", + "compress", + "conj", + "conjugate", + "copy", + "cumprod", + "cumsum", + "diagonal", + "dot", + "flatten", + "getfield", + "max", + "mean", + "min", + "newbyteorder", + "prod", + "ptp", + "ravel", + "repeat", + "reshape", + "round", + "searchsorted", + "squeeze", + "std", + "sum", + "swapaxes", + "take", + "trace", + "transpose", + "var", + "view") def _inferred_ndarray_method_call(self, func_name): node = builder.extract_node( From bef091da6efc9d2c1e579bdbf28c32c37b6fd2dd Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 11:09:08 +0200 Subject: [PATCH 28/40] Add .python-version file and .vscode directory --- .gitignore | 3 +++ astroid/brain/brain_numpy_core_numerictypes.py | 1 + astroid/brain/brain_numpy_random_mtrand.py | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 66d64d3e5d..7dc2c3d5fc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ astroid.egg-info/ .cache/ .eggs/ .pytest_cache/ +.python-version +.vscode/ + diff --git a/astroid/brain/brain_numpy_core_numerictypes.py b/astroid/brain/brain_numpy_core_numerictypes.py index f8bd63a969..fa4c421acb 100644 --- a/astroid/brain/brain_numpy_core_numerictypes.py +++ b/astroid/brain/brain_numpy_core_numerictypes.py @@ -3,6 +3,7 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER +# TODO(hippo91) : correct the methods signature. """Astroid hooks for numpy.core.numerictypes module.""" diff --git a/astroid/brain/brain_numpy_random_mtrand.py b/astroid/brain/brain_numpy_random_mtrand.py index 2279494355..3a0fd78363 100644 --- a/astroid/brain/brain_numpy_random_mtrand.py +++ b/astroid/brain/brain_numpy_random_mtrand.py @@ -3,7 +3,7 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER - +# TODO(hippo91) : correct the functions return types """Astroid hooks for numpy.random.mtrand module.""" import astroid From c1679a6ef6c36ca312cb173268d6565f43eefb6e Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 11:21:53 +0200 Subject: [PATCH 29/40] Add the __init__ method for datetime64and timedelta64 --- ChangeLog | 12 ++++++++++++ astroid/brain/brain_numpy_core_numerictypes.py | 6 ++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1a4e4eff5f..0453ea4230 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,18 @@ What's New in astroid 2.3.0? ============================ Release Date: TBA +* Numpy brain support is improved. + Numpy's fondamental type ``numpy.ndarray`` has its own brain : ``brain_numpy_ndarray`` and + each numpy module that necessitates brain action has now its own numpy brain : + + - ``numpy.core.numeric`` + - ``numpy.core.function_base`` + - ``numpy.core.multiarray`` + - ``numpy.core.numeric`` + - ``numpy.core.numerictypes`` + - ``numpy.core.umath`` + - ``numpy.random.mtrand`` + * Drop a superfluous and wrong callcontext when inferring the result of a context manager Close PyCQA/pylint#2859 diff --git a/astroid/brain/brain_numpy_core_numerictypes.py b/astroid/brain/brain_numpy_core_numerictypes.py index fa4c421acb..069b1472ba 100644 --- a/astroid/brain/brain_numpy_core_numerictypes.py +++ b/astroid/brain/brain_numpy_core_numerictypes.py @@ -134,7 +134,8 @@ class flexible(generic): pass class bool_(generic): pass class number(generic): def __neg__(self): return uninferable - class datetime64(generic): pass + class datetime64(generic): + def __init__(self, nb, unit=None): pass class void(flexible): @@ -192,7 +193,8 @@ class uint32(unsignedinteger): pass class uint8(unsignedinteger): pass class _typedict(dict): pass class complex192(complexfloating): pass - class timedelta64(signedinteger): pass + class timedelta64(signedinteger): + def __init__(self, nb, unit=None): pass class int32(signedinteger): pass class uint16(unsignedinteger): pass class float32(floating): pass From c10320b4acaa15e92044d4477f9efd026f3b41fb Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 16:05:51 +0200 Subject: [PATCH 30/40] Add the function numpy.empty --- astroid/brain/brain_numpy_core_multiarray.py | 14 ++++++++++++++ .../tests/unittest_brain_numpy_core_multiarray.py | 1 + 2 files changed, 15 insertions(+) diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py index e23a4bdbb4..ce2efd6603 100644 --- a/astroid/brain/brain_numpy_core_multiarray.py +++ b/astroid/brain/brain_numpy_core_multiarray.py @@ -71,6 +71,14 @@ def where(condition, x=None, y=None): node = astroid.extract_node(src) return node.infer(context=context) +def infer_numpy_core_multiarray_empty(node, context=None): + src = """ + def empty(shape, dtype=float, order='C'): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + def looks_like_numpy_core_multiarray_member(member_name, node): return (isinstance(node, astroid.Attribute) @@ -108,3 +116,9 @@ def looks_like_numpy_core_multiarray_member(member_name, node): functools.partial(looks_like_numpy_core_multiarray_member, "where") ) +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_multiarray_empty), + functools.partial(looks_like_numpy_core_multiarray_member, "empty") +) + diff --git a/astroid/tests/unittest_brain_numpy_core_multiarray.py b/astroid/tests/unittest_brain_numpy_core_multiarray.py index e534548250..f85dbb9130 100644 --- a/astroid/tests/unittest_brain_numpy_core_multiarray.py +++ b/astroid/tests/unittest_brain_numpy_core_multiarray.py @@ -51,6 +51,7 @@ class BrainNumpyCoreMultiarrayTest(SubTestWrapper): ('dot', "[1, 2]", "[1, 2]"), ('empty_like', "[1, 2]"), ('where', '[True, False]', "[1, 2]", "[2, 1]"), + ('empty', "[1, 2]"), ) def _inferred_numpy_func_call(self, func_name, *func_args): From d05ff50c9e77f1bac9cefb8255f45186216a4772 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 16:29:54 +0200 Subject: [PATCH 31/40] Add definition for numpy.ones and numpy.zeros functions --- astroid/brain/brain_numpy_core_multiarray.py | 14 +++++++++++++ astroid/brain/brain_numpy_core_numeric.py | 21 +++++++++++++++++++ .../unittest_brain_numpy_core_multiarray.py | 1 + .../unittest_brain_numpy_core_numeric.py | 1 + 4 files changed, 37 insertions(+) diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py index ce2efd6603..2aae85fc3f 100644 --- a/astroid/brain/brain_numpy_core_multiarray.py +++ b/astroid/brain/brain_numpy_core_multiarray.py @@ -80,6 +80,14 @@ def empty(shape, dtype=float, order='C'): return node.infer(context=context) +def infer_numpy_core_multiarray_empty(node, context=None): + src = """ + def zeros(shape, dtype=float, order='C'): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + def looks_like_numpy_core_multiarray_member(member_name, node): return (isinstance(node, astroid.Attribute) and node.attrname == member_name @@ -122,3 +130,9 @@ def looks_like_numpy_core_multiarray_member(member_name, node): functools.partial(looks_like_numpy_core_multiarray_member, "empty") ) +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_multiarray_empty), + functools.partial(looks_like_numpy_core_multiarray_member, "zeros") +) + diff --git a/astroid/brain/brain_numpy_core_numeric.py b/astroid/brain/brain_numpy_core_numeric.py index 0f2800740f..65f363201d 100644 --- a/astroid/brain/brain_numpy_core_numeric.py +++ b/astroid/brain/brain_numpy_core_numeric.py @@ -6,6 +6,7 @@ """Astroid hooks for numpy.core.numeric module.""" +import functools import astroid @@ -22,4 +23,24 @@ def full_like(a, fill_value, dtype=None, order='K', subok=True): return numpy.nd astroid.register_module_extender( astroid.MANAGER, "numpy.core.numeric", numpy_core_numeric_transform +) + +def infer_numpy_core_numeric_ones(node, context=None): + src = """ + def ones(shape, dtype=None, order='C'): + return numpy.ndarray([0, 0]) + """ + node = astroid.extract_node(src) + return node.infer(context=context) + +def looks_like_numpy_core_numeric_member(member_name, node): + return (isinstance(node, astroid.Attribute) + and node.attrname == member_name + and node.expr.inferred()[-1].name == 'numpy') + + +astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(infer_numpy_core_numeric_ones), + functools.partial(looks_like_numpy_core_numeric_member, "ones") ) \ No newline at end of file diff --git a/astroid/tests/unittest_brain_numpy_core_multiarray.py b/astroid/tests/unittest_brain_numpy_core_multiarray.py index f85dbb9130..938895c609 100644 --- a/astroid/tests/unittest_brain_numpy_core_multiarray.py +++ b/astroid/tests/unittest_brain_numpy_core_multiarray.py @@ -52,6 +52,7 @@ class BrainNumpyCoreMultiarrayTest(SubTestWrapper): ('empty_like', "[1, 2]"), ('where', '[True, False]', "[1, 2]", "[2, 1]"), ('empty', "[1, 2]"), + ('zeros', "[1, 2]"), ) def _inferred_numpy_func_call(self, func_name, *func_args): diff --git a/astroid/tests/unittest_brain_numpy_core_numeric.py b/astroid/tests/unittest_brain_numpy_core_numeric.py index f764d6d396..34c35a9052 100644 --- a/astroid/tests/unittest_brain_numpy_core_numeric.py +++ b/astroid/tests/unittest_brain_numpy_core_numeric.py @@ -47,6 +47,7 @@ class BrainNumpyCoreNumericTest(SubTestWrapper): ('zeros_like', "[1, 2]"), ('full_like', "[1, 2]", '4'), ('ones_like', "[1, 2]"), + ('ones', "[1, 2]"), ) def _inferred_numpy_func_call(self, func_name, *func_args): From 42ce258940f39d195187319e2166808310d767cb Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 17:18:34 +0200 Subject: [PATCH 32/40] Reformat for easier new function introduction --- astroid/brain/brain_numpy_core_multiarray.py | 130 +++++-------------- 1 file changed, 32 insertions(+), 98 deletions(-) diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py index 2aae85fc3f..9dc7e66b9d 100644 --- a/astroid/brain/brain_numpy_core_multiarray.py +++ b/astroid/brain/brain_numpy_core_multiarray.py @@ -27,112 +27,46 @@ def vdot(a, b): astroid.MANAGER, "numpy.core.multiarray", numpy_core_multiarray_transform ) -def infer_numpy_core_multiarray_array(node, context=None): - src = """ - def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - -def infer_numpy_core_multiarray_concatenate(node, context=None): - src = """ - def concatenate(arrays, axis=None, out=None): - return numpy.ndarray((0, 0)) - """ +def infer_numpy_core_multiarray_member(src, node, context=None): node = astroid.extract_node(src) return node.infer(context=context) -def infer_numpy_core_multiarray_dot(node, context=None): - src = """ - def dot(a, b, out=None): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - - -def infer_numpy_core_multiarray_empty_like(node, context=None): - src = """ - def empty_like(a, dtype=None, order='K', subok=True): - return numpy.ndarray((0, 0)) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - - -def infer_numpy_core_multiarray_where(node, context=None): - src = """ - def where(condition, x=None, y=None): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - -def infer_numpy_core_multiarray_empty(node, context=None): - src = """ - def empty(shape, dtype=float, order='C'): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - - -def infer_numpy_core_multiarray_empty(node, context=None): - src = """ - def zeros(shape, dtype=float, order='C'): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - def looks_like_numpy_core_multiarray_member(member_name, node): return (isinstance(node, astroid.Attribute) and node.attrname == member_name and node.expr.inferred()[-1].name == 'numpy') -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_multiarray_array), - functools.partial(looks_like_numpy_core_multiarray_member, "array") -) - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_multiarray_dot), - functools.partial(looks_like_numpy_core_multiarray_member, "dot") -) - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_multiarray_empty_like), - functools.partial(looks_like_numpy_core_multiarray_member, "empty_like") -) - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_multiarray_concatenate), - functools.partial(looks_like_numpy_core_multiarray_member, "concatenate") -) - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_multiarray_where), - functools.partial(looks_like_numpy_core_multiarray_member, "where") -) - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_multiarray_empty), - functools.partial(looks_like_numpy_core_multiarray_member, "empty") -) - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_multiarray_empty), - functools.partial(looks_like_numpy_core_multiarray_member, "zeros") -) - +RETURNING_NDARRAY_METHODS = { + "array": + """def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): + return numpy.ndarray([0, 0])""", + "dot": + """def dot(a, b, out=None): + return numpy.ndarray([0, 0])""", + "empty_like": + """def empty_like(a, dtype=None, order='K', subok=True): + return numpy.ndarray((0, 0))""", + "concatenate": + """def concatenate(arrays, axis=None, out=None): + return numpy.ndarray((0, 0))""", + "where": + """def where(condition, x=None, y=None): + return numpy.ndarray([0, 0])""", + "empty": + """def empty(shape, dtype=float, order='C'): + return numpy.ndarray([0, 0])""", + "zeros": + """def zeros(shape, dtype=float, order='C'): + return numpy.ndarray([0, 0])""" +} + +for method_name, function_src in RETURNING_NDARRAY_METHODS.items(): + inference_function = functools.partial(infer_numpy_core_multiarray_member, function_src) + astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(inference_function), + functools.partial(looks_like_numpy_core_multiarray_member, method_name) + ) From 585e118db8b5c88a2082aab6fbb113daa920b27c Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 20 Apr 2019 19:34:35 +0200 Subject: [PATCH 33/40] Factorize functions inference system --- .../brain/brain_numpy_core_function_base.py | 70 ++++++------------- astroid/brain/brain_numpy_core_multiarray.py | 20 ++---- astroid/brain/brain_numpy_utils.py | 21 ++++++ 3 files changed, 48 insertions(+), 63 deletions(-) create mode 100644 astroid/brain/brain_numpy_utils.py diff --git a/astroid/brain/brain_numpy_core_function_base.py b/astroid/brain/brain_numpy_core_function_base.py index 79cb743376..f75ee6ae6e 100644 --- a/astroid/brain/brain_numpy_core_function_base.py +++ b/astroid/brain/brain_numpy_core_function_base.py @@ -8,51 +8,25 @@ import functools import astroid - -def infer_numpy_core_function_base_linspace(node, context=None): - src = """ - def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - -def infer_numpy_core_function_base_logspace(node, context=None): - src = """ - def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - -def infer_numpy_core_function_base_geomspace(node, context=None): - src = """ - def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - -def looks_like_numpy_core_function_base_member(member_name, node): - return (isinstance(node, astroid.Attribute) - and node.attrname == member_name - and node.expr.inferred()[-1].name == 'numpy') - - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_function_base_linspace), - functools.partial(looks_like_numpy_core_function_base_member, "linspace") -) - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_function_base_logspace), - functools.partial(looks_like_numpy_core_function_base_member, "logspace") -) - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_function_base_geomspace), - functools.partial(looks_like_numpy_core_function_base_member, "geomspace") -) \ No newline at end of file +from brain_numpy_utils import looks_like_numpy_member, infer_numpy_member + + +METHODS_TO_BE_INFERRED = { + "linspace": + """def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): + return numpy.ndarray([0, 0])""", + "logspace": + """def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0): + return numpy.ndarray([0, 0])""", + "geomspace": + """def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): + return numpy.ndarray([0, 0])""" +} + +for func_name, func_src in METHODS_TO_BE_INFERRED.items(): + inference_function = functools.partial(infer_numpy_member, func_src) + astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(inference_function), + functools.partial(looks_like_numpy_member, func_name) + ) diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py index 9dc7e66b9d..9f7d7f2e3c 100644 --- a/astroid/brain/brain_numpy_core_multiarray.py +++ b/astroid/brain/brain_numpy_core_multiarray.py @@ -8,6 +8,7 @@ import functools import astroid +from brain_numpy_utils import looks_like_numpy_member, infer_numpy_member def numpy_core_multiarray_transform(): @@ -28,18 +29,7 @@ def vdot(a, b): ) -def infer_numpy_core_multiarray_member(src, node, context=None): - node = astroid.extract_node(src) - return node.infer(context=context) - - -def looks_like_numpy_core_multiarray_member(member_name, node): - return (isinstance(node, astroid.Attribute) - and node.attrname == member_name - and node.expr.inferred()[-1].name == 'numpy') - - -RETURNING_NDARRAY_METHODS = { +METHODS_TO_BE_INFERRED = { "array": """def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): return numpy.ndarray([0, 0])""", @@ -63,10 +53,10 @@ def looks_like_numpy_core_multiarray_member(member_name, node): return numpy.ndarray([0, 0])""" } -for method_name, function_src in RETURNING_NDARRAY_METHODS.items(): - inference_function = functools.partial(infer_numpy_core_multiarray_member, function_src) +for method_name, function_src in METHODS_TO_BE_INFERRED.items(): + inference_function = functools.partial(infer_numpy_member, function_src) astroid.MANAGER.register_transform( astroid.Attribute, astroid.inference_tip(inference_function), - functools.partial(looks_like_numpy_core_multiarray_member, method_name) + functools.partial(looks_like_numpy_member, method_name) ) diff --git a/astroid/brain/brain_numpy_utils.py b/astroid/brain/brain_numpy_utils.py new file mode 100644 index 0000000000..4de4ad46f1 --- /dev/null +++ b/astroid/brain/brain_numpy_utils.py @@ -0,0 +1,21 @@ +# Copyright (c) 2018-2019 hippo91 + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER + + +"""Different utilities for the numpy brains""" + + +import astroid + + +def infer_numpy_member(src, node, context=None): + node = astroid.extract_node(src) + return node.infer(context=context) + + +def looks_like_numpy_member(member_name, node): + return (isinstance(node, astroid.Attribute) + and node.attrname == member_name + and node.expr.inferred()[-1].name == 'numpy') From 7d5ae0df80702586b0da23f38ea6021274522a86 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 21 Apr 2019 09:26:54 +0200 Subject: [PATCH 34/40] Refactor to make the introduction of new functions easier --- astroid/brain/brain_numpy_core_numeric.py | 35 +++++++++++------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/astroid/brain/brain_numpy_core_numeric.py b/astroid/brain/brain_numpy_core_numeric.py index 65f363201d..d128a7adeb 100644 --- a/astroid/brain/brain_numpy_core_numeric.py +++ b/astroid/brain/brain_numpy_core_numeric.py @@ -8,6 +8,7 @@ import functools import astroid +from brain_numpy_utils import looks_like_numpy_member, infer_numpy_member def numpy_core_numeric_transform(): @@ -25,22 +26,18 @@ def full_like(a, fill_value, dtype=None, order='K', subok=True): return numpy.nd astroid.MANAGER, "numpy.core.numeric", numpy_core_numeric_transform ) -def infer_numpy_core_numeric_ones(node, context=None): - src = """ - def ones(shape, dtype=None, order='C'): - return numpy.ndarray([0, 0]) - """ - node = astroid.extract_node(src) - return node.infer(context=context) - -def looks_like_numpy_core_numeric_member(member_name, node): - return (isinstance(node, astroid.Attribute) - and node.attrname == member_name - and node.expr.inferred()[-1].name == 'numpy') - - -astroid.MANAGER.register_transform( - astroid.Attribute, - astroid.inference_tip(infer_numpy_core_numeric_ones), - functools.partial(looks_like_numpy_core_numeric_member, "ones") -) \ No newline at end of file + +METHODS_TO_BE_INFERRED = { + "ones": + """def ones(shape, dtype=None, order='C'): + return numpy.ndarray([0, 0])""" +} + + +for method_name, function_src in METHODS_TO_BE_INFERRED.items(): + inference_function = functools.partial(infer_numpy_member, function_src) + astroid.MANAGER.register_transform( + astroid.Attribute, + astroid.inference_tip(inference_function), + functools.partial(looks_like_numpy_member, method_name) + ) \ No newline at end of file From 4ab338eddd516a8cfdb0de23623d6ff39f083def Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sun, 21 Apr 2019 10:04:08 +0200 Subject: [PATCH 35/40] Refomat according to black --- astroid/brain/brain_numpy_core_fromnumeric.py | 8 ++-- .../brain/brain_numpy_core_function_base.py | 13 +++---- astroid/brain/brain_numpy_core_multiarray.py | 25 +++++-------- astroid/brain/brain_numpy_core_numeric.py | 10 ++--- .../brain/brain_numpy_core_numerictypes.py | 2 +- astroid/brain/brain_numpy_core_umath.py | 3 +- astroid/brain/brain_numpy_ndarray.py | 8 ++-- astroid/brain/brain_numpy_random_mtrand.py | 2 +- astroid/brain/brain_numpy_utils.py | 8 ++-- .../unittest_brain_numpy_core_fromnumeric.py | 21 +++++++---- ...unittest_brain_numpy_core_function_base.py | 25 ++++++++----- .../unittest_brain_numpy_core_multiarray.py | 37 +++++++++++-------- .../unittest_brain_numpy_core_numeric.py | 27 +++++++++----- .../tests/unittest_brain_numpy_core_umath.py | 28 +++++++++----- astroid/tests/unittest_brain_numpy_ndarray.py | 25 +++++++++---- 15 files changed, 143 insertions(+), 99 deletions(-) diff --git a/astroid/brain/brain_numpy_core_fromnumeric.py b/astroid/brain/brain_numpy_core_fromnumeric.py index 4988fe953f..43b30e4ded 100644 --- a/astroid/brain/brain_numpy_core_fromnumeric.py +++ b/astroid/brain/brain_numpy_core_fromnumeric.py @@ -8,14 +8,16 @@ import astroid + def numpy_core_fromnumeric_transform(): return astroid.parse( - """ + """ def sum(a, axis=None, dtype=None, out=None, keepdims=None, initial=None): return numpy.ndarray([0, 0]) - """) + """ + ) astroid.register_module_extender( astroid.MANAGER, "numpy.core.fromnumeric", numpy_core_fromnumeric_transform -) \ No newline at end of file +) diff --git a/astroid/brain/brain_numpy_core_function_base.py b/astroid/brain/brain_numpy_core_function_base.py index f75ee6ae6e..05a73d9624 100644 --- a/astroid/brain/brain_numpy_core_function_base.py +++ b/astroid/brain/brain_numpy_core_function_base.py @@ -12,15 +12,12 @@ METHODS_TO_BE_INFERRED = { - "linspace": - """def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): + "linspace": """def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): return numpy.ndarray([0, 0])""", - "logspace": - """def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0): + "logspace": """def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0): + return numpy.ndarray([0, 0])""", + "geomspace": """def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): return numpy.ndarray([0, 0])""", - "geomspace": - """def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): - return numpy.ndarray([0, 0])""" } for func_name, func_src in METHODS_TO_BE_INFERRED.items(): @@ -28,5 +25,5 @@ astroid.MANAGER.register_transform( astroid.Attribute, astroid.inference_tip(inference_function), - functools.partial(looks_like_numpy_member, func_name) + functools.partial(looks_like_numpy_member, func_name), ) diff --git a/astroid/brain/brain_numpy_core_multiarray.py b/astroid/brain/brain_numpy_core_multiarray.py index 9f7d7f2e3c..3032acc99a 100644 --- a/astroid/brain/brain_numpy_core_multiarray.py +++ b/astroid/brain/brain_numpy_core_multiarray.py @@ -30,27 +30,20 @@ def vdot(a, b): METHODS_TO_BE_INFERRED = { - "array": - """def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): + "array": """def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): return numpy.ndarray([0, 0])""", - "dot": - """def dot(a, b, out=None): + "dot": """def dot(a, b, out=None): return numpy.ndarray([0, 0])""", - "empty_like": - """def empty_like(a, dtype=None, order='K', subok=True): + "empty_like": """def empty_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0))""", - "concatenate": - """def concatenate(arrays, axis=None, out=None): + "concatenate": """def concatenate(arrays, axis=None, out=None): return numpy.ndarray((0, 0))""", - "where": - """def where(condition, x=None, y=None): + "where": """def where(condition, x=None, y=None): return numpy.ndarray([0, 0])""", - "empty": - """def empty(shape, dtype=float, order='C'): + "empty": """def empty(shape, dtype=float, order='C'): + return numpy.ndarray([0, 0])""", + "zeros": """def zeros(shape, dtype=float, order='C'): return numpy.ndarray([0, 0])""", - "zeros": - """def zeros(shape, dtype=float, order='C'): - return numpy.ndarray([0, 0])""" } for method_name, function_src in METHODS_TO_BE_INFERRED.items(): @@ -58,5 +51,5 @@ def vdot(a, b): astroid.MANAGER.register_transform( astroid.Attribute, astroid.inference_tip(inference_function), - functools.partial(looks_like_numpy_member, method_name) + functools.partial(looks_like_numpy_member, method_name), ) diff --git a/astroid/brain/brain_numpy_core_numeric.py b/astroid/brain/brain_numpy_core_numeric.py index d128a7adeb..ba43c9415d 100644 --- a/astroid/brain/brain_numpy_core_numeric.py +++ b/astroid/brain/brain_numpy_core_numeric.py @@ -20,7 +20,8 @@ def zeros_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0 def ones_like(a, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) def full_like(a, fill_value, dtype=None, order='K', subok=True): return numpy.ndarray((0, 0)) """ - ) + ) + astroid.register_module_extender( astroid.MANAGER, "numpy.core.numeric", numpy_core_numeric_transform @@ -28,8 +29,7 @@ def full_like(a, fill_value, dtype=None, order='K', subok=True): return numpy.nd METHODS_TO_BE_INFERRED = { - "ones": - """def ones(shape, dtype=None, order='C'): + "ones": """def ones(shape, dtype=None, order='C'): return numpy.ndarray([0, 0])""" } @@ -39,5 +39,5 @@ def full_like(a, fill_value, dtype=None, order='K', subok=True): return numpy.nd astroid.MANAGER.register_transform( astroid.Attribute, astroid.inference_tip(inference_function), - functools.partial(looks_like_numpy_member, method_name) - ) \ No newline at end of file + functools.partial(looks_like_numpy_member, method_name), + ) diff --git a/astroid/brain/brain_numpy_core_numerictypes.py b/astroid/brain/brain_numpy_core_numerictypes.py index 069b1472ba..42021fae65 100644 --- a/astroid/brain/brain_numpy_core_numerictypes.py +++ b/astroid/brain/brain_numpy_core_numerictypes.py @@ -247,4 +247,4 @@ class int64(signedinteger): pass astroid.register_module_extender( astroid.MANAGER, "numpy.core.numerictypes", numpy_core_numerictypes_transform -) \ No newline at end of file +) diff --git a/astroid/brain/brain_numpy_core_umath.py b/astroid/brain/brain_numpy_core_umath.py index 8ad46ba906..459d38c727 100644 --- a/astroid/brain/brain_numpy_core_umath.py +++ b/astroid/brain/brain_numpy_core_umath.py @@ -8,6 +8,7 @@ import astroid + def numpy_core_umath_transform(): ufunc_optional_keyword_arguments = ( """out=None, where=True, casting='same_kind', order='K', """ @@ -101,4 +102,4 @@ def true_divide(x1, x2, {opt_args:s}): return numpy.ndarray((0, 0)) astroid.register_module_extender( astroid.MANAGER, "numpy.core.umath", numpy_core_umath_transform -) \ No newline at end of file +) diff --git a/astroid/brain/brain_numpy_ndarray.py b/astroid/brain/brain_numpy_ndarray.py index 3ab190efb1..8c231a3009 100644 --- a/astroid/brain/brain_numpy_ndarray.py +++ b/astroid/brain/brain_numpy_ndarray.py @@ -141,11 +141,13 @@ def view(self, dtype=None, type=None): return np.ndarray([0, 0]) node = astroid.extract_node(ndarray) return node.infer(context=context) + def _looks_like_numpy_ndarray(node): - return isinstance(node, astroid.Attribute) and node.attrname == 'ndarray' + return isinstance(node, astroid.Attribute) and node.attrname == "ndarray" + astroid.MANAGER.register_transform( astroid.Attribute, astroid.inference_tip(infer_numpy_ndarray), - _looks_like_numpy_ndarray -) \ No newline at end of file + _looks_like_numpy_ndarray, +) diff --git a/astroid/brain/brain_numpy_random_mtrand.py b/astroid/brain/brain_numpy_random_mtrand.py index 3a0fd78363..772bfc4e3e 100644 --- a/astroid/brain/brain_numpy_random_mtrand.py +++ b/astroid/brain/brain_numpy_random_mtrand.py @@ -67,4 +67,4 @@ def zipf(a, size=None): return uninferable astroid.register_module_extender( astroid.MANAGER, "numpy.random.mtrand", numpy_random_mtrand_transform -) \ No newline at end of file +) diff --git a/astroid/brain/brain_numpy_utils.py b/astroid/brain/brain_numpy_utils.py index 4de4ad46f1..388a5a5f33 100644 --- a/astroid/brain/brain_numpy_utils.py +++ b/astroid/brain/brain_numpy_utils.py @@ -16,6 +16,8 @@ def infer_numpy_member(src, node, context=None): def looks_like_numpy_member(member_name, node): - return (isinstance(node, astroid.Attribute) - and node.attrname == member_name - and node.expr.inferred()[-1].name == 'numpy') + return ( + isinstance(node, astroid.Attribute) + and node.attrname == member_name + and node.expr.inferred()[-1].name == "numpy" + ) diff --git a/astroid/tests/unittest_brain_numpy_core_fromnumeric.py b/astroid/tests/unittest_brain_numpy_core_fromnumeric.py index c6c2319d94..154f28a897 100644 --- a/astroid/tests/unittest_brain_numpy_core_fromnumeric.py +++ b/astroid/tests/unittest_brain_numpy_core_fromnumeric.py @@ -43,9 +43,8 @@ class BrainNumpyCoreFromNumericTest(SubTestWrapper): """ Test the numpy core fromnumeric brain module """ - numpy_functions = ( - ('sum', "[1, 2]"), - ) + + numpy_functions = (("sum", "[1, 2]"),) def _inferred_numpy_func_call(self, func_name, *func_args): node = builder.extract_node( @@ -63,14 +62,20 @@ def test_numpy_function_calls_inferred_as_ndarray(self): """ Test that calls to numpy functions are inferred as numpy.ndarray """ - licit_array_types = ('.ndarray',) + licit_array_types = (".ndarray",) for func_ in self.numpy_functions: with self.subTest(typ=func_): inferred_values = list(self._inferred_numpy_func_call(*func_)) - self.assertTrue(len(inferred_values) == 1, - msg="Too much inferred value for {:s}".format(func_[0])) - self.assertTrue(inferred_values[-1].pytype() in licit_array_types, - msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + self.assertTrue( + len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0]), + ) + self.assertTrue( + inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format( + func_[0], inferred_values[-1].pytype() + ), + ) if __name__ == "__main__": diff --git a/astroid/tests/unittest_brain_numpy_core_function_base.py b/astroid/tests/unittest_brain_numpy_core_function_base.py index 7cf548c76b..506e1f8280 100644 --- a/astroid/tests/unittest_brain_numpy_core_function_base.py +++ b/astroid/tests/unittest_brain_numpy_core_function_base.py @@ -43,11 +43,12 @@ class BrainNumpyCoreFunctionBaseTest(SubTestWrapper): """ Test the numpy core numeric brain module """ + numpy_functions = ( - ("linspace", "1, 100"), - ("logspace", "1, 100"), - ("geomspace", "1, 100"), - ) + ("linspace", "1, 100"), + ("logspace", "1, 100"), + ("geomspace", "1, 100"), + ) def _inferred_numpy_func_call(self, func_name, *func_args): node = builder.extract_node( @@ -65,14 +66,20 @@ def test_numpy_function_calls_inferred_as_ndarray(self): """ Test that calls to numpy functions are inferred as numpy.ndarray """ - licit_array_types = ('.ndarray',) + licit_array_types = (".ndarray",) for func_ in self.numpy_functions: with self.subTest(typ=func_): inferred_values = list(self._inferred_numpy_func_call(*func_)) - self.assertTrue(len(inferred_values) == 1, - msg="Too much inferred value for {:s}".format(func_[0])) - self.assertTrue(inferred_values[-1].pytype() in licit_array_types, - msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + self.assertTrue( + len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0]), + ) + self.assertTrue( + inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format( + func_[0], inferred_values[-1].pytype() + ), + ) if __name__ == "__main__": diff --git a/astroid/tests/unittest_brain_numpy_core_multiarray.py b/astroid/tests/unittest_brain_numpy_core_multiarray.py index 938895c609..8367395677 100644 --- a/astroid/tests/unittest_brain_numpy_core_multiarray.py +++ b/astroid/tests/unittest_brain_numpy_core_multiarray.py @@ -43,17 +43,18 @@ class BrainNumpyCoreMultiarrayTest(SubTestWrapper): """ Test the numpy core multiarray brain module """ + numpy_functions = ( - ('array', "[1, 2]"), - ('inner', "[1, 2]", "[1, 2]"), - ('vdot', "[1, 2]", "[1, 2]"), - ('concatenate', "([1, 2], [1, 2])"), - ('dot', "[1, 2]", "[1, 2]"), - ('empty_like', "[1, 2]"), - ('where', '[True, False]', "[1, 2]", "[2, 1]"), - ('empty', "[1, 2]"), - ('zeros', "[1, 2]"), - ) + ("array", "[1, 2]"), + ("inner", "[1, 2]", "[1, 2]"), + ("vdot", "[1, 2]", "[1, 2]"), + ("concatenate", "([1, 2], [1, 2])"), + ("dot", "[1, 2]", "[1, 2]"), + ("empty_like", "[1, 2]"), + ("where", "[True, False]", "[1, 2]", "[2, 1]"), + ("empty", "[1, 2]"), + ("zeros", "[1, 2]"), + ) def _inferred_numpy_func_call(self, func_name, *func_args): node = builder.extract_node( @@ -71,14 +72,20 @@ def test_numpy_function_calls_inferred_as_ndarray(self): """ Test that calls to numpy functions are inferred as numpy.ndarray """ - licit_array_types = ('.ndarray',) + licit_array_types = (".ndarray",) for func_ in self.numpy_functions: with self.subTest(typ=func_): inferred_values = list(self._inferred_numpy_func_call(*func_)) - self.assertTrue(len(inferred_values) == 1, - msg="Too much inferred value for {:s}".format(func_[0])) - self.assertTrue(inferred_values[-1].pytype() in licit_array_types, - msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + self.assertTrue( + len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0]), + ) + self.assertTrue( + inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format( + func_[0], inferred_values[-1].pytype() + ), + ) if __name__ == "__main__": diff --git a/astroid/tests/unittest_brain_numpy_core_numeric.py b/astroid/tests/unittest_brain_numpy_core_numeric.py index 34c35a9052..ccb76fd916 100644 --- a/astroid/tests/unittest_brain_numpy_core_numeric.py +++ b/astroid/tests/unittest_brain_numpy_core_numeric.py @@ -43,12 +43,13 @@ class BrainNumpyCoreNumericTest(SubTestWrapper): """ Test the numpy core numeric brain module """ + numpy_functions = ( - ('zeros_like', "[1, 2]"), - ('full_like', "[1, 2]", '4'), - ('ones_like', "[1, 2]"), - ('ones', "[1, 2]"), - ) + ("zeros_like", "[1, 2]"), + ("full_like", "[1, 2]", "4"), + ("ones_like", "[1, 2]"), + ("ones", "[1, 2]"), + ) def _inferred_numpy_func_call(self, func_name, *func_args): node = builder.extract_node( @@ -66,14 +67,20 @@ def test_numpy_function_calls_inferred_as_ndarray(self): """ Test that calls to numpy functions are inferred as numpy.ndarray """ - licit_array_types = ('.ndarray',) + licit_array_types = (".ndarray",) for func_ in self.numpy_functions: with self.subTest(typ=func_): inferred_values = list(self._inferred_numpy_func_call(*func_)) - self.assertTrue(len(inferred_values) == 1, - msg="Too much inferred value for {:s}".format(func_[0])) - self.assertTrue(inferred_values[-1].pytype() in licit_array_types, - msg="Illicit type for {:s} ({})".format(func_[0], inferred_values[-1].pytype())) + self.assertTrue( + len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_[0]), + ) + self.assertTrue( + inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format( + func_[0], inferred_values[-1].pytype() + ), + ) if __name__ == "__main__": diff --git a/astroid/tests/unittest_brain_numpy_core_umath.py b/astroid/tests/unittest_brain_numpy_core_umath.py index cb0b87906d..6822ac3290 100644 --- a/astroid/tests/unittest_brain_numpy_core_umath.py +++ b/astroid/tests/unittest_brain_numpy_core_umath.py @@ -229,7 +229,9 @@ def _inferred_numpy_func_call(self, func_name, *func_args): import numpy as np func = np.{:s} func() - """.format(func_name) + """.format( + func_name + ) ) return node.infer() @@ -237,18 +239,26 @@ def test_numpy_core_umath_functions_return_type(self): """ Test that functions which should return a ndarray do return it """ - ndarray_returning_func = [f + ndarray_returning_func = [ + f for f in self.all_ufunc - if f not in ('geterrobj', 'seterrobj', 'frexp', 'modf') - ] - licit_array_types = ('.ndarray',) + if f not in ("geterrobj", "seterrobj", "frexp", "modf") + ] + licit_array_types = (".ndarray",) for func_ in ndarray_returning_func: with self.subTest(typ=func_): inferred_values = list(self._inferred_numpy_func_call(func_)) - self.assertTrue(len(inferred_values) == 1, - msg="Too much inferred value for {:s}".format(func_)) - self.assertTrue(inferred_values[-1].pytype() in licit_array_types, - msg="Illicit type for {:s} ({})".format(func_, inferred_values[-1].pytype())) + self.assertTrue( + len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_), + ) + self.assertTrue( + inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format( + func_, inferred_values[-1].pytype() + ), + ) + if __name__ == "__main__": unittest.main() diff --git a/astroid/tests/unittest_brain_numpy_ndarray.py b/astroid/tests/unittest_brain_numpy_ndarray.py index 88215dafec..5283649eaa 100644 --- a/astroid/tests/unittest_brain_numpy_ndarray.py +++ b/astroid/tests/unittest_brain_numpy_ndarray.py @@ -45,6 +45,7 @@ class NumpyBrainNdarrayTest(SubTestWrapper): """ Test that calls to numpy functions returning arrays are correctly inferred """ + ndarray_returning_ndarray_methods = ( "__abs__", "__add__", @@ -124,7 +125,8 @@ class NumpyBrainNdarrayTest(SubTestWrapper): "trace", "transpose", "var", - "view") + "view", + ) def _inferred_ndarray_method_call(self, func_name): node = builder.extract_node( @@ -132,7 +134,9 @@ def _inferred_ndarray_method_call(self, func_name): import numpy as np test_array = np.ndarray((2, 2)) test_array.{:s}() - """.format(func_name) + """.format( + func_name + ) ) return node.infer() @@ -140,14 +144,21 @@ def test_numpy_function_calls_inferred_as_ndarray(self): """ Test that some calls to numpy functions are inferred as numpy.ndarray """ - licit_array_types = ('.ndarray') + licit_array_types = ".ndarray" for func_ in self.ndarray_returning_ndarray_methods: with self.subTest(typ=func_): inferred_values = list(self._inferred_ndarray_method_call(func_)) - self.assertTrue(len(inferred_values) == 1, - msg="Too much inferred value for {:s}".format(func_)) - self.assertTrue(inferred_values[-1].pytype() in licit_array_types, - msg="Illicit type for {:s} ({})".format(func_, inferred_values[-1].pytype())) + self.assertTrue( + len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(func_), + ) + self.assertTrue( + inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format( + func_, inferred_values[-1].pytype() + ), + ) + if __name__ == "__main__": unittest.main() From ee3d323436ca2c73ddf5184207bd6badc6dd9496 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Fri, 26 Apr 2019 15:42:01 +0200 Subject: [PATCH 36/40] Corrects the way a numpy member is identified --- astroid/brain/brain_numpy_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astroid/brain/brain_numpy_utils.py b/astroid/brain/brain_numpy_utils.py index 388a5a5f33..34ff4d2bda 100644 --- a/astroid/brain/brain_numpy_utils.py +++ b/astroid/brain/brain_numpy_utils.py @@ -19,5 +19,5 @@ def looks_like_numpy_member(member_name, node): return ( isinstance(node, astroid.Attribute) and node.attrname == member_name - and node.expr.inferred()[-1].name == "numpy" + and node.expr.inferred()[0].name.startswith("numpy") ) From 4ad2fd1c80cab63c85f2636a8849d9b58c0c8cf7 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Fri, 26 Apr 2019 16:00:43 +0200 Subject: [PATCH 37/40] Add the references to pylint bugs corrected --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 0453ea4230..2f0b26457b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,12 @@ Release Date: TBA - ``numpy.core.umath`` - ``numpy.random.mtrand`` + Close PyCQA/pylint2865 + Close PyCQA/pylint2747 + Close PyCQA/pylint2721 + Close PyCQA/pylint2326 + Close PyCQA/pylint2021 + * Drop a superfluous and wrong callcontext when inferring the result of a context manager Close PyCQA/pylint#2859 From 442dcae900ca665f686142967dc58de349054edf Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 25 May 2019 21:47:44 +0200 Subject: [PATCH 38/40] Deleting personal setup --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 7dc2c3d5fc..66d64d3e5d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,3 @@ astroid.egg-info/ .cache/ .eggs/ .pytest_cache/ -.python-version -.vscode/ - From c2bb4f68fdab7feecfdd51079e1163c4cc0be179 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 25 May 2019 21:48:30 +0200 Subject: [PATCH 39/40] Avoid use of inference engine before it is fully set up. Add docstrings --- astroid/brain/brain_numpy_utils.py | 36 ++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/astroid/brain/brain_numpy_utils.py b/astroid/brain/brain_numpy_utils.py index 34ff4d2bda..964b63693c 100644 --- a/astroid/brain/brain_numpy_utils.py +++ b/astroid/brain/brain_numpy_utils.py @@ -15,9 +15,41 @@ def infer_numpy_member(src, node, context=None): return node.infer(context=context) -def looks_like_numpy_member(member_name, node): +def _is_a_numpy_module(node: astroid.node_classes.Name) -> bool: + """ + Returns True if the node is a representation of a numpy module. + + For example in : + import numpy as np + x = np.linspace(1, 2) + The node is a representation of the numpy module. + + :param node: node to test + :return: True if the node is a representation of the numpy module. + """ + module_nickname = node.name + potential_import_target = [ + x for x in node.lookup(module_nickname)[1] if isinstance(x, astroid.Import) + ] + for target in potential_import_target: + if ("numpy", module_nickname) in target.names: + return True + return False + + +def looks_like_numpy_member( + member_name: str, node: astroid.node_classes.NodeNG +) -> bool: + """ + Returns True if the node is a member of numpy whose + name is member_name. + + :param member_name: name of the member + :param node: node to test + :return: True if the node is a member of numpy + """ return ( isinstance(node, astroid.Attribute) and node.attrname == member_name - and node.expr.inferred()[0].name.startswith("numpy") + and _is_a_numpy_module(node.expr) ) From f8d12d275c18579615f7e63d701ce0b421facb27 Mon Sep 17 00:00:00 2001 From: hippo91 Date: Sat, 25 May 2019 21:48:58 +0200 Subject: [PATCH 40/40] Deleting useless subTest mock for python version prior to 3.4 --- .../unittest_brain_numpy_core_fromnumeric.py | 25 +------------------ ...unittest_brain_numpy_core_function_base.py | 25 +------------------ .../unittest_brain_numpy_core_multiarray.py | 25 +------------------ .../unittest_brain_numpy_core_numeric.py | 25 +------------------ .../unittest_brain_numpy_core_numerictypes.py | 25 +------------------ .../tests/unittest_brain_numpy_core_umath.py | 25 +------------------ astroid/tests/unittest_brain_numpy_ndarray.py | 25 +------------------ .../unittest_brain_numpy_random_mtrand.py | 25 +------------------ 8 files changed, 8 insertions(+), 192 deletions(-) diff --git a/astroid/tests/unittest_brain_numpy_core_fromnumeric.py b/astroid/tests/unittest_brain_numpy_core_fromnumeric.py index 154f28a897..16d73e2ee0 100644 --- a/astroid/tests/unittest_brain_numpy_core_fromnumeric.py +++ b/astroid/tests/unittest_brain_numpy_core_fromnumeric.py @@ -4,7 +4,6 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER import unittest -import contextlib try: import numpy # pylint: disable=unused-import @@ -16,30 +15,8 @@ from astroid import builder -class SubTestWrapper(unittest.TestCase): - """ - A class for supporting all unittest version wether or not subTest is available - """ - - def subTest(self, msg=None, **params): - try: - # For python versions above 3.5 this should be ok - return super(SubTestWrapper, self).subTest(msg, **params) - except AttributeError: - #  For python versions below 3.5 - return subTestMock(msg) - - -@contextlib.contextmanager -def subTestMock(msg=None): - """ - A mock for subTest which do nothing - """ - yield msg - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class BrainNumpyCoreFromNumericTest(SubTestWrapper): +class BrainNumpyCoreFromNumericTest(unittest.TestCase): """ Test the numpy core fromnumeric brain module """ diff --git a/astroid/tests/unittest_brain_numpy_core_function_base.py b/astroid/tests/unittest_brain_numpy_core_function_base.py index 506e1f8280..06a940c839 100644 --- a/astroid/tests/unittest_brain_numpy_core_function_base.py +++ b/astroid/tests/unittest_brain_numpy_core_function_base.py @@ -4,7 +4,6 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER import unittest -import contextlib try: import numpy # pylint: disable=unused-import @@ -16,30 +15,8 @@ from astroid import builder -class SubTestWrapper(unittest.TestCase): - """ - A class for supporting all unittest version wether or not subTest is available - """ - - def subTest(self, msg=None, **params): - try: - # For python versions above 3.5 this should be ok - return super(SubTestWrapper, self).subTest(msg, **params) - except AttributeError: - #  For python versions below 3.5 - return subTestMock(msg) - - -@contextlib.contextmanager -def subTestMock(msg=None): - """ - A mock for subTest which do nothing - """ - yield msg - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class BrainNumpyCoreFunctionBaseTest(SubTestWrapper): +class BrainNumpyCoreFunctionBaseTest(unittest.TestCase): """ Test the numpy core numeric brain module """ diff --git a/astroid/tests/unittest_brain_numpy_core_multiarray.py b/astroid/tests/unittest_brain_numpy_core_multiarray.py index 8367395677..d7009815af 100644 --- a/astroid/tests/unittest_brain_numpy_core_multiarray.py +++ b/astroid/tests/unittest_brain_numpy_core_multiarray.py @@ -4,7 +4,6 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER import unittest -import contextlib try: import numpy # pylint: disable=unused-import @@ -16,30 +15,8 @@ from astroid import builder -class SubTestWrapper(unittest.TestCase): - """ - A class for supporting all unittest version wether or not subTest is available - """ - - def subTest(self, msg=None, **params): - try: - # For python versions above 3.5 this should be ok - return super(SubTestWrapper, self).subTest(msg, **params) - except AttributeError: - #  For python versions below 3.5 - return subTestMock(msg) - - -@contextlib.contextmanager -def subTestMock(msg=None): - """ - A mock for subTest which do nothing - """ - yield msg - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class BrainNumpyCoreMultiarrayTest(SubTestWrapper): +class BrainNumpyCoreMultiarrayTest(unittest.TestCase): """ Test the numpy core multiarray brain module """ diff --git a/astroid/tests/unittest_brain_numpy_core_numeric.py b/astroid/tests/unittest_brain_numpy_core_numeric.py index ccb76fd916..56b7d0d632 100644 --- a/astroid/tests/unittest_brain_numpy_core_numeric.py +++ b/astroid/tests/unittest_brain_numpy_core_numeric.py @@ -4,7 +4,6 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER import unittest -import contextlib try: import numpy # pylint: disable=unused-import @@ -16,30 +15,8 @@ from astroid import builder -class SubTestWrapper(unittest.TestCase): - """ - A class for supporting all unittest version wether or not subTest is available - """ - - def subTest(self, msg=None, **params): - try: - # For python versions above 3.5 this should be ok - return super(SubTestWrapper, self).subTest(msg, **params) - except AttributeError: - #  For python versions below 3.5 - return subTestMock(msg) - - -@contextlib.contextmanager -def subTestMock(msg=None): - """ - A mock for subTest which do nothing - """ - yield msg - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class BrainNumpyCoreNumericTest(SubTestWrapper): +class BrainNumpyCoreNumericTest(unittest.TestCase): """ Test the numpy core numeric brain module """ diff --git a/astroid/tests/unittest_brain_numpy_core_numerictypes.py b/astroid/tests/unittest_brain_numpy_core_numerictypes.py index 5e4ebbac2a..768a5570bd 100644 --- a/astroid/tests/unittest_brain_numpy_core_numerictypes.py +++ b/astroid/tests/unittest_brain_numpy_core_numerictypes.py @@ -6,7 +6,6 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER import unittest -import contextlib try: import numpy # pylint: disable=unused-import @@ -19,30 +18,8 @@ from astroid import nodes -class SubTestWrapper(unittest.TestCase): - """ - A class for supporting all unittest version wether or not subTest is available - """ - - def subTest(self, msg=None, **params): - try: - # For python versions above 3.5 this should be ok - return super(SubTestWrapper, self).subTest(msg, **params) - except AttributeError: - #  For python versions below 3.5 - return subTestMock(msg) - - -@contextlib.contextmanager -def subTestMock(msg=None): - """ - A mock for subTest which do nothing - """ - yield msg - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class NumpyBrainCoreNumericTypesTest(SubTestWrapper): +class NumpyBrainCoreNumericTypesTest(unittest.TestCase): """ Test of all the missing types defined in numerictypes module. """ diff --git a/astroid/tests/unittest_brain_numpy_core_umath.py b/astroid/tests/unittest_brain_numpy_core_umath.py index 6822ac3290..7030323fc5 100644 --- a/astroid/tests/unittest_brain_numpy_core_umath.py +++ b/astroid/tests/unittest_brain_numpy_core_umath.py @@ -4,7 +4,6 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER import unittest -import contextlib try: import numpy # pylint: disable=unused-import @@ -17,30 +16,8 @@ from astroid import nodes -class SubTestWrapper(unittest.TestCase): - """ - A class for supporting all unittest version wether or not subTest is available - """ - - def subTest(self, msg=None, **params): - try: - # For python versions above 3.5 this should be ok - return super(SubTestWrapper, self).subTest(msg, **params) - except AttributeError: - #  For python versions below 3.5 - return subTestMock(msg) - - -@contextlib.contextmanager -def subTestMock(msg=None): - """ - A mock for subTest which do nothing - """ - yield msg - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class NumpyBrainCoreUmathTest(SubTestWrapper): +class NumpyBrainCoreUmathTest(unittest.TestCase): """ Test of all members of numpy.core.umath module """ diff --git a/astroid/tests/unittest_brain_numpy_ndarray.py b/astroid/tests/unittest_brain_numpy_ndarray.py index 5283649eaa..d982f7f6bb 100644 --- a/astroid/tests/unittest_brain_numpy_ndarray.py +++ b/astroid/tests/unittest_brain_numpy_ndarray.py @@ -6,7 +6,6 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER import unittest -import contextlib try: import numpy # pylint: disable=unused-import @@ -18,30 +17,8 @@ from astroid import builder -class SubTestWrapper(unittest.TestCase): - """ - A class for supporting all unittest version wether or not subTest is available - """ - - def subTest(self, msg=None, **params): - try: - # For python versions above 3.5 this should be ok - return super(SubTestWrapper, self).subTest(msg, **params) - except AttributeError: - #  For python versions below 3.5 - return subTestMock(msg) - - -@contextlib.contextmanager -def subTestMock(msg=None): - """ - A mock for subTest which do nothing - """ - yield msg - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class NumpyBrainNdarrayTest(SubTestWrapper): +class NumpyBrainNdarrayTest(unittest.TestCase): """ Test that calls to numpy functions returning arrays are correctly inferred """ diff --git a/astroid/tests/unittest_brain_numpy_random_mtrand.py b/astroid/tests/unittest_brain_numpy_random_mtrand.py index 71d7bd09c9..4ca296f11d 100644 --- a/astroid/tests/unittest_brain_numpy_random_mtrand.py +++ b/astroid/tests/unittest_brain_numpy_random_mtrand.py @@ -6,7 +6,6 @@ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER import unittest -import contextlib try: import numpy # pylint: disable=unused-import @@ -19,30 +18,8 @@ from astroid import nodes -class SubTestWrapper(unittest.TestCase): - """ - A class for supporting all unittest version wether or not subTest is available - """ - - def subTest(self, msg=None, **params): - try: - # For python versions above 3.5 this should be ok - return super(SubTestWrapper, self).subTest(msg, **params) - except AttributeError: - #  For python versions below 3.5 - return subTestMock(msg) - - -@contextlib.contextmanager -def subTestMock(msg=None): - """ - A mock for subTest which do nothing - """ - yield msg - - @unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.") -class NumpyBrainRandomMtrandTest(SubTestWrapper): +class NumpyBrainRandomMtrandTest(unittest.TestCase): """ Test of all the functions of numpy.random.mtrand module. """