Permalink
Browse files

add `float_precision` trait to PlainTextFormatter

* moved content of %precision into _float_precision_changed
* %precision is now 2 lines that simply sets PTF.float_precision
* added doctests for %precision
* added tests for PTF.float_precision
  • Loading branch information...
1 parent 0f285a7 commit a41b73bf0851a1970682f224d4129ed62331b35e @minrk committed Feb 22, 2011
Showing with 128 additions and 37 deletions.
  1. +55 −2 IPython/core/formatters.py
  2. +6 −31 IPython/core/magic.py
  3. +47 −3 IPython/core/tests/test_formatters.py
  4. +20 −1 IPython/core/tests/test_magic.py
View
@@ -20,14 +20,15 @@
#-----------------------------------------------------------------------------
# Stdlib imports
+import sys
import abc
# We must use StringIO, as cStringIO doesn't handle unicode properly.
from StringIO import StringIO
# Our own imports
from IPython.config.configurable import Configurable
from IPython.external import pretty
-from IPython.utils.traitlets import Bool, Dict, Int, Str
+from IPython.utils.traitlets import Bool, Dict, Int, Str, CStr
#-----------------------------------------------------------------------------
@@ -352,13 +353,65 @@ def dtype_pprinter(obj, p, cycle):
# The newline character.
newline = Str('\n', config=True)
+
+ # format-string for pprinting floats
+ float_format = Str('%r')
+ # setter for float precision, either int or direct format-string
+ float_precision = CStr('', config=True)
+
+ def _float_precision_changed(self, name, old, new):
+ """float_precision changed, set float_format accordingly.
+
+ float_precision can be set by int or str.
+ This will set float_format, after interpreting input.
+ If numpy has been imported, numpy print precision will also be set.
+
+ integer `n` sets format to '%.nf', otherwise, format set directly.
+
+ An empty string returns to defaults (repr for float, 8 for numpy).
+
+ This parameter can be set via the '%precision' magic.
+ """
+
+ if '%' in new:
+ # got explicit format string
+ fmt = new
+ try:
+ fmt%3.14159
+ except Exception:
+ raise ValueError("Precision must be int or format string, not %r"%new)
+ elif new:
+ # otherwise, should be an int
+ try:
+ i = int(new)
+ assert i >= 0
+ except ValueError:
+ raise ValueError("Precision must be int or format string, not %r"%new)
+ except AssertionError:
+ raise ValueError("int precision must be non-negative, not %r"%i)
+
+ fmt = '%%.%if'%i
+ if 'numpy' in sys.modules:
+ # set numpy precision if it has been imported
+ import numpy
+ numpy.set_printoptions(precision=i)
+ else:
+ # default back to repr
+ fmt = '%r'
+ if 'numpy' in sys.modules:
+ import numpy
+ # numpy default is 8
+ numpy.set_printoptions(precision=8)
+ self.float_format = fmt
# Use the default pretty printers from IPython.external.pretty.
def _singleton_printers_default(self):
return pretty._singleton_pprinters.copy()
def _type_printers_default(self):
- return pretty._type_pprinters.copy()
+ d = pretty._type_pprinters.copy()
+ d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
+ return d
def _deferred_printers_default(self):
return pretty._deferred_type_pprinters.copy()
View
@@ -3478,58 +3478,33 @@ def magic_precision(self, s=''):
In [1]: from math import pi
In [2]: %precision 3
+ Out[2]: '%.3f'
In [3]: pi
Out[3]: 3.142
In [4]: %precision %i
+ Out[4]: '%i'
In [5]: pi
Out[5]: 3
In [6]: %precision %e
+ Out[6]: '%e'
In [7]: pi**10
Out[7]: 9.364805e+04
In [8]: %precision
+ Out[8]: '%r'
In [9]: pi**10
Out[9]: 93648.047476082982
"""
- if '%' in s:
- # got explicit format string
- fmt = s
- try:
- fmt%3.14159
- except Exception:
- raise ValueError("Precision must be int or format string, not %r"%s)
- elif s:
- # otherwise, should be an int
- try:
- i = int(s)
- assert i >= 0
- except (ValueError, AssertionError):
- raise ValueError("Precision must be non-negative int or format string, not %r"%s)
-
- fmt = '%%.%if'%i
- if 'numpy' in sys.modules:
- import numpy
- numpy.set_printoptions(precision=i)
- else:
- # default back to repr
- fmt = '%r'
- if 'numpy' in sys.modules:
- import numpy
- # numpy default is 8
- numpy.set_printoptions(precision=8)
-
- def _pretty_float(obj,p,cycle):
- p.text(fmt%obj)
-
ptformatter = self.shell.display_formatter.formatters['text/plain']
- ptformatter.for_type(float, _pretty_float)
+ ptformatter.float_precision = s
+ return ptformatter.float_format
# end Magic
@@ -1,9 +1,15 @@
"""Tests for the Formatters.
"""
+from math import pi
+
+try:
+ import numpy
+except:
+ numpy = None
import nose.tools as nt
-from IPython.core.formatters import FormatterABC, DefaultFormatter
+from IPython.core.formatters import FormatterABC, PlainTextFormatter
class A(object):
def __repr__(self):
@@ -17,7 +23,7 @@ def foo_printer(obj, pp, cycle):
pp.text('foo')
def test_pretty():
- f = DefaultFormatter()
+ f = PlainTextFormatter()
f.for_type(A, foo_printer)
nt.assert_equals(f(A()), 'foo')
nt.assert_equals(f(B()), 'foo')
@@ -26,5 +32,43 @@ def test_pretty():
nt.assert_equals(f(B()), 'B()')
def test_deferred():
- f = DefaultFormatter()
+ f = PlainTextFormatter()
+
+def test_precision():
+ """test various values for float_precision."""
+ f = PlainTextFormatter()
+ nt.assert_equals(f(pi), repr(pi))
+ f.float_precision = 0
+ if numpy:
+ po = numpy.get_printoptions()
+ nt.assert_equals(po['precision'], 0)
+ nt.assert_equals(f(pi), '3')
+ f.float_precision = 2
+ if numpy:
+ po = numpy.get_printoptions()
+ nt.assert_equals(po['precision'], 2)
+ nt.assert_equals(f(pi), '3.14')
+ f.float_precision = '%g'
+ if numpy:
+ po = numpy.get_printoptions()
+ nt.assert_equals(po['precision'], 2)
+ nt.assert_equals(f(pi), '3.14159')
+ f.float_precision = '%e'
+ nt.assert_equals(f(pi), '3.141593e+00')
+ f.float_precision = ''
+ if numpy:
+ po = numpy.get_printoptions()
+ nt.assert_equals(po['precision'], 8)
+ nt.assert_equals(f(pi), repr(pi))
+
+def test_bad_precision():
+ """test various invalid values for float_precision."""
+ f = PlainTextFormatter()
+ def set_fp(p):
+ f.float_precision=p
+ nt.assert_raises(ValueError, set_fp, '%')
+ nt.assert_raises(ValueError, set_fp, '%.3f%i')
+ nt.assert_raises(ValueError, set_fp, 'foo')
+ nt.assert_raises(ValueError, set_fp, -1)
+
@@ -386,4 +386,23 @@ def doctest_who():
In [7]: %who_ls
Out[7]: ['alpha', 'beta']
- """
+ """
+
+def doctest_precision():
+ """doctest for %precision
+
+ In [1]: f = get_ipython().shell.display_formatter.formatters['text/plain']
+
+ In [2]: %precision 5
+ Out[2]: '%.5f'
+
+ In [3]: f.float_format
+ Out[3]: '%.5f'
+
+ In [4]: %precision %e
+ Out[4]: '%e'
+
+ In [5]: f(3.1415927)
+ Out[5]: '3.141593e+00'
+ """
+

0 comments on commit a41b73b

Please sign in to comment.