diff options
-rw-r--r-- | doc/release/1.8.0-notes.rst | 18 | ||||
-rw-r--r-- | doc/source/reference/c-api.types-and-structures.rst | 10 | ||||
-rw-r--r-- | numpy/core/include/numpy/ufuncobject.h | 14 | ||||
-rw-r--r-- | numpy/core/setup.py | 7 | ||||
-rw-r--r-- | numpy/core/src/multiarray/arraytypes.c.src | 2 | ||||
-rw-r--r-- | numpy/core/src/umath/operand_flag_tests.c.src | 106 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 92 | ||||
-rw-r--r-- | numpy/core/src/umath/umathmodule.c | 6 | ||||
-rw-r--r-- | numpy/core/tests/test_api.py | 8 | ||||
-rw-r--r-- | numpy/core/tests/test_regression.py | 5 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 14 | ||||
-rw-r--r-- | numpy/lib/arraypad.py | 190 | ||||
-rw-r--r-- | numpy/lib/stride_tricks.py | 5 | ||||
-rw-r--r-- | numpy/testing/nosetester.py | 8 |
14 files changed, 371 insertions, 114 deletions
diff --git a/doc/release/1.8.0-notes.rst b/doc/release/1.8.0-notes.rst index c5c9d6e8d..e65658ad3 100644 --- a/doc/release/1.8.0-notes.rst +++ b/doc/release/1.8.0-notes.rst @@ -159,3 +159,21 @@ General Use of non-integer indices has been deprecated. Previously float indices were truncated to integers without warning. +C-API +~~~~~ + +New Features +============ + +When creating a ufunc, the default ufunc operand flags can be overridden +via the new op_flags attribute of the ufunc object. For example, to set +the operand flag for the first input to read/write: + +PyObject \*ufunc = PyUFunc_FromFuncAndData(...); +ufunc->op_flags[0] = NPY_ITER_READWRITE; + +This allows a ufunc to perform an operation in place. Also, global nditer flags +can be overridden via the new iter_flags attribute of the ufunc object. +For example, to set the reduce flag for a ufunc: + +ufunc->iter_flags = NPY_ITER_REDUCE_OK; diff --git a/doc/source/reference/c-api.types-and-structures.rst b/doc/source/reference/c-api.types-and-structures.rst index 07c7e07be..79a888912 100644 --- a/doc/source/reference/c-api.types-and-structures.rst +++ b/doc/source/reference/c-api.types-and-structures.rst @@ -652,6 +652,8 @@ PyUFunc_Type void *ptr; PyObject *obj; PyObject *userloops; + npy_uint32 *op_flags; + npy_uint32 *iter_flags; } PyUFuncObject; .. cmacro:: PyUFuncObject.PyObject_HEAD @@ -755,6 +757,14 @@ PyUFunc_Type numbers are always larger than :cdata:`NPY_USERDEF`. + .. cmember:: npy_uint32 PyUFuncObject.op_flags + + Override the default operand flags for each ufunc operand. + + .. cmember:: npy_uint32 PyUFuncObject.iter_flags + + Override the default nditer flags for the ufunc. + PyArrayIter_Type ---------------- diff --git a/numpy/core/include/numpy/ufuncobject.h b/numpy/core/include/numpy/ufuncobject.h index 076dd880c..686d12c38 100644 --- a/numpy/core/include/numpy/ufuncobject.h +++ b/numpy/core/include/numpy/ufuncobject.h @@ -212,6 +212,20 @@ typedef struct _tagPyUFuncObject { * A function which returns a masked inner loop for the ufunc. */ PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector; + + /* + * List of flags for each operand when ufunc is called by nditer object. + * These flags will be used in addition to the default flags for each + * operand set by nditer object. + */ + npy_uint32 *op_flags; + + /* + * List of global flags used when ufunc is called by nditer object. + * These flags will be used in addition to the default global flags + * set by nditer object. + */ + npy_uint32 iter_flags; } PyUFuncObject; #include "arrayobject.h" diff --git a/numpy/core/setup.py b/numpy/core/setup.py index 6df82b3fa..3b08d6edd 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -935,6 +935,13 @@ def configuration(parent_package='',top_path=None): config.add_extension('multiarray_tests', sources = [join('src', 'multiarray', 'multiarray_tests.c.src')]) + ####################################################################### + # operand_flag_tests module # + ####################################################################### + + config.add_extension('operand_flag_tests', + sources = [join('src','umath', 'operand_flag_tests.c.src')]) + config.add_data_dir('tests') config.add_data_dir('tests/data') diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src index aff4c36dd..4a5c13a6a 100644 --- a/numpy/core/src/multiarray/arraytypes.c.src +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -2321,7 +2321,7 @@ VOID_nonzero (char *ip, PyArrayObject *ap) * TODO: temporarily modifying the array like this * is bad coding style, should be changed. */ - ((PyArrayObject_fields *)ap)->descr = descr; + ((PyArrayObject_fields *)ap)->descr = new; ((PyArrayObject_fields *)ap)->flags = savedflags; if ((new->alignment > 1) && !__ALIGNED(ip + offset, new->alignment)) { diff --git a/numpy/core/src/umath/operand_flag_tests.c.src b/numpy/core/src/umath/operand_flag_tests.c.src new file mode 100644 index 000000000..0cae4db36 --- /dev/null +++ b/numpy/core/src/umath/operand_flag_tests.c.src @@ -0,0 +1,106 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include <stdint.h> +#include <math.h> +#include <Python.h> +#include <structmember.h> +#include <numpy/arrayobject.h> +#include <numpy/ufuncobject.h> +#include "numpy/npy_3kcompat.h" + + +static PyMethodDef TestMethods[] = { + {NULL, NULL, 0, NULL} +}; + + +static void +inplace_add(char **args, npy_intp *dimensions, npy_intp *steps, void *data) +{ + npy_intp i; + npy_intp n = dimensions[0]; + char *in1 = args[0]; + char *in2 = args[1]; + npy_intp in1_step = steps[0]; + npy_intp in2_step = steps[1]; + + for (i = 0; i < n; i++) { + (*(long *)in1) = *(long*)in1 + *(long*)in2; + in1 += in1_step; + in2 += in2_step; + } +} + + +/*This a pointer to the above function*/ +PyUFuncGenericFunction funcs[1] = {&inplace_add}; + +/* These are the input and return dtypes of logit.*/ +static char types[2] = {NPY_LONG, NPY_LONG}; + +static void *data[1] = {NULL}; + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "operand_flag_tests", + NULL, + -1, + TestMethods, + NULL, + NULL, + NULL, + NULL +}; + +#define RETVAL m +PyMODINIT_FUNC PyInit_operand_flag_tests(void) +{ +#else +#define RETVAL +PyMODINIT_FUNC initoperand_flag_tests(void) +{ +#endif + PyObject *m = NULL; + PyObject *ufunc; + +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("operand_flag_tests", TestMethods); +#endif + if (m == NULL) { + goto fail; + } + + import_array(); + import_umath(); + + ufunc = PyUFunc_FromFuncAndData(funcs, data, types, 1, 2, 0, + PyUFunc_None, "inplace_add", + "inplace_add_docstring", 0); + + /* + * Set flags to turn off buffering for first input operand, + * so that result can be written back to input operand. + */ + ((PyUFuncObject*)ufunc)->op_flags[0] = NPY_ITER_READWRITE; + ((PyUFuncObject*)ufunc)->iter_flags = NPY_ITER_REDUCE_OK; + PyModule_AddObject(m, "inplace_add", (PyObject*)ufunc); + + return RETVAL; + +fail: + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot load operand_flag_tests module."); + } +#if defined(NPY_PY3K) + if (m) { + Py_DECREF(m); + m = NULL; + } +#endif + return RETVAL; + +} diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 3d3f63d4e..a3a164731 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -1181,34 +1181,46 @@ iterator_loop(PyUFuncObject *ufunc, npy_intp *count_ptr; PyArrayObject **op_it; + npy_uint32 iter_flags; NPY_BEGIN_THREADS_DEF; /* Set up the flags */ for (i = 0; i < nin; ++i) { - op_flags[i] = NPY_ITER_READONLY| + op_flags[i] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; + /* + * If READWRITE flag has been set for this operand, + * then clear default READONLY flag + */ + op_flags[i] |= ufunc->op_flags[i]; + if (op_flags[i] & (NPY_ITER_READWRITE | NPY_ITER_WRITEONLY)) { + op_flags[i] &= ~NPY_ITER_READONLY; + } } for (i = nin; i < nop; ++i) { - op_flags[i] = NPY_ITER_WRITEONLY| - NPY_ITER_ALIGNED| - NPY_ITER_ALLOCATE| - NPY_ITER_NO_BROADCAST| + op_flags[i] = NPY_ITER_WRITEONLY | + NPY_ITER_ALIGNED | + NPY_ITER_ALLOCATE | + NPY_ITER_NO_BROADCAST | NPY_ITER_NO_SUBTYPE; } + iter_flags = ufunc->iter_flags | + NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_REFS_OK | + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_BUFFERED | + NPY_ITER_GROWINNER | + NPY_ITER_DELAY_BUFALLOC; + /* * Allocate the iterator. Because the types of the inputs * were already checked, we use the casting rule 'unsafe' which * is faster to calculate. */ iter = NpyIter_AdvancedNew(nop, op, - NPY_ITER_EXTERNAL_LOOP| - NPY_ITER_REFS_OK| - NPY_ITER_ZEROSIZE_OK| - NPY_ITER_BUFFERED| - NPY_ITER_GROWINNER| - NPY_ITER_DELAY_BUFALLOC, + iter_flags, order, NPY_UNSAFE_CASTING, op_flags, dtype, -1, NULL, NULL, buffersize); @@ -1462,6 +1474,7 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, npy_intp *countptr; PyArrayObject **op_it; + npy_uint32 iter_flags; NPY_BEGIN_THREADS_DEF; @@ -1481,6 +1494,14 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, op_flags[i] = default_op_in_flags | NPY_ITER_READONLY | NPY_ITER_ALIGNED; + /* + * If READWRITE flag has been set for this operand, + * then clear default READONLY flag + */ + op_flags[i] |= ufunc->op_flags[i]; + if (op_flags[i] & (NPY_ITER_READWRITE | NPY_ITER_WRITEONLY)) { + op_flags[i] &= ~NPY_ITER_READONLY; + } } for (i = nin; i < nop; ++i) { op_flags[i] = default_op_out_flags | @@ -1496,17 +1517,20 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, NPY_UF_DBG_PRINT("Making iterator\n"); + iter_flags = ufunc->iter_flags | + NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_REFS_OK | + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_BUFFERED | + NPY_ITER_GROWINNER; + /* * Allocate the iterator. Because the types of the inputs * were already checked, we use the casting rule 'unsafe' which * is faster to calculate. */ iter = NpyIter_AdvancedNew(nop + ((wheremask != NULL) ? 1 : 0), op, - NPY_ITER_EXTERNAL_LOOP | - NPY_ITER_REFS_OK | - NPY_ITER_ZEROSIZE_OK | - NPY_ITER_BUFFERED | - NPY_ITER_GROWINNER, + iter_flags, order, NPY_UNSAFE_CASTING, op_flags, dtypes, -1, NULL, NULL, buffersize); @@ -1663,8 +1687,8 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, npy_uint32 op_flags[NPY_MAXARGS]; npy_intp iter_shape[NPY_MAXARGS]; - NpyIter *iter = NULL; + npy_uint32 iter_flags; /* These parameters come from extobj= or from a TLS global */ int buffersize = 0, errormask = 0; @@ -1964,9 +1988,17 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, * can't do buffering, so must COPY or UPDATEIFCOPY. */ for (i = 0; i < nin; ++i) { - op_flags[i] = NPY_ITER_READONLY| - NPY_ITER_COPY| + op_flags[i] = NPY_ITER_READONLY | + NPY_ITER_COPY | NPY_ITER_ALIGNED; + /* + * If READWRITE flag has been set for this operand, + * then clear default READONLY flag + */ + op_flags[i] |= ufunc->op_flags[i]; + if (op_flags[i] & (NPY_ITER_READWRITE | NPY_ITER_WRITEONLY)) { + op_flags[i] &= ~NPY_ITER_READONLY; + } } for (i = nin; i < nop; ++i) { op_flags[i] = NPY_ITER_READWRITE| @@ -1976,11 +2008,14 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, NPY_ITER_NO_BROADCAST; } + iter_flags = ufunc->iter_flags | + NPY_ITER_MULTI_INDEX | + NPY_ITER_REFS_OK | + NPY_ITER_REDUCE_OK | + NPY_ITER_ZEROSIZE_OK; + /* Create the iterator */ - iter = NpyIter_AdvancedNew(nop, op, NPY_ITER_MULTI_INDEX| - NPY_ITER_REFS_OK| - NPY_ITER_REDUCE_OK| - NPY_ITER_ZEROSIZE_OK, + iter = NpyIter_AdvancedNew(nop, op, iter_flags, order, NPY_UNSAFE_CASTING, op_flags, dtypes, iter_ndim, op_axes, iter_shape, 0); @@ -4227,6 +4262,14 @@ PyUFunc_FromFuncAndDataAndSignature(PyUFuncGenericFunction *func, void **data, } ufunc->doc = doc; + ufunc->op_flags = PyArray_malloc(sizeof(npy_uint32)*ufunc->nargs); + if (ufunc->op_flags == NULL) { + return PyErr_NoMemory(); + } + memset(ufunc->op_flags, 0, sizeof(npy_uint32)*ufunc->nargs); + + ufunc->iter_flags = 0; + /* generalized ufunc */ ufunc->core_enabled = 0; ufunc->core_num_dim_ix = 0; @@ -4476,6 +4519,9 @@ ufunc_dealloc(PyUFuncObject *ufunc) if (ufunc->ptr) { PyArray_free(ufunc->ptr); } + if (ufunc->op_flags) { + PyArray_free(ufunc->op_flags); + } Py_XDECREF(ufunc->userloops); Py_XDECREF(ufunc->obj); PyArray_free(ufunc); diff --git a/numpy/core/src/umath/umathmodule.c b/numpy/core/src/umath/umathmodule.c index e06cdedd1..0b789de26 100644 --- a/numpy/core/src/umath/umathmodule.c +++ b/numpy/core/src/umath/umathmodule.c @@ -123,6 +123,12 @@ ufunc_frompyfunc(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *NPY_UNUS self->core_dim_ixs = NULL; self->core_offsets = NULL; self->core_signature = NULL; + self->op_flags = PyArray_malloc(sizeof(npy_uint32)*self->nargs); + if (self->op_flags == NULL) { + return PyErr_NoMemory(); + } + memset(self->op_flags, 0, sizeof(npy_uint32)*self->nargs); + self->iter_flags = 0; self->type_resolver = &object_ufunc_type_resolver; self->legacy_inner_loop_selector = &object_ufunc_loop_selector; diff --git a/numpy/core/tests/test_api.py b/numpy/core/tests/test_api.py index 376097f7b..1f56d6cf6 100644 --- a/numpy/core/tests/test_api.py +++ b/numpy/core/tests/test_api.py @@ -276,5 +276,13 @@ def test_contiguous_flags(): check_contig(a.ravel(), True, True) check_contig(np.ones((1,3,1)).squeeze(), True, True) +def test_broadcast_arrays(): + # Test user defined dtypes + a = np.array([(1,2,3)], dtype='u4,u4,u4') + b = np.array([(1,2,3),(4,5,6),(7,8,9)], dtype='u4,u4,u4') + result = np.broadcast_arrays(a, b) + assert_equal(result[0], np.array([(1,2,3),(1,2,3),(1,2,3)], dtype='u4,u4,u4')) + assert_equal(result[1], np.array([(1,2,3),(4,5,6),(7,8,9)], dtype='u4,u4,u4')) + if __name__ == "__main__": run_module_suite() diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index cb8415ee7..bb0bf029b 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -1898,6 +1898,11 @@ class TestRegression(TestCase): order='F') assert_array_equal(arr2, data_back) + def test_structured_count_nonzero(self): + arr = np.array([0, 1]).astype('i4, (2)i4')[:1] + count = np.count_nonzero(arr) + assert_equal(count, 0) + diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 816b22052..3005da8da 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -5,6 +5,7 @@ import sys import numpy as np from numpy.testing import * import numpy.core.umath_tests as umt +import numpy.core.operand_flag_tests as opflag_tests from numpy.compat import asbytes from numpy.core.test_rational import * @@ -799,6 +800,19 @@ class TestUfunc(TestCase): # no output type should raise TypeError assert_raises(TypeError, test_add, a, b) + + def test_operand_flags(self): + a = np.arange(16, dtype='i8').reshape(4,4) + b = np.arange(9, dtype='i8').reshape(3,3) + opflag_tests.inplace_add(a[:-1,:-1], b) + assert_equal(a, np.array([[0,2,4,3],[7,9,11,7], + [14,16,18,11],[12,13,14,15]], dtype='i8')) + + a = np.array(0) + opflag_tests.inplace_add(a, 3) + assert_equal(a, 3) + opflag_tests.inplace_add(a, [3, 4]) + assert_equal(a, 10) if __name__ == "__main__": run_module_suite() diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py index 112a8dae9..09ca99332 100644 --- a/numpy/lib/arraypad.py +++ b/numpy/lib/arraypad.py @@ -11,18 +11,18 @@ from numpy.compat import long __all__ = ['pad'] -################################################################################ +############################################################################### # Private utility functions. def _create_vector(vector, pad_tuple, before_val, after_val): - ''' + """ Private function which creates the padded vector. Parameters ---------- vector : ndarray of rank 1, length N + pad_tuple[0] + pad_tuple[1] - Input vector including blank padded values. `N` is the lenth of the + Input vector including blank padded values. `N` is the lenth of the original vector. pad_tuple : tuple This tuple represents the (before, after) width of the padding along @@ -36,7 +36,8 @@ def _create_vector(vector, pad_tuple, before_val, after_val): ------- _create_vector : ndarray Vector with before_val and after_val replacing the blank pad values. - ''' + + """ vector[:pad_tuple[0]] = before_val if pad_tuple[1] > 0: vector[-pad_tuple[1]:] = after_val @@ -44,7 +45,7 @@ def _create_vector(vector, pad_tuple, before_val, after_val): def _normalize_shape(narray, shape): - ''' + """ Private function which does some checks and normalizes the possibly much simpler representations of 'pad_width', 'stat_length', 'constant_values', 'end_values'. @@ -69,11 +70,12 @@ def _normalize_shape(narray, shape): int => ((int, int), (int, int), ...) [[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...) ((int1, int2), (int3, int4), ...) => no change - [[int1, int2], ] => ((int1, int2), (int1, int2), ...] + [[int1, int2], ] => ((int1, int2), (int1, int2), ...) ((int1, int2), ) => ((int1, int2), (int1, int2), ...) - [[int , ), ) => ((int, int), (int, int), ...) + [[int , ], ] => ((int, int), (int, int), ...) ((int , ), ) => ((int, int), (int, int), ...) - ''' + + """ normshp = None shapelen = len(np.shape(narray)) if (isinstance(shape, int)): @@ -94,14 +96,14 @@ def _normalize_shape(narray, shape): and isinstance(shape[0], (int, float, long)) and len(shape) == 2): normshp = (shape, ) * shapelen - if normshp == None: + if normshp is None: fmt = "Unable to create correctly shaped tuple from %s" raise ValueError(fmt % (shape,)) return normshp def _validate_lengths(narray, number_elements): - ''' + """ Private function which does some checks and reformats pad_width and stat_length using _normalize_shape. @@ -125,22 +127,22 @@ def _validate_lengths(narray, number_elements): int => ((int, int), (int, int), ...) [[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...) ((int1, int2), (int3, int4), ...) => no change - [[int1, int2], ] => ((int1, int2), (int1, int2), ...] + [[int1, int2], ] => ((int1, int2), (int1, int2), ...) ((int1, int2), ) => ((int1, int2), (int1, int2), ...) - [[int , ), ) => ((int, int), (int, int), ...) + [[int , ], ] => ((int, int), (int, int), ...) ((int , ), ) => ((int, int), (int, int), ...) - ''' - shapelen = len(np.shape(narray)) + + """ normshp = _normalize_shape(narray, number_elements) for i in normshp: if i[0] < 0 or i[1] < 0: - fmt ="%s cannot contain negative values." + fmt = "%s cannot contain negative values." raise ValueError(fmt % (number_elements,)) return normshp def _create_stat_vectors(vector, pad_tuple, iaxis, kwargs): - ''' + """ Returns the portion of the vector required for any statistic. Parameters @@ -153,7 +155,7 @@ def _create_stat_vectors(vector, pad_tuple, iaxis, kwargs): iaxis : int The axis currently being looped across. kwargs : keyword arguments - Keyword arguments. Only 'stat_length' is used. 'stat_length' + Keyword arguments. Only 'stat_length' is used. 'stat_length' defaults to the entire vector if not supplied. Return @@ -161,7 +163,8 @@ def _create_stat_vectors(vector, pad_tuple, iaxis, kwargs): _create_stat_vectors : ndarray The values from the original vector that will be used to calculate the statistic. - ''' + + """ # Can't have 0 represent the end if a slice... a[1:0] doesnt' work pt1 = -pad_tuple[1] @@ -186,7 +189,7 @@ def _create_stat_vectors(vector, pad_tuple, iaxis, kwargs): def _maximum(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_maximum. Parameters @@ -199,20 +202,21 @@ def _maximum(vector, pad_tuple, iaxis, kwargs): iaxis : int The axis currently being looped across. kwargs : keyword arguments - Keyword arguments. Only 'stat_length' is used. 'stat_length' + Keyword arguments. Only 'stat_length' is used. 'stat_length' defaults to the entire vector if not supplied. Return ------ _maximum : ndarray Padded vector - ''' + + """ sbvec, savec = _create_stat_vectors(vector, pad_tuple, iaxis, kwargs) return _create_vector(vector, pad_tuple, max(sbvec), max(savec)) def _minimum(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_minimum. Parameters @@ -225,20 +229,21 @@ def _minimum(vector, pad_tuple, iaxis, kwargs): iaxis : int The axis currently being looped across. kwargs : keyword arguments - Keyword arguments. Only 'stat_length' is used. 'stat_length' + Keyword arguments. Only 'stat_length' is used. 'stat_length' defaults to the entire vector if not supplied. Return ------ _minimum : ndarray Padded vector - ''' + + """ sbvec, savec = _create_stat_vectors(vector, pad_tuple, iaxis, kwargs) return _create_vector(vector, pad_tuple, min(sbvec), min(savec)) def _median(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_median. Parameters @@ -251,21 +256,22 @@ def _median(vector, pad_tuple, iaxis, kwargs): iaxis : int The axis currently being looped across. kwargs : keyword arguments - Keyword arguments. Only 'stat_length' is used. 'stat_length' + Keyword arguments. Only 'stat_length' is used. 'stat_length' defaults to the entire vector if not supplied. Return ------ _median : ndarray Padded vector - ''' + + """ sbvec, savec = _create_stat_vectors(vector, pad_tuple, iaxis, kwargs) return _create_vector(vector, pad_tuple, np.median(sbvec), np.median(savec)) def _mean(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_mean. Parameters @@ -278,21 +284,22 @@ def _mean(vector, pad_tuple, iaxis, kwargs): iaxis : int The axis currently being looped across. kwargs : keyword arguments - Keyword arguments. Only 'stat_length' is used. 'stat_length' + Keyword arguments. Only 'stat_length' is used. 'stat_length' defaults to the entire vector if not supplied. Return ------ _mean : ndarray Padded vector - ''' + + """ sbvec, savec = _create_stat_vectors(vector, pad_tuple, iaxis, kwargs) return _create_vector(vector, pad_tuple, np.average(sbvec), np.average(savec)) def _constant(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_constant. @@ -306,19 +313,20 @@ def _constant(vector, pad_tuple, iaxis, kwargs): iaxis : int The axis currently being looped across. kwargs : keyword arguments - Keyword arguments. Need 'constant_values' keyword argument. + Keyword arguments. Need 'constant_values' keyword argument. Return ------ _constant : ndarray Padded vector - ''' + + """ nconstant = kwargs['constant_values'][iaxis] return _create_vector(vector, pad_tuple, nconstant[0], nconstant[1]) def _linear_ramp(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_linear_ramp. @@ -330,7 +338,7 @@ def _linear_ramp(vector, pad_tuple, iaxis, kwargs): This tuple represents the (before, after) width of the padding along this particular iaxis. iaxis : int - The axis currently being looped across. Not used in _linear_ramp. + The axis currently being looped across. Not used in _linear_ramp. kwargs : keyword arguments Keyword arguments. Not used in _linear_ramp. @@ -338,7 +346,8 @@ def _linear_ramp(vector, pad_tuple, iaxis, kwargs): ------ _linear_ramp : ndarray Padded vector - ''' + + """ end_values = kwargs['end_values'][iaxis] before_delta = ((vector[pad_tuple[0]] - end_values[0]) / float(pad_tuple[0])) @@ -360,7 +369,7 @@ def _linear_ramp(vector, pad_tuple, iaxis, kwargs): def _reflect(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_reflect. Parameters @@ -371,7 +380,7 @@ def _reflect(vector, pad_tuple, iaxis, kwargs): This tuple represents the (before, after) width of the padding along this particular iaxis. iaxis : int - The axis currently being looped across. Not used in _reflect. + The axis currently being looped across. Not used in _reflect. kwargs : keyword arguments Keyword arguments. Not used in _reflect. @@ -379,7 +388,8 @@ def _reflect(vector, pad_tuple, iaxis, kwargs): ------ _reflect : ndarray Padded vector - ''' + + """ # Can't have pad_tuple[1] be used in the slice if == to 0. if pad_tuple[1] == 0: after_vector = vector[pad_tuple[0]:None] @@ -389,11 +399,9 @@ def _reflect(vector, pad_tuple, iaxis, kwargs): reverse = after_vector[::-1] before_vector = np.resize( - np.concatenate( - (after_vector[1:-1], reverse)), pad_tuple[0])[::-1] + np.concatenate((after_vector[1:-1], reverse)), pad_tuple[0])[::-1] after_vector = np.resize( - np.concatenate( - (reverse[1:-1], after_vector)), pad_tuple[1]) + np.concatenate((reverse[1:-1], after_vector)), pad_tuple[1]) if kwargs['reflect_type'] == 'even': pass @@ -402,12 +410,12 @@ def _reflect(vector, pad_tuple, iaxis, kwargs): after_vector = 2 * vector[-pad_tuple[-1] - 1] - after_vector else: raise ValueError("The keyword '%s' cannot have the value '%s'." - % ('reflect_type', kwargs['reflect_type'])) + % ('reflect_type', kwargs['reflect_type'])) return _create_vector(vector, pad_tuple, before_vector, after_vector) def _symmetric(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_symmetric. @@ -419,7 +427,7 @@ def _symmetric(vector, pad_tuple, iaxis, kwargs): This tuple represents the (before, after) width of the padding along this particular iaxis. iaxis : int - The axis currently being looped across. Not used in _symmetric. + The axis currently being looped across. Not used in _symmetric. kwargs : keyword arguments Keyword arguments. Not used in _symmetric. @@ -427,16 +435,19 @@ def _symmetric(vector, pad_tuple, iaxis, kwargs): ------ _symmetric : ndarray Padded vector - ''' + + """ if pad_tuple[1] == 0: after_vector = vector[pad_tuple[0]:None] else: after_vector = vector[pad_tuple[0]:-pad_tuple[1]] - before_vector = np.resize( np.concatenate( (after_vector, - after_vector[::-1])), pad_tuple[0])[::-1] - after_vector = np.resize( np.concatenate( (after_vector[::-1], - after_vector)), pad_tuple[1]) + before_vector = np.resize( + np.concatenate((after_vector, after_vector[::-1])), + pad_tuple[0])[::-1] + after_vector = np.resize( + np.concatenate((after_vector[::-1], after_vector)), + pad_tuple[1]) if kwargs['reflect_type'] == 'even': pass @@ -445,12 +456,12 @@ def _symmetric(vector, pad_tuple, iaxis, kwargs): after_vector = 2 * vector[-pad_tuple[1] - 1] - after_vector else: raise ValueError("The keyword '%s' cannot have the value '%s'." - % ('reflect_type', kwargs['reflect_type'])) + % ('reflect_type', kwargs['reflect_type'])) return _create_vector(vector, pad_tuple, before_vector, after_vector) def _wrap(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_wrap. Parameters @@ -469,7 +480,8 @@ def _wrap(vector, pad_tuple, iaxis, kwargs): ------ _wrap : ndarray Padded vector - ''' + + """ if pad_tuple[1] == 0: after_vector = vector[pad_tuple[0]:None] else: @@ -482,7 +494,7 @@ def _wrap(vector, pad_tuple, iaxis, kwargs): def _edge(vector, pad_tuple, iaxis, kwargs): - ''' + """ Private function to calculate the before/after vectors for pad_edge. Parameters @@ -501,12 +513,13 @@ def _edge(vector, pad_tuple, iaxis, kwargs): ------ _edge : ndarray Padded vector - ''' + + """ return _create_vector(vector, pad_tuple, vector[pad_tuple[0]], vector[-pad_tuple[1] - 1]) -################################################################################ +############################################################################### # Public functions @@ -695,44 +708,44 @@ def pad(array, pad_width, mode=None, **kwargs): [10, 10, 3, 4, 5, 10, 10], [10, 10, 10, 10, 10, 10, 10], [10, 10, 10, 10, 10, 10, 10]]) - """ + """ narray = np.array(array) pad_width = _validate_lengths(narray, pad_width) modefunc = { - 'constant': _constant, - 'edge': _edge, - 'linear_ramp': _linear_ramp, - 'maximum': _maximum, - 'mean': _mean, - 'median': _median, - 'minimum': _minimum, - 'reflect': _reflect, - 'symmetric': _symmetric, - 'wrap': _wrap, - } + 'constant': _constant, + 'edge': _edge, + 'linear_ramp': _linear_ramp, + 'maximum': _maximum, + 'mean': _mean, + 'median': _median, + 'minimum': _minimum, + 'reflect': _reflect, + 'symmetric': _symmetric, + 'wrap': _wrap, + } allowedkwargs = { - 'constant': ['constant_values'], - 'edge': [], - 'linear_ramp': ['end_values'], - 'maximum': ['stat_length'], - 'mean': ['stat_length'], - 'median': ['stat_length'], - 'minimum': ['stat_length'], - 'reflect': ['reflect_type'], - 'symmetric': ['reflect_type'], - 'wrap': [], - } + 'constant': ['constant_values'], + 'edge': [], + 'linear_ramp': ['end_values'], + 'maximum': ['stat_length'], + 'mean': ['stat_length'], + 'median': ['stat_length'], + 'minimum': ['stat_length'], + 'reflect': ['reflect_type'], + 'symmetric': ['reflect_type'], + 'wrap': [], + } kwdefaults = { - 'stat_length': None, - 'constant_values': 0, - 'end_values': 0, - 'reflect_type': 'even', - } + 'stat_length': None, + 'constant_values': 0, + 'end_values': 0, + 'reflect_type': 'even', + } if isinstance(mode, str): function = modefunc[mode] @@ -741,7 +754,7 @@ def pad(array, pad_width, mode=None, **kwargs): for key in kwargs: if key not in allowedkwargs[mode]: raise ValueError('%s keyword not in allowed keywords %s' % - (key, allowedkwargs[mode])) + (key, allowedkwargs[mode])) # Set kwarg defaults for kw in allowedkwargs[mode]: @@ -753,9 +766,9 @@ def pad(array, pad_width, mode=None, **kwargs): kwargs[i] = _validate_lengths(narray, kwargs[i]) if i in ['end_values', 'constant_values']: kwargs[i] = _normalize_shape(narray, kwargs[i]) - elif mode == None: + elif mode is None: raise ValueError('Keyword "mode" must be a function or one of %s.' % - (list(modefunc.keys()),)) + (list(modefunc.keys()),)) else: # User supplied function, I hope function = mode @@ -781,4 +794,3 @@ def pad(array, pad_width, mode=None, **kwargs): iaxis, kwargs) return newmat - diff --git a/numpy/lib/stride_tricks.py b/numpy/lib/stride_tricks.py index 1f08131ec..7b6b06fdc 100644 --- a/numpy/lib/stride_tricks.py +++ b/numpy/lib/stride_tricks.py @@ -27,7 +27,10 @@ def as_strided(x, shape=None, strides=None): interface['shape'] = tuple(shape) if strides is not None: interface['strides'] = tuple(strides) - return np.asarray(DummyArray(interface, base=x)) + array = np.asarray(DummyArray(interface, base=x)) + # Make sure dtype is correct in case of custom dtype + array.dtype = x.dtype + return array def broadcast_arrays(*args): """ diff --git a/numpy/testing/nosetester.py b/numpy/testing/nosetester.py index d07a5ad0b..e3f96b9a9 100644 --- a/numpy/testing/nosetester.py +++ b/numpy/testing/nosetester.py @@ -188,6 +188,14 @@ class NoseTester(object): label = 'not slow' argv += ['-A', label] argv += ['--verbosity', str(verbose)] + + # When installing with setuptools, and also in some other cases, the + # test_*.py files end up marked +x executable. Nose, by default, does + # not run files marked with +x as they might be scripts. However, in + # our case nose only looks for test_*.py files under the package + # directory, which should be safe. + argv += ['--exe'] + if extra_argv: argv += extra_argv return argv |