From d931ffa4d54716d15a85d24a89520e6da0f841cf Mon Sep 17 00:00:00 2001 From: Will Stott Date: Tue, 14 Jan 2020 14:41:46 +0000 Subject: minor typo fix --- pint/default_en.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pint/default_en.txt b/pint/default_en.txt index 6d5fe6a..8bd4133 100644 --- a/pint/default_en.txt +++ b/pint/default_en.txt @@ -36,7 +36,7 @@ # [density] = [mass] / [volume] # # Note that primary dimensions don't need to be declared; they can be -# defined or the first time in a unit definition. +# defined for the first time in a unit definition. # E.g. see below `meter = [length]` # # -- cgit v1.2.1 From 547bc938aa36e32443c65ff49914466974452a2d Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 02:10:32 -0600 Subject: Don't raise error if key starts with _[digit] --- pint/util.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pint/util.py b/pint/util.py index aff507b..95badf1 100644 --- a/pint/util.py +++ b/pint/util.py @@ -876,7 +876,11 @@ def getattr_maybe_raise(self, item): """ # Double-underscore attributes are tricky to detect because they are # automatically prefixed with the class name - which may be a subclass of self - if item.startswith("_") or item.endswith("__"): + if ( + item.startswith("_") + and not item.lstrip('_')[0].isdigit() + or item.endswith("__") + ): raise AttributeError("%r object has no attribute %r" % (self, item)) -- cgit v1.2.1 From f6ffaf4eb5aa16108b0bc8c061820c1942776975 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 02:17:42 -0600 Subject: Update docstring for getattr_maybe_raise --- pint/util.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pint/util.py b/pint/util.py index 95badf1..d3c06ac 100644 --- a/pint/util.py +++ b/pint/util.py @@ -862,12 +862,16 @@ def infer_base_unit(q): def getattr_maybe_raise(self, item): - """Helper function to invoke at the beginning of all overridden ``__getattr__`` - methods. Raise AttributeError if the user tries to ask for a _ or __ attribute. + """Helper function invoked at start of all overridden ``__getattr__``. + + Raise AttributeError if the user tries to ask for a _ or __ attribute, + *unless* it is immediately followed by a number, to enable units + encompassing constants, such as ``L / _100km``. Parameters ---------- - item : + item : string + Item to be found. Returns -- cgit v1.2.1 From 774fc6f4ffe97837796358322cdfaa9d28ba4036 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 02:34:23 -0600 Subject: Add test for no attribute error in _100km --- pint/testsuite/test_issues.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py index 3036022..79c9d6b 100644 --- a/pint/testsuite/test_issues.py +++ b/pint/testsuite/test_issues.py @@ -697,6 +697,14 @@ class TestIssues(QuantityTestCase): with self.assertRaises(DimensionalityError): q.to("joule") + def test_issue507(self): + # leading underscore in unit works with numbers + u.define('_100km = 100 * kilometer') + battery_ec = 16 * u.kWh / u._100km + # ... but not with text + u.define('_home = 4700 * kWh / year') + with self.assertRaises(AttributeError): + home_elec_power = 1 * u._home try: -- cgit v1.2.1 From 2b10cbd4972f689555d28af29e1ce862e9e5bb44 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 02:35:58 -0600 Subject: Format strings according to black --- pint/testsuite/test_issues.py | 5 +++-- pint/util.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py index 79c9d6b..0f9da35 100644 --- a/pint/testsuite/test_issues.py +++ b/pint/testsuite/test_issues.py @@ -699,13 +699,14 @@ class TestIssues(QuantityTestCase): def test_issue507(self): # leading underscore in unit works with numbers - u.define('_100km = 100 * kilometer') + u.define("_100km = 100 * kilometer") battery_ec = 16 * u.kWh / u._100km # ... but not with text - u.define('_home = 4700 * kWh / year') + u.define("_home = 4700 * kWh / year") with self.assertRaises(AttributeError): home_elec_power = 1 * u._home + try: @pytest.mark.skipif(np is None, reason="NumPy is not available") diff --git a/pint/util.py b/pint/util.py index d3c06ac..55ed7e2 100644 --- a/pint/util.py +++ b/pint/util.py @@ -882,7 +882,7 @@ def getattr_maybe_raise(self, item): # automatically prefixed with the class name - which may be a subclass of self if ( item.startswith("_") - and not item.lstrip('_')[0].isdigit() + and not item.lstrip("_")[0].isdigit() or item.endswith("__") ): raise AttributeError("%r object has no attribute %r" % (self, item)) -- cgit v1.2.1 From f912b9375006154eeffa929333a2d0a8052a2ca8 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 02:45:47 -0600 Subject: Add example to documentation --- docs/defining.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/defining.rst b/docs/defining.rst index 7aba5bb..152893a 100644 --- a/docs/defining.rst +++ b/docs/defining.rst @@ -138,3 +138,17 @@ Same for aliases and derived dimensions: .. warning:: Units, prefixes, aliases and dimensions added programmatically are forgotten when the program ends. + + +Units with constants +-------------------- + +Some units, such as ``L/100km``, contain constants. These can be defined with a +leading underscore: + +.. doctest:: + + >>> ureg.define('_100km = 100 * kilometer') + >>> ureg.define('mpg = 1 * mile / gallon') + >>> fuel_ec_europe = 5 * ureg.L / ureg._100km + >>> fuel_ec_us = (1 / fuel_ec_europe).to(ureg.mpg) -- cgit v1.2.1 From 275d23908fa0d3289f3e6e4cc97534db4f1d8f64 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 02:47:27 -0600 Subject: Add entry to CHANGES file --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 6fdb38d..6c645b9 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,8 @@ Pint Changelog - Added additional NumPy function implementations (allclose, intersect1d) (Issue #979, Thanks Jon Thielen) +- Allow constants in units by using a leading underscore (Issue #989, Thanks + Juan Nunez-Iglesias) 0.10.1 (2020-01-07) ------------------- -- cgit v1.2.1 From d0d8674286fd54ac40d1485d899fc62868b565b2 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 21:58:20 -0600 Subject: Fix incorrect use of u instead of ureg in tests --- pint/testsuite/test_issues.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py index 0f9da35..29b7771 100644 --- a/pint/testsuite/test_issues.py +++ b/pint/testsuite/test_issues.py @@ -699,12 +699,12 @@ class TestIssues(QuantityTestCase): def test_issue507(self): # leading underscore in unit works with numbers - u.define("_100km = 100 * kilometer") - battery_ec = 16 * u.kWh / u._100km + ureg.define("_100km = 100 * kilometer") + battery_ec = 16 * ureg.kWh / ureg._100km # ... but not with text - u.define("_home = 4700 * kWh / year") + ureg.define("_home = 4700 * kWh / year") with self.assertRaises(AttributeError): - home_elec_power = 1 * u._home + home_elec_power = 1 * ureg._home try: -- cgit v1.2.1 From f28923e64e494948261735918da9d84c49f49bd8 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 22:03:09 -0600 Subject: Check for attributes containing only '_' --- pint/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pint/util.py b/pint/util.py index 55ed7e2..c314583 100644 --- a/pint/util.py +++ b/pint/util.py @@ -880,10 +880,10 @@ def getattr_maybe_raise(self, item): """ # Double-underscore attributes are tricky to detect because they are # automatically prefixed with the class name - which may be a subclass of self - if ( + if item.endswith("__") or ( item.startswith("_") + and len(item.lstrip("_")) > 1 and not item.lstrip("_")[0].isdigit() - or item.endswith("__") ): raise AttributeError("%r object has no attribute %r" % (self, item)) -- cgit v1.2.1 From e40f2eb31af985b865ca5e464210fbaee38fdadb Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 22:09:08 -0600 Subject: Add test for attribute _ and fix logic ;) --- pint/testsuite/test_issues.py | 4 ++++ pint/util.py | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py index 29b7771..4514989 100644 --- a/pint/testsuite/test_issues.py +++ b/pint/testsuite/test_issues.py @@ -705,6 +705,10 @@ class TestIssues(QuantityTestCase): ureg.define("_home = 4700 * kWh / year") with self.assertRaises(AttributeError): home_elec_power = 1 * ureg._home + # ... or with *only* underscores + ureg.define("_ = 45 * km") + with self.assertRaises(AttributeError): + one_blank = 1 * ureg._ try: diff --git a/pint/util.py b/pint/util.py index c314583..71078d3 100644 --- a/pint/util.py +++ b/pint/util.py @@ -880,10 +880,10 @@ def getattr_maybe_raise(self, item): """ # Double-underscore attributes are tricky to detect because they are # automatically prefixed with the class name - which may be a subclass of self - if item.endswith("__") or ( - item.startswith("_") - and len(item.lstrip("_")) > 1 - and not item.lstrip("_")[0].isdigit() + if ( + item.endswith("__") + or len(item.lstrip("_")) == 0 + or (item.startswith("_") and not item.lstrip("_")[0].isdigit()) ): raise AttributeError("%r object has no attribute %r" % (self, item)) -- cgit v1.2.1 From 9b022e29daf8e87b97d4d3626e88992e84658038 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 15 Jan 2020 23:24:29 -0600 Subject: Ignore unassigned variables in flake8 in test suite --- pint/testsuite/test_issues.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py index 4514989..cc04e9f 100644 --- a/pint/testsuite/test_issues.py +++ b/pint/testsuite/test_issues.py @@ -700,15 +700,15 @@ class TestIssues(QuantityTestCase): def test_issue507(self): # leading underscore in unit works with numbers ureg.define("_100km = 100 * kilometer") - battery_ec = 16 * ureg.kWh / ureg._100km + battery_ec = 16 * ureg.kWh / ureg._100km # noqa: F841 # ... but not with text ureg.define("_home = 4700 * kWh / year") with self.assertRaises(AttributeError): - home_elec_power = 1 * ureg._home + home_elec_power = 1 * ureg._home # noqa: F841 # ... or with *only* underscores ureg.define("_ = 45 * km") with self.assertRaises(AttributeError): - one_blank = 1 * ureg._ + one_blank = 1 * ureg._ # noqa: F841 try: -- cgit v1.2.1 From 7df09524bf16fdb8a215ad10c38627e5221de146 Mon Sep 17 00:00:00 2001 From: Keewis Date: Fri, 17 Jan 2020 18:34:12 +0100 Subject: import the code from the issue --- pint/quantity.py | 18 ++++++++++++++++++ pint/registry.py | 11 +++++++++++ pint/unit.py | 19 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/pint/quantity.py b/pint/quantity.py index 09f7aed..64bae6f 100644 --- a/pint/quantity.py +++ b/pint/quantity.py @@ -504,6 +504,24 @@ class Quantity(PrettyIPython, SharedRegistryObject): return self._REGISTRY.get_compatible_units(self._units) + def is_compatible_with(self, other, *contexts, **ctx_kwargs): + if contexts: + try: + self.to(other, *contexts, **ctx_kwargs) + return True + except DimensionalityError: + return False + + if isinstance(other, (self._REGISTRY.Quantity, self._REGISTRY.Unit)): + return self.dimensionality == other.dimensionality + + if isinstance(other, str): + return ( + self.dimensionality == self._REGISTRY.parse_units(other).dimensionality + ) + + return self.dimensionless + def _convert_magnitude_not_inplace(self, other, *contexts, **ctx_kwargs): if contexts: with self._REGISTRY.context(*contexts, **ctx_kwargs): diff --git a/pint/registry.py b/pint/registry.py index 4ff9790..755de87 100644 --- a/pint/registry.py +++ b/pint/registry.py @@ -854,6 +854,17 @@ class BaseRegistry(metaclass=RegistryMeta): src_dim = self._get_dimensionality(input_units) return self._cache.dimensional_equivalents[src_dim] + def is_compatible_with(self, obj1, obj2, *contexts, **ctx_kwargs): + if isinstance(obj1, (self.Quantity, self.Unit)): + return obj1.is_compatible_with(obj2, *contexts, **ctx_kwargs) + + if isinstance(obj1, str): + return self.parse_expression(obj1).is_compatible_with( + obj2, *contexts, **ctx_kwargs + ) + + return not isinstance(obj2, (self.Quantity, self.Unit)) + def convert(self, value, src, dst, inplace=False): """Convert value from some source to destination units. diff --git a/pint/unit.py b/pint/unit.py index 14bf19b..505f975 100644 --- a/pint/unit.py +++ b/pint/unit.py @@ -15,6 +15,7 @@ from numbers import Number from .compat import NUMERIC_TYPES, is_upcast_type from .definitions import UnitDefinition +from .errors import DimensionalityError from .formatting import siunitx_format_unit from .util import PrettyIPython, SharedRegistryObject, UnitsContainer @@ -143,6 +144,24 @@ class Unit(PrettyIPython, SharedRegistryObject): return self._REGISTRY.get_compatible_units(self) + def is_compatible_with(self, other, *contexts, **ctx_kwargs): + if contexts: + try: + (1 * self).to(other, *contexts, **ctx_kwargs) + return True + except DimensionalityError: + return False + + if isinstance(other, (self._REGISTRY.Quantity, self._REGISTRY.Unit)): + return self.dimensionality == other.dimensionality + + if isinstance(other, str): + return ( + self.dimensionality == self._REGISTRY.parse_units(other).dimensionality + ) + + return self.dimensionless + def __mul__(self, other): if self._check(other): if isinstance(other, self.__class__): -- cgit v1.2.1 From 73898ca52acc5ba5ea96963a70a1dcd67967b6a8 Mon Sep 17 00:00:00 2001 From: Keewis Date: Fri, 17 Jan 2020 22:39:13 +0100 Subject: add docstrings --- pint/quantity.py | 16 ++++++++++++++++ pint/registry.py | 16 ++++++++++++++++ pint/unit.py | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/pint/quantity.py b/pint/quantity.py index 64bae6f..8a3494f 100644 --- a/pint/quantity.py +++ b/pint/quantity.py @@ -505,6 +505,22 @@ class Quantity(PrettyIPython, SharedRegistryObject): return self._REGISTRY.get_compatible_units(self._units) def is_compatible_with(self, other, *contexts, **ctx_kwargs): + """ check if the other object is compatible + + Parameters + ---------- + other + The object to check. Treated as dimensionless if not a + Quantity, Unit or str. + *contexts : str or pint.Context + Contexts to use in the transformation. + **ctx_kwargs : + Values for the Context/s + + Returns + ------- + bool + """ if contexts: try: self.to(other, *contexts, **ctx_kwargs) diff --git a/pint/registry.py b/pint/registry.py index 755de87..01b640b 100644 --- a/pint/registry.py +++ b/pint/registry.py @@ -855,6 +855,22 @@ class BaseRegistry(metaclass=RegistryMeta): return self._cache.dimensional_equivalents[src_dim] def is_compatible_with(self, obj1, obj2, *contexts, **ctx_kwargs): + """ check if the other object is compatible + + Parameters + ---------- + obj1, obj2 + The objects to check against each other. Treated as + dimensionless if not a Quantity, Unit or str. + *contexts : str or pint.Context + Contexts to use in the transformation. + **ctx_kwargs : + Values for the Context/s + + Returns + ------- + bool + """ if isinstance(obj1, (self.Quantity, self.Unit)): return obj1.is_compatible_with(obj2, *contexts, **ctx_kwargs) diff --git a/pint/unit.py b/pint/unit.py index 505f975..ef7aeef 100644 --- a/pint/unit.py +++ b/pint/unit.py @@ -145,6 +145,22 @@ class Unit(PrettyIPython, SharedRegistryObject): return self._REGISTRY.get_compatible_units(self) def is_compatible_with(self, other, *contexts, **ctx_kwargs): + """ check if the other object is compatible + + Parameters + ---------- + other + The object to check. Treated as dimensionless if not a + Quantity, Unit or str. + *contexts : str or pint.Context + Contexts to use in the transformation. + **ctx_kwargs : + Values for the Context/s + + Returns + ------- + bool + """ if contexts: try: (1 * self).to(other, *contexts, **ctx_kwargs) -- cgit v1.2.1 From 7befc5bcaae53449c9229a4d3ea6648698ab9678 Mon Sep 17 00:00:00 2001 From: Keewis Date: Mon, 20 Jan 2020 14:11:04 +0100 Subject: change the implementation of `pad` to treat non-quantities as dimensionless --- pint/numpy_func.py | 10 +++++++--- pint/testsuite/test_numpy.py | 13 +++++++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pint/numpy_func.py b/pint/numpy_func.py index 1fd7d8c..63c16b3 100644 --- a/pint/numpy_func.py +++ b/pint/numpy_func.py @@ -654,10 +654,14 @@ def _pad(array, pad_width, mode="constant", **kwargs): def _recursive_convert(arg, unit): if iterable(arg): return tuple(_recursive_convert(a, unit=unit) for a in arg) - elif _is_quantity(arg): - return arg.m_as(unit) else: - return arg + if not _is_quantity(arg): + if arg == 0: + arg = unit._REGISTRY.Quantity(arg, unit) + else: + arg = unit._REGISTRY.Quantity(arg, "dimensionless") + + return arg.m_as(unit) # pad only dispatches on array argument, so we know it is a Quantity units = array.units diff --git a/pint/testsuite/test_numpy.py b/pint/testsuite/test_numpy.py index 0efb476..5c0174d 100644 --- a/pint/testsuite/test_numpy.py +++ b/pint/testsuite/test_numpy.py @@ -1067,9 +1067,18 @@ class TestNumpyUnclassified(TestNumpyMethods): def test_pad(self): # Tests reproduced with modification from NumPy documentation a = [1, 2, 3, 4, 5] * self.ureg.m + b = self.Q_([4, 6, 8, 9, -3], "degC") + + self.assertQuantityEqual( + np.pad(a, (2, 3), "constant", constant_values=(0, 600 * self.ureg.cm)), + [0, 0, 1, 2, 3, 4, 5, 6, 6, 6] * self.ureg.m, + ) self.assertQuantityEqual( - np.pad(a, (2, 3), "constant", constant_values=(4, 600 * self.ureg.cm)), - [4, 4, 1, 2, 3, 4, 5, 6, 6, 6] * self.ureg.m, + np.pad(b, (2, 1), "constant", constant_values=self.Q_(10, "degC")), + self.Q_([10, 10, 4, 6, 8, 9, -3, 10], "degC"), + ) + self.assertRaises( + DimensionalityError, np.pad, a, (2, 3), "constant", constant_values=4 ) self.assertQuantityEqual( np.pad(a, (2, 3), "edge"), [1, 1, 1, 2, 3, 4, 5, 5, 5, 5] * self.ureg.m -- cgit v1.2.1 From 0226bf46972a6297ce06b3f683f802961fa68bd8 Mon Sep 17 00:00:00 2001 From: Keewis Date: Mon, 20 Jan 2020 14:17:36 +0100 Subject: remove the unneeded else: --- pint/numpy_func.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pint/numpy_func.py b/pint/numpy_func.py index 63c16b3..1073643 100644 --- a/pint/numpy_func.py +++ b/pint/numpy_func.py @@ -654,14 +654,13 @@ def _pad(array, pad_width, mode="constant", **kwargs): def _recursive_convert(arg, unit): if iterable(arg): return tuple(_recursive_convert(a, unit=unit) for a in arg) - else: - if not _is_quantity(arg): - if arg == 0: - arg = unit._REGISTRY.Quantity(arg, unit) - else: - arg = unit._REGISTRY.Quantity(arg, "dimensionless") + elif not _is_quantity(arg): + if arg == 0: + arg = unit._REGISTRY.Quantity(arg, unit) + else: + arg = unit._REGISTRY.Quantity(arg, "dimensionless") - return arg.m_as(unit) + return arg.m_as(unit) # pad only dispatches on array argument, so we know it is a Quantity units = array.units -- cgit v1.2.1 From 90bad48e56e6cbbbb146d1abc6f3c95aa40dcf50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jules=20Ch=C3=A9ron?= Date: Tue, 21 Jan 2020 21:46:40 +0100 Subject: Fixed #960 - Handles unit in to_compact. - Use same function infer_base_unit on Quantity based on input unit. - Add unit test in test_issues.py --- AUTHORS | 1 + CHANGES | 1 + pint/quantity.py | 2 ++ pint/testsuite/test_issues.py | 5 +++++ 4 files changed, 9 insertions(+) diff --git a/AUTHORS b/AUTHORS index 21ba865..db3229e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -27,6 +27,7 @@ Other contributors, listed alphabetically, are: * Joel B. Mohler * John David Reaver * Jonas Olson +* Jules Chéron * Kaido Kert * Kenneth D. Mankoff * Kevin Davies diff --git a/CHANGES b/CHANGES index 6c645b9..115edca 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,7 @@ Pint Changelog (Issue #979, Thanks Jon Thielen) - Allow constants in units by using a leading underscore (Issue #989, Thanks Juan Nunez-Iglesias) +- Fixed bug where to_compact handled prefix units incorrectly (Issue #960) 0.10.1 (2020-01-07) ------------------- diff --git a/pint/quantity.py b/pint/quantity.py index 09f7aed..051fc84 100644 --- a/pint/quantity.py +++ b/pint/quantity.py @@ -689,6 +689,8 @@ class Quantity(PrettyIPython, SharedRegistryObject): if unit is None: unit = infer_base_unit(self) + else: + unit = infer_base_unit(self.__class__(1, unit)) q_base = self.to(unit) diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py index cc04e9f..5f42717 100644 --- a/pint/testsuite/test_issues.py +++ b/pint/testsuite/test_issues.py @@ -710,6 +710,11 @@ class TestIssues(QuantityTestCase): with self.assertRaises(AttributeError): one_blank = 1 * ureg._ # noqa: F841 + def test_issue960(self): + q = (1 * ureg.nanometer).to_compact("micrometer") + assert q.units == ureg.nanometer + assert q.magnitude == 1 + try: -- cgit v1.2.1 From 17c5514dce35022566a7a00efc36b335767c1c63 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 29 Jan 2020 18:00:19 +0100 Subject: add install instructions and a warning about the status of pint-pandas --- docs/pint-pandas.ipynb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/pint-pandas.ipynb b/docs/pint-pandas.ipynb index 390831e..c1ac467 100644 --- a/docs/pint-pandas.ipynb +++ b/docs/pint-pandas.ipynb @@ -6,7 +6,22 @@ "source": [ "# Pandas support\n", "\n", - "It is convenient to use the Pandas package when dealing with numerical data, so Pint provides PintArray. A PintArray is a Pandas Extension Array, which allows Pandas to recognise the Quantity and store it in Pandas DataFrames and Series." + "
\n", + "\n", + "**Warning:** pandas support is currently experimental, don't expect everything to work.\n", + "\n", + "
\n", + "\n", + "It is convenient to use the Pandas package when dealing with numerical data, so Pint provides PintArray. A PintArray is a Pandas Extension Array, which allows Pandas to recognise the Quantity and store it in Pandas DataFrames and Series.\n", + "\n", + "
\n", + "\n", + "**Note:** Pandas support is provided by `pint-pandas`. However, it is not available on PyPI yet, install it with\n", + "```\n", + "python -m pip install git+https://github.com/hgrecco/pint-pandas.git\n", + "```\n", + "\n", + "
\n" ] }, { -- cgit v1.2.1 From 1673da70cdab6070643c1a93f3e19d625aeb3e53 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 29 Jan 2020 18:01:21 +0100 Subject: use pintpandas when accessing pandas functionality --- docs/pint-pandas.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pint-pandas.ipynb b/docs/pint-pandas.ipynb index c1ac467..dd392c5 100644 --- a/docs/pint-pandas.ipynb +++ b/docs/pint-pandas.ipynb @@ -1234,7 +1234,7 @@ } ], "source": [ - "pint.PintType.ureg.default_format = \"~P\"\n", + "pintpandas.PintType.ureg.default_format = \"~P\"\n", "df_.pint.dequantify()" ] }, @@ -1387,7 +1387,7 @@ "metadata": {}, "outputs": [], "source": [ - "PA_ = pint.PintArray" + "PA_ = pintpandas.PintArray" ] }, { @@ -1420,7 +1420,7 @@ "metadata": {}, "outputs": [], "source": [ - "pint.PintType.ureg = ureg" + "pintpandas.PintType.ureg = ureg" ] }, { -- cgit v1.2.1 From 9138c874a79717c95cfea33ee4ebdc6682fb3553 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 29 Jan 2020 18:02:10 +0100 Subject: style fixes --- docs/pint-pandas.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/pint-pandas.ipynb b/docs/pint-pandas.ipynb index dd392c5..d56f266 100644 --- a/docs/pint-pandas.ipynb +++ b/docs/pint-pandas.ipynb @@ -546,8 +546,8 @@ } ], "source": [ - "df = pd.read_csv(io.StringIO(test_data),header=[0,1])\n", - "# df = pd.read_csv(\"/path/to/test_data.csv\",header=[0,1])\n", + "df = pd.read_csv(io.StringIO(test_data), header=[0, 1])\n", + "# df = pd.read_csv(\"/path/to/test_data.csv\", header=[0, 1])\n", "df" ] }, @@ -705,7 +705,7 @@ } ], "source": [ - "df_.speed*df_.torque" + "df_.speed * df_.torque" ] }, { @@ -889,7 +889,7 @@ } ], "source": [ - "df_['mech power'] = df_.speed*df_.torque\n", + "df_['mech power'] = df_.speed * df_.torque\n", "df_['fluid power'] = df_['fuel flow rate'] * df_['rail pressure']\n", "df_" ] @@ -1403,8 +1403,8 @@ "metadata": {}, "outputs": [], "source": [ - "ureg=pint.UnitRegistry()\n", - "Q_=ureg.Quantity" + "ureg = pint.UnitRegistry()\n", + "Q_ = ureg.Quantity" ] }, { -- cgit v1.2.1 From 0a03462515bca32258f948ae17c97a30d2c5b51d Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 29 Jan 2020 18:27:33 +0100 Subject: fix a reference in the numpy page --- docs/numpy.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/numpy.ipynb b/docs/numpy.ipynb index 2dc6078..4ed462b 100644 --- a/docs/numpy.ipynb +++ b/docs/numpy.ipynb @@ -778,7 +778,7 @@ "To achive these function and ufunc overrides, Pint uses the ``__array_function__`` and ``__array_ufunc__`` protocols respectively, as recommened by NumPy. This means that functions and ufuncs that Pint does not explicitly handle will error, rather than return a value with units stripped (in contrast to Pint's behavior prior to v0.10). For more\n", "information on these protocols, see .\n", "\n", - "This behaviour introduces some performance penalties and increased memory usage. Quantities that must be converted to other units require additional memory and CPU cycles. Therefore, for numerically intensive code, you might want to convert the objects first and then use directly the magnitude, such as by using Pint's `wraps` utility (see [wrapping](wrapping.html)).\n", + "This behaviour introduces some performance penalties and increased memory usage. Quantities that must be converted to other units require additional memory and CPU cycles. Therefore, for numerically intensive code, you might want to convert the objects first and then use directly the magnitude, such as by using Pint's `wraps` utility (see [wrapping](wrapping.rst)).\n", "\n", "Array interface protocol attributes (such as `__array_struct__` and\n", "`__array_interface__`) are available on Pint Quantities by deferring to the corresponding `__array_*` attribute on the magnitude as casted to an ndarray. This has been found to be potentially incorrect and to cause unexpected behavior, and has therefore been deprecated. As of the next minor version of Pint (or when the `PINT_ARRAY_PROTOCOL_FALLBACK` environment variable is set to 0 prior to importing Pint as done at the beginning of this page), attempting to access these attributes will instead raise an AttributeError." -- cgit v1.2.1 From ba09ff7c4762cbecd629c0dcd18b54f3bc297641 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 29 Jan 2020 18:27:59 +0100 Subject: replace the note with a installation section --- docs/pint-pandas.ipynb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/pint-pandas.ipynb b/docs/pint-pandas.ipynb index d56f266..e213aff 100644 --- a/docs/pint-pandas.ipynb +++ b/docs/pint-pandas.ipynb @@ -12,16 +12,20 @@ "\n", "\n", "\n", - "It is convenient to use the Pandas package when dealing with numerical data, so Pint provides PintArray. A PintArray is a Pandas Extension Array, which allows Pandas to recognise the Quantity and store it in Pandas DataFrames and Series.\n", + "It is convenient to use the Pandas package when dealing with numerical data, so Pint provides PintArray. A PintArray is a Pandas Extension Array, which allows Pandas to recognise the Quantity and store it in Pandas DataFrames and Series." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation\n", "\n", - "
\n", "\n", - "**Note:** Pandas support is provided by `pint-pandas`. However, it is not available on PyPI yet, install it with\n", + "Pandas support is provided by `pint-pandas`. It is not available on PyPI yet, to install it use\n", "```\n", "python -m pip install git+https://github.com/hgrecco/pint-pandas.git\n", - "```\n", - "\n", - "
\n" + "```" ] }, { -- cgit v1.2.1 From ae9f3c1022493cdf09eb6a36f833adcb0cb74add Mon Sep 17 00:00:00 2001 From: 5igno Date: Tue, 4 Feb 2020 15:21:46 +0100 Subject: Change default numpy datatype to np.ptype("int") The test function test_result_type_numpy_func checks the datatype for [[1, 2], [3, 4]] * self.ureg.m to be integer. The test originally ensured the datatype to be np.ptype("int64"), but that fails in 32 bit environments. Using np.ptype("int") instead ensure that the quantity is of default integer type, making numpy itself decide whether it should be np.ptype("int64") or np.ptype("int32"). - [x] Closes #1006 - [x] Executed ``black -t py36 . && isort -rc . && flake8`` with no errors - [x] The change is fully covered by automated unit tests - [ ] ~~Documented in docs/ as appropriate~~ - [ ] Added an entry to the CHANGES file --- pint/testsuite/test_numpy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pint/testsuite/test_numpy.py b/pint/testsuite/test_numpy.py index 0efb476..b0bc9e3 100644 --- a/pint/testsuite/test_numpy.py +++ b/pint/testsuite/test_numpy.py @@ -885,7 +885,7 @@ class TestNumpyUnclassified(TestNumpyMethods): @helpers.requires_array_function_protocol() def test_result_type_numpy_func(self): - self.assertEqual(np.result_type(self.q), np.dtype("int64")) + self.assertEqual(np.result_type(self.q), np.dtype("int")) @helpers.requires_array_function_protocol() def test_nan_to_num_numpy_func(self): -- cgit v1.2.1 From ccea5e1d32f1186ed4b5a23fa1c5740cf4cc9de4 Mon Sep 17 00:00:00 2001 From: Hernan Date: Tue, 4 Feb 2020 22:26:42 -0300 Subject: Reorganize long_description Remove AUTHORS and CHANGES and replace them by a link to github to improve readability in PyPI Closes #983 --- README.rst | 9 +++++++++ setup.cfg | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6c99466..f90ea45 100644 --- a/README.rst +++ b/README.rst @@ -142,6 +142,13 @@ ufuncs are supported including automatic conversion of units. For example quantity will be radian. +Pint is maintained by a community of scientists, programmers and entusiasts around the world. +See AUTHORS_ for a complete list. + +To review an ordered list of notable changes for each version of a project, +see CHANGES_ + + .. _Website: http://www.dimensionalanalysis.org/ .. _`comprehensive list of physical units, prefixes and constants`: https://github.com/hgrecco/pint/blob/master/pint/default_en.txt .. _`uncertainties package`: https://pythonhosted.org/uncertainties/ @@ -150,3 +157,5 @@ quantity will be radian. .. _`Babel`: http://babel.pocoo.org/ .. _`Pandas Extension Types`: https://pandas.pydata.org/pandas-docs/stable/extending.html#extension-types .. _`pint-pandas Jupyter notebook`: https://github.com/hgrecco/pint-pandas/blob/master/notebooks/pandas_support.ipynb +.. _`AUTHORS`: https://github.com/hgrecco/pint/blob/master/AUTHORS +.. _`CHANGES`: https://github.com/hgrecco/pint/blob/master/CHANGES \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index a95b2ca..83320c1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,7 +4,7 @@ author = Hernan E. Grecco author_email = hernan.grecco@gmail.com license = BSD description = Physical quantities module -long_description = file: README.rst, AUTHORS, CHANGES +long_description = file: README.rst keywords = physical, quantities, unit, conversion, science url = https://github.com/hgrecco/pint classifiers = -- cgit v1.2.1 From 5b60ba0afb9f875bd08895ee9746dbf7264f5a5c Mon Sep 17 00:00:00 2001 From: Hernan Date: Tue, 4 Feb 2020 22:28:08 -0300 Subject: Remove `default_en_0.6.txt` This file is no longer necessary and it can always be fetched from github if needed Closes #985 --- pint/default_en_0.6.txt | 360 ------------------------------------------------ 1 file changed, 360 deletions(-) delete mode 100644 pint/default_en_0.6.txt diff --git a/pint/default_en_0.6.txt b/pint/default_en_0.6.txt deleted file mode 100644 index fb722c0..0000000 --- a/pint/default_en_0.6.txt +++ /dev/null @@ -1,360 +0,0 @@ -# Default Pint units definition file -# Based on the International System of Units -# Language: english -# :copyright: 2013 by Pint Authors, see AUTHORS for more details. - -# decimal prefixes -yocto- = 1e-24 = y- -zepto- = 1e-21 = z- -atto- = 1e-18 = a- -femto- = 1e-15 = f- -pico- = 1e-12 = p- -nano- = 1e-9 = n- -micro- = 1e-6 = u- = µ- -milli- = 1e-3 = m- -centi- = 1e-2 = c- -deci- = 1e-1 = d- -deca- = 1e+1 = da- -hecto- = 1e2 = h- -kilo- = 1e3 = k- -mega- = 1e6 = M- -giga- = 1e9 = G- -tera- = 1e12 = T- -peta- = 1e15 = P- -exa- = 1e18 = E- -zetta- = 1e21 = Z- -yotta- = 1e24 = Y- - -# binary_prefixes -kibi- = 2**10 = Ki- -mebi- = 2**20 = Mi- -gibi- = 2**30 = Gi- -tebi- = 2**40 = Ti- -pebi- = 2**50 = Pi- -exbi- = 2**60 = Ei- -zebi- = 2**70 = Zi- -yobi- = 2**80 = Yi- - -# reference -meter = [length] = m = metre -second = [time] = s = sec -ampere = [current] = A = amp -candela = [luminosity] = cd = candle -gram = [mass] = g -mole = [substance] = mol -kelvin = [temperature]; offset: 0 = K = degK -radian = [] = rad -bit = [] -count = [] - -@import constants_en.txt - -# acceleration -[acceleration] = [length] / [time] ** 2 - -# Angle -turn = 2 * pi * radian = revolution = cycle = circle -degree = pi / 180 * radian = deg = arcdeg = arcdegree = angular_degree -arcminute = arcdeg / 60 = arcmin = arc_minute = angular_minute -arcsecond = arcmin / 60 = arcsec = arc_second = angular_second -steradian = radian ** 2 = sr - -# Area -[area] = [length] ** 2 -are = 100 * m**2 -barn = 1e-28 * m ** 2 = b -cmil = 5.067075e-10 * m ** 2 = circular_mils -darcy = 9.869233e-13 * m ** 2 -acre = 4046.8564224 * m ** 2 = international_acre -hectare = 100 * are = ha -US_survey_acre = 160 * rod ** 2 - -# EM -esu = 1 * erg**0.5 * centimeter**0.5 = statcoulombs = statC = franklin = Fr -esu_per_second = 1 * esu / second = statampere -ampere_turn = 1 * A -gilbert = 10 / (4 * pi ) * ampere_turn -coulomb = ampere * second = C -volt = joule / coulomb = V -farad = coulomb / volt = F -ohm = volt / ampere = Ω -siemens = ampere / volt = S = mho -weber = volt * second = Wb -tesla = weber / meter ** 2 = T -henry = weber / ampere = H -elementary_charge = 1.602176487e-19 * coulomb = e -chemical_faraday = 9.64957e4 * coulomb -physical_faraday = 9.65219e4 * coulomb -faraday = 96485.3399 * coulomb = C12_faraday -gamma = 1e-9 * tesla -gauss = 1e-4 * tesla -maxwell = 1e-8 * weber = mx -oersted = 1000 / (4 * pi) * A / m = Oe -statfarad = 1.112650e-12 * farad = statF = stF -stathenry = 8.987554e11 * henry = statH = stH -statmho = 1.112650e-12 * siemens = statS = stS -statohm = 8.987554e11 * ohm -statvolt = 2.997925e2 * volt = statV = stV -unit_pole = 1.256637e-7 * weber - -# Energy -[energy] = [force] * [length] -joule = newton * meter = J -erg = dyne * centimeter -btu = 1.05505585262e3 * joule = Btu = BTU = british_thermal_unit -electron_volt = 1.60217653e-19 * J = eV -quadrillion_btu = 10**15 * btu = quad -thm = 100000 * BTU = therm = EC_therm -cal = 4.184 * joule = calorie = thermochemical_calorie -international_steam_table_calorie = 4.1868 * joule -ton_TNT = 4.184e9 * joule = tTNT -US_therm = 1.054804e8 * joule -watt_hour = watt * hour = Wh = watthour -hartree = 4.35974394e-18 * joule = E_h = hartree_energy - -# Force -[force] = [mass] * [acceleration] -newton = kilogram * meter / second ** 2 = N -dyne = gram * centimeter / second ** 2 = dyn -force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond -force_gram = g_0 * gram = gf = gram_force -force_ounce = g_0 * ounce = ozf = ounce_force -force_pound = g_0 * lb = lbf = pound_force -force_ton = 2000 * force_pound = ton_force -poundal = lb * feet / second ** 2 = pdl -kip = 1000*lbf - -# Frequency -[frequency] = 1 / [time] -hertz = 1 / second = Hz = rps -revolutions_per_minute = revolution / minute = rpm -counts_per_second = count / second = cps - -# Heat -#RSI = degK * meter ** 2 / watt -#clo = 0.155 * RSI = clos -#R_value = foot ** 2 * degF * hour / btu - -# Information -byte = 8 * bit = B = octet -baud = bit / second = Bd = bps - -# Irradiance -peak_sun_hour = 1000 * watt_hour / meter**2 = PSH -langley = thermochemical_calorie / centimeter**2 = Langley - -# Length -angstrom = 1e-10 * meter = Å = ångström = Å -inch = 2.54 * centimeter = in = international_inch = inches = international_inches -foot = 12 * inch = ft = international_foot = feet = international_feet -mile = 5280 * foot = mi = international_mile -yard = 3 * feet = yd = international_yard -mil = inch / 1000 = thou -parsec = 3.08568025e16 * meter = pc -light_year = speed_of_light * julian_year = ly = lightyear -astronomical_unit = 149597870691 * meter = au -nautical_mile = 1.852e3 * meter = nmi -printers_point = 127 * millimeter / 360 = point -printers_pica = 12 * printers_point = pica -US_survey_foot = 1200 * meter / 3937 -US_survey_yard = 3 * US_survey_foot -US_survey_mile = 5280 * US_survey_foot = US_statute_mile -rod = 16.5 * US_survey_foot = pole = perch -furlong = 660 * US_survey_foot -fathom = 6 * US_survey_foot -chain = 66 * US_survey_foot -barleycorn = inch / 3 -arpentlin = 191.835 * feet -kayser = 1 / centimeter = wavenumber - -# Mass -dram = oz / 16 = dr = avoirdupois_dram -ounce = 28.349523125 * gram = oz = avoirdupois_ounce -pound = 0.45359237 * kilogram = lb = avoirdupois_pound -stone = 14 * lb = st -carat = 200 * milligram -grain = 64.79891 * milligram = gr -long_hundredweight = 112 * lb -short_hundredweight = 100 * lb -metric_ton = 1000 * kilogram = t = tonne -pennyweight = 24 * gram = dwt -slug = 14.59390 * kilogram -troy_ounce = 480 * grain = toz = apounce = apothecary_ounce -troy_pound = 12 * toz = tlb = appound = apothecary_pound -drachm = 60 * grain = apdram = apothecary_dram -atomic_mass_unit = 1.660538782e-27 * kilogram = u = amu = dalton = Da -scruple = 20 * grain -bag = 94 * lb -ton = 2000 * lb = short_ton - -# Textile -denier = gram / (9000 * meter) -tex = gram / (1000 * meter) -dtex = decitex - -# Photometry -lumen = candela * steradian = lm -lux = lumen / meter ** 2 = lx - -# Power -[power] = [energy] / [time] -watt = joule / second = W = volt_ampere = VA -horsepower = 33000 * ft * lbf / min = hp = UK_horsepower = British_horsepower -boiler_horsepower = 33475 * btu / hour -metric_horsepower = 75 * force_kilogram * meter / second -electric_horsepower = 746 * watt -hydraulic_horsepower = 550 * feet * lbf / second -refrigeration_ton = 12000 * btu / hour = ton_of_refrigeration - -# Pressure -[pressure] = [force] / [area] -Hg = gravity * 13.59510 * gram / centimeter ** 3 = mercury = conventional_mercury -mercury_60F = gravity * 13.5568 * gram / centimeter ** 3 -H2O = gravity * 1000 * kilogram / meter ** 3 = h2o = water = conventional_water -water_4C = gravity * 999.972 * kilogram / meter ** 3 = water_39F -water_60F = gravity * 999.001 * kilogram / m ** 3 -pascal = newton / meter ** 2 = Pa -bar = 100000 * pascal -atmosphere = 101325 * pascal = atm = standard_atmosphere -technical_atmosphere = kilogram * gravity / centimeter ** 2 = at -torr = atm / 760 -pound_force_per_square_inch = pound * gravity / inch ** 2 = psi -kip_per_square_inch = kip / inch ** 2 = ksi -barye = 0.1 * newton / meter ** 2 = barie = barad = barrie = baryd = Ba -mm_Hg = millimeter * Hg = mmHg = millimeter_Hg = millimeter_Hg_0C -cm_Hg = centimeter * Hg = cmHg = centimeter_Hg -in_Hg = inch * Hg = inHg = inch_Hg = inch_Hg_32F -inch_Hg_60F = inch * mercury_60F -inch_H2O_39F = inch * water_39F -inch_H2O_60F = inch * water_60F -footH2O = ft * water -cmH2O = centimeter * water -foot_H2O = ft * water = ftH2O -standard_liter_per_minute = 1.68875 * Pa * m ** 3 / s = slpm = slm - -# Radiation -Bq = Hz = becquerel -curie = 3.7e10 * Bq = Ci -rutherford = 1e6*Bq = rd = Rd -Gy = joule / kilogram = gray = Sv = sievert -rem = 1e-2 * sievert -rads = 1e-2 * gray -roentgen = 2.58e-4 * coulomb / kilogram - -# Temperature -degC = kelvin; offset: 273.15 = celsius -degR = 5 / 9 * kelvin; offset: 0 = rankine -degF = 5 / 9 * kelvin; offset: 255.372222 = fahrenheit - -# Time -minute = 60 * second = min -hour = 60 * minute = hr -day = 24 * hour -week = 7 * day -fortnight = 2 * week -year = 31556925.9747 * second -month = year / 12 -shake = 1e-8 * second -sidereal_day = day / 1.00273790935079524 -sidereal_hour = sidereal_day / 24 -sidereal_minute = sidereal_hour / 60 -sidereal_second = sidereal_minute / 60 -sidereal_year = 366.25636042 * sidereal_day -sidereal_month = 27.321661 * sidereal_day -tropical_month = 27.321661 * day -synodic_month = 29.530589 * day = lunar_month -common_year = 365 * day -leap_year = 366 * day -julian_year = 365.25 * day -gregorian_year = 365.2425 * day -millenium = 1000 * year = millenia = milenia = milenium -eon = 1e9 * year -work_year = 2056 * hour -work_month = work_year / 12 - -# Velocity -[speed] = [length] / [time] -knot = nautical_mile / hour = kt = knot_international = international_knot = nautical_miles_per_hour -mph = mile / hour = MPH -kph = kilometer / hour = KPH - -# Viscosity -[viscosity] = [pressure] * [time] -poise = 1e-1 * Pa * second = P -stokes = 1e-4 * meter ** 2 / second = St -rhe = 10 / (Pa * s) - -# Volume -[volume] = [length] ** 3 -liter = 1e-3 * m ** 3 = l = L = litre -cc = centimeter ** 3 = cubic_centimeter -stere = meter ** 3 -gross_register_ton = 100 * foot ** 3 = register_ton = GRT -acre_foot = acre * foot = acre_feet -board_foot = foot ** 2 * inch = FBM -bushel = 2150.42 * inch ** 3 = bu = US_bushel -dry_gallon = bushel / 8 = US_dry_gallon -dry_quart = dry_gallon / 4 = US_dry_quart -dry_pint = dry_quart / 2 = US_dry_pint -gallon = 231 * inch ** 3 = liquid_gallon = US_liquid_gallon -quart = gallon / 4 = liquid_quart = US_liquid_quart -pint = quart / 2 = pt = liquid_pint = US_liquid_pint -cup = pint / 2 = liquid_cup = US_liquid_cup -gill = cup / 2 = liquid_gill = US_liquid_gill -fluid_ounce = gill / 4 = floz = US_fluid_ounce = US_liquid_ounce -imperial_bushel = 36.36872 * liter = UK_bushel -imperial_gallon = imperial_bushel / 8 = UK_gallon -imperial_quart = imperial_gallon / 4 = UK_quart -imperial_pint = imperial_quart / 2 = UK_pint -imperial_cup = imperial_pint / 2 = UK_cup -imperial_gill = imperial_cup / 2 = UK_gill -imperial_floz = imperial_gill / 5 = UK_fluid_ounce = imperial_fluid_ounce -barrel = 42 * gallon = bbl -tablespoon = floz / 2 = tbsp = Tbsp = Tblsp = tblsp = tbs = Tbl -teaspoon = tablespoon / 3 = tsp -peck = bushel / 4 = pk -fluid_dram = floz / 8 = fldr = fluidram -firkin = barrel / 4 - - -@context(n=1) spectroscopy = sp - # n index of refraction of the medium. - [length] <-> [frequency]: speed_of_light / n / value - [frequency] -> [energy]: planck_constant * value - [energy] -> [frequency]: value / planck_constant -@end - -@context boltzmann - [temperature] -> [energy]: boltzmann_constant * value - [energy] -> [temperature]: value / boltzmann_constant -@end - -@context(mw=0,volume=0,solvent_mass=0) chemistry = chem - # mw is the molecular weight of the species - # volume is the volume of the solution - # solvent_mass is the mass of solvent in the solution - - # moles -> mass require the molecular weight - [substance] -> [mass]: value * mw - [mass] -> [substance]: value / mw - - # moles/volume -> mass/volume and moles/mass -> mass / mass - # require the molecular weight - [substance] / [volume] -> [mass] / [volume]: value * mw - [mass] / [volume] -> [substance] / [volume]: value / mw - [substance] / [mass] -> [mass] / [mass]: value * mw - [mass] / [mass] -> [substance] / [mass]: value / mw - - # moles/volume -> moles requires the solution volume - [substance] / [volume] -> [substance]: value * volume - [substance] -> [substance] / [volume]: value / volume - - # moles/mass -> moles requires the solvent (usually water) mass - [substance] / [mass] -> [substance]: value * solvent_mass - [substance] -> [substance] / [mass]: value / solvent_mass - - # moles/mass -> moles/volume require the solvent mass and the volume - [substance] / [mass] -> [substance]/[volume]: value * solvent_mass / volume - [substance] / [volume] -> [substance] / [mass]: value / solvent_mass * volume - -@end -- cgit v1.2.1 From e14d78b18c7e324a1d13b63f596350020671fa07 Mon Sep 17 00:00:00 2001 From: Hernan Date: Wed, 5 Feb 2020 10:14:37 -0300 Subject: Updated CHANGES --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 785ad6c..32b3a42 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,8 @@ Pint Changelog 0.11 (unreleased) ----------------- +- Remove `default_en_0.6.txt` +- Reorganize long_description. - Moved Pi to defintions files. - Use ints (not floats) a defaults at many points in the codebase as in Python 3 the true division is the default one. -- cgit v1.2.1 From 056810bf0160cb370eb85f4eed0560791f5ad8a9 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 5 Feb 2020 14:39:56 +0100 Subject: also allow nan as a special value --- pint/numpy_func.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pint/numpy_func.py b/pint/numpy_func.py index 1073643..10f4114 100644 --- a/pint/numpy_func.py +++ b/pint/numpy_func.py @@ -655,7 +655,7 @@ def _pad(array, pad_width, mode="constant", **kwargs): if iterable(arg): return tuple(_recursive_convert(a, unit=unit) for a in arg) elif not _is_quantity(arg): - if arg == 0: + if arg == 0 or np.isnan(arg): arg = unit._REGISTRY.Quantity(arg, unit) else: arg = unit._REGISTRY.Quantity(arg, "dimensionless") -- cgit v1.2.1 From d7af72a11bcf45c47a911a4ec5c3abf2f2d6ac0a Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 5 Feb 2020 14:47:11 +0100 Subject: test that passing a bare np.nan does not raise --- pint/testsuite/test_numpy.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pint/testsuite/test_numpy.py b/pint/testsuite/test_numpy.py index b03b0a6..595aa3f 100644 --- a/pint/testsuite/test_numpy.py +++ b/pint/testsuite/test_numpy.py @@ -1067,15 +1067,17 @@ class TestNumpyUnclassified(TestNumpyMethods): def test_pad(self): # Tests reproduced with modification from NumPy documentation a = [1, 2, 3, 4, 5] * self.ureg.m - b = self.Q_([4, 6, 8, 9, -3], "degC") + b = self.Q_([4.0, 6.0, 8.0, 9.0, -3.0], "degC") self.assertQuantityEqual( np.pad(a, (2, 3), "constant", constant_values=(0, 600 * self.ureg.cm)), [0, 0, 1, 2, 3, 4, 5, 6, 6, 6] * self.ureg.m, ) self.assertQuantityEqual( - np.pad(b, (2, 1), "constant", constant_values=self.Q_(10, "degC")), - self.Q_([10, 10, 4, 6, 8, 9, -3, 10], "degC"), + np.pad( + b, (2, 1), "constant", constant_values=(np.nan, self.Q_(10, "degC")) + ), + self.Q_([np.nan, np.nan, 4, 6, 8, 9, -3, 10], "degC"), ) self.assertRaises( DimensionalityError, np.pad, a, (2, 3), "constant", constant_values=4 -- cgit v1.2.1 From 95efc46795c2ec22d78c41cd81394728c0488cd1 Mon Sep 17 00:00:00 2001 From: Abdurrahmaan Iqbal Date: Thu, 6 Feb 2020 20:07:10 +0000 Subject: Implement parse_pattern function --- docs/tutorial.rst | 50 ++++++++++++++++++++++++++------ pint/registry.py | 69 +++++++++++++++++++++++++++++++++++++++++++++ pint/testsuite/test_unit.py | 41 +++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 9 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 158d2ad..9693444 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -251,14 +251,14 @@ or .. note:: Pint´s rule for parsing strings with a mixture of numbers and units is that **units are treated with the same precedence as numbers**. - + For example, the unit of .. doctest:: >>> Q_('3 l / 100 km') - + may be unexpected first but is a consequence of applying this rule. Use brackets to get the expected result: @@ -272,6 +272,38 @@ brackets to get the expected result: exposed to when parsing information from untrusted sources. +Strings containing values can be parsed using the ``ureg.parse_pattern`` function. A ``format``-like string with the units defined in it is used as the pattern: + +.. doctest:: + + >>> input_string = '10 feet 10 inches' + >>> pattern = '{feet} feet {inch} inches' + >>> ureg.parse_pattern(input_string, pattern) + [10.0 , 10.0 ] + +To search for multiple matches, set the ``many`` parameter to ``True``. The following example also demonstrates how the parser is able to find matches in amongst filler characters: + +.. doctest:: + + >>> input_string = '10 feet - 20 feet ! 30 feet.' + >>> pattern = '{feet} feet' + >>> ureg.parse_pattern(input_string, pattern, many=True) + [[10.0 ], [20.0 ], [30.0 ]] + +The full power of regex can also be employed when writing patterns: + +.. doctest:: + + >>> input_string = "10` - 20 feet ! 30 ft." + >>> pattern = r"{feet}(`| feet| ft)" + >>> ureg.parse_pattern(input_string, pattern, many=True) + [[10.0 ], [20.0 ], [30.0 ]] + +*Note that the curly brackets (``{}``) are converted to a float-matching pattern by the parser.* + +This function is useful for tasks such as bulk extraction of units from thousands of uniform strings or even very large texts with units dotted around in no particular pattern. + + .. _sec-string-formatting: String formatting @@ -303,12 +335,12 @@ Pint supports float formatting for numpy arrays as well: >>> # scientific form formatting with unit pretty printing >>> print('The array is {:+.2E~P}'.format(accel)) The array is [-1.10E+00 +1.00E-06 +1.25E+00 +1.30E+00] m/s² - + Pint also supports 'f-strings'_ from python>=3.6 : .. doctest:: - >>> accel = 1.3 * ureg['meter/second**2'] + >>> accel = 1.3 * ureg['meter/second**2'] >>> print(f'The str is {accel}') The str is 1.3 meter / second ** 2 >>> print(f'The str is {accel:.3e}') @@ -318,7 +350,7 @@ Pint also supports 'f-strings'_ from python>=3.6 : >>> print(f'The str is {accel:~.3e}') The str is 1.300e+00 m / s ** 2 >>> print(f'The str is {accel:~H}') - The str is 1.3 m/s² + The str is 1.3 m/s² But Pint also extends the standard formatting capabilities for unicode and LaTeX representations: @@ -349,11 +381,11 @@ If you want to use abbreviated unit names, prefix the specification with `~`: The same is true for latex (`L`) and HTML (`H`) specs. .. note:: - The abbreviated unit is drawn from the unit registry where the 3rd item in the - equivalence chain (ie 1 = 2 = **3**) will be returned when the prefix '~' is + The abbreviated unit is drawn from the unit registry where the 3rd item in the + equivalence chain (ie 1 = 2 = **3**) will be returned when the prefix '~' is used. The 1st item in the chain is the canonical name of the unit. -The formatting specs (ie 'L', 'H', 'P') can be used with Python string 'formatting +The formatting specs (ie 'L', 'H', 'P') can be used with Python string 'formatting syntax'_ for custom float representations. For example, scientific notation: ..doctest:: @@ -438,4 +470,4 @@ also define the registry as the application registry:: .. _`serious security problems`: http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html .. _`Babel`: http://babel.pocoo.org/ .. _'formatting syntax': https://docs.python.org/3/library/string.html#format-specification-mini-language -.. _'f-strings': https://www.python.org/dev/peps/pep-0498/ \ No newline at end of file +.. _'f-strings': https://www.python.org/dev/peps/pep-0498/ diff --git a/pint/registry.py b/pint/registry.py index 4ff9790..6aca174 100644 --- a/pint/registry.py +++ b/pint/registry.py @@ -85,6 +85,19 @@ from .util import ( _BLOCK_RE = re.compile(r" |\(") +@functools.lru_cache() +def pattern_to_regex(pattern): + if hasattr(pattern, "finditer"): + pattern = pattern.pattern + + # Replace "{unit_name}" match string with float regex with unit_name as group + pattern = re.sub( + r"{(\w+)}", r"(?P<\1>[+-]?[0-9]+(?:.[0-9]+)?(?:[Ee][+-]?[0-9]+)?)", pattern + ) + + return re.compile(pattern) + + class RegistryMeta(type): """This is just to call after_init at the right time instead of asking the developer to do it when subclassing. @@ -1086,6 +1099,62 @@ class BaseRegistry(metaclass=RegistryMeta): else: raise Exception("unknown token type") + def parse_pattern( + self, input_string, pattern, case_sensitive=True, use_decimal=False, many=False + ): + """Parse a string with a given regex pattern and returns result. + + Parameters + ---------- + input_string : + + pattern_string: + The regex parse string + case_sensitive : + (Default value = True) + use_decimal : + (Default value = False) + many : + Match many results + (Default value = False) + + + Returns + ------- + + """ + + if not input_string: + return self.Quantity(1) + + # Parse string + pattern = pattern_to_regex(pattern) + matched = re.finditer(pattern, input_string) + + # Extract result(s) + results = [] + for match in matched: + # Extract units from result + match = match.groupdict() + + # Parse units + units = [] + for unit, value in match.items(): + # Construct measure by multiplying value by unit + units.append( + float(value) + * self.parse_expression(unit, case_sensitive, use_decimal) + ) + + # Add to results + results.append(units) + + # Return first match only + if not many: + return results[0] + + return results + def parse_expression( self, input_string, case_sensitive=True, use_decimal=False, **values ): diff --git a/pint/testsuite/test_unit.py b/pint/testsuite/test_unit.py index 0b6c086..d7eb649 100644 --- a/pint/testsuite/test_unit.py +++ b/pint/testsuite/test_unit.py @@ -658,6 +658,47 @@ class TestRegistry(QuantityTestCase): self.assertEqual(ureg.parse_units(""), ureg.Unit("")) self.assertRaises(ValueError, ureg.parse_units, "2 * meter") + def test_parse_string_pattern(self): + ureg = self.ureg + self.assertEqual( + ureg.parse_pattern("10'11", r"{foot}'{inch}"), + [ureg.Quantity(10.0, "foot"), ureg.Quantity(11.0, "inch")], + ) + + def test_parse_string_pattern_no_preprocess(self): + """Were preprocessors enabled, this would be interpreted as 10*11, not + two separate units, and thus cause the parsing to fail""" + ureg = self.ureg + self.assertEqual( + ureg.parse_pattern("10 11", r"{kg} {lb}"), + [ureg.Quantity(10.0, "kilogram"), ureg.Quantity(11.0, "pound")], + ) + + def test_parse_pattern_many_results(self): + ureg = self.ureg + self.assertEqual( + ureg.parse_pattern( + "1.5kg or 2kg will be fine, if you do not have 3kg", + r"{kg}kg", + many=True, + ), + [ + [ureg.Quantity(1.5, "kilogram")], + [ureg.Quantity(2.0, "kilogram")], + [ureg.Quantity(3.0, "kilogram")], + ], + ) + + def test_parse_pattern_many_results_two_units(self): + ureg = self.ureg + self.assertEqual( + ureg.parse_pattern("10'10 or 10'11", "{foot}'{inch}", many=True), + [ + [ureg.Quantity(10.0, "foot"), ureg.Quantity(10.0, "inch")], + [ureg.Quantity(10.0, "foot"), ureg.Quantity(11.0, "inch")], + ], + ) + class TestCompatibleUnits(QuantityTestCase): FORCE_NDARRAY = False -- cgit v1.2.1 From a22c1bbf1db5dc3a7017b9c37ec4bc5eaeb95039 Mon Sep 17 00:00:00 2001 From: Jellby Date: Sat, 8 Feb 2020 18:04:05 +0100 Subject: Adding pint-convert script (see #1012) --- CHANGES | 5 ++- pint/constants_en.txt | 2 +- pint/pint-convert | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 3 +- 4 files changed, 121 insertions(+), 4 deletions(-) create mode 100755 pint/pint-convert diff --git a/CHANGES b/CHANGES index 32b3a42..19d02a6 100644 --- a/CHANGES +++ b/CHANGES @@ -4,9 +4,10 @@ Pint Changelog 0.11 (unreleased) ----------------- -- Remove `default_en_0.6.txt` +- Added pint-convert script. +- Remove `default_en_0.6.txt`. - Reorganize long_description. -- Moved Pi to defintions files. +- Moved Pi to definitions files. - Use ints (not floats) a defaults at many points in the codebase as in Python 3 the true division is the default one. - **BREAKING CHANGE**: diff --git a/pint/constants_en.txt b/pint/constants_en.txt index fa485fa..c3ecbf1 100644 --- a/pint/constants_en.txt +++ b/pint/constants_en.txt @@ -8,7 +8,7 @@ #### MATHEMATICAL CONSTANTS #### # As computed by Maxima with fpprec:50 -pi = 3.1415926535897932384626433832795028841971693993751 = π # pi +pi = 3.1415926535897932384626433832795028841971693993751 = π # pi tansec = 4.8481368111333441675396429478852851658848753880815e-6 # tangent of 1 arc-second ~ arc_second/radian ln10 = 2.3025850929940456840179914546843642076011014886288 # natural logarithm of 10 wien_x = 4.9651142317442763036987591313228939440555849867973 # solution to (x-5)*exp(x)+5 = 0 => x = W(5/exp(5))+5 diff --git a/pint/pint-convert b/pint/pint-convert new file mode 100755 index 0000000..d2540a3 --- /dev/null +++ b/pint/pint-convert @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 + +""" + pint_convert + ~~~~~~~~~~~~ + + :copyright: 2020 by Pint Authors, see AUTHORS for more details. + :license: BSD, see LICENSE for more details. +""" + +import argparse +from pint import UnitRegistry +import sys +import re + +parser = argparse.ArgumentParser(description='Unit converter.') +parser.add_argument('-s', '--system', metavar='sys', default='SI', help='unit system to convert to (default: SI)') +parser.add_argument('-p', '--prec', metavar='n', type=int, default=12, help='number of maximum significant figures (default: 12)') +parser.add_argument('-u', '--prec-unc', metavar='n', type=int, default=2, help='number of maximum uncertainty digits (default: 2)') +parser.add_argument('-U', '--no-unc', dest='unc', action='store_false', help='ignore uncertainties in constants') +parser.add_argument('-C', '--no-corr', dest='corr', action='store_false', help='ignore correlations between constants') +parser.add_argument('fr', metavar='from', type=str, help='unit or quantity to convert from') +parser.add_argument('to', type=str, nargs='?', help='unit to convert to') +args = parser.parse_args() + +ureg = UnitRegistry() +ureg.auto_reduce_dimensions = True +ureg.autoconvert_offset_to_baseunit = True +ureg.enable_contexts('Gau', 'ESU', 'sp', 'energy', 'boltzmann') +ureg.default_system = args.system + +if args.unc: + import uncertainties + # Measured constans subject to correlation + # R_i: Rydberg constant + # g_e: Electron g factor + # m_u: Atomic mass constant + # m_e: Electron mass + # m_p: Proton mass + # m_n: Neutron mass + R_i = (ureg._units['R_inf'].converter.scale, 0.0000000000021e7) + g_e = (ureg._units['g_e'].converter.scale, 0.00000000000035) + m_u = (ureg._units['m_u'].converter.scale, 0.00000000050e-27) + m_e = (ureg._units['m_e'].converter.scale, 0.00000000028e-30) + m_p = (ureg._units['m_p'].converter.scale, 0.00000000051e-27) + m_n = (ureg._units['m_n'].converter.scale, 0.00000000095e-27) + if args.corr: + # Correlation matrix between measured constants (to be completed below) + # R_i g_e m_u m_e m_p m_n + corr = [[ 1.0 , -0.00206, 0.00369, 0.00436, 0.00194, 0.00233], # R_i + [ -0.00206, 1.0 , 0.99029, 0.99490, 0.97560, 0.52445], # g_e + [ 0.00369, 0.99029, 1.0 , 0.99536, 0.98516, 0.52959], # m_u + [ 0.00436, 0.99490, 0.99536, 1.0 , 0.98058, 0.52714], # m_e + [ 0.00194, 0.97560, 0.98516, 0.98058, 1.0 , 0.51521], # m_p + [ 0.00233, 0.52445, 0.52959, 0.52714, 0.51521, 1.0 ]] # m_n + (R_i, g_e, m_u, m_e, m_p, m_n) = uncertainties.correlated_values_norm([R_i, g_e, m_u, m_e, m_p, m_n], corr) + else: + R_i = uncertainties.ufloat(*R_i) + g_e = uncertainties.ufloat(*g_e) + m_u = uncertainties.ufloat(*m_u) + m_e = uncertainties.ufloat(*m_e) + m_p = uncertainties.ufloat(*m_p) + m_n = uncertainties.ufloat(*m_n) + ureg._units['R_inf'].converter.scale = R_i + ureg._units['g_e'].converter.scale = g_e + ureg._units['m_u'].converter.scale = m_u + ureg._units['m_e'].converter.scale = m_e + ureg._units['m_p'].converter.scale = m_p + ureg._units['m_n'].converter.scale = m_n + + # Measured constants with zero correlation + ureg._units['gravitational_constant'].converter.scale = uncertainties.ufloat(ureg._units['gravitational_constant'].converter.scale, 0.00015e-11) + ureg._units['d_220'].converter.scale = uncertainties.ufloat(ureg._units['d_220'].converter.scale, 0.000000032e-10) + ureg._units['K_alpha_Cu_d_220'].converter.scale = uncertainties.ufloat(ureg._units['K_alpha_Cu_d_220'].converter.scale, 0.00000022) + ureg._units['K_alpha_Mo_d_220'].converter.scale = uncertainties.ufloat(ureg._units['K_alpha_Mo_d_220'].converter.scale, 0.00000019) + ureg._units['K_alpha_W_d_220'].converter.scale = uncertainties.ufloat(ureg._units['K_alpha_W_d_220'].converter.scale, 0.000000098) + + ureg._root_units_cache = dict() + ureg._build_cache() + +def convert(u_from, u_to=None, unc=None, factor=None): + q = ureg.Quantity(u_from) + fmt = '.{}g'.format(args.prec) + if unc: + q = q.plus_minus(unc) + if u_to: + nq = q.to(u_to) + else: + nq = q.to_base_units() + if (factor): + q *= ureg.Quantity(factor) + nq *= ureg.Quantity(factor).to_base_units() + prec_unc = use_unc(nq.magnitude, fmt, args.prec_unc) + if (prec_unc > 0): + fmt = '.{}uS'.format(prec_unc) + else: + try: + nq = nq.magnitude.n * nq.units + except: + pass + fmt = '{:' + fmt + '} {:~P}' + print(('{:} = ' + fmt).format(q, nq.magnitude, nq.units)) + +def use_unc(num, fmt, prec_unc): + unc = 0 + try: + if (isinstance(num, uncertainties.UFloat)): + full = ('{:'+fmt+'}').format(num) + unc = re.search(r'\+\/-[0.]*([\d.]*)', full).group(1) + unc = len(unc.replace('.', '')) + except: + pass + return max(0, min(prec_unc, unc)) + +convert(args.fr, args.to) diff --git a/setup.cfg b/setup.cfg index 83320c1..2777599 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,6 +30,7 @@ python_requires = >=3.6 install_requires = setuptools setup_requires = setuptools; setuptools_scm test_suite = pint.testsuite.testsuite +scripts = pint/pint-convert [options.extras_require] numpy = numpy >= 1.14 @@ -74,4 +75,4 @@ use_parentheses=True line_length=88 [zest.releaser] -python-file-with-version = version.py \ No newline at end of file +python-file-with-version = version.py -- cgit v1.2.1 From c9fb459cea94b20937105da463cd2f65d3837628 Mon Sep 17 00:00:00 2001 From: Jellby Date: Sun, 9 Feb 2020 21:46:12 +0100 Subject: Typo fix --- pint/pint-convert | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pint/pint-convert b/pint/pint-convert index d2540a3..ff17dec 100755 --- a/pint/pint-convert +++ b/pint/pint-convert @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ - pint_convert + pint-convert ~~~~~~~~~~~~ :copyright: 2020 by Pint Authors, see AUTHORS for more details. @@ -9,9 +9,10 @@ """ import argparse -from pint import UnitRegistry -import sys import re +import sys + +from pint import UnitRegistry parser = argparse.ArgumentParser(description='Unit converter.') parser.add_argument('-s', '--system', metavar='sys', default='SI', help='unit system to convert to (default: SI)') -- cgit v1.2.1 From 5c51692227fe81d595764a35e685a435d91253cf Mon Sep 17 00:00:00 2001 From: Jellby Date: Mon, 10 Feb 2020 20:12:33 +0100 Subject: Add pint-convert documentation --- README.rst | 10 +++++- docs/index.rst | 1 + docs/pint-convert.rst | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++ pint/pint-convert | 8 +++-- 4 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 docs/pint-convert.rst diff --git a/README.rst b/README.rst index f90ea45..97cda30 100644 --- a/README.rst +++ b/README.rst @@ -87,12 +87,20 @@ Documentation Full documentation is available at http://pint.readthedocs.org/ + GUI Website ----------- This Website_ wraps Pint's "dimensional analysis" methods to provide a GUI. +Command-line converter +---------------------- + +A command-line script `pint-convert` provides a quick way to convert between +units or get conversion factors. + + Design principles ----------------- @@ -158,4 +166,4 @@ see CHANGES_ .. _`Pandas Extension Types`: https://pandas.pydata.org/pandas-docs/stable/extending.html#extension-types .. _`pint-pandas Jupyter notebook`: https://github.com/hgrecco/pint-pandas/blob/master/notebooks/pandas_support.ipynb .. _`AUTHORS`: https://github.com/hgrecco/pint/blob/master/AUTHORS -.. _`CHANGES`: https://github.com/hgrecco/pint/blob/master/CHANGES \ No newline at end of file +.. _`CHANGES`: https://github.com/hgrecco/pint/blob/master/CHANGES diff --git a/docs/index.rst b/docs/index.rst index e72ed87..5d22dda 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -128,6 +128,7 @@ User Guide systems currencies pint-pandas.ipynb + pint-convert More information ---------------- diff --git a/docs/pint-convert.rst b/docs/pint-convert.rst new file mode 100644 index 0000000..8d548f8 --- /dev/null +++ b/docs/pint-convert.rst @@ -0,0 +1,91 @@ +.. _convert: + +Command-line script +=================== + +The script `pint-convert` allows a quick conversion to a target system or +between arbitrary compatible units. + +By default, `pint-convert` converts to SI units:: + + $ pint-convert 225lb + 225 pound = 102.05828325 kg + +use the `--sys` argument to change it:: + + $ pint-convert --sys US 102kg + 102 kilogram = 224.871507429 lb + +or specify directly the target units:: + + $ pint-convert 102kg lb + 102 kilogram = 224.871507429 lb + +The input quantity can contain expressions:: + + $ pint-convert 7ft+2in + 7.166666666666667 foot = 2.1844 m + +in some cases parentheses and quotes may be needed:: + + $ pint-convert "225lb/(7ft+2in)" + 31.3953488372093 pound / foot = 46.7214261353 kg/m + +If a number is omitted, 1 is assumed:: + + $ pint-convert km mi + 1 kilometer = 0.621371192237 mi + +The default precision is 12 significant figures, it can be changed with `-p`, +but note that the accuracy may be affected by floating-point errors:: + + $ pint-convert -p 3 mi + 1 mile = 1.61e+03 m + + $ pint-convert -p 30 ly km + 1 light_year = 9460730472580.80078125 km + +Some contexts are automatically enabled, allowing conversion between not fully +compatible units:: + + $ pint-convert 540nm + 540 nanometer = 5.4e-07 m + + $ pint-convert kcal/mol + $ 1.0 kilocalorie / mole = 4184 kg·m²/mol/s² + + $ pint-convert 540nm kcal/mol + 540 nanometer = 52.9471025594 kcal/mol + +With the `uncertainties` package, the experimental uncertainty in the physical +constants is considered, and the result is given in compact notation, with the +uncertainty in the last figures in parentheses:: + + $ pint-convert Eh eV + 1 hartree = 27.21138624599(5) eV + +The precision is limited by both the maximum number of significant digits (`-p`) +and the maximum number of uncertainty digits (`-u`, 2 by default):: + + $ pint-convert -p 20 Eh eV + 1 hartree = 27.211386245988(52) eV + + $ pint-convert -p 20 -u 4 Eh eV + 1 hartree = 27.21138624598847(5207) eV + +The uncertainty can be disabled with `-U`):: + + $ pint-convert -p 20 -U Eh eV + 1 hartree = 27.211386245988471444 eV + +Correlations between experimental constants are also known, and taken into +account. Use `-C` to disable it:: + + $ pint-convert --sys atomic m_p + 1 proton_mass = 1836.15267344(11) m_e + + $ pint-convert --sys atomic -C m_p + 1 proton_mass = 1836.15267344(79) m_e + +Again, note that results may differ slightly, usually in the last figure, from +more authoritative sources, mainly due to floating-point errors. diff --git a/pint/pint-convert b/pint/pint-convert index ff17dec..da7df23 100755 --- a/pint/pint-convert +++ b/pint/pint-convert @@ -14,7 +14,7 @@ import sys from pint import UnitRegistry -parser = argparse.ArgumentParser(description='Unit converter.') +parser = argparse.ArgumentParser(description='Unit converter.', usage=argparse.SUPPRESS) parser.add_argument('-s', '--system', metavar='sys', default='SI', help='unit system to convert to (default: SI)') parser.add_argument('-p', '--prec', metavar='n', type=int, default=12, help='number of maximum significant figures (default: 12)') parser.add_argument('-u', '--prec-unc', metavar='n', type=int, default=2, help='number of maximum uncertainty digits (default: 2)') @@ -22,7 +22,11 @@ parser.add_argument('-U', '--no-unc', dest='unc', action='store_false', help='ig parser.add_argument('-C', '--no-corr', dest='corr', action='store_false', help='ignore correlations between constants') parser.add_argument('fr', metavar='from', type=str, help='unit or quantity to convert from') parser.add_argument('to', type=str, nargs='?', help='unit to convert to') -args = parser.parse_args() +try: + args = parser.parse_args() +except SystemExit: + parser.print_help() + raise ureg = UnitRegistry() ureg.auto_reduce_dimensions = True -- cgit v1.2.1 From fa86d1af3cbb7904a53f08d4e0c08e4cec25519a Mon Sep 17 00:00:00 2001 From: Hernan Date: Tue, 11 Feb 2020 00:45:11 -0300 Subject: Make `__str__` and `__format__` locale aware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this commit, all string formatting operations are locale aware >>> ureg.set_fmt_locale('fr_FR') >>> str(accel) '1.3 mètre par seconde²' >>> "%s" % accel '1.3 mètre par seconde²' >>> "{}".format(accel) '1.3 mètre par seconde²' It should not break any code as the default locale value for the Registry is `None` (meaning do not localize). Close #984 --- CHANGES | 1 + docs/tutorial.rst | 19 ++++++++++++++++++- pint/quantity.py | 6 ++++++ pint/registry.py | 5 ++++- pint/testsuite/helpers.py | 4 ++++ pint/testsuite/test_babel.py | 35 +++++++++++++++++++++++++++++++++-- 6 files changed, 66 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 32b3a42..6273f36 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,7 @@ Pint Changelog 0.11 (unreleased) ----------------- +- Make `__str__` and `__format__` locale aware - Remove `default_en_0.6.txt` - Reorganize long_description. - Moved Pi to defintions files. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 9693444..ac9c2b3 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -419,10 +419,27 @@ Finally, if Babel_ is installed you can translate unit names to any language >>> accel.format_babel(locale='fr_FR') '1.3 mètre par seconde²' -You can also specify the format locale at u +You can also specify the format locale at the registry level either at creation: >>> ureg = UnitRegistry(fmt_locale='fr_FR') +or later: + +.. doctest:: + + >>> ureg.set_fmt_locale('fr_FR') + +and by doing that, string formatting is now localized: + +.. doctest:: + + >>> str(accel) + '1.3 mètre par seconde²' + >>> "%s" % accel + '1.3 mètre par seconde²' + >>> "{}".format(accel) + '1.3 mètre par seconde²' + Using Pint in your projects --------------------------- diff --git a/pint/quantity.py b/pint/quantity.py index 051fc84..faf9d34 100644 --- a/pint/quantity.py +++ b/pint/quantity.py @@ -252,6 +252,9 @@ class Quantity(PrettyIPython, SharedRegistryObject): return ret def __str__(self): + if self._REGISTRY.fmt_locale is not None: + return self.format_babel() + return format(self) def __bytes__(self): @@ -270,6 +273,9 @@ class Quantity(PrettyIPython, SharedRegistryObject): _exp_pattern = re.compile(r"([0-9]\.?[0-9]*)e(-?)\+?0*([0-9]+)") def __format__(self, spec): + if self._REGISTRY.fmt_locale is not None: + return self.format_babel(spec) + spec = spec or self.default_format if "L" in spec: diff --git a/pint/registry.py b/pint/registry.py index c42729f..3d43a70 100644 --- a/pint/registry.py +++ b/pint/registry.py @@ -172,6 +172,9 @@ class BaseRegistry(metaclass=RegistryMeta): #: type: Dict[str, (SourceIterator -> None)] _parsers = None + #: Babel.Locale instance or None + fmt_locale = None + #: List to be used in addition of units when dir(registry) is called. #: Also used for autocompletion in IPython. _dir = [ @@ -216,7 +219,7 @@ class BaseRegistry(metaclass=RegistryMeta): self.auto_reduce_dimensions = auto_reduce_dimensions #: Default locale identifier string, used when calling format_babel without explicit locale. - self.fmt_locale = self.set_fmt_locale(fmt_locale) + self.set_fmt_locale(fmt_locale) #: Map between name (string) and value (string) of defaults stored in the #: definitions file. diff --git a/pint/testsuite/helpers.py b/pint/testsuite/helpers.py index 5a91391..2bf743c 100644 --- a/pint/testsuite/helpers.py +++ b/pint/testsuite/helpers.py @@ -67,6 +67,10 @@ def requires_babel(): return unittest.skipUnless(HAS_BABEL, "Requires Babel with units support") +def requires_not_babel(): + return unittest.skipIf(HAS_BABEL, "Requires Babel is not installed") + + def requires_uncertainties(): return unittest.skipUnless(HAS_UNCERTAINTIES, "Requires Uncertainties") diff --git a/pint/testsuite/test_babel.py b/pint/testsuite/test_babel.py index 2aac0cd..def7c83 100644 --- a/pint/testsuite/test_babel.py +++ b/pint/testsuite/test_babel.py @@ -5,6 +5,14 @@ from pint.testsuite import BaseTestCase, helpers class TestBabel(BaseTestCase): + @helpers.requires_not_babel() + def test_no_babel(self): + ureg = UnitRegistry() + distance = 24.0 * ureg.meter + self.assertRaises( + Exception, distance.format_babel, locale="fr_FR", length="long" + ) + @helpers.requires_babel() def test_format(self): ureg = UnitRegistry() @@ -46,9 +54,32 @@ class TestBabel(BaseTestCase): mks = ureg.get_system("mks") self.assertEqual(mks.format_babel(locale="fr_FR"), "métrique") - def test_nobabel(self): + @helpers.requires_babel() + def test_no_registry_locale(self): ureg = UnitRegistry() distance = 24.0 * ureg.meter self.assertRaises( - Exception, distance.format_babel, locale="fr_FR", length="long" + Exception, distance.format_babel, ) + + @helpers.requires_babel() + def test_str(self): + ureg = UnitRegistry() + d = 24.0 * ureg.meter + + s = "24.0 meter" + self.assertEqual(str(d), s) + self.assertEqual("%s" % d, s) + self.assertEqual("{}".format(d), s) + + ureg.set_fmt_locale("fr_FR") + s = "24.0 mètres" + self.assertEqual(str(d), s) + self.assertEqual("%s" % d, s) + self.assertEqual("{}".format(d), s) + + ureg.set_fmt_locale(None) + s = "24.0 meter" + self.assertEqual(str(d), s) + self.assertEqual("%s" % d, s) + self.assertEqual("{}".format(d), s) -- cgit v1.2.1 From 39e5b49e219a0cb46c0662b6dd1488c7c99ef46e Mon Sep 17 00:00:00 2001 From: KOLANICH Date: Wed, 12 Feb 2020 18:59:27 +0300 Subject: Use setuptools_scm via pyproject.toml --- CHANGES | 1 + pyproject.toml | 5 +++++ setup.py | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 pyproject.toml diff --git a/CHANGES b/CHANGES index 32b3a42..2fb9e3a 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,7 @@ Pint Changelog 0.11 (unreleased) ----------------- +- Now we use `pyproject.toml` for providing `setuptools_scm` settings - Remove `default_en_0.6.txt` - Reorganize long_description. - Moved Pi to defintions files. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..771af68 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,5 @@ +[build-system] +requires = ["setuptools>=41", "wheel", "setuptools_scm[toml]>=3.4.3"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] diff --git a/setup.py b/setup.py index 57e6ccd..f4f9665 100644 --- a/setup.py +++ b/setup.py @@ -2,4 +2,4 @@ from setuptools import setup if __name__ == "__main__": - setup(use_scm_version=True) + setup() -- cgit v1.2.1 From 41bcb6358621c1684a560620d81b50277743953c Mon Sep 17 00:00:00 2001 From: Jon Thielen Date: Tue, 18 Feb 2020 12:30:45 -0600 Subject: Remove the array interface protocol fallback --- CHANGES | 3 +++ docs/numpy.ipynb | 9 ++------- pint/compat.py | 4 ---- pint/quantity.py | 30 +----------------------------- pint/testsuite/test_numpy.py | 13 ------------- 5 files changed, 6 insertions(+), 53 deletions(-) diff --git a/CHANGES b/CHANGES index 2fb9e3a..a4f5f4a 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ Pint Changelog 0.11 (unreleased) ----------------- +- **BREAKING CHANGE**: + The array protocol fallback deprecated in version 0.10 has been removed. + (Issue #1029, Thanks Jon Thielen) - Now we use `pyproject.toml` for providing `setuptools_scm` settings - Remove `default_en_0.6.txt` - Reorganize long_description. diff --git a/docs/numpy.ipynb b/docs/numpy.ipynb index 4ed462b..41b6491 100644 --- a/docs/numpy.ipynb +++ b/docs/numpy.ipynb @@ -24,10 +24,6 @@ "# Import NumPy\n", "import numpy as np\n", "\n", - "# Disable Pint's old fallback behavior (must come before importing Pint)\n", - "import os\n", - "os.environ['PINT_ARRAY_PROTOCOL_FALLBACK'] = \"0\"\n", - "\n", "# Import Pint\n", "import pint\n", "ureg = pint.UnitRegistry()\n", @@ -780,8 +776,7 @@ "\n", "This behaviour introduces some performance penalties and increased memory usage. Quantities that must be converted to other units require additional memory and CPU cycles. Therefore, for numerically intensive code, you might want to convert the objects first and then use directly the magnitude, such as by using Pint's `wraps` utility (see [wrapping](wrapping.rst)).\n", "\n", - "Array interface protocol attributes (such as `__array_struct__` and\n", - "`__array_interface__`) are available on Pint Quantities by deferring to the corresponding `__array_*` attribute on the magnitude as casted to an ndarray. This has been found to be potentially incorrect and to cause unexpected behavior, and has therefore been deprecated. As of the next minor version of Pint (or when the `PINT_ARRAY_PROTOCOL_FALLBACK` environment variable is set to 0 prior to importing Pint as done at the beginning of this page), attempting to access these attributes will instead raise an AttributeError." + "Attempting to access array interface protocol attributes (such as `__array_struct__` and `__array_interface__`) on Pint Quantities will raise an AttributeError, since a Quantity is meant to behave as a \"duck array,\" and not a pure ndarray." ] } ], @@ -801,7 +796,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.7" + "version": "3.7.6" } }, "nbformat": 4, diff --git a/pint/compat.py b/pint/compat.py index 6fb27ee..e6037b2 100644 --- a/pint/compat.py +++ b/pint/compat.py @@ -7,7 +7,6 @@ :copyright: 2013 by Pint Authors, see AUTHORS for more details. :license: BSD, see LICENSE for more details. """ -import os import tokenize from decimal import Decimal from io import BytesIO @@ -97,8 +96,6 @@ try: NP_NO_VALUE = np._NoValue - ARRAY_FALLBACK = bool(int(os.environ.get("PINT_ARRAY_PROTOCOL_FALLBACK", 1))) - except ImportError: np = None @@ -112,7 +109,6 @@ except ImportError: HAS_NUMPY_ARRAY_FUNCTION = False SKIP_ARRAY_FUNCTION_CHANGE_WARNING = True NP_NO_VALUE = None - ARRAY_FALLBACK = False def _to_magnitude(value, force_ndarray=False, force_ndarray_like=False): if force_ndarray or force_ndarray_like: diff --git a/pint/quantity.py b/pint/quantity.py index 051fc84..59b97d2 100644 --- a/pint/quantity.py +++ b/pint/quantity.py @@ -22,7 +22,6 @@ from pkg_resources.extern.packaging import version from .compat import SKIP_ARRAY_FUNCTION_CHANGE_WARNING # noqa: F401 from .compat import ( - ARRAY_FALLBACK, NUMPY_VER, BehaviorChangeWarning, _to_magnitude, @@ -1658,34 +1657,7 @@ class Quantity(PrettyIPython, SharedRegistryObject): def __getattr__(self, item): if item.startswith("__array_"): # Handle array protocol attributes other than `__array__` - if ARRAY_FALLBACK: - # Deprecated fallback behavior - warnings.warn( - ( - f"Array protocol attribute {item} accessed, with unit of the " - "Quantity being stripped. This attribute will become unavailable " - "in the next minor version of Pint. To make this potentially " - "incorrect attribute unavailable now, set the " - "PINT_ARRAY_PROTOCOL_FALLBACK environment variable to 0 before " - "importing Pint." - ), - DeprecationWarning, - stacklevel=2, - ) - - if is_duck_array_type(type(self._magnitude)): - # Defer to magnitude, and don't catch any AttributeErrors - return getattr(self._magnitude, item) - else: - # If an `__array_` attribute is requested but the magnitude is not - # a duck array, we convert the magnitude to a numpy ndarray. - magnitude_as_array = _to_magnitude( - self._magnitude, force_ndarray=True - ) - return getattr(magnitude_as_array, item) - else: - # TODO (next minor version): ARRAY_FALLBACK is removed and this becomes the standard behavior - raise AttributeError(f"Array protocol attribute {item} not available.") + raise AttributeError(f"Array protocol attribute {item} not available.") elif item in HANDLED_UFUNCS or item in self._wrapped_numpy_methods: magnitude_as_duck_array = _to_magnitude( self._magnitude, force_ndarray_like=True diff --git a/pint/testsuite/test_numpy.py b/pint/testsuite/test_numpy.py index 595aa3f..05aea96 100644 --- a/pint/testsuite/test_numpy.py +++ b/pint/testsuite/test_numpy.py @@ -1031,28 +1031,15 @@ class TestNumpyUnclassified(TestNumpyMethods): np.array([[1, 0, 2], [3, 0, 4]]) * self.ureg.m, ) - @patch("pint.quantity.ARRAY_FALLBACK", False) def test_ndarray_downcast(self): with self.assertWarns(UnitStrippedWarning): np.asarray(self.q) - @patch("pint.quantity.ARRAY_FALLBACK", False) def test_ndarray_downcast_with_dtype(self): with self.assertWarns(UnitStrippedWarning): qarr = np.asarray(self.q, dtype=np.float64) self.assertEqual(qarr.dtype, np.float64) - def test_array_protocol_fallback(self): - with self.assertWarns(DeprecationWarning) as cm: - for attr in ("__array_struct__", "__array_interface__"): - getattr(self.q, attr) - warning_text = str(cm.warnings[0].message) - self.assertTrue( - f"unit of the Quantity being stripped" in warning_text - and "will become unavailable" in warning_text - ) - - @patch("pint.quantity.ARRAY_FALLBACK", False) def test_array_protocol_unavailable(self): for attr in ("__array_struct__", "__array_interface__"): self.assertRaises(AttributeError, getattr, self.q, attr) -- cgit v1.2.1 From e82b9b059ddf30739b362b6a233e832c3d3eddb5 Mon Sep 17 00:00:00 2001 From: Jon Thielen Date: Tue, 18 Feb 2020 13:57:39 -0600 Subject: Remove array function warning on first creation --- CHANGES | 3 +++ pint/compat.py | 23 ----------------------- pint/quantity.py | 11 ----------- pint/testsuite/test_numpy.py | 1 - pint/testsuite/test_quantity.py | 9 +++------ 5 files changed, 6 insertions(+), 41 deletions(-) diff --git a/CHANGES b/CHANGES index a4f5f4a..933afc4 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ Pint Changelog 0.11 (unreleased) ----------------- +- Quantities wrapping NumPy arrays will no longer warning for the changed + array function behavior introduced in 0.10. + (Issue #1029, Thanks Jon Thielen) - **BREAKING CHANGE**: The array protocol fallback deprecated in version 0.10 has been removed. (Issue #1029, Thanks Jon Thielen) diff --git a/pint/compat.py b/pint/compat.py index e6037b2..e8e1a1b 100644 --- a/pint/compat.py +++ b/pint/compat.py @@ -36,27 +36,6 @@ class BehaviorChangeWarning(UserWarning): pass -array_function_change_msg = """The way Pint handles NumPy operations has changed with the -implementation of NEP 18. Unimplemented NumPy operations will now fail instead of making -assumptions about units. Some functions, eg concat, will now return Quanties with units, where -they returned ndarrays previously. See https://github.com/hgrecco/pint/pull/905. - -To hide this warning, wrap your first creation of an array Quantity with -warnings.catch_warnings(), like the following: - -import numpy as np -import warnings -from pint import Quantity - -with warnings.catch_warnings(): - warnings.simplefilter("ignore") - Quantity([]) - -To disable the new behavior, see -https://www.numpy.org/neps/nep-0018-array-function-protocol.html#implementation -""" - - try: import numpy as np from numpy import ndarray @@ -92,7 +71,6 @@ try: return False HAS_NUMPY_ARRAY_FUNCTION = _test_array_function_protocol() - SKIP_ARRAY_FUNCTION_CHANGE_WARNING = not HAS_NUMPY_ARRAY_FUNCTION NP_NO_VALUE = np._NoValue @@ -107,7 +85,6 @@ except ImportError: NUMPY_VER = "0" NUMERIC_TYPES = (Number, Decimal) HAS_NUMPY_ARRAY_FUNCTION = False - SKIP_ARRAY_FUNCTION_CHANGE_WARNING = True NP_NO_VALUE = None def _to_magnitude(value, force_ndarray=False, force_ndarray_like=False): diff --git a/pint/quantity.py b/pint/quantity.py index 59b97d2..91eee2a 100644 --- a/pint/quantity.py +++ b/pint/quantity.py @@ -20,12 +20,9 @@ import warnings from pkg_resources.extern.packaging import version -from .compat import SKIP_ARRAY_FUNCTION_CHANGE_WARNING # noqa: F401 from .compat import ( NUMPY_VER, - BehaviorChangeWarning, _to_magnitude, - array_function_change_msg, babel_parse, eq, is_duck_array_type, @@ -160,8 +157,6 @@ class Quantity(PrettyIPython, SharedRegistryObject): return _unpickle, (Quantity, self.magnitude, self._units) def __new__(cls, value, units=None): - global SKIP_ARRAY_FUNCTION_CHANGE_WARNING - if is_upcast_type(type(value)): raise TypeError(f"Quantity cannot wrap upcast type {type(value)}") elif units is None: @@ -214,12 +209,6 @@ class Quantity(PrettyIPython, SharedRegistryObject): inst.__used = False inst.__handling = None - if not SKIP_ARRAY_FUNCTION_CHANGE_WARNING and isinstance( - inst._magnitude, ndarray - ): - warnings.warn(array_function_change_msg, BehaviorChangeWarning) - SKIP_ARRAY_FUNCTION_CHANGE_WARNING = True - return inst @property diff --git a/pint/testsuite/test_numpy.py b/pint/testsuite/test_numpy.py index 05aea96..3eeab6c 100644 --- a/pint/testsuite/test_numpy.py +++ b/pint/testsuite/test_numpy.py @@ -1,7 +1,6 @@ import copy import operator as op import unittest -from unittest.mock import patch from pint import DimensionalityError, OffsetUnitCalculusError, UnitStrippedWarning from pint.compat import np diff --git a/pint/testsuite/test_quantity.py b/pint/testsuite/test_quantity.py index fbfd773..51faf1a 100644 --- a/pint/testsuite/test_quantity.py +++ b/pint/testsuite/test_quantity.py @@ -6,7 +6,7 @@ import warnings from unittest.mock import patch from pint import DimensionalityError, OffsetUnitCalculusError, UnitRegistry -from pint.compat import BehaviorChangeWarning, np +from pint.compat import np from pint.testsuite import QuantityTestCase, helpers from pint.testsuite.parameterized import ParameterizedTestCase from pint.unit import UnitsContainer @@ -531,11 +531,8 @@ class TestQuantity(QuantityTestCase): iter(x) @helpers.requires_array_function_protocol() - @patch("pint.quantity.SKIP_ARRAY_FUNCTION_CHANGE_WARNING", False) - def test_array_function_warning_on_creation(self): - # Test that warning is raised on first creation, but not second - with self.assertWarns(BehaviorChangeWarning): - self.Q_([]) + def test_no_longer_array_function_warning_on_creation(self): + # Test that warning is no longer raised on first creation with warnings.catch_warnings(): warnings.filterwarnings("error") self.Q_([]) -- cgit v1.2.1 From 0b3e73694a4cc19184173589750d8184df766e81 Mon Sep 17 00:00:00 2001 From: Hernan Date: Wed, 19 Feb 2020 13:52:53 -0300 Subject: Rename `ParsedDefinition` to `PreprocessedDefinition` Close #1010 --- pint/definitions.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pint/definitions.py b/pint/definitions.py index 8ffa153..5dfc0ea 100644 --- a/pint/definitions.py +++ b/pint/definitions.py @@ -15,8 +15,8 @@ from .errors import DefinitionSyntaxError from .util import ParserHelper, UnitsContainer, _is_dim -class ParsedDefinition( - namedtuple("ParsedDefinition", "name symbol aliases value rhs_parts") +class PreprocessedDefinition( + namedtuple("PreprocessedDefinition", "name symbol aliases value rhs_parts") ): """Splits a definition into the constitutive parts. @@ -125,7 +125,7 @@ class Definition: Parameters ---------- - definition : str or ParsedDefinition + definition : str or PreprocessedDefinition Returns ------- @@ -133,7 +133,7 @@ class Definition: """ if isinstance(definition, str): - definition = ParsedDefinition.from_string(definition) + definition = PreprocessedDefinition.from_string(definition) if definition.name.startswith("@alias "): return AliasDefinition.from_string(definition) @@ -184,7 +184,7 @@ class PrefixDefinition(Definition): @classmethod def from_string(cls, definition): if isinstance(definition, str): - definition = ParsedDefinition.from_string(definition) + definition = PreprocessedDefinition.from_string(definition) aliases = tuple(alias.strip("-") for alias in definition.aliases) if definition.symbol: @@ -228,7 +228,7 @@ class UnitDefinition(Definition): @classmethod def from_string(cls, definition): if isinstance(definition, str): - definition = ParsedDefinition.from_string(definition) + definition = PreprocessedDefinition.from_string(definition) if ";" in definition.value: [converter, modifiers] = definition.value.split(";", 2) @@ -294,7 +294,7 @@ class DimensionDefinition(Definition): @classmethod def from_string(cls, definition): if isinstance(definition, str): - definition = ParsedDefinition.from_string(definition) + definition = PreprocessedDefinition.from_string(definition) converter = ParserHelper.from_string(definition.value) @@ -336,7 +336,7 @@ class AliasDefinition(Definition): def from_string(cls, definition): if isinstance(definition, str): - definition = ParsedDefinition.from_string(definition) + definition = PreprocessedDefinition.from_string(definition) name = definition.name[len("@alias ") :].lstrip() return AliasDefinition(name, tuple(definition.rhs_parts)) -- cgit v1.2.1 From 80c412610ff9b587a9fd28d554fa9bbba52e4940 Mon Sep 17 00:00:00 2001 From: Hernan Date: Wed, 19 Feb 2020 19:41:25 -0300 Subject: Include .coveragerc --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 0cf6865..cd897ad 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include AUTHORS CHANGES LICENSE README.rst BADGES.rst version.txt readthedocs.yml +include AUTHORS CHANGES LICENSE README.rst BADGES.rst version.txt readthedocs.yml .coveragerc recursive-include pint * recursive-include docs * recursive-include bench * -- cgit v1.2.1 From 3d713cf920c1f164c1c3c2fcfab96956467b0d64 Mon Sep 17 00:00:00 2001 From: Hernan Date: Wed, 19 Feb 2020 19:41:53 -0300 Subject: Preparing release 0.11 --- CHANGES | 2 +- version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index c823d74..3b4df2a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,7 @@ Pint Changelog ============== -0.11 (unreleased) +0.11 (2020-02-19) ----------------- - Added pint-convert script. diff --git a/version.py b/version.py index 17a86c7..b9d3d60 100644 --- a/version.py +++ b/version.py @@ -2,5 +2,5 @@ # flake8: noqa # fmt: off -__version__ = '0.11.dev0' +__version__ = '0.11' # fmt: on -- cgit v1.2.1 From a0465dc5eebb64f13897294860f4b56bbade1321 Mon Sep 17 00:00:00 2001 From: Hernan Date: Wed, 19 Feb 2020 19:42:20 -0300 Subject: Back to development: 0.12 --- CHANGES | 6 ++++++ version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 3b4df2a..8e9c715 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,12 @@ Pint Changelog ============== +0.12 (unreleased) +----------------- + +- Nothing changed yet. + + 0.11 (2020-02-19) ----------------- diff --git a/version.py b/version.py index b9d3d60..16c455f 100644 --- a/version.py +++ b/version.py @@ -2,5 +2,5 @@ # flake8: noqa # fmt: off -__version__ = '0.11' +__version__ = '0.12.dev0' # fmt: on -- cgit v1.2.1 From 5b7d1d27660c04c268e454d3ff530d170e0a2048 Mon Sep 17 00:00:00 2001 From: mark-boer Date: Fri, 21 Feb 2020 16:24:53 +0100 Subject: fix for key error in numpy.pad --- CHANGES | 4 +++- pint/numpy_func.py | 7 +++---- pint/testsuite/test_numpy.py | 7 +++++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 2fb9e3a..65fd3bc 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,8 @@ Pint Changelog - Allow constants in units by using a leading underscore (Issue #989, Thanks Juan Nunez-Iglesias) - Fixed bug where to_compact handled prefix units incorrectly (Issue #960) +- Fixed bug where numpy.pad didn't work without specifying constant_values or + end_values (Issue #1026) 0.10.1 (2020-01-07) ------------------- @@ -235,7 +237,7 @@ Pint Changelog - Added several new units and Systems (Issues #749, #737, ) - Started experimental pandas support - (Issue #746 and others. Thanks andrewgsavage, znicholls and others) + (Issue #746 and others. Thanks andrewgsavage, znicholls and others) - wraps and checks now supports kwargs and defaults. (Issue #660, thanks jondoesntgit) diff --git a/pint/numpy_func.py b/pint/numpy_func.py index 10f4114..c03887b 100644 --- a/pint/numpy_func.py +++ b/pint/numpy_func.py @@ -667,10 +667,9 @@ def _pad(array, pad_width, mode="constant", **kwargs): # Handle flexible constant_values and end_values, converting to units if Quantity # and ignoring if not - if mode == "constant": - kwargs["constant_values"] = _recursive_convert(kwargs["constant_values"], units) - elif mode == "linear_ramp": - kwargs["end_values"] = _recursive_convert(kwargs["end_values"], units) + for key in ("constant_values", "end_values"): + if key in kwargs: + kwargs[key] = _recursive_convert(kwargs[key], units) return units._REGISTRY.Quantity( np.pad(array._magnitude, pad_width, mode=mode, **kwargs), units diff --git a/pint/testsuite/test_numpy.py b/pint/testsuite/test_numpy.py index 595aa3f..6775e75 100644 --- a/pint/testsuite/test_numpy.py +++ b/pint/testsuite/test_numpy.py @@ -1069,6 +1069,9 @@ class TestNumpyUnclassified(TestNumpyMethods): a = [1, 2, 3, 4, 5] * self.ureg.m b = self.Q_([4.0, 6.0, 8.0, 9.0, -3.0], "degC") + self.assertQuantityEqual( + np.pad(a, (2, 3), "constant"), [0, 0, 1, 2, 3, 4, 5, 0, 0, 0] * self.ureg.m, + ) self.assertQuantityEqual( np.pad(a, (2, 3), "constant", constant_values=(0, 600 * self.ureg.cm)), [0, 0, 1, 2, 3, 4, 5, 6, 6, 6] * self.ureg.m, @@ -1085,6 +1088,10 @@ class TestNumpyUnclassified(TestNumpyMethods): self.assertQuantityEqual( np.pad(a, (2, 3), "edge"), [1, 1, 1, 2, 3, 4, 5, 5, 5, 5] * self.ureg.m ) + self.assertQuantityEqual( + np.pad(a, (2, 3), "linear_ramp"), + [0, 0, 1, 2, 3, 4, 5, 3, 1, 0] * self.ureg.m, + ) self.assertQuantityEqual( np.pad(a, (2, 3), "linear_ramp", end_values=(5, -4) * self.ureg.m), [5, 3, 1, 2, 3, 4, 5, 2, -1, -4] * self.ureg.m, -- cgit v1.2.1