Merge branch 'master' of git://github.com/CD3/pint into CD3-master

This commit is contained in:
Hernan Grecco
2015-12-22 00:04:01 -03:00
9 changed files with 91 additions and 3 deletions

View File

@@ -248,6 +248,15 @@ If you want to use abbreviated unit names, prefix the specification with `~`:
The same is true for latex (`L`) and HTML (`H`) specs.
Pint also supports the LaTeX siunitx package:
.. doctest::
>>> accel = 1.3 * ureg['meter/second**2']
>>> # siunitx Latex print
>>> print('The siunitx representation is {:Lx}'.format(accel))
The siunitx representation is \SI[]{1.3}{\meter\per\second\squared}
Finally, you can specify a default format specification:
>>> 'The acceleration is {}'.format(accel)

View File

@@ -190,6 +190,43 @@ def format_unit(unit, spec):
return result
def siunitx_format_unit(units):
'''Returns LaTeX code for the unit that can be put into an siunitx command.'''
# NOTE: unit registry is required to identify unit prefixes.
registry = units._REGISTRY
def _tothe(power):
if power == 1:
return ''
elif power == 2:
return r'\squared'
elif power == 3:
return r'\cubed'
else:
return r'\tothe{%d}' % (power)
l = []
# loop through all units in the container
for unit, power in sorted(units._units.items()):
# remove unit prefix if it exists
# siunit supports \prefix commands
prefix = None
for p in registry._prefixes.values():
p = str(p)
if len(p) > 0 and unit.find(p) == 0:
prefix = p
unit = unit.replace( prefix, '', 1 )
if power < 0:
l.append(r'\per')
if not prefix is None:
l.append(r'\{0}'.format(prefix))
l.append(r'\{0}'.format(unit))
l.append(r'{0}'.format(_tothe(abs(power))))
return ''.join(l)
def remove_custom_flags(spec):
for flag in _KNOWN_TYPES:
if flag:

View File

@@ -10,7 +10,7 @@
from __future__ import division, unicode_literals, print_function, absolute_import
from .compat import ufloat
from .formatting import _FORMATS
from .formatting import _FORMATS, siunitx_format_unit
MISSING = object()
@@ -65,6 +65,22 @@ class _Measurement(object):
return '{0}'.format(self)
def __format__(self, spec):
# special cases
if 'Lx' in spec: # the LaTeX siunitx code
# the uncertainties module supports formatting
# numbers in value(unc) notation (i.e. 1.23(45) instead of 1.23 +/- 0.45),
# which siunitx actually accepts as input. we just need to give the 'S'
# formatting option for the uncertainties module.
spec = spec.replace('Lx','S')
# todo: add support for extracting options
opts = 'separate-uncertainty=true'
mstr = format( self.magnitude, spec )
ustr = siunitx_format_unit(self.units)
ret = r'\SI[%s]{%s}{%s}'%( opts, mstr, ustr )
return ret
# standard cases
if 'L' in spec:
newpm = pm = r' \pm '
pars = _FORMATS['L']['parentheses_fmt']

View File

@@ -15,7 +15,7 @@ import operator
import functools
import bisect
from .formatting import remove_custom_flags
from .formatting import remove_custom_flags, siunitx_format_unit
from .errors import (DimensionalityError, OffsetUnitCalculusError,
UndefinedUnitError)
from .definitions import UnitDefinition
@@ -118,6 +118,18 @@ class _Quantity(SharedRegistryObject):
def __format__(self, spec):
spec = spec or self.default_format
# special cases
if 'Lx' in spec: # the LaTeX siunitx code
spec = spec.replace('Lx','')
# todo: add support for extracting options
opts = ''
mstr = format(self.magnitude,spec)
ustr = siunitx_format_unit(self.units)
ret = r'\SI[%s]{%s}{%s}'%( opts, mstr, ustr )
return ret
# standard cases
if '#' in spec:
spec = spec.replace('#', '')
obj = self.to_compact()

View File

@@ -51,11 +51,13 @@ class TestMeasurement(QuantityTestCase):
self.assertEqual('{0:L}'.format(m), r'\left(4.00 \pm 0.10\right) second^{2}')
self.assertEqual('{0:H}'.format(m), '(4.00 &plusmn; 0.10) second<sup>2</sup>')
self.assertEqual('{0:C}'.format(m), '(4.00+/-0.10) second**2')
self.assertEqual('{0:Lx}'.format(m), r'\SI[separate-uncertainty=true]{4.00(10)}{\second\squared}')
self.assertEqual('{0:.1f}'.format(m), '(4.0 +/- 0.1) second ** 2')
self.assertEqual('{0:.1fP}'.format(m), '(4.0 ± 0.1) second²')
self.assertEqual('{0:.1fL}'.format(m), r'\left(4.0 \pm 0.1\right) second^{2}')
self.assertEqual('{0:.1fH}'.format(m), '(4.0 &plusmn; 0.1) second<sup>2</sup>')
self.assertEqual('{0:.1fC}'.format(m), '(4.0+/-0.1) second**2')
self.assertEqual('{0:.1fLx}'.format(m), '\SI[separate-uncertainty=true]{4.0(1)}{\second\squared}')
def test_format_paru(self):
v, u = self.Q_(0.20, 's ** 2'), self.Q_(0.01, 's ** 2')
@@ -75,6 +77,8 @@ class TestMeasurement(QuantityTestCase):
self.assertEqual('{0:.3uL}'.format(m), r'\left(0.2000 \pm 0.0100\right) second^{2}')
self.assertEqual('{0:.3uH}'.format(m), '(0.2000 &plusmn; 0.0100) second<sup>2</sup>')
self.assertEqual('{0:.3uC}'.format(m), '(0.2000+/-0.0100) second**2')
self.assertEqual('{0:.3uLx}'.format(m), '\SI[separate-uncertainty=true]{0.2000(100)}{\second\squared}')
self.assertEqual('{0:.1uLx}'.format(m), '\SI[separate-uncertainty=true]{0.20(1)}{\second\squared}')
def test_format_percu(self):
self.test_format_perce()

View File

@@ -104,6 +104,7 @@ class TestQuantity(QuantityTestCase):
('{0:P~}', '4.12345678 kg·m²/s'),
('{0:H~}', '4.12345678 kg m<sup>2</sup>/s'),
('{0:C~}', '4.12345678 kg*m**2/s'),
('{0:Lx}', r'\SI[]{4.12345678}{\kilo\gram\meter\squared\per\second}'),
):
self.assertEqual(spec.format(x), result)

View File

@@ -32,6 +32,7 @@ class TestUnit(QuantityTestCase):
('{0:P}', 'kilogram·meter²/second'),
('{0:H}', 'kilogram meter<sup>2</sup>/second'),
('{0:C}', 'kilogram*meter**2/second'),
('{0:Lx}', r'\si[]{\kilo\gram\meter\squared\per\second}'),
('{0:~}', 'kg * m ** 2 / s'),
('{0:L~}', r'\frac{kg \cdot m^{2}}{s}'),
('{0:P~}', 'kg·m²/s'),

View File

@@ -30,6 +30,7 @@ from .util import (logger, pi_theorem, solve_dependencies, ParserHelper,
find_shortest_path, UnitsContainer, _is_dim,
SharedRegistryObject, to_units_container)
from .compat import tokenizer, string_types, NUMERIC_TYPES, long_type, zip_longest
from .formatting import siunitx_format_unit
from .definitions import (Definition, UnitDefinition, PrefixDefinition,
DimensionDefinition)
from .converters import ScaleConverter
@@ -99,6 +100,13 @@ class _Unit(SharedRegistryObject):
def __format__(self, spec):
spec = spec or self.default_format
# special cases
if 'Lx' in spec: # the LaTeX siunitx code
opts = ''
ustr = siunitx_format_unit(self)
ret = r'\si[%s]{%s}'%( opts, ustr )
return ret
if '~' in spec:
if self.dimensionless:

View File

@@ -22,7 +22,7 @@ from token import STRING, NAME, OP, NUMBER
from tokenize import untokenize
from .compat import string_types, tokenizer, lru_cache, NullHandler, maketrans, NUMERIC_TYPES
from .formatting import format_unit
from .formatting import format_unit,siunitx_format_unit
from .pint_eval import build_eval_tree
logger = logging.getLogger(__name__)