diff options
| -rw-r--r-- | doc/release/1.14.0-notes.rst | 20 | ||||
| -rw-r--r-- | numpy/core/arrayprint.py | 367 | ||||
| -rw-r--r-- | numpy/core/tests/test_arrayprint.py | 136 | ||||
| -rw-r--r-- | numpy/core/tests/test_regression.py | 2 | ||||
| -rw-r--r-- | numpy/polynomial/tests/test_printing.py | 24 | ||||
| -rw-r--r-- | numpy/testing/tests/test_utils.py | 24 |
6 files changed, 338 insertions, 235 deletions
diff --git a/doc/release/1.14.0-notes.rst b/doc/release/1.14.0-notes.rst index 73d2bf6a3..c9f1cec76 100644 --- a/doc/release/1.14.0-notes.rst +++ b/doc/release/1.14.0-notes.rst @@ -304,3 +304,23 @@ source to the destination. Using field "titles" in multiple-field indexing is now disallowed, as is repeating a field name in a multiple-field index. +``sign`` option added to ``np.setprintoptions`` and ``np.array2string`` +----------------------------------------------------------------------- +This option controls printing of the sign of floating-point types, and may be +one of the characters '-', '+' or ' ', or the string 'legacy'. With '+' numpy +always prints the sign of positive values, with ' ' it always prints a space +(whitespace character) in the sign position of positive values, and with '-' it +will omit the sign character for positive values, and with 'legacy' it will +behave like ' ' except no space is printed in 0d arrays. The new default is '-'. + +Unneeded whitespace in float array printing removed +--------------------------------------------------- +The new default of ``sign='-'`` (see last note) means that the ``repr`` of +float arrays now often omits the whitespace characters previously used to +display the sign. This new behavior can be disabled to mostly reproduce numpy +1.13 behavior by calling ``np.set_printoptions(sign='legacy')``. + +``threshold`` and ``edgeitems`` options added to ``np.array2string`` +----------------------------------------------------------------- +These options could previously be controlled using ``np.set_printoptions``, but +now can be changed on a per-call basis as arguments to ``np.array2string``. diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py index b8e60562f..e0da9f81e 100644 --- a/numpy/core/arrayprint.py +++ b/numpy/core/arrayprint.py @@ -38,7 +38,7 @@ else: import numpy as np from . import numerictypes as _nt -from .umath import maximum, minimum, absolute, not_equal, isnan, isinf +from .umath import absolute, not_equal, isnan, isinf from . import multiarray from .multiarray import (array, format_longfloat, datetime_as_string, datetime_data, dtype, ndarray) @@ -55,24 +55,36 @@ else: _MAXINT = sys.maxint _MININT = -sys.maxint - 1 -def product(x, y): - return x*y +_format_options = { + 'edgeitems': 3, # repr N leading and trailing items of each dimension + 'threshold': 1000, # total items > triggers array summarization + 'precision': 8, # precision of floating point representations + 'suppress': False, # suppress printing small floating values in exp format + 'linewidth': 75, + 'nanstr': 'nan', + 'infstr': 'inf', + 'sign': '-', + 'formatter': None } -_summaryEdgeItems = 3 # repr N leading and trailing items of each dimension -_summaryThreshold = 1000 # total items > triggers array summarization +def _make_options_dict(precision=None, threshold=None, edgeitems=None, + linewidth=None, suppress=None, nanstr=None, infstr=None, + sign=None, formatter=None): + """ make a dictionary out of the non-None arguments, plus sanity checks """ -_float_output_precision = 8 -_float_output_suppress_small = False -_line_width = 75 -_nan_str = 'nan' -_inf_str = 'inf' -_formatter = None # formatting function for array elements + options = {k: v for k, v in locals().items() if v is not None} + if suppress is not None: + options['suppress'] = bool(suppress) + + if sign not in [None, '-', '+', ' ', 'legacy']: + raise ValueError("sign option must be one of " + "' ', '+', '-', or 'legacy'") + + return options def set_printoptions(precision=None, threshold=None, edgeitems=None, - linewidth=None, suppress=None, - nanstr=None, infstr=None, - formatter=None): + linewidth=None, suppress=None, nanstr=None, infstr=None, + formatter=None, sign=None): """ Set printing options. @@ -102,6 +114,12 @@ def set_printoptions(precision=None, threshold=None, edgeitems=None, String representation of floating point not-a-number (default nan). infstr : str, optional String representation of floating point infinity (default inf). + sign : string, either '-', '+', ' ' or 'legacy', optional + Controls printing of the sign of floating-point types. If '+', always + print the sign of positive values. If ' ', always prints a space + (whitespace character) in the sign position of positive values. If + '-', omit the sign character of positive values. If 'legacy', print a + space for positive values except in 0d arrays. (default '-') formatter : dict of callables, optional If not None, the keys should indicate the type(s) that the respective formatting function applies to. Callables should return a string. @@ -177,26 +195,12 @@ def set_printoptions(precision=None, threshold=None, edgeitems=None, ... linewidth=75, nanstr='nan', precision=8, ... suppress=False, threshold=1000, formatter=None) """ + opt = _make_options_dict(precision, threshold, edgeitems, linewidth, + suppress, nanstr, infstr, sign, formatter) + # formatter is always reset + opt['formatter'] = formatter + _format_options.update(opt) - global _summaryThreshold, _summaryEdgeItems, _float_output_precision - global _line_width, _float_output_suppress_small, _nan_str, _inf_str - global _formatter - - if linewidth is not None: - _line_width = linewidth - if threshold is not None: - _summaryThreshold = threshold - if edgeitems is not None: - _summaryEdgeItems = edgeitems - if precision is not None: - _float_output_precision = precision - if suppress is not None: - _float_output_suppress_small = not not suppress - if nanstr is not None: - _nan_str = nanstr - if infstr is not None: - _inf_str = infstr - _formatter = formatter def get_printoptions(): """ @@ -215,6 +219,7 @@ def get_printoptions(): - nanstr : str - infstr : str - formatter : dict of callables + - sign : str For a full description of these options, see `set_printoptions`. @@ -223,40 +228,25 @@ def get_printoptions(): set_printoptions, set_string_function """ - d = dict(precision=_float_output_precision, - threshold=_summaryThreshold, - edgeitems=_summaryEdgeItems, - linewidth=_line_width, - suppress=_float_output_suppress_small, - nanstr=_nan_str, - infstr=_inf_str, - formatter=_formatter) - return d + return _format_options.copy() def _leading_trailing(a): + edgeitems = _format_options['edgeitems'] if a.ndim == 1: - if len(a) > 2*_summaryEdgeItems: - b = concatenate((a[:_summaryEdgeItems], - a[-_summaryEdgeItems:])) + if len(a) > 2*edgeitems: + b = concatenate((a[:edgeitems], a[-edgeitems:])) else: b = a else: - if len(a) > 2*_summaryEdgeItems: - l = [_leading_trailing(a[i]) for i in range( - min(len(a), _summaryEdgeItems))] + if len(a) > 2*edgeitems: + l = [_leading_trailing(a[i]) for i in range(min(len(a), edgeitems))] l.extend([_leading_trailing(a[-i]) for i in range( - min(len(a), _summaryEdgeItems), 0, -1)]) + min(len(a), edgeitems), 0, -1)]) else: l = [_leading_trailing(a[i]) for i in range(0, len(a))] b = concatenate(tuple(l)) return b -def _boolFormatter(x): - if x: - return ' True' - else: - return 'False' - def _object_format(o): """ Object arrays containing lists should be printed unambiguously """ if type(o) is list: @@ -268,15 +258,16 @@ def _object_format(o): def repr_format(x): return repr(x) -def _get_formatdict(data, precision, suppress_small, formatter): +def _get_formatdict(data, **opt): + prec, supp, sign = opt['precision'], opt['suppress'], opt['sign'] + # wrapped in lambdas to avoid taking a code path with the wrong type of data - formatdict = {'bool': lambda: _boolFormatter, + formatdict = {'bool': lambda: BoolFormat(data), 'int': lambda: IntegerFormat(data), - 'float': lambda: FloatFormat(data, precision, suppress_small), - 'longfloat': lambda: LongFloatFormat(precision), - 'complexfloat': lambda: ComplexFormat(data, precision, - suppress_small), - 'longcomplexfloat': lambda: LongComplexFormat(precision), + 'float': lambda: FloatFormat(data, prec, supp, sign), + 'longfloat': lambda: LongFloatFormat(prec), + 'complexfloat': lambda: ComplexFormat(data, prec, supp, sign), + 'longcomplexfloat': lambda: LongComplexFormat(prec), 'datetime': lambda: DatetimeFormat(data), 'timedelta': lambda: TimedeltaFormat(data), 'object': lambda: _object_format, @@ -288,6 +279,7 @@ def _get_formatdict(data, precision, suppress_small, formatter): def indirect(x): return lambda: x + formatter = opt['formatter'] if formatter is not None: fkeys = [k for k in formatter.keys() if formatter[k] is not None] if 'all' in fkeys: @@ -311,7 +303,7 @@ def _get_formatdict(data, precision, suppress_small, formatter): return formatdict -def _get_format_function(data, precision, suppress_small, formatter): +def _get_format_function(data, **options): """ find the right formatting function for the dtype_ """ @@ -319,16 +311,14 @@ def _get_format_function(data, precision, suppress_small, formatter): if dtype_.fields is not None: format_functions = [] for field_name in dtype_.names: - field_values = data[field_name] - format_function = _get_format_function( - ravel(field_values), precision, suppress_small, formatter) + format_function = _get_format_function(data[field_name], **options) if dtype_[field_name].shape != (): format_function = SubArrayFormat(format_function) format_functions.append(format_function) return StructureFormat(format_functions) dtypeobj = dtype_.type - formatdict = _get_formatdict(data, precision, suppress_small, formatter) + formatdict = _get_formatdict(data, **options) if issubclass(dtypeobj, _nt.bool_): return formatdict['bool']() elif issubclass(dtypeobj, _nt.integer): @@ -355,30 +345,6 @@ def _get_format_function(data, precision, suppress_small, formatter): else: return formatdict['numpystr']() -def _array2string(a, max_line_width, precision, suppress_small, separator=' ', - prefix="", formatter=None): - - if a.size > _summaryThreshold: - summary_insert = "..., " - data = _leading_trailing(a) - else: - summary_insert = "" - data = ravel(asarray(a)) - - # find the right formatting function for the array - format_function = _get_format_function(data, precision, - suppress_small, formatter) - - # skip over "[" - next_line_prefix = " " - # skip over array( - next_line_prefix += " "*len(prefix) - - lst = _formatArray(a, format_function, a.ndim, max_line_width, - next_line_prefix, separator, - _summaryEdgeItems, summary_insert)[:-1] - return lst - def _recursive_guard(fillvalue='...'): """ @@ -409,12 +375,34 @@ def _recursive_guard(fillvalue='...'): return decorating_function -# gracefully handle recursive calls - this comes up when object arrays contain -# themselves +# gracefully handle recursive calls, when object arrays contain themselves @_recursive_guard() +def _array2string(a, options, separator=' ', prefix=""): + if a.size > options['threshold']: + summary_insert = "..., " + data = _leading_trailing(a) + else: + summary_insert = "" + data = asarray(a) + + # find the right formatting function for the array + format_function = _get_format_function(data, **options) + + # skip over "[" + next_line_prefix = " " + # skip over array( + next_line_prefix += " "*len(prefix) + + lst = _formatArray(a, format_function, a.ndim, options['linewidth'], + next_line_prefix, separator, + options['edgeitems'], summary_insert)[:-1] + return lst + + def array2string(a, max_line_width=None, precision=None, suppress_small=None, separator=' ', prefix="", - style=np._NoValue, formatter=None): + style=np._NoValue, formatter=None, threshold=None, + edgeitems=None, sign=None): """ Return a string representation of an array. @@ -469,6 +457,18 @@ def array2string(a, max_line_width=None, precision=None, - 'float_kind' : sets 'float' and 'longfloat' - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat' - 'str_kind' : sets 'str' and 'numpystr' + threshold : int, optional + Total number of array elements which trigger summarization + rather than full repr. + edgeitems : int, optional + Number of array items in summary at beginning and end of + each dimension. + sign : string, either '-', '+', ' ' or 'legacy', optional + Controls printing of the sign of floating-point types. If '+', always + print the sign of positive values. If ' ', always prints a space + (whitespace character) in the sign position of positive values. If + '-', omit the sign character of positive values. If 'legacy', print a + space for positive values except in 0d arrays. Returns ------- @@ -509,30 +509,22 @@ def array2string(a, max_line_width=None, precision=None, '[0x0L 0x1L 0x2L]' """ - # Deprecation 05-16-2017 v1.14 if style is not np._NoValue: warnings.warn("'style' argument is deprecated and no longer functional", DeprecationWarning, stacklevel=3) - if max_line_width is None: - max_line_width = _line_width - - if precision is None: - precision = _float_output_precision - - if suppress_small is None: - suppress_small = _float_output_suppress_small - - if formatter is None: - formatter = _formatter + overrides = _make_options_dict(precision, threshold, edgeitems, + max_line_width, suppress_small, None, None, + sign, formatter) + options = _format_options.copy() + options.update(overrides) if a.size == 0: # treat as a null array if any of shape elements == 0 lst = "[]" else: - lst = _array2string(a, max_line_width, precision, suppress_small, - separator, prefix, formatter=formatter) + lst = _array2string(a, options, separator, prefix) return lst @@ -613,30 +605,38 @@ def _formatArray(a, format_function, rank, max_line_len, class FloatFormat(object): def __init__(self, data, precision, suppress_small, sign=False): + # for backcompatibility, accept bools + if isinstance(sign, bool): + sign = '+' if sign else '-' + + self._legacy = False + if sign == 'legacy': + self._legacy = True + sign = '-' if data.shape == () else ' ' + self.precision = precision self.suppress_small = suppress_small self.sign = sign self.exp_format = False self.large_exponent = False - self.max_str_len = 0 - try: - self.fillFormat(data) - except (TypeError, NotImplementedError): - # if reduce(data) fails, this instance will not be called, just - # instantiated in formatdict. - pass + + self.fillFormat(data) def fillFormat(self, data): with errstate(all='ignore'): - special = isnan(data) | isinf(data) + hasinf = isinf(data) + special = isnan(data) | hasinf valid = not_equal(data, 0) & ~special - non_zero = absolute(data.compress(valid)) + non_zero = data[valid] + abs_non_zero = absolute(non_zero) if len(non_zero) == 0: max_val = 0. min_val = 0. + min_val_sgn = 0. else: - max_val = maximum.reduce(non_zero) - min_val = minimum.reduce(non_zero) + max_val = np.max(abs_non_zero) + min_val = np.min(abs_non_zero) + min_val_sgn = np.min(non_zero) if max_val >= 1.e8: self.exp_format = True if not self.suppress_small and (min_val < 0.0001 @@ -645,51 +645,57 @@ class FloatFormat(object): if self.exp_format: self.large_exponent = 0 < min_val < 1e-99 or max_val >= 1e100 - self.max_str_len = 8 + self.precision - if self.large_exponent: - self.max_str_len += 1 - if self.sign: - format = '%+' - else: - format = '%' - format = format + '%d.%de' % (self.max_str_len, self.precision) + + signpos = self.sign != '-' or any(non_zero < 0) + # for back-compatibility with np 1.13, use two spaces + if self._legacy: + signpos = 2 + max_str_len = signpos + 6 + self.precision + self.large_exponent + + conversion = '' if self.sign == '-' else self.sign + format = '%' + conversion + '%d.%de' % (max_str_len, self.precision) else: - format = '%%.%df' % (self.precision,) - if len(non_zero): - precision = max([_digits(x, self.precision, format) - for x in non_zero]) + if len(non_zero) and self.precision > 0: + precision = self.precision + trim_zero = lambda s: precision - (len(s) - len(s.rstrip('0'))) + fmt = '%%.%df' % (precision,) + precision = max(trim_zero(fmt % x) for x in abs_non_zero) else: precision = 0 - precision = min(self.precision, precision) - self.max_str_len = len(str(int(max_val))) + precision + 2 + + int_len = len(str(int(max_val))) + signpos = self.sign != '-' or (len(str(int(min_val_sgn))) > int_len) + max_str_len = signpos + int_len + 1 + precision + if any(special): - self.max_str_len = max(self.max_str_len, - len(_nan_str), - len(_inf_str)+1) - if self.sign: - format = '%#+' - else: - format = '%#' - format = format + '%d.%df' % (self.max_str_len, precision) + neginf = self.sign != '-' or any(data[hasinf] < 0) + nanlen = len(_format_options['nanstr']) + inflen = len(_format_options['infstr']) + neginf + max_str_len = max(max_str_len, nanlen, inflen) - self.special_fmt = '%%%ds' % (self.max_str_len,) + conversion = '' if self.sign == '-' else self.sign + format = '%#' + conversion + '%d.%df' % (max_str_len, precision) + + self.special_fmt = '%%%ds' % (max_str_len,) self.format = format def __call__(self, x, strip_zeros=True): with errstate(invalid='ignore'): if isnan(x): - if self.sign: - return self.special_fmt % ('+' + _nan_str,) + nan_str = _format_options['nanstr'] + if self.sign == '+': + return self.special_fmt % ('+' + nan_str,) else: - return self.special_fmt % (_nan_str,) + return self.special_fmt % (nan_str,) elif isinf(x): + inf_str = _format_options['infstr'] if x > 0: - if self.sign: - return self.special_fmt % ('+' + _inf_str,) + if self.sign == '+': + return self.special_fmt % ('+' + inf_str,) else: - return self.special_fmt % (_inf_str,) + return self.special_fmt % (inf_str,) else: - return self.special_fmt % ('-' + _inf_str,) + return self.special_fmt % ('-' + inf_str,) s = self.format % x if self.large_exponent: @@ -706,21 +712,11 @@ class FloatFormat(object): s = z + ' '*(len(s)-len(z)) return s - -def _digits(x, precision, format): - if precision > 0: - s = format % x - z = s.rstrip('0') - return precision - len(s) + len(z) - else: - return 0 - - class IntegerFormat(object): def __init__(self, data): try: - max_str_len = max(len(str(maximum.reduce(data))), - len(str(minimum.reduce(data)))) + max_str_len = max(len(str(np.max(data))), + len(str(np.min(data)))) self.format = '%' + str(max_str_len) + 'd' except (TypeError, NotImplementedError): # if reduce(data) fails, this instance will not be called, just @@ -736,29 +732,45 @@ class IntegerFormat(object): else: return "%s" % x +class BoolFormat(object): + def __init__(self, data, **kwargs): + # add an extra space so " True" and "False" have the same length and + # array elements align nicely when printed, except in 0d arrays + self.truestr = ' True' if data.shape != () else 'True' + + def __call__(self, x): + return self.truestr if x else "False" + + class LongFloatFormat(object): # XXX Have to add something to determine the width to use a la FloatFormat # Right now, things won't line up properly def __init__(self, precision, sign=False): + # for backcompatibility, accept bools + if isinstance(sign, bool): + sign = '+' if sign else '-' + self.precision = precision self.sign = sign def __call__(self, x): if isnan(x): - if self.sign: - return '+' + _nan_str + nan_str = _format_options['nanstr'] + if self.sign == '+': + return '+' + nan_str else: - return ' ' + _nan_str + return ' ' + nan_str elif isinf(x): + inf_str = _format_options['infstr'] if x > 0: - if self.sign: - return '+' + _inf_str + if self.sign == '+': + return '+' + inf_str else: - return ' ' + _inf_str + return ' ' + inf_str else: - return '-' + _inf_str + return '-' + inf_str elif x >= 0: - if self.sign: + if self.sign == '+': return '+' + format_longfloat(x, self.precision) else: return ' ' + format_longfloat(x, self.precision) @@ -769,7 +781,7 @@ class LongFloatFormat(object): class LongComplexFormat(object): def __init__(self, precision): self.real_format = LongFloatFormat(precision) - self.imag_format = LongFloatFormat(precision, sign=True) + self.imag_format = LongFloatFormat(precision, sign='+') def __call__(self, x): r = self.real_format(x.real) @@ -778,10 +790,15 @@ class LongComplexFormat(object): class ComplexFormat(object): - def __init__(self, x, precision, suppress_small): - self.real_format = FloatFormat(x.real, precision, suppress_small) + def __init__(self, x, precision, suppress_small, sign=False): + # for backcompatibility, accept bools + if isinstance(sign, bool): + sign = '+' if sign else '-' + + self.real_format = FloatFormat(x.real, precision, suppress_small, + sign=sign) self.imag_format = FloatFormat(x.imag, precision, suppress_small, - sign=True) + sign='+') def __call__(self, x): r = self.real_format(x.real, strip_zeros=False) @@ -823,8 +840,8 @@ class TimedeltaFormat(object): v = int_view[not_equal(int_view, nat_value.view(int_dtype))] if len(v) > 0: # Max str length of non-NaT elements - max_str_len = max(len(str(maximum.reduce(v))), - len(str(minimum.reduce(v)))) + max_str_len = max(len(str(np.max(v))), + len(str(np.min(v)))) else: max_str_len = 0 if len(v) < len(data): diff --git a/numpy/core/tests/test_arrayprint.py b/numpy/core/tests/test_arrayprint.py index 7d4acd35d..b03229447 100644 --- a/numpy/core/tests/test_arrayprint.py +++ b/numpy/core/tests/test_arrayprint.py @@ -11,7 +11,7 @@ from numpy.testing import ( class TestArrayRepr(object): def test_nan_inf(self): x = np.array([np.nan, np.inf]) - assert_equal(repr(x), 'array([ nan, inf])') + assert_equal(repr(x), 'array([nan, inf])') def test_subclass(self): class sub(np.ndarray): pass @@ -68,45 +68,45 @@ class TestComplexArray(object): dtypes = [np.complex64, np.cdouble, np.clongdouble] actual = [str(np.array([c], dt)) for c in cvals for dt in dtypes] wanted = [ - '[ 0.+0.j]', '[ 0.+0.j]', '[ 0.0+0.0j]', - '[ 0.+1.j]', '[ 0.+1.j]', '[ 0.0+1.0j]', - '[ 0.-1.j]', '[ 0.-1.j]', '[ 0.0-1.0j]', - '[ 0.+infj]', '[ 0.+infj]', '[ 0.0+infj]', - '[ 0.-infj]', '[ 0.-infj]', '[ 0.0-infj]', - '[ 0.+nanj]', '[ 0.+nanj]', '[ 0.0+nanj]', - '[ 1.+0.j]', '[ 1.+0.j]', '[ 1.0+0.0j]', - '[ 1.+1.j]', '[ 1.+1.j]', '[ 1.0+1.0j]', - '[ 1.-1.j]', '[ 1.-1.j]', '[ 1.0-1.0j]', - '[ 1.+infj]', '[ 1.+infj]', '[ 1.0+infj]', - '[ 1.-infj]', '[ 1.-infj]', '[ 1.0-infj]', - '[ 1.+nanj]', '[ 1.+nanj]', '[ 1.0+nanj]', + '[0.+0.j]', '[0.+0.j]', '[ 0.0+0.0j]', + '[0.+1.j]', '[0.+1.j]', '[ 0.0+1.0j]', + '[0.-1.j]', '[0.-1.j]', '[ 0.0-1.0j]', + '[0.+infj]', '[0.+infj]', '[ 0.0+infj]', + '[0.-infj]', '[0.-infj]', '[ 0.0-infj]', + '[0.+nanj]', '[0.+nanj]', '[ 0.0+nanj]', + '[1.+0.j]', '[1.+0.j]', '[ 1.0+0.0j]', + '[1.+1.j]', '[1.+1.j]', '[ 1.0+1.0j]', + '[1.-1.j]', '[1.-1.j]', '[ 1.0-1.0j]', + '[1.+infj]', '[1.+infj]', '[ 1.0+infj]', + '[1.-infj]', '[1.-infj]', '[ 1.0-infj]', + '[1.+nanj]', '[1.+nanj]', '[ 1.0+nanj]', '[-1.+0.j]', '[-1.+0.j]', '[-1.0+0.0j]', '[-1.+1.j]', '[-1.+1.j]', '[-1.0+1.0j]', '[-1.-1.j]', '[-1.-1.j]', '[-1.0-1.0j]', '[-1.+infj]', '[-1.+infj]', '[-1.0+infj]', '[-1.-infj]', '[-1.-infj]', '[-1.0-infj]', '[-1.+nanj]', '[-1.+nanj]', '[-1.0+nanj]', - '[ inf+0.j]', '[ inf+0.j]', '[ inf+0.0j]', - '[ inf+1.j]', '[ inf+1.j]', '[ inf+1.0j]', - '[ inf-1.j]', '[ inf-1.j]', '[ inf-1.0j]', - '[ inf+infj]', '[ inf+infj]', '[ inf+infj]', - '[ inf-infj]', '[ inf-infj]', '[ inf-infj]', - '[ inf+nanj]', '[ inf+nanj]', '[ inf+nanj]', + '[inf+0.j]', '[inf+0.j]', '[ inf+0.0j]', + '[inf+1.j]', '[inf+1.j]', '[ inf+1.0j]', + '[inf-1.j]', '[inf-1.j]', '[ inf-1.0j]', + '[inf+infj]', '[inf+infj]', '[ inf+infj]', + '[inf-infj]', '[inf-infj]', '[ inf-infj]', + '[inf+nanj]', '[inf+nanj]', '[ inf+nanj]', '[-inf+0.j]', '[-inf+0.j]', '[-inf+0.0j]', '[-inf+1.j]', '[-inf+1.j]', '[-inf+1.0j]', '[-inf-1.j]', '[-inf-1.j]', '[-inf-1.0j]', '[-inf+infj]', '[-inf+infj]', '[-inf+infj]', '[-inf-infj]', '[-inf-infj]', '[-inf-infj]', '[-inf+nanj]', '[-inf+nanj]', '[-inf+nanj]', - '[ nan+0.j]', '[ nan+0.j]', '[ nan+0.0j]', - '[ nan+1.j]', '[ nan+1.j]', '[ nan+1.0j]', - '[ nan-1.j]', '[ nan-1.j]', '[ nan-1.0j]', - '[ nan+infj]', '[ nan+infj]', '[ nan+infj]', - '[ nan-infj]', '[ nan-infj]', '[ nan-infj]', - '[ nan+nanj]', '[ nan+nanj]', '[ nan+nanj]'] + '[nan+0.j]', '[nan+0.j]', '[ nan+0.0j]', + '[nan+1.j]', '[nan+1.j]', '[ nan+1.0j]', + '[nan-1.j]', '[nan-1.j]', '[ nan-1.0j]', + '[nan+infj]', '[nan+infj]', '[ nan+infj]', + '[nan-infj]', '[nan-infj]', '[ nan-infj]', + '[nan+nanj]', '[nan+nanj]', '[ nan+nanj]'] for res, val in zip(actual, wanted): - assert_(res == val) + assert_equal(res, val) class TestArray2String(object): def test_basic(self): @@ -157,7 +157,7 @@ class TestArray2String(object): dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))]) x = np.array([('Sarah', (8.0, 7.0)), ('John', (6.0, 7.0))], dtype=dt) assert_equal(np.array2string(x), - "[('Sarah', [ 8., 7.]) ('John', [ 6., 7.])]") + "[('Sarah', [8., 7.]) ('John', [6., 7.])]") # for issue #5692 A = np.zeros(shape=10, dtype=[("A", "M8[s]")]) @@ -180,7 +180,7 @@ class TestArray2String(object): # See #8172 array_scalar = np.array( (1., 2.1234567890123456789, 3.), dtype=('f8,f8,f8')) - assert_equal(np.array2string(array_scalar), "( 1., 2.12345679, 3.)") + assert_equal(np.array2string(array_scalar), "(1., 2.12345679, 3.)") class TestPrintOptions(object): @@ -194,17 +194,17 @@ class TestPrintOptions(object): def test_basic(self): x = np.array([1.5, 0, 1.234567890]) - assert_equal(repr(x), "array([ 1.5 , 0. , 1.23456789])") + assert_equal(repr(x), "array([1.5 , 0. , 1.23456789])") np.set_printoptions(precision=4) - assert_equal(repr(x), "array([ 1.5 , 0. , 1.2346])") + assert_equal(repr(x), "array([1.5 , 0. , 1.2346])") def test_precision_zero(self): np.set_printoptions(precision=0) for values, string in ( - ([0.], " 0."), ([.3], " 0."), ([-.3], "-0."), ([.7], " 1."), - ([1.5], " 2."), ([-1.5], "-2."), ([-15.34], "-15."), - ([100.], " 100."), ([.2, -1, 122.51], " 0., -1., 123."), - ([0], "0"), ([-12], "-12"), ([complex(.3, -.7)], " 0.-1.j")): + ([0.], "0."), ([.3], "0."), ([-.3], "-0."), ([.7], "1."), + ([1.5], "2."), ([-1.5], "-2."), ([-15.34], "-15."), + ([100.], "100."), ([.2, -1, 122.51], " 0., -1., 123."), + ([0], "0"), ([-12], "-12"), ([complex(.3, -.7)], "0.-1.j")): x = np.array(values) assert_equal(repr(x), "array([%s])" % string) @@ -234,7 +234,7 @@ class TestPrintOptions(object): np.set_printoptions(formatter={'float':lambda x: str(x-1)}) assert_equal(repr(x), "array([-1.0, 0.0, 1.0])") np.set_printoptions(formatter={'float_kind':None}) - assert_equal(repr(x), "array([ 0., 1., 2.])") + assert_equal(repr(x), "array([0., 1., 2.])") def test_0d_arrays(self): assert_equal(repr(np.datetime64('2005-02-25')[...]), @@ -244,6 +244,72 @@ class TestPrintOptions(object): np.set_printoptions(formatter={'all':lambda x: "test"}) assert_equal(repr(x), "array(test)") + def test_float_spacing(self): + x = np.array([1., 2., 3.]) + y = np.array([1., 2., -10.]) + z = np.array([100., 2., -1.]) + w = np.array([-100., 2., 1.]) + + assert_equal(repr(x), 'array([1., 2., 3.])') + assert_equal(repr(y), 'array([ 1., 2., -10.])') + assert_equal(repr(np.array(y[0])), 'array(1.)') + assert_equal(repr(np.array(y[-1])), 'array(-10.)') + assert_equal(repr(z), 'array([100., 2., -1.])') + assert_equal(repr(w), 'array([-100., 2., 1.])') + + assert_equal(repr(np.array([np.nan, np.inf])), 'array([nan, inf])') + assert_equal(repr(np.array([np.nan, -np.inf])), 'array([ nan, -inf])') + + x = np.array([np.inf, 100000, 1.1234]) + y = np.array([np.inf, 100000, -1.1234]) + z = np.array([np.inf, 1.1234, -1e120]) + np.set_printoptions(precision=2) + assert_equal(repr(x), 'array([ inf, 1.00e+05, 1.12e+00])') + assert_equal(repr(y), 'array([ inf, 1.00e+05, -1.12e+00])') + assert_equal(repr(z), 'array([ inf, 1.12e+000, -1.00e+120])') + + def test_bool_spacing(self): + assert_equal(repr(np.array([True, True])), + 'array([ True, True], dtype=bool)') + assert_equal(repr(np.array([True, False])), + 'array([ True, False], dtype=bool)') + assert_equal(repr(np.array([True])), + 'array([ True], dtype=bool)') + assert_equal(repr(np.array(True)), + 'array(True, dtype=bool)') + assert_equal(repr(np.array(False)), + 'array(False, dtype=bool)') + + def test_sign_spacing(self): + a = np.arange(4.) + b = np.array([1.234e9]) + + assert_equal(repr(a), 'array([0., 1., 2., 3.])') + assert_equal(repr(np.array(1.)), 'array(1.)') + assert_equal(repr(b), 'array([1.23400000e+09])') + + np.set_printoptions(sign=' ') + assert_equal(repr(a), 'array([ 0., 1., 2., 3.])') + assert_equal(repr(np.array(1.)), 'array( 1.)') + assert_equal(repr(b), 'array([ 1.23400000e+09])') + + np.set_printoptions(sign='+') + assert_equal(repr(a), 'array([+0., +1., +2., +3.])') + assert_equal(repr(np.array(1.)), 'array(+1.)') + assert_equal(repr(b), 'array([+1.23400000e+09])') + + np.set_printoptions(sign='legacy') + assert_equal(repr(a), 'array([ 0., 1., 2., 3.])') + assert_equal(repr(np.array(1.)), 'array(1.)') + assert_equal(repr(b), 'array([ 1.23400000e+09])') + + def test_sign_spacing_structured(self): + a = np.ones(2, dtype='f,f') + assert_equal(repr(a), "array([(1., 1.), (1., 1.)],\n" + " dtype=[('f0', '<f4'), ('f1', '<f4')])") + assert_equal(repr(a[0]), "(1., 1.)") + + def test_unicode_object_array(): import sys if sys.version_info[0] >= 3: diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 84469d03b..34f9080fb 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -858,7 +858,7 @@ class TestRegression(object): def test_sign_bit(self): x = np.array([0, -0.0, 0]) - assert_equal(str(np.abs(x)), '[ 0. 0. 0.]') + assert_equal(str(np.abs(x)), '[0. 0. 0.]') def test_flat_index_byteswap(self): for dt in (np.dtype('<i4'), np.dtype('>i4')): diff --git a/numpy/polynomial/tests/test_printing.py b/numpy/polynomial/tests/test_printing.py index f403812c9..939d48a86 100644 --- a/numpy/polynomial/tests/test_printing.py +++ b/numpy/polynomial/tests/test_printing.py @@ -7,64 +7,64 @@ from numpy.testing import run_module_suite, assert_equal class TestStr(object): def test_polynomial_str(self): res = str(poly.Polynomial([0, 1])) - tgt = 'poly([ 0. 1.])' + tgt = 'poly([0. 1.])' assert_equal(res, tgt) def test_chebyshev_str(self): res = str(poly.Chebyshev([0, 1])) - tgt = 'cheb([ 0. 1.])' + tgt = 'cheb([0. 1.])' assert_equal(res, tgt) def test_legendre_str(self): res = str(poly.Legendre([0, 1])) - tgt = 'leg([ 0. 1.])' + tgt = 'leg([0. 1.])' assert_equal(res, tgt) def test_hermite_str(self): res = str(poly.Hermite([0, 1])) - tgt = 'herm([ 0. 1.])' + tgt = 'herm([0. 1.])' assert_equal(res, tgt) def test_hermiteE_str(self): res = str(poly.HermiteE([0, 1])) - tgt = 'herme([ 0. 1.])' + tgt = 'herme([0. 1.])' assert_equal(res, tgt) def test_laguerre_str(self): res = str(poly.Laguerre([0, 1])) - tgt = 'lag([ 0. 1.])' + tgt = 'lag([0. 1.])' assert_equal(res, tgt) class TestRepr(object): def test_polynomial_str(self): res = repr(poly.Polynomial([0, 1])) - tgt = 'Polynomial([ 0., 1.], domain=[-1, 1], window=[-1, 1])' + tgt = 'Polynomial([0., 1.], domain=[-1, 1], window=[-1, 1])' assert_equal(res, tgt) def test_chebyshev_str(self): res = repr(poly.Chebyshev([0, 1])) - tgt = 'Chebyshev([ 0., 1.], domain=[-1, 1], window=[-1, 1])' + tgt = 'Chebyshev([0., 1.], domain=[-1, 1], window=[-1, 1])' assert_equal(res, tgt) def test_legendre_repr(self): res = repr(poly.Legendre([0, 1])) - tgt = 'Legendre([ 0., 1.], domain=[-1, 1], window=[-1, 1])' + tgt = 'Legendre([0., 1.], domain=[-1, 1], window=[-1, 1])' assert_equal(res, tgt) def test_hermite_repr(self): res = repr(poly.Hermite([0, 1])) - tgt = 'Hermite([ 0., 1.], domain=[-1, 1], window=[-1, 1])' + tgt = 'Hermite([0., 1.], domain=[-1, 1], window=[-1, 1])' assert_equal(res, tgt) def test_hermiteE_repr(self): res = repr(poly.HermiteE([0, 1])) - tgt = 'HermiteE([ 0., 1.], domain=[-1, 1], window=[-1, 1])' + tgt = 'HermiteE([0., 1.], domain=[-1, 1], window=[-1, 1])' assert_equal(res, tgt) def test_laguerre_repr(self): res = repr(poly.Laguerre([0, 1])) - tgt = 'Laguerre([ 0., 1.], domain=[0, 1], window=[0, 1])' + tgt = 'Laguerre([0., 1.], domain=[0, 1], window=[0, 1])' assert_equal(res, tgt) diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py index 493c538af..1a2a621ea 100644 --- a/numpy/testing/tests/test_utils.py +++ b/numpy/testing/tests/test_utils.py @@ -159,9 +159,9 @@ class TestBuildErrorMessage(unittest.TestCase): err_msg = 'There is a mismatch' a = build_err_msg([x, y], err_msg) - b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array([ ' - '1.00001, 2.00002, 3.00003])\n DESIRED: array([ 1.00002, ' - '2.00003, 3.00004])') + b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array([' + '1.00001, 2.00002, 3.00003])\n DESIRED: array([1.00002, ' + '2.00003, 3.00004])') self.assertEqual(a, b) def test_build_err_msg_no_verbose(self): @@ -179,8 +179,8 @@ class TestBuildErrorMessage(unittest.TestCase): err_msg = 'There is a mismatch' a = build_err_msg([x, y], err_msg, names=('FOO', 'BAR')) - b = ('\nItems are not equal: There is a mismatch\n FOO: array([ ' - '1.00001, 2.00002, 3.00003])\n BAR: array([ 1.00002, 2.00003, ' + b = ('\nItems are not equal: There is a mismatch\n FOO: array([' + '1.00001, 2.00002, 3.00003])\n BAR: array([1.00002, 2.00003, ' '3.00004])') self.assertEqual(a, b) @@ -190,9 +190,9 @@ class TestBuildErrorMessage(unittest.TestCase): err_msg = 'There is a mismatch' a = build_err_msg([x, y], err_msg, precision=10) - b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array([ ' - '1.000000001, 2.00002 , 3.00003 ])\n DESIRED: array([ ' - '1.000000002, 2.00003 , 3.00004 ])') + b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array([' + '1.000000001, 2.00002 , 3.00003 ])\n DESIRED: array([' + '1.000000002, 2.00003 , 3.00004 ])') self.assertEqual(a, b) @@ -433,8 +433,8 @@ class TestAlmostEqual(_GenericTest, unittest.TestCase): # test with a different amount of decimal digits # note that we only check for the formatting of the arrays themselves - b = ('x: array([ 1.00000000001, 2.00000000002, 3.00003 ' - ' ])\n y: array([ 1.00000000002, 2.00000000003, 3.00004 ])') + b = ('x: array([1.00000000001, 2.00000000002, 3.00003 ' + ' ])\n y: array([1.00000000002, 2.00000000003, 3.00004 ])') try: self._assert_func(x, y, decimal=12) except AssertionError as e: @@ -443,8 +443,8 @@ class TestAlmostEqual(_GenericTest, unittest.TestCase): # with the default value of decimal digits, only the 3rd element differs # note that we only check for the formatting of the arrays themselves - b = ('x: array([ 1. , 2. , 3.00003])\n y: array([ 1. , ' - '2. , 3.00004])') + b = ('x: array([1. , 2. , 3.00003])\n y: array([1. , ' + '2. , 3.00004])') try: self._assert_func(x, y) except AssertionError as e: |
