diff --git a/docs/tutorial.rst b/docs/tutorial.rst
index 8499ea4..e92b622 100644
--- a/docs/tutorial.rst
+++ b/docs/tutorial.rst
@@ -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)
diff --git a/pint/formatting.py b/pint/formatting.py
index 2a70710..8d7f8e6 100644
--- a/pint/formatting.py
+++ b/pint/formatting.py
@@ -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:
diff --git a/pint/measurement.py b/pint/measurement.py
index e82591d..d0d239f 100644
--- a/pint/measurement.py
+++ b/pint/measurement.py
@@ -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']
diff --git a/pint/quantity.py b/pint/quantity.py
index b0fade5..07dcdd5 100644
--- a/pint/quantity.py
+++ b/pint/quantity.py
@@ -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()
diff --git a/pint/testsuite/test_measurement.py b/pint/testsuite/test_measurement.py
index bf1487c..b7f2a50 100644
--- a/pint/testsuite/test_measurement.py
+++ b/pint/testsuite/test_measurement.py
@@ -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 ± 0.10) second2')
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 ± 0.1) second2')
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 ± 0.0100) second2')
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()
diff --git a/pint/testsuite/test_quantity.py b/pint/testsuite/test_quantity.py
index d701364..3ed98a2 100644
--- a/pint/testsuite/test_quantity.py
+++ b/pint/testsuite/test_quantity.py
@@ -104,6 +104,7 @@ class TestQuantity(QuantityTestCase):
('{0:P~}', '4.12345678 kg·m²/s'),
('{0:H~}', '4.12345678 kg m2/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)
diff --git a/pint/testsuite/test_unit.py b/pint/testsuite/test_unit.py
index edbb2fa..d170c90 100644
--- a/pint/testsuite/test_unit.py
+++ b/pint/testsuite/test_unit.py
@@ -32,6 +32,7 @@ class TestUnit(QuantityTestCase):
('{0:P}', 'kilogram·meter²/second'),
('{0:H}', 'kilogram meter2/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'),
diff --git a/pint/unit.py b/pint/unit.py
index bbf9dfb..98aaa0f 100644
--- a/pint/unit.py
+++ b/pint/unit.py
@@ -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:
diff --git a/pint/util.py b/pint/util.py
index 31e8206..d0bd14f 100644
--- a/pint/util.py
+++ b/pint/util.py
@@ -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__)