From 3be9fb4c444417a046d5d0e0ae3a5bf82345016c Mon Sep 17 00:00:00 2001 From: Alexander Marchuk Date: Tue, 8 Jul 2014 20:39:20 +0400 Subject: [PATCH] fix and tests for PY-8836 (false positive after ndarray and int multiplication) and PY-13422 (wrong return type in numpy.ones quickdoc) Conflicts: python/testSrc/com/jetbrains/python/PyTypeTest.java --- .../NumpyDocStringTypeProvider.java | 9 ++ python/testData/quickdoc/NumPyOnesDoc.html | 2 + python/testData/quickdoc/NumPyOnesDoc.py | 4 + .../quickdoc/NumPyOnesDoc/numpy/__init__.py | 5 + .../NumPyOnesDoc/numpy/core/__init__.py | 6 + .../NumPyOnesDoc/numpy/core/multiarray.py | 120 ++++++++++++++++ .../NumPyOnesDoc/numpy/core/numeric.py | 51 +++++++ .../numpy/__init__.py | 5 + .../numpy/core/__init__.py | 6 + .../numpy/core/multiarray.py | 129 ++++++++++++++++++ .../numpy/core/numeric.py | 51 +++++++ .../com/jetbrains/python/PyQuickDocTest.java | 10 +- .../com/jetbrains/python/PyTypeTest.java | 43 ++++-- 13 files changed, 432 insertions(+), 9 deletions(-) create mode 100644 python/testData/quickdoc/NumPyOnesDoc.html create mode 100644 python/testData/quickdoc/NumPyOnesDoc.py create mode 100644 python/testData/quickdoc/NumPyOnesDoc/numpy/__init__.py create mode 100644 python/testData/quickdoc/NumPyOnesDoc/numpy/core/__init__.py create mode 100644 python/testData/quickdoc/NumPyOnesDoc/numpy/core/multiarray.py create mode 100644 python/testData/quickdoc/NumPyOnesDoc/numpy/core/numeric.py create mode 100644 python/testData/types/NumpyArrayIntMultiplicationType/numpy/__init__.py create mode 100644 python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/__init__.py create mode 100644 python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/multiarray.py create mode 100644 python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/numeric.py diff --git a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java index 18786ed32ee5..1abd08650ad0 100644 --- a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java +++ b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java @@ -168,4 +168,13 @@ public class NumpyDocStringTypeProvider extends PyTypeProviderBase { } return null; } + + @Nullable + @Override + public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) { + if (callable instanceof PyFunction) { + return getCallType((PyFunction)callable, null, context); + } + return null; + } } diff --git a/python/testData/quickdoc/NumPyOnesDoc.html b/python/testData/quickdoc/NumPyOnesDoc.html new file mode 100644 index 000000000000..22c482b10807 --- /dev/null +++ b/python/testData/quickdoc/NumPyOnesDoc.html @@ -0,0 +1,2 @@ +def ones(shape, dtype=None, order='C') +Inferred type: (shape: int, dtype: object, order: str) -> ndarray
diff --git a/python/testData/quickdoc/NumPyOnesDoc.py b/python/testData/quickdoc/NumPyOnesDoc.py new file mode 100644 index 000000000000..8d2130158c9e --- /dev/null +++ b/python/testData/quickdoc/NumPyOnesDoc.py @@ -0,0 +1,4 @@ +import numpy as np + +x = np.ones(10) + diff --git a/python/testData/quickdoc/NumPyOnesDoc/numpy/__init__.py b/python/testData/quickdoc/NumPyOnesDoc/numpy/__init__.py new file mode 100644 index 000000000000..d58ac8cf7af0 --- /dev/null +++ b/python/testData/quickdoc/NumPyOnesDoc/numpy/__init__.py @@ -0,0 +1,5 @@ +from . import core +from .core import * + +__all__ = [] +__all__.extend(core.__all__) diff --git a/python/testData/quickdoc/NumPyOnesDoc/numpy/core/__init__.py b/python/testData/quickdoc/NumPyOnesDoc/numpy/core/__init__.py new file mode 100644 index 000000000000..51afb32bcebe --- /dev/null +++ b/python/testData/quickdoc/NumPyOnesDoc/numpy/core/__init__.py @@ -0,0 +1,6 @@ +from . import multiarray +from . import numeric +from .numeric import * + +__all__ = [] +__all__ += numeric.__all__ diff --git a/python/testData/quickdoc/NumPyOnesDoc/numpy/core/multiarray.py b/python/testData/quickdoc/NumPyOnesDoc/numpy/core/multiarray.py new file mode 100644 index 000000000000..6eae8aed6e5d --- /dev/null +++ b/python/testData/quickdoc/NumPyOnesDoc/numpy/core/multiarray.py @@ -0,0 +1,120 @@ +class ndarray(object): + """ + ndarray(shape, dtype=float, buffer=None, offset=0, + strides=None, order=None) + + An array object represents a multidimensional, homogeneous array + of fixed-size items. An associated data-type object describes the + format of each element in the array (its byte-order, how many bytes it + occupies in memory, whether it is an integer, a floating point number, + or something else, etc.) + + Arrays should be constructed using `array`, `zeros` or `empty` (refer + to the See Also section below). The parameters given here refer to + a low-level method (`ndarray(...)`) for instantiating an array. + + For more information, refer to the `numpy` module and examine the + the methods and attributes of an array. + + Parameters + ---------- + (for the __new__ method; see Notes below) + + shape : tuple of ints + Shape of created array. + dtype : data-type, optional + Any object that can be interpreted as a numpy data type. + buffer : object exposing buffer interface, optional + Used to fill the array with data. + offset : int, optional + Offset of array data in buffer. + strides : tuple of ints, optional + Strides of data in memory. + order : {'C', 'F'}, optional + Row-major or column-major order. + + Attributes + ---------- + T : ndarray + Transpose of the array. + data : buffer + The array's elements, in memory. + dtype : dtype object + Describes the format of the elements in the array. + flags : dict + Dictionary containing information related to memory use, e.g., + 'C_CONTIGUOUS', 'OWNDATA', 'WRITEABLE', etc. + flat : numpy.flatiter object + Flattened version of the array as an iterator. The iterator + allows assignments, e.g., ``x.flat = 3`` (See `ndarray.flat` for + assignment examples; TODO). + imag : ndarray + Imaginary part of the array. + real : ndarray + Real part of the array. + size : int + Number of elements in the array. + itemsize : int + The memory use of each array element in bytes. + nbytes : int + The total number of bytes required to store the array data, + i.e., ``itemsize * size``. + ndim : int + The array's number of dimensions. + shape : tuple of ints + Shape of the array. + strides : tuple of ints + The step-size required to move from one element to the next in + memory. For example, a contiguous ``(3, 4)`` array of type + ``int16`` in C-order has strides ``(8, 2)``. This implies that + to move from element to element in memory requires jumps of 2 bytes. + To move from row-to-row, one needs to jump 8 bytes at a time + (``2 * 4``). + ctypes : ctypes object + Class containing properties of the array needed for interaction + with ctypes. + base : ndarray + If the array is a view into another array, that array is its `base` + (unless that array is also a view). The `base` array is where the + array data is actually stored. + + See Also + -------- + array : Construct an array. + zeros : Create an array, each element of which is zero. + empty : Create an array, but leave its allocated memory unchanged (i.e., + it contains "garbage"). + dtype : Create a data-type. + + Notes + ----- + There are two modes of creating an array using ``__new__``: + + 1. If `buffer` is None, then only `shape`, `dtype`, and `order` + are used. + 2. If `buffer` is an object exposing the buffer interface, then + all keywords are interpreted. + + No ``__init__`` method is needed because the array is fully initialized + after the ``__new__`` method. + + Examples + -------- + These examples illustrate the low-level `ndarray` constructor. Refer + to the `See Also` section above for easier ways of constructing an + ndarray. + + First mode, `buffer` is None: + + >>> np.ndarray(shape=(2,2), dtype=float, order='F') + array([[ -1.13698227e+002, 4.25087011e-303], + [ 2.88528414e-306, 3.27025015e-309]]) #random + + Second mode: + + >>> np.ndarray((2,), buffer=np.array([1,2,3]), + ... offset=np.int_().itemsize, + ... dtype=int) # offset = 1*itemsize, i.e. skip first element + array([2, 3]) + """ + pass diff --git a/python/testData/quickdoc/NumPyOnesDoc/numpy/core/numeric.py b/python/testData/quickdoc/NumPyOnesDoc/numpy/core/numeric.py new file mode 100644 index 000000000000..19e7b0f6aeb2 --- /dev/null +++ b/python/testData/quickdoc/NumPyOnesDoc/numpy/core/numeric.py @@ -0,0 +1,51 @@ +from . import multiarray + +__all__ = ['ndarray', 'ones'] + + +ndarray = multiarray.ndarray + +def ones(shape, dtype=None, order='C'): + """ + **Test docstring** + Return a new array of given shape and type, filled with ones. + + Parameters + ---------- + shape : int or sequence of ints + Shape of the new array, e.g., ``(2, 3)`` or ``2``. + dtype : data-type, optional + The desired data-type for the array, e.g., `numpy.int8`. Default is + `numpy.float64`. + order : {'C', 'F'}, optional + Whether to store multidimensional data in C- or Fortran-contiguous + (row- or column-wise) order in memory. + + Returns + ------- + out : ndarray + Array of ones with the given shape, dtype, and order. + + See Also + -------- + zeros, ones_like + + Examples + -------- + >>> np.ones(5) + array([ 1., 1., 1., 1., 1.]) + + >>> np.ones((5,), dtype=np.int) + array([1, 1, 1, 1, 1]) + + >>> np.ones((2, 1)) + array([[ 1.], + [ 1.]]) + + >>> s = (2,2) + >>> np.ones(s) + array([[ 1., 1.], + [ 1., 1.]]) + + """ + pass diff --git a/python/testData/types/NumpyArrayIntMultiplicationType/numpy/__init__.py b/python/testData/types/NumpyArrayIntMultiplicationType/numpy/__init__.py new file mode 100644 index 000000000000..d58ac8cf7af0 --- /dev/null +++ b/python/testData/types/NumpyArrayIntMultiplicationType/numpy/__init__.py @@ -0,0 +1,5 @@ +from . import core +from .core import * + +__all__ = [] +__all__.extend(core.__all__) diff --git a/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/__init__.py b/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/__init__.py new file mode 100644 index 000000000000..51afb32bcebe --- /dev/null +++ b/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/__init__.py @@ -0,0 +1,6 @@ +from . import multiarray +from . import numeric +from .numeric import * + +__all__ = [] +__all__ += numeric.__all__ diff --git a/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/multiarray.py b/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/multiarray.py new file mode 100644 index 000000000000..ceb35f28b175 --- /dev/null +++ b/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/multiarray.py @@ -0,0 +1,129 @@ +class ndarray(object): + """ + ndarray(shape, dtype=float, buffer=None, offset=0, + strides=None, order=None) + + An array object represents a multidimensional, homogeneous array + of fixed-size items. An associated data-type object describes the + format of each element in the array (its byte-order, how many bytes it + occupies in memory, whether it is an integer, a floating point number, + or something else, etc.) + + Arrays should be constructed using `array`, `zeros` or `empty` (refer + to the See Also section below). The parameters given here refer to + a low-level method (`ndarray(...)`) for instantiating an array. + + For more information, refer to the `numpy` module and examine the + the methods and attributes of an array. + + Parameters + ---------- + (for the __new__ method; see Notes below) + + shape : tuple of ints + Shape of created array. + dtype : data-type, optional + Any object that can be interpreted as a numpy data type. + buffer : object exposing buffer interface, optional + Used to fill the array with data. + offset : int, optional + Offset of array data in buffer. + strides : tuple of ints, optional + Strides of data in memory. + order : {'C', 'F'}, optional + Row-major or column-major order. + + Attributes + ---------- + T : ndarray + Transpose of the array. + data : buffer + The array's elements, in memory. + dtype : dtype object + Describes the format of the elements in the array. + flags : dict + Dictionary containing information related to memory use, e.g., + 'C_CONTIGUOUS', 'OWNDATA', 'WRITEABLE', etc. + flat : numpy.flatiter object + Flattened version of the array as an iterator. The iterator + allows assignments, e.g., ``x.flat = 3`` (See `ndarray.flat` for + assignment examples; TODO). + imag : ndarray + Imaginary part of the array. + real : ndarray + Real part of the array. + size : int + Number of elements in the array. + itemsize : int + The memory use of each array element in bytes. + nbytes : int + The total number of bytes required to store the array data, + i.e., ``itemsize * size``. + ndim : int + The array's number of dimensions. + shape : tuple of ints + Shape of the array. + strides : tuple of ints + The step-size required to move from one element to the next in + memory. For example, a contiguous ``(3, 4)`` array of type + ``int16`` in C-order has strides ``(8, 2)``. This implies that + to move from element to element in memory requires jumps of 2 bytes. + To move from row-to-row, one needs to jump 8 bytes at a time + (``2 * 4``). + ctypes : ctypes object + Class containing properties of the array needed for interaction + with ctypes. + base : ndarray + If the array is a view into another array, that array is its `base` + (unless that array is also a view). The `base` array is where the + array data is actually stored. + + See Also + -------- + array : Construct an array. + zeros : Create an array, each element of which is zero. + empty : Create an array, but leave its allocated memory unchanged (i.e., + it contains "garbage"). + dtype : Create a data-type. + + Notes + ----- + There are two modes of creating an array using ``__new__``: + + 1. If `buffer` is None, then only `shape`, `dtype`, and `order` + are used. + 2. If `buffer` is an object exposing the buffer interface, then + all keywords are interpreted. + + No ``__init__`` method is needed because the array is fully initialized + after the ``__new__`` method. + + Examples + -------- + These examples illustrate the low-level `ndarray` constructor. Refer + to the `See Also` section above for easier ways of constructing an + ndarray. + + First mode, `buffer` is None: + + >>> np.ndarray(shape=(2,2), dtype=float, order='F') + array([[ -1.13698227e+002, 4.25087011e-303], + [ 2.88528414e-306, 3.27025015e-309]]) #random + + Second mode: + + >>> np.ndarray((2,), buffer=np.array([1,2,3]), + ... offset=np.int_().itemsize, + ... dtype=int) # offset = 1*itemsize, i.e. skip first element + array([2, 3]) + """ + pass + + + def __mul__(self, y): + """ x.__mul__(y) <==> x*y """ + pass + + def __rmul__(self, y): + """ x.__rmul__(y) <==> x*y """ + pass diff --git a/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/numeric.py b/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/numeric.py new file mode 100644 index 000000000000..19e7b0f6aeb2 --- /dev/null +++ b/python/testData/types/NumpyArrayIntMultiplicationType/numpy/core/numeric.py @@ -0,0 +1,51 @@ +from . import multiarray + +__all__ = ['ndarray', 'ones'] + + +ndarray = multiarray.ndarray + +def ones(shape, dtype=None, order='C'): + """ + **Test docstring** + Return a new array of given shape and type, filled with ones. + + Parameters + ---------- + shape : int or sequence of ints + Shape of the new array, e.g., ``(2, 3)`` or ``2``. + dtype : data-type, optional + The desired data-type for the array, e.g., `numpy.int8`. Default is + `numpy.float64`. + order : {'C', 'F'}, optional + Whether to store multidimensional data in C- or Fortran-contiguous + (row- or column-wise) order in memory. + + Returns + ------- + out : ndarray + Array of ones with the given shape, dtype, and order. + + See Also + -------- + zeros, ones_like + + Examples + -------- + >>> np.ones(5) + array([ 1., 1., 1., 1., 1.]) + + >>> np.ones((5,), dtype=np.int) + array([1, 1, 1, 1, 1]) + + >>> np.ones((2, 1)) + array([[ 1.], + [ 1.]]) + + >>> s = (2,2) + >>> np.ones(s) + array([[ 1., 1.], + [ 1., 1.]]) + + """ + pass diff --git a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java index ec7e7eddd84a..56e023e789e1 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java @@ -27,6 +27,8 @@ import com.jetbrains.python.fixtures.LightMarkedTestCase; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.TypeEvalContext; import junit.framework.Assert; import java.io.IOException; @@ -240,7 +242,7 @@ public class PyQuickDocTest extends LightMarkedTestCase { public void testHoverOverMethod() { checkHover(); } - + public void testHoverOverParameter() { checkHover(); } @@ -248,4 +250,10 @@ public class PyQuickDocTest extends LightMarkedTestCase { public void testHoverOverControlFlowUnion() { checkHover(); } + + // PY-13422 + public void testNumPyOnesDoc() { + myFixture.copyDirectoryToProject("/quickdoc/" + getTestName(false), ""); + checkHover(); + } } diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index b6ed1090edad..548fe14a4458 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -194,14 +194,16 @@ public class PyTypeTest extends PyTestCase { "def foo(*args):\n" + " '''@rtype: C{str}'''\n" + " return args[0]" + - "expr = foo('')"); + "expr = foo('')" + ); } public void testEpydocParamType() { doTest("str", "def foo(s):\n" + " '''@type s: C{str}'''\n" + - " expr = s"); + " expr = s" + ); } public void testEpydocIvarType() { @@ -385,7 +387,8 @@ public class PyTypeTest extends PyTestCase { " return 1\n" + "g = f\n" + "h = g\n" + - "expr = h()\n"); + "expr = h()\n" + ); } public void testPropertyOfUnionType() { @@ -454,7 +457,8 @@ public class PyTypeTest extends PyTestCase { "\n" + " def __init__(self):\n" + " self.foo = 3\n" + - " expr = self.foo\n"); + " expr = self.foo\n" + ); } // PY-7215 @@ -465,7 +469,8 @@ public class PyTypeTest extends PyTestCase { " yield 10\n" + " return list(g())\n" + "\n" + - "expr = f()\n"); + "expr = f()\n" + ); } public void testGeneratorNextType() { @@ -508,7 +513,8 @@ public class PyTypeTest extends PyTestCase { doTest("list[list]", "def f():\n" + " return [f()]\n" + - "expr = f()\n"); + "expr = f()\n" + ); } // PY-5084 @@ -519,7 +525,8 @@ public class PyTypeTest extends PyTestCase { " if isinstance(x, int):\n" + " print(x)\n" + " else:\n" + - " expr = x\n"); + " expr = x\n" + ); } // PY-5614 @@ -606,7 +613,8 @@ public class PyTypeTest extends PyTestCase { " :rtype: T\n" + " '''\n" + "def bar(x):\n" + - " expr = foo(x)\n"); + " expr = foo(x)\n" + ); } public void testIterationTypeFromGetItem() { @@ -866,6 +874,13 @@ public class PyTypeTest extends PyTestCase { "expr = C(10).foo()\n"); } + // PY-8836 + public void testNumpyArrayIntMultiplicationType() { + doMultiFileTest("ndarray", + "import numpy as np\n" + + "expr = np.ones(10) * 2\n"); + } + private static TypeEvalContext getTypeEvalContext(@NotNull PyExpression element) { return TypeEvalContext.userInitiated(element.getContainingFile()).withTracing(); } @@ -882,4 +897,16 @@ public class PyTypeTest extends PyTestCase { final String actualType = PythonDocumentationProvider.getTypeName(actual, context); assertEquals(expectedType, actualType); } + + public static final String TEST_DIRECTORY = "/types/"; + + private void doMultiFileTest(final String expectedType, final String text) { + final String testName = getTestName(false); + myFixture.copyDirectoryToProject(TEST_DIRECTORY + testName, ""); + PyExpression expr = parseExpr(text); + TypeEvalContext context = getTypeEvalContext(expr); + PyType actual = context.getType(expr); + final String actualType = PythonDocumentationProvider.getTypeName(actual, context); + assertEquals(expectedType, actualType); + } }