diff --git a/doc/release/1.16.0-notes.rst b/doc/release/1.16.0-notes.rst index 0ba4636d9317..89f1fe2cc703 100644 --- a/doc/release/1.16.0-notes.rst +++ b/doc/release/1.16.0-notes.rst @@ -113,6 +113,12 @@ details. The ``out`` argument to these functions is now always tested for memory overlap to avoid corrupted results when memory overlap occurs. +Detailed docstrings for scalar numeric types +-------------------------------------------- +The ``help`` function, when applied to numeric types such as `np.intc`, +`np.int_`, and `np.longlong`, now lists all of the aliased names for that type, +distinguishing between platform -dependent and -independent aliases. + Changes ======= diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index e1e546c52832..d4b6765d01c7 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -10,6 +10,8 @@ """ from __future__ import division, absolute_import, print_function +from numpy.core import numerictypes as _numerictypes +from numpy.core import dtype from numpy.core.function_base import add_newdoc ############################################################################### @@ -7970,62 +7972,157 @@ def luf(lamdaexpr, *args, **kwargs): # ############################################################################## -add_newdoc('numpy.core.numerictypes', 'bool_', - """NumPy's Boolean type. Character code: ``?``. Alias: bool8""") +def numeric_type_aliases(aliases): + def type_aliases_gen(): + for alias, doc in aliases: + try: + alias_type = getattr(_numerictypes, alias) + except AttributeError: + # The set of aliases that actually exist varies between platforms + pass + else: + yield (alias_type, alias, doc) + return list(type_aliases_gen()) + + +possible_aliases = numeric_type_aliases([ + ('int8', '8-bit signed integer (-128 to 127)'), + ('int16', '16-bit signed integer (-32768 to 32767)'), + ('int32', '32-bit signed integer (-2147483648 to 2147483647)'), + ('int64', '64-bit signed integer (-9223372036854775808 to 9223372036854775807)'), + ('intp', 'Signed integer large enough to fit pointer, compatible with C ``intptr_t``'), + ('uint8', '8-bit unsigned integer (0 to 255)'), + ('uint16', '16-bit unsigned integer (0 to 65535)'), + ('uint32', '32-bit unsigned integer (0 to 4294967295)'), + ('uint64', '64-bit unsigned integer (0 to 18446744073709551615)'), + ('uintp', 'Unsigned integer large enough to fit pointer, compatible with C ``uintptr_t``'), + ('float16', '16-bit-precision floating-point number type: sign bit, 5 bits exponent, 10 bits mantissa'), + ('float32', '32-bit-precision floating-point number type: sign bit, 8 bits exponent, 23 bits mantissa'), + ('float64', '64-bit precision floating-point number type: sign bit, 11 bits exponent, 52 bits mantissa'), + ('float96', '96-bit extended-precision floating-point number type'), + ('float128', '128-bit extended-precision floating-point number type'), + ('complex64', 'Complex number type composed of 2 32-bit-precision floating-point numbers'), + ('complex128', 'Complex number type composed of 2 64-bit-precision floating-point numbers'), + ('complex192', 'Complex number type composed of 2 96-bit extended-precision floating-point numbers'), + ('complex256', 'Complex number type composed of 2 128-bit extended-precision floating-point numbers'), + ]) + + +def add_newdoc_for_scalar_type(obj, fixed_aliases, doc): + o = getattr(_numerictypes, obj) + + character_code = dtype(o).char + canonical_name_doc = "" if obj == o.__name__ else "Canonical name: ``np.{}``.\n ".format(obj) + alias_doc = ''.join("Alias: ``np.{}``.\n ".format(alias) for alias in fixed_aliases) + alias_doc += ''.join("Alias *on this platform*: ``np.{}``: {}.\n ".format(alias, doc) + for (alias_type, alias, doc) in possible_aliases if alias_type is o) + + docstring = """ + {doc} + Character code: ``'{character_code}'``. + {canonical_name_doc}{alias_doc} + """.format(doc=doc.strip(), character_code=character_code, + canonical_name_doc=canonical_name_doc, alias_doc=alias_doc) + + add_newdoc('numpy.core.numerictypes', obj, docstring) + + +add_newdoc_for_scalar_type('bool_', ['bool8'], + """ + Boolean type (True or False), stored as a byte. + """) -add_newdoc('numpy.core.numerictypes', 'complex64', +add_newdoc_for_scalar_type('byte', [], """ - Complex number type composed of two 32 bit floats. Character code: 'F'. + Signed integer type, compatible with C ``char``. + """) +add_newdoc_for_scalar_type('short', [], + """ + Signed integer type, compatible with C ``short``. """) -add_newdoc('numpy.core.numerictypes', 'complex128', +add_newdoc_for_scalar_type('intc', [], """ - Complex number type composed of two 64 bit floats. Character code: 'D'. - Python complex compatible. + Signed integer type, compatible with C ``int``. + """) +add_newdoc_for_scalar_type('int_', [], + """ + Signed integer type, compatible with Python `int` anc C ``long``. """) -add_newdoc('numpy.core.numerictypes', 'complex256', +add_newdoc_for_scalar_type('longlong', [], """ - Complex number type composed of two 128-bit floats. Character code: 'G'. + Signed integer type, compatible with C ``long long``. + """) +add_newdoc_for_scalar_type('ubyte', [], + """ + Unsigned integer type, compatible with C ``unsigned char``. """) -add_newdoc('numpy.core.numerictypes', 'float32', +add_newdoc_for_scalar_type('ushort', [], """ - 32-bit floating-point number. Character code 'f'. C float compatible. + Unsigned integer type, compatible with C ``unsigned short``. + """) +add_newdoc_for_scalar_type('uintc', [], + """ + Unsigned integer type, compatible with C ``unsigned int``. """) -add_newdoc('numpy.core.numerictypes', 'float64', +add_newdoc_for_scalar_type('uint', [], """ - 64-bit floating-point number. Character code 'd'. Python float compatible. + Unsigned integer type, compatible with C ``unsigned long``. + """) +add_newdoc_for_scalar_type('ulonglong', [], + """ + Signed integer type, compatible with C ``unsigned long long``. """) -add_newdoc('numpy.core.numerictypes', 'float96', +add_newdoc_for_scalar_type('half', [], """ + Half-precision floating-point number type. """) -add_newdoc('numpy.core.numerictypes', 'float128', +add_newdoc_for_scalar_type('single', [], """ - 128-bit floating-point number. Character code: 'g'. C long float - compatible. + Single-precision floating-point number type, compatible with C ``float``. + """) +add_newdoc_for_scalar_type('double', ['float_'], + """ + Double-precision floating-point number type, compatible with Python `float` + and C ``double``. """) -add_newdoc('numpy.core.numerictypes', 'int8', - """8-bit integer. Character code ``b``. C char compatible.""") +add_newdoc_for_scalar_type('longdouble', ['longfloat'], + """ + Extended-precision floating-point number type, compatible with C + ``long double`` but not necessarily with IEEE 754 quadruple-precision. + """) -add_newdoc('numpy.core.numerictypes', 'int16', - """16-bit integer. Character code ``h``. C short compatible.""") +add_newdoc_for_scalar_type('csingle', ['singlecomplex'], + """ + Complex number type composed of two single-precision floating-point + numbers. + """) -add_newdoc('numpy.core.numerictypes', 'int32', - """32-bit integer. Character code 'i'. C int compatible.""") +add_newdoc_for_scalar_type('cdouble', ['cfloat', 'complex_'], + """ + Complex number type composed of two double-precision floating-point + numbers, compatible with Python `complex`. + """) -add_newdoc('numpy.core.numerictypes', 'int64', - """64-bit integer. Character code 'l'. Python int compatible.""") +add_newdoc_for_scalar_type('clongdouble', ['clongfloat', 'longcomplex'], + """ + Complex number type composed of two extended-precision floating-point + numbers. + """) -add_newdoc('numpy.core.numerictypes', 'object_', - """Any Python object. Character code: 'O'.""") +add_newdoc_for_scalar_type('object_', [], + """ + Any Python object. + """) diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index fdd4d7878765..6dd8b1a298ae 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -3748,30 +3748,21 @@ static PyMappingMethods gentype_as_mapping = { * #CNAME = FLOAT, DOUBLE, LONGDOUBLE# */ #if NPY_BITSOF_@CNAME@ == 16 -#define _THIS_SIZE2 "16" -#define _THIS_SIZE1 "32" +#define _THIS_SIZE "32" #elif NPY_BITSOF_@CNAME@ == 32 -#define _THIS_SIZE2 "32" -#define _THIS_SIZE1 "64" +#define _THIS_SIZE "64" #elif NPY_BITSOF_@CNAME@ == 64 -#define _THIS_SIZE2 "64" -#define _THIS_SIZE1 "128" +#define _THIS_SIZE "128" #elif NPY_BITSOF_@CNAME@ == 80 -#define _THIS_SIZE2 "80" -#define _THIS_SIZE1 "160" +#define _THIS_SIZE "160" #elif NPY_BITSOF_@CNAME@ == 96 -#define _THIS_SIZE2 "96" -#define _THIS_SIZE1 "192" +#define _THIS_SIZE "192" #elif NPY_BITSOF_@CNAME@ == 128 -#define _THIS_SIZE2 "128" -#define _THIS_SIZE1 "256" +#define _THIS_SIZE "256" #elif NPY_BITSOF_@CNAME@ == 256 -#define _THIS_SIZE2 "256" -#define _THIS_SIZE1 "512" +#define _THIS_SIZE "512" #endif -#define _THIS_DOC "Composed of two " _THIS_SIZE2 " bit floats" - NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { #if defined(NPY_PY3K) PyVarObject_HEAD_INIT(0, 0) @@ -3779,7 +3770,7 @@ NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { PyObject_HEAD_INIT(0) 0, /* ob_size */ #endif - "numpy.@name@" _THIS_SIZE1, /* tp_name*/ + "numpy.@name@" _THIS_SIZE, /* tp_name*/ sizeof(Py@NAME@ScalarObject), /* tp_basicsize*/ 0, /* tp_itemsize*/ 0, /* tp_dealloc*/ @@ -3802,7 +3793,7 @@ NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { 0, /* tp_setattro*/ 0, /* tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /* tp_flags*/ - _THIS_DOC, /* tp_doc */ + 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ @@ -3830,9 +3821,7 @@ NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { 0, /* tp_del */ 0, /* tp_version_tag */ }; -#undef _THIS_SIZE1 -#undef _THIS_SIZE2 -#undef _THIS_DOC +#undef _THIS_SIZE /**end repeat**/ diff --git a/numpy/core/tests/test_numerictypes.py b/numpy/core/tests/test_numerictypes.py index 0eae9e05970d..8b059de3dc12 100644 --- a/numpy/core/tests/test_numerictypes.py +++ b/numpy/core/tests/test_numerictypes.py @@ -444,3 +444,13 @@ def test_complex(self, t): @pytest.mark.parametrize('t', [np.bool_, np.object_, np.unicode_, np.bytes_, np.void]) def test_other(self, t): assert_equal(np.maximum_sctype(t), t) + + +@pytest.mark.skipif(sys.flags.optimize > 1, + reason="no docstrings present to inspect when PYTHONOPTIMIZE/Py_OptimizeFlag > 1") +class TestDocStrings(object): + def test_platform_dependent_aliases(self): + if np.int64 is np.int_: + assert_('int64' in np.int_.__doc__) + elif np.int64 is np.longlong: + assert_('int64' in np.longlong.__doc__)