[pypy-commit] pypy numpy-back-to-applevel: start adding necessary things for using applevel __str__ and __repr__
fijal
noreply at buildbot.pypy.org
Sat Jan 21 23:11:15 CET 2012
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: numpy-back-to-applevel
Changeset: r51612:616ba3da7de7
Date: 2012-01-21 21:46 +0200
http://bitbucket.org/pypy/pypy/changeset/616ba3da7de7/
Log: start adding necessary things for using applevel __str__ and
__repr__
diff --git a/lib_pypy/numpypy/core/__init__.py b/lib_pypy/numpypy/core/__init__.py
--- a/lib_pypy/numpypy/core/__init__.py
+++ b/lib_pypy/numpypy/core/__init__.py
@@ -1,1 +1,2 @@
from .fromnumeric import *
+from .numeric import *
diff --git a/lib_pypy/numpypy/core/arrayprint.py b/lib_pypy/numpypy/core/arrayprint.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/numpypy/core/arrayprint.py
@@ -0,0 +1,785 @@
+"""Array printing function
+
+$Id: arrayprint.py,v 1.9 2005/09/13 13:58:44 teoliphant Exp $
+"""
+__all__ = ["array2string", "set_printoptions", "get_printoptions"]
+__docformat__ = 'restructuredtext'
+
+#
+# Written by Konrad Hinsen <hinsenk at ere.umontreal.ca>
+# last revision: 1996-3-13
+# modified by Jim Hugunin 1997-3-3 for repr's and str's (and other details)
+# and by Perry Greenfield 2000-4-1 for numarray
+# and by Travis Oliphant 2005-8-22 for numpy
+
+import sys
+import _numpypy as _nt
+from _numpypy import maximum, minimum, absolute, not_equal #, isnan, isinf
+#from _numpypy import format_longfloat, datetime_as_string, datetime_data, isna
+from fromnumeric import ravel
+
+
+def product(x, y): return x*y
+
+_summaryEdgeItems = 3 # repr N leading and trailing items of each dimension
+_summaryThreshold = 1000 # total items > triggers array summarization
+
+_float_output_precision = 8
+_float_output_suppress_small = False
+_line_width = 75
+_nan_str = 'nan'
+_inf_str = 'inf'
+_na_str = 'NA'
+_formatter = None # formatting function for array elements
+
+if sys.version_info[0] >= 3:
+ from functools import reduce
+
+def set_printoptions(precision=None, threshold=None, edgeitems=None,
+ linewidth=None, suppress=None,
+ nanstr=None, infstr=None, nastr=None,
+ formatter=None):
+ """
+ Set printing options.
+
+ These options determine the way floating point numbers, arrays and
+ other NumPy objects are displayed.
+
+ Parameters
+ ----------
+ precision : int, optional
+ Number of digits of precision for floating point output (default 8).
+ threshold : int, optional
+ Total number of array elements which trigger summarization
+ rather than full repr (default 1000).
+ edgeitems : int, optional
+ Number of array items in summary at beginning and end of
+ each dimension (default 3).
+ linewidth : int, optional
+ The number of characters per line for the purpose of inserting
+ line breaks (default 75).
+ suppress : bool, optional
+ Whether or not suppress printing of small floating point values
+ using scientific notation (default False).
+ nanstr : str, optional
+ String representation of floating point not-a-number (default nan).
+ infstr : str, optional
+ String representation of floating point infinity (default inf).
+ nastr : str, optional
+ String representation of NA missing value (default NA).
+ 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.
+ Types that are not specified (by their corresponding keys) are handled
+ by the default formatters. Individual types for which a formatter
+ can be set are::
+
+ - 'bool'
+ - 'int'
+ - 'timedelta' : a `numpy.timedelta64`
+ - 'datetime' : a `numpy.datetime64`
+ - 'float'
+ - 'longfloat' : 128-bit floats
+ - 'complexfloat'
+ - 'longcomplexfloat' : composed of two 128-bit floats
+ - 'numpy_str' : types `numpy.string_` and `numpy.unicode_`
+ - 'str' : all other strings
+
+ Other keys that can be used to set a group of types at once are::
+
+ - 'all' : sets all types
+ - 'int_kind' : sets 'int'
+ - 'float_kind' : sets 'float' and 'longfloat'
+ - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat'
+ - 'str_kind' : sets 'str' and 'numpystr'
+
+ See Also
+ --------
+ get_printoptions, set_string_function, array2string
+
+ Notes
+ -----
+ `formatter` is always reset with a call to `set_printoptions`.
+
+ Examples
+ --------
+ Floating point precision can be set:
+
+ >>> np.set_printoptions(precision=4)
+ >>> print np.array([1.123456789])
+ [ 1.1235]
+
+ Long arrays can be summarised:
+
+ >>> np.set_printoptions(threshold=5)
+ >>> print np.arange(10)
+ [0 1 2 ..., 7 8 9]
+
+ Small results can be suppressed:
+
+ >>> eps = np.finfo(float).eps
+ >>> x = np.arange(4.)
+ >>> x**2 - (x + eps)**2
+ array([ -4.9304e-32, -4.4409e-16, 0.0000e+00, 0.0000e+00])
+ >>> np.set_printoptions(suppress=True)
+ >>> x**2 - (x + eps)**2
+ array([-0., -0., 0., 0.])
+
+ A custom formatter can be used to display array elements as desired:
+
+ >>> np.set_printoptions(formatter={'all':lambda x: 'int: '+str(-x)})
+ >>> x = np.arange(3)
+ >>> x
+ array([int: 0, int: -1, int: -2])
+ >>> np.set_printoptions() # formatter gets reset
+ >>> x
+ array([0, 1, 2])
+
+ To put back the default options, you can use:
+
+ >>> np.set_printoptions(edgeitems=3,infstr='inf',
+ ... linewidth=75, nanstr='nan', precision=8,
+ ... suppress=False, threshold=1000, formatter=None)
+ """
+
+ global _summaryThreshold, _summaryEdgeItems, _float_output_precision, \
+ _line_width, _float_output_suppress_small, _nan_str, _inf_str, \
+ _na_str, _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
+ if nastr is not None:
+ _na_str = nastr
+ _formatter = formatter
+
+def get_printoptions():
+ """
+ Return the current print options.
+
+ Returns
+ -------
+ print_opts : dict
+ Dictionary of current print options with keys
+
+ - precision : int
+ - threshold : int
+ - edgeitems : int
+ - linewidth : int
+ - suppress : bool
+ - nanstr : str
+ - infstr : str
+ - formatter : dict of callables
+
+ For a full description of these options, see `set_printoptions`.
+
+ See Also
+ --------
+ 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,
+ nastr=_na_str,
+ formatter=_formatter)
+ return d
+
+def _leading_trailing(a):
+ import numeric as _nc
+ if a.ndim == 1:
+ if len(a) > 2*_summaryEdgeItems:
+ b = _nc.concatenate((a[:_summaryEdgeItems],
+ a[-_summaryEdgeItems:]))
+ else:
+ b = a
+ else:
+ if len(a) > 2*_summaryEdgeItems:
+ l = [_leading_trailing(a[i]) for i in range(
+ min(len(a), _summaryEdgeItems))]
+ l.extend([_leading_trailing(a[-i]) for i in range(
+ min(len(a), _summaryEdgeItems),0,-1)])
+ else:
+ l = [_leading_trailing(a[i]) for i in range(0, len(a))]
+ b = _nc.concatenate(tuple(l))
+ return b
+
+def _boolFormatter(x):
+ if isna(x):
+ return str(x).replace('NA', _na_str, 1)
+ elif x:
+ return ' True'
+ else:
+ return 'False'
+
+
+def repr_format(x):
+ if isna(x):
+ return str(x).replace('NA', _na_str, 1)
+ else:
+ return repr(x)
+
+def _array2string(a, max_line_width, precision, suppress_small, separator=' ',
+ prefix="", formatter=None):
+
+ 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
+
+ if a.size > _summaryThreshold:
+ summary_insert = "..., "
+ data = _leading_trailing(a)
+ else:
+ summary_insert = ""
+ data = ravel(a)
+
+ formatdict = {'bool' : _boolFormatter,
+ 'int' : IntegerFormat(data),
+ 'float' : FloatFormat(data, precision, suppress_small),
+ 'longfloat' : LongFloatFormat(precision),
+ 'complexfloat' : ComplexFormat(data, precision,
+ suppress_small),
+ 'longcomplexfloat' : LongComplexFormat(precision),
+ 'datetime' : DatetimeFormat(data),
+ 'timedelta' : TimedeltaFormat(data),
+ 'numpystr' : repr_format,
+ 'str' : str}
+
+ if formatter is not None:
+ fkeys = [k for k in formatter.keys() if formatter[k] is not None]
+ if 'all' in fkeys:
+ for key in formatdict.keys():
+ formatdict[key] = formatter['all']
+ if 'int_kind' in fkeys:
+ for key in ['int']:
+ formatdict[key] = formatter['int_kind']
+ if 'float_kind' in fkeys:
+ for key in ['float', 'longfloat']:
+ formatdict[key] = formatter['float_kind']
+ if 'complex_kind' in fkeys:
+ for key in ['complexfloat', 'longcomplexfloat']:
+ formatdict[key] = formatter['complex_kind']
+ if 'str_kind' in fkeys:
+ for key in ['numpystr', 'str']:
+ formatdict[key] = formatter['str_kind']
+ for key in formatdict.keys():
+ if key in fkeys:
+ formatdict[key] = formatter[key]
+
+ try:
+ format_function = a._format
+ msg = "The `_format` attribute is deprecated in Numpy 2.0 and " \
+ "will be removed in 2.1. Use the `formatter` kw instead."
+ import warnings
+ warnings.warn(msg, DeprecationWarning)
+ except AttributeError:
+ # find the right formatting function for the array
+ dtypeobj = a.dtype.type
+ if issubclass(dtypeobj, _nt.bool_):
+ format_function = formatdict['bool']
+ elif issubclass(dtypeobj, _nt.integer):
+ if issubclass(dtypeobj, _nt.timedelta64):
+ format_function = formatdict['timedelta']
+ else:
+ format_function = formatdict['int']
+ elif issubclass(dtypeobj, _nt.floating):
+ if issubclass(dtypeobj, _nt.longfloat):
+ format_function = formatdict['longfloat']
+ else:
+ format_function = formatdict['float']
+ elif issubclass(dtypeobj, _nt.complexfloating):
+ if issubclass(dtypeobj, _nt.clongfloat):
+ format_function = formatdict['longcomplexfloat']
+ else:
+ format_function = formatdict['complexfloat']
+ elif issubclass(dtypeobj, (_nt.unicode_, _nt.string_)):
+ format_function = formatdict['numpystr']
+ elif issubclass(dtypeobj, _nt.datetime64):
+ format_function = formatdict['datetime']
+ else:
+ format_function = formatdict['str']
+
+ # skip over "["
+ next_line_prefix = " "
+ # skip over array(
+ next_line_prefix += " "*len(prefix)
+
+ lst = _formatArray(a, format_function, len(a.shape), max_line_width,
+ next_line_prefix, separator,
+ _summaryEdgeItems, summary_insert)[:-1]
+ return lst
+
+def _convert_arrays(obj):
+ import numeric as _nc
+ newtup = []
+ for k in obj:
+ if isinstance(k, _nc.ndarray):
+ k = k.tolist()
+ elif isinstance(k, tuple):
+ k = _convert_arrays(k)
+ newtup.append(k)
+ return tuple(newtup)
+
+
+def array2string(a, max_line_width=None, precision=None,
+ suppress_small=None, separator=' ', prefix="",
+ style=repr, formatter=None):
+ """
+ Return a string representation of an array.
+
+ Parameters
+ ----------
+ a : ndarray
+ Input array.
+ max_line_width : int, optional
+ The maximum number of columns the string should span. Newline
+ characters splits the string appropriately after array elements.
+ precision : int, optional
+ Floating point precision. Default is the current printing
+ precision (usually 8), which can be altered using `set_printoptions`.
+ suppress_small : bool, optional
+ Represent very small numbers as zero. A number is "very small" if it
+ is smaller than the current printing precision.
+ separator : str, optional
+ Inserted between elements.
+ prefix : str, optional
+ An array is typically printed as::
+
+ 'prefix(' + array2string(a) + ')'
+
+ The length of the prefix string is used to align the
+ output correctly.
+ style : function, optional
+ A function that accepts an ndarray and returns a string. Used only
+ when the shape of `a` is equal to ``()``, i.e. for 0-D arrays.
+ 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.
+ Types that are not specified (by their corresponding keys) are handled
+ by the default formatters. Individual types for which a formatter
+ can be set are::
+
+ - 'bool'
+ - 'int'
+ - 'timedelta' : a `numpy.timedelta64`
+ - 'datetime' : a `numpy.datetime64`
+ - 'float'
+ - 'longfloat' : 128-bit floats
+ - 'complexfloat'
+ - 'longcomplexfloat' : composed of two 128-bit floats
+ - 'numpy_str' : types `numpy.string_` and `numpy.unicode_`
+ - 'str' : all other strings
+
+ Other keys that can be used to set a group of types at once are::
+
+ - 'all' : sets all types
+ - 'int_kind' : sets 'int'
+ - 'float_kind' : sets 'float' and 'longfloat'
+ - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat'
+ - 'str_kind' : sets 'str' and 'numpystr'
+
+ Returns
+ -------
+ array_str : str
+ String representation of the array.
+
+ Raises
+ ------
+ TypeError : if a callable in `formatter` does not return a string.
+
+ See Also
+ --------
+ array_str, array_repr, set_printoptions, get_printoptions
+
+ Notes
+ -----
+ If a formatter is specified for a certain type, the `precision` keyword is
+ ignored for that type.
+
+ Examples
+ --------
+ >>> x = np.array([1e-16,1,2,3])
+ >>> print np.array2string(x, precision=2, separator=',',
+ ... suppress_small=True)
+ [ 0., 1., 2., 3.]
+
+ >>> x = np.arange(3.)
+ >>> np.array2string(x, formatter={'float_kind':lambda x: "%.2f" % x})
+ '[0.00 1.00 2.00]'
+
+ >>> x = np.arange(3)
+ >>> np.array2string(x, formatter={'int':lambda x: hex(x)})
+ '[0x0L 0x1L 0x2L]'
+
+ """
+
+ if a.shape == ():
+ x = a.item()
+ if isna(x):
+ lst = str(x).replace('NA', _na_str, 1)
+ else:
+ try:
+ lst = a._format(x)
+ msg = "The `_format` attribute is deprecated in Numpy " \
+ "2.0 and will be removed in 2.1. Use the " \
+ "`formatter` kw instead."
+ import warnings
+ warnings.warn(msg, DeprecationWarning)
+ except AttributeError:
+ if isinstance(x, tuple):
+ x = _convert_arrays(x)
+ lst = style(x)
+ elif reduce(product, a.shape) == 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)
+ return lst
+
+def _extendLine(s, line, word, max_line_len, next_line_prefix):
+ if len(line.rstrip()) + len(word.rstrip()) >= max_line_len:
+ s += line.rstrip() + "\n"
+ line = next_line_prefix
+ line += word
+ return s, line
+
+
+def _formatArray(a, format_function, rank, max_line_len,
+ next_line_prefix, separator, edge_items, summary_insert):
+ """formatArray is designed for two modes of operation:
+
+ 1. Full output
+
+ 2. Summarized output
+
+ """
+ if rank == 0:
+ obj = a.item()
+ if isinstance(obj, tuple):
+ obj = _convert_arrays(obj)
+ return str(obj)
+
+ if summary_insert and 2*edge_items < len(a):
+ leading_items, trailing_items, summary_insert1 = \
+ edge_items, edge_items, summary_insert
+ else:
+ leading_items, trailing_items, summary_insert1 = 0, len(a), ""
+
+ if rank == 1:
+ s = ""
+ line = next_line_prefix
+ for i in xrange(leading_items):
+ word = format_function(a[i]) + separator
+ s, line = _extendLine(s, line, word, max_line_len, next_line_prefix)
+
+ if summary_insert1:
+ s, line = _extendLine(s, line, summary_insert1, max_line_len, next_line_prefix)
+
+ for i in xrange(trailing_items, 1, -1):
+ word = format_function(a[-i]) + separator
+ s, line = _extendLine(s, line, word, max_line_len, next_line_prefix)
+
+ word = format_function(a[-1])
+ s, line = _extendLine(s, line, word, max_line_len, next_line_prefix)
+ s += line + "]\n"
+ s = '[' + s[len(next_line_prefix):]
+ else:
+ s = '['
+ sep = separator.rstrip()
+ for i in xrange(leading_items):
+ if i > 0:
+ s += next_line_prefix
+ s += _formatArray(a[i], format_function, rank-1, max_line_len,
+ " " + next_line_prefix, separator, edge_items,
+ summary_insert)
+ s = s.rstrip() + sep.rstrip() + '\n'*max(rank-1,1)
+
+ if summary_insert1:
+ s += next_line_prefix + summary_insert1 + "\n"
+
+ for i in xrange(trailing_items, 1, -1):
+ if leading_items or i != trailing_items:
+ s += next_line_prefix
+ s += _formatArray(a[-i], format_function, rank-1, max_line_len,
+ " " + next_line_prefix, separator, edge_items,
+ summary_insert)
+ s = s.rstrip() + sep.rstrip() + '\n'*max(rank-1,1)
+ if leading_items or trailing_items > 1:
+ s += next_line_prefix
+ s += _formatArray(a[-1], format_function, rank-1, max_line_len,
+ " " + next_line_prefix, separator, edge_items,
+ summary_insert).rstrip()+']\n'
+ return s
+
+class FloatFormat(object):
+ def __init__(self, data, precision, suppress_small, sign=False):
+ 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
+
+ def fillFormat(self, data):
+ import numeric as _nc
+ errstate = _nc.seterr(all='ignore')
+ try:
+ special = isnan(data) | isinf(data) | isna(data)
+ special[isna(data)] = False
+ valid = not_equal(data, 0) & ~special
+ valid[isna(data)] = False
+ non_zero = absolute(data.compress(valid))
+ if len(non_zero) == 0:
+ max_val = 0.
+ min_val = 0.
+ else:
+ max_val = maximum.reduce(non_zero, skipna=True)
+ min_val = minimum.reduce(non_zero, skipna=True)
+ if max_val >= 1.e8:
+ self.exp_format = True
+ if not self.suppress_small and (min_val < 0.0001
+ or max_val/min_val > 1000.):
+ self.exp_format = True
+ finally:
+ _nc.seterr(**errstate)
+
+ 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)
+ else:
+ format = '%%.%df' % (self.precision,)
+ if len(non_zero):
+ precision = max([_digits(x, self.precision, format)
+ for x in non_zero])
+ else:
+ precision = 0
+ precision = min(self.precision, precision)
+ self.max_str_len = len(str(int(max_val))) + precision + 2
+ if _nc.any(special):
+ self.max_str_len = max(self.max_str_len,
+ len(_nan_str),
+ len(_inf_str)+1,
+ len(_na_str))
+ if self.sign:
+ format = '%#+'
+ else:
+ format = '%#'
+ format = format + '%d.%df' % (self.max_str_len, precision)
+
+ self.special_fmt = '%%%ds' % (self.max_str_len,)
+ self.format = format
+
+ def __call__(self, x, strip_zeros=True):
+ import numeric as _nc
+ err = _nc.seterr(invalid='ignore')
+ try:
+ if isna(x):
+ return self.special_fmt % (str(x).replace('NA', _na_str, 1),)
+ elif isnan(x):
+ if self.sign:
+ return self.special_fmt % ('+' + _nan_str,)
+ else:
+ return self.special_fmt % (_nan_str,)
+ elif isinf(x):
+ if x > 0:
+ if self.sign:
+ return self.special_fmt % ('+' + _inf_str,)
+ else:
+ return self.special_fmt % (_inf_str,)
+ else:
+ return self.special_fmt % ('-' + _inf_str,)
+ finally:
+ _nc.seterr(**err)
+
+ s = self.format % x
+ if self.large_exponent:
+ # 3-digit exponent
+ expsign = s[-3]
+ if expsign == '+' or expsign == '-':
+ s = s[1:-2] + '0' + s[-2:]
+ elif self.exp_format:
+ # 2-digit exponent
+ if s[-3] == '0':
+ s = ' ' + s[:-3] + s[-2:]
+ elif strip_zeros:
+ z = s.rstrip('0')
+ s = z + ' '*(len(s)-len(z))
+ return s
+
+
+def _digits(x, precision, format):
+ s = format % x
+ z = s.rstrip('0')
+ return precision - len(s) + len(z)
+
+
+_MAXINT = sys.maxint
+_MININT = -sys.maxint-1
+class IntegerFormat(object):
+ def __init__(self, data):
+ try:
+ max_str_len = max(len(str(maximum.reduce(data, skipna=True))),
+ len(str(minimum.reduce(data, skipna=True))))
+ self.format = '%' + str(max_str_len) + 'd'
+ except TypeError, NotImplementedError:
+ # if reduce(data) fails, this instance will not be called, just
+ # instantiated in formatdict.
+ pass
+ except ValueError:
+ # this occurs when everything is NA
+ pass
+
+ def __call__(self, x):
+ if isna(x):
+ return str(x).replace('NA', _na_str, 1)
+ elif _MININT < x < _MAXINT:
+ return self.format % x
+ else:
+ return "%s" % x
+
+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):
+ self.precision = precision
+ self.sign = sign
+
+ def __call__(self, x):
+ if isna(x):
+ return str(x).replace('NA', _na_str, 1)
+ elif isnan(x):
+ if self.sign:
+ return '+' + _nan_str
+ else:
+ return ' ' + _nan_str
+ elif isinf(x):
+ if x > 0:
+ if self.sign:
+ return '+' + _inf_str
+ else:
+ return ' ' + _inf_str
+ else:
+ return '-' + _inf_str
+ elif x >= 0:
+ if self.sign:
+ return '+' + format_longfloat(x, self.precision)
+ else:
+ return ' ' + format_longfloat(x, self.precision)
+ else:
+ return format_longfloat(x, self.precision)
+
+
+class LongComplexFormat(object):
+ def __init__(self, precision):
+ self.real_format = LongFloatFormat(precision)
+ self.imag_format = LongFloatFormat(precision, sign=True)
+
+ def __call__(self, x):
+ if isna(x):
+ return str(x).replace('NA', _na_str, 1)
+ else:
+ r = self.real_format(x.real)
+ i = self.imag_format(x.imag)
+ return r + i + 'j'
+
+
+class ComplexFormat(object):
+ def __init__(self, x, precision, suppress_small):
+ self.real_format = FloatFormat(x.real, precision, suppress_small)
+ self.imag_format = FloatFormat(x.imag, precision, suppress_small,
+ sign=True)
+
+ def __call__(self, x):
+ if isna(x):
+ return str(x).replace('NA', _na_str, 1)
+ else:
+ r = self.real_format(x.real, strip_zeros=False)
+ i = self.imag_format(x.imag, strip_zeros=False)
+ if not self.imag_format.exp_format:
+ z = i.rstrip('0')
+ i = z + 'j' + ' '*(len(i)-len(z))
+ else:
+ i = i + 'j'
+ return r + i
+
+class DatetimeFormat(object):
+ def __init__(self, x, unit=None,
+ timezone=None, casting='same_kind'):
+ # Get the unit from the dtype
+ if unit is None:
+ if x.dtype.kind == 'M':
+ unit = datetime_data(x.dtype)[0]
+ else:
+ unit = 's'
+
+ # If timezone is default, make it 'local' or 'UTC' based on the unit
+ if timezone is None:
+ # Date units -> UTC, time units -> local
+ if unit in ('Y', 'M', 'W', 'D'):
+ self.timezone = 'UTC'
+ else:
+ self.timezone = 'local'
+ else:
+ self.timezone = timezone
+ self.unit = unit
+ self.casting = casting
+
+ def __call__(self, x):
+ if isna(x):
+ return str(x).replace('NA', _na_str, 1)
+ else:
+ return "'%s'" % datetime_as_string(x,
+ unit=self.unit,
+ timezone=self.timezone,
+ casting=self.casting)
+
+class TimedeltaFormat(object):
+ def __init__(self, data):
+ if data.dtype.kind == 'm':
+ v = data.view('i8')
+ max_str_len = max(len(str(maximum.reduce(v))),
+ len(str(minimum.reduce(v))))
+ self.format = '%' + str(max_str_len) + 'd'
+
+ def __call__(self, x):
+ if isna(x):
+ return str(x).replace('NA', _na_str, 1)
+ else:
+ return self.format % x.astype('i8')
+
diff --git a/lib_pypy/numpypy/core/numeric.py b/lib_pypy/numpypy/core/numeric.py
--- a/lib_pypy/numpypy/core/numeric.py
+++ b/lib_pypy/numpypy/core/numeric.py
@@ -1,5 +1,8 @@
-from _numpypy import array
+from _numpypy import array, ndarray, int_, float_ #, complex_# , longlong
+import sys
+import _numpypy as multiarray # ARGH
+from numpypy.core.arrayprint import array2string
def asanyarray(a, dtype=None, order=None, maskna=None, ownmaskna=False):
"""
@@ -60,3 +63,245 @@
"""
return array(a, dtype, copy=False, order=order, subok=True,
maskna=maskna, ownmaskna=ownmaskna)
+
+def base_repr(number, base=2, padding=0):
+ """
+ Return a string representation of a number in the given base system.
+
+ Parameters
+ ----------
+ number : int
+ The value to convert. Only positive values are handled.
+ base : int, optional
+ Convert `number` to the `base` number system. The valid range is 2-36,
+ the default value is 2.
+ padding : int, optional
+ Number of zeros padded on the left. Default is 0 (no padding).
+
+ Returns
+ -------
+ out : str
+ String representation of `number` in `base` system.
+
+ See Also
+ --------
+ binary_repr : Faster version of `base_repr` for base 2.
+
+ Examples
+ --------
+ >>> np.base_repr(5)
+ '101'
+ >>> np.base_repr(6, 5)
+ '11'
+ >>> np.base_repr(7, base=5, padding=3)
+ '00012'
+
+ >>> np.base_repr(10, base=16)
+ 'A'
+ >>> np.base_repr(32, base=16)
+ '20'
+
+ """
+ digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ if base > len(digits):
+ raise ValueError("Bases greater than 36 not handled in base_repr.")
+
+ num = abs(number)
+ res = []
+ while num:
+ res.append(digits[num % base])
+ num //= base
+ if padding:
+ res.append('0' * padding)
+ if number < 0:
+ res.append('-')
+ return ''.join(reversed(res or '0'))
+
+_typelessdata = [int_, float_]#, complex_]
+# XXX
+#if issubclass(intc, int):
+# _typelessdata.append(intc)
+
+#if issubclass(longlong, int):
+# _typelessdata.append(longlong)
+
+def array_repr(arr, max_line_width=None, precision=None, suppress_small=None):
+ """
+ Return the string representation of an array.
+
+ Parameters
+ ----------
+ arr : ndarray
+ Input array.
+ max_line_width : int, optional
+ The maximum number of columns the string should span. Newline
+ characters split the string appropriately after array elements.
+ precision : int, optional
+ Floating point precision. Default is the current printing precision
+ (usually 8), which can be altered using `set_printoptions`.
+ suppress_small : bool, optional
+ Represent very small numbers as zero, default is False. Very small
+ is defined by `precision`, if the precision is 8 then
+ numbers smaller than 5e-9 are represented as zero.
+
+ Returns
+ -------
+ string : str
+ The string representation of an array.
+
+ See Also
+ --------
+ array_str, array2string, set_printoptions
+
+ Examples
+ --------
+ >>> np.array_repr(np.array([1,2]))
+ 'array([1, 2])'
+ >>> np.array_repr(np.ma.array([0.]))
+ 'MaskedArray([ 0.])'
+ >>> np.array_repr(np.array([], np.int32))
+ 'array([], dtype=int32)'
+
+ >>> x = np.array([1e-6, 4e-7, 2, 3])
+ >>> np.array_repr(x, precision=6, suppress_small=True)
+ 'array([ 0.000001, 0. , 2. , 3. ])'
+
+ """
+ if arr.size > 0 or arr.shape==(0,):
+ lst = array2string(arr, max_line_width, precision, suppress_small,
+ ', ', "array(")
+ else: # show zero-length shape unless it is (0,)
+ lst = "[], shape=%s" % (repr(arr.shape),)
+
+ if arr.__class__ is not ndarray:
+ cName= arr.__class__.__name__
+ else:
+ cName = "array"
+
+ skipdtype = (arr.dtype.type in _typelessdata) and arr.size > 0
+
+ if arr.flags.maskna:
+ whichna = isna(arr)
+ # If nothing is NA, explicitly signal the NA-mask
+ if not any(whichna):
+ lst += ", maskna=True"
+ # If everything is NA, can't skip the dtype
+ if skipdtype and all(whichna):
+ skipdtype = False
+
+ if skipdtype:
+ return "%s(%s)" % (cName, lst)
+ else:
+ typename = arr.dtype.name
+ # Quote typename in the output if it is "complex".
+ if typename and not (typename[0].isalpha() and typename.isalnum()):
+ typename = "'%s'" % typename
+
+ lf = ''
+ if 0 or issubclass(arr.dtype.type, flexible):
+ if arr.dtype.names:
+ typename = "%s" % str(arr.dtype)
+ else:
+ typename = "'%s'" % str(arr.dtype)
+ lf = '\n'+' '*len("array(")
+ return cName + "(%s, %sdtype=%s)" % (lst, lf, typename)
+
+def array_str(a, max_line_width=None, precision=None, suppress_small=None):
+ """
+ Return a string representation of the data in an array.
+
+ The data in the array is returned as a single string. This function is
+ similar to `array_repr`, the difference being that `array_repr` also
+ returns information on the kind of array and its data type.
+
+ Parameters
+ ----------
+ a : ndarray
+ Input array.
+ max_line_width : int, optional
+ Inserts newlines if text is longer than `max_line_width`. The
+ default is, indirectly, 75.
+ precision : int, optional
+ Floating point precision. Default is the current printing precision
+ (usually 8), which can be altered using `set_printoptions`.
+ suppress_small : bool, optional
+ Represent numbers "very close" to zero as zero; default is False.
+ Very close is defined by precision: if the precision is 8, e.g.,
+ numbers smaller (in absolute value) than 5e-9 are represented as
+ zero.
+
+ See Also
+ --------
+ array2string, array_repr, set_printoptions
+
+ Examples
+ --------
+ >>> np.array_str(np.arange(3))
+ '[0 1 2]'
+
+ """
+ return array2string(a, max_line_width, precision, suppress_small, ' ', "", str)
+
+def set_string_function(f, repr=True):
+ """
+ Set a Python function to be used when pretty printing arrays.
+
+ Parameters
+ ----------
+ f : function or None
+ Function to be used to pretty print arrays. The function should expect
+ a single array argument and return a string of the representation of
+ the array. If None, the function is reset to the default NumPy function
+ to print arrays.
+ repr : bool, optional
+ If True (default), the function for pretty printing (``__repr__``)
+ is set, if False the function that returns the default string
+ representation (``__str__``) is set.
+
+ See Also
+ --------
+ set_printoptions, get_printoptions
+
+ Examples
+ --------
+ >>> def pprint(arr):
+ ... return 'HA! - What are you going to do now?'
+ ...
+ >>> np.set_string_function(pprint)
+ >>> a = np.arange(10)
+ >>> a
+ HA! - What are you going to do now?
+ >>> print a
+ [0 1 2 3 4 5 6 7 8 9]
+
+ We can reset the function to the default:
+
+ >>> np.set_string_function(None)
+ >>> a
+ array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+
+ `repr` affects either pretty printing or normal string representation.
+ Note that ``__repr__`` is still affected by setting ``__str__``
+ because the width of each array element in the returned string becomes
+ equal to the length of the result of ``__str__()``.
+
+ >>> x = np.arange(4)
+ >>> np.set_string_function(lambda x:'random', repr=False)
+ >>> x.__str__()
+ 'random'
+ >>> x.__repr__()
+ 'array([ 0, 1, 2, 3])'
+
+ """
+ if f is None:
+ if repr:
+ return multiarray.set_string_function(array_repr, 1)
+ else:
+ return multiarray.set_string_function(array_str, 0)
+ else:
+ return multiarray.set_string_function(f, repr)
+
+set_string_function(array_str, 0)
+set_string_function(array_repr, 1)
+
+little_endian = (sys.byteorder == 'little')
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -28,6 +28,8 @@
'fromstring': 'interp_support.fromstring',
'flatiter': 'interp_numarray.W_FlatIterator',
+ 'set_string_function': 'appbridge.set_string_function',
+
'count_reduce_items': 'interp_numarray.count_reduce_items',
'True_': 'types.Bool.True',
diff --git a/pypy/module/micronumpy/appbridge.py b/pypy/module/micronumpy/appbridge.py
--- a/pypy/module/micronumpy/appbridge.py
+++ b/pypy/module/micronumpy/appbridge.py
@@ -5,6 +5,8 @@
w__var = None
w__std = None
w_module = None
+ w_array_repr = None
+ w_array_str = None
def __init__(self, space):
self.w_import = space.appexec([], """():
@@ -24,5 +26,12 @@
setattr(self, 'w_' + name, w_meth)
return space.call_function(w_meth, *args)
+def set_string_function(space, w_f, w_repr):
+ cache = get_appbridge_cache(space)
+ if space.is_true(w_repr):
+ cache.w_array_repr = w_f
+ else:
+ cache.w_array_str = w_f
+
def get_appbridge_cache(space):
return space.fromcache(AppBridgeCache)
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -303,6 +303,12 @@
return space.wrap(res.build())
def descr_str(self, space):
+ cache = get_appbridge_cache(space)
+ if cache.w_array_str is None:
+ raise OperationError(space.w_RuntimeError, space.wrap(
+ "str function not set"))
+ return space.call_function(cache.w_array_str, self)
+
ret = StringBuilder()
concrete = self.get_concrete_or_scalar()
concrete.to_str(space, 0, ret, ' ')
diff --git a/pypy/module/test_lib_pypy/numpypy/core/test_numeric.py b/pypy/module/test_lib_pypy/numpypy/core/test_numeric.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/test_lib_pypy/numpypy/core/test_numeric.py
@@ -0,0 +1,21 @@
+
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestBaseRepr(BaseNumpyAppTest):
+ def test_base3(self):
+ from numpypy import base_repr
+ assert base_repr(3**5, 3) == '100000'
+
+ def test_positive(self):
+ from numpypy import base_repr
+ assert base_repr(12, 10) == '12'
+ assert base_repr(12, 10, 4) == '000012'
+ assert base_repr(12, 4) == '30'
+ assert base_repr(3731624803700888, 36) == '10QR0ROFCEW'
+
+ def test_negative(self):
+ from numpypy import base_repr
+ assert base_repr(-12, 10) == '-12'
+ assert base_repr(-12, 10, 4) == '-000012'
+ assert base_repr(-12, 4) == '-30'
More information about the pypy-commit
mailing list