Skip to content

Commit

Permalink
add float_precision trait to PlainTextFormatter
Browse files Browse the repository at this point in the history
* 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
minrk committed Feb 22, 2011
1 parent 0f285a7 commit a41b73b
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 37 deletions.
57 changes: 55 additions & 2 deletions IPython/core/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


#-----------------------------------------------------------------------------
Expand Down Expand Up @@ -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()
Expand Down
37 changes: 6 additions & 31 deletions IPython/core/magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
50 changes: 47 additions & 3 deletions IPython/core/tests/test_formatters.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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')
Expand All @@ -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)


21 changes: 20 additions & 1 deletion IPython/core/tests/test_magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.