Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-Pint for openSUSE:Factory 
checked in at 2021-01-26 14:46:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Pint (Old)
 and      /work/SRC/openSUSE:Factory/.python-Pint.new.28504 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-Pint"

Tue Jan 26 14:46:04 2021 rev:11 rq:865060 version:0.16.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-Pint/python-Pint.changes  2020-09-21 
17:34:09.632489274 +0200
+++ /work/SRC/openSUSE:Factory/.python-Pint.new.28504/python-Pint.changes       
2021-01-26 14:49:48.155681927 +0100
@@ -1,0 +2,25 @@
+Wed Jan 20 16:54:45 UTC 2021 - John Vandenberg <jay...@gmail.com>
+
+- Use %python_alternative to fix multi Python 3 builds
+
+-------------------------------------------------------------------
+Sat Oct 10 19:19:46 UTC 2020 - Arun Persaud <a...@gmx.de>
+
+- update to version 0.16.1:
+  * Fix unpickling, now it is using the APP_REGISTRY as expected.
+    (Issue #1175)
+  * require importlib-[resources|metadata]
+
+- changes from version 0.16 :
+  * Fixed issue where performing an operation of a Quantity with
+    certain units would perform an in-place unit conversion that
+    modified the operand in addition to the returned value (Issues
+    #1102 & #1144)
+  * Implements Logarithmic Units like dBm, dB or decade (Issue #71,
+    Thanks Dima Pustakhod, Clark Willison, Giorgio Signorello, Steven
+    Casagrande, Jonathan Wheeler)
+  * Drop dependency on setuptools pkg_resources to read package
+    resources, using std lib importlib.resources instead.  (Issue
+    #1080)
+
+-------------------------------------------------------------------

Old:
----
  Pint-0.15.tar.gz

New:
----
  Pint-0.16.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-Pint.spec ++++++
--- /var/tmp/diff_new_pack.JU4gFo/_old  2021-01-26 14:49:48.767682762 +0100
+++ /var/tmp/diff_new_pack.JU4gFo/_new  2021-01-26 14:49:48.771682767 +0100
@@ -19,23 +19,25 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define         skip_python2 1
 Name:           python-Pint
-Version:        0.15
+Version:        0.16.1
 Release:        0
 Summary:        Physical quantities module
 License:        BSD-3-Clause
 URL:            https://github.com/hgrecco/pint
 Source:         
https://files.pythonhosted.org/packages/source/P/Pint/Pint-%{version}.tar.gz
+BuildRequires:  %{python_module importlib-metadata}
+BuildRequires:  %{python_module importlib-resources}
 BuildRequires:  %{python_module setuptools_scm}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-importlib-metadata
+Requires:       python-importlib-resources
 Requires:       python-packaging
 Requires:       python-uncertainties >= 3.0
 Recommends:     python-numpy
 BuildArch:      noarch
 # SECTION test requirements
-BuildRequires:  %{python_module importlib-metadata}
 BuildRequires:  %{python_module numpy}
 BuildRequires:  %{python_module packaging}
 BuildRequires:  %{python_module pytest >= 4.0}
@@ -61,6 +63,7 @@
 
 %install
 %python_install
+%python_clone -a %{buildroot}%{_bindir}/pint-convert
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
@@ -68,10 +71,16 @@
 # See: https://github.com/hgrecco/pint/issues/1006
 %pytest -k 'not test_result_type_numpy_func'
 
+%post
+%python_install_alternative pint-convert
+
+%postun
+%python_uninstall_alternative pint-convert
+
 %files %{python_files}
 %license LICENSE
 %doc AUTHORS CHANGES README.rst
-%{_bindir}/pint-convert
+%python_alternative %{_bindir}/pint-convert
 %{python_sitelib}/Pint-0*-py*.egg-info
 %{python_sitelib}/pint/
 

++++++ Pint-0.15.tar.gz -> Pint-0.16.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/.gitignore new/Pint-0.16.1/.gitignore
--- old/Pint-0.15/.gitignore    2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/.gitignore  2020-09-22 05:12:30.000000000 +0200
@@ -12,6 +12,7 @@
 *pytest_cache*
 .eggs
 .mypy_cache
+pip-wheel-metadata
 
 # WebDAV file system cache files
 .DAV/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/.readthedocs.yml 
new/Pint-0.16.1/.readthedocs.yml
--- old/Pint-0.15/.readthedocs.yml      1970-01-01 01:00:00.000000000 +0100
+++ new/Pint-0.16.1/.readthedocs.yml    2020-09-22 05:12:30.000000000 +0200
@@ -0,0 +1,12 @@
+version: 2
+build:
+  image: latest
+sphinx:
+  configuration: docs/conf.py
+  fail_on_warning: false
+python:
+   version: 3.7
+   install:
+     - requirements: requirements_docs.txt
+     - method: pip
+       path: .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/.travis.yml new/Pint-0.16.1/.travis.yml
--- old/Pint-0.15/.travis.yml   2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/.travis.yml 2020-09-22 05:12:30.000000000 +0200
@@ -15,7 +15,7 @@
   # Refer to history of 
https://github.com/lebigot/uncertainties/blob/master/setup.py
   # for min/max Python versions supported by uncertainties
 
-  - PKGS="python=3.7 flake8 black isort"  # Have linters fail first and quickly
+  - PKGS="python=3.7 flake8 black==19.10b0 isort"  # Have linters fail first 
and quickly
   # Pinned packages to match readthedocs CI 
https://readthedocs.org/projects/pint/
   - PKGS="python=3.7 ipython matplotlib nbsphinx numpy pandas jupyter_client 
ipykernel python-graphviz graphviz xarray sparse dask[complete] sphinx 
Pygments==2.3.1 docutils==0.14 alabaster commonmark==0.8.1 recommonmark==0.5.0"
   - PKGS="python=3.6"
@@ -65,6 +65,7 @@
   # this is superslow but suck it up until updates to pandas are made
   # - if [[ $PANDAS == '1' ]]; then pip install numpy cython pytest pytest-cov 
nbval; pip install 
git+https://github.com/pandas-dev/pandas.git@bdb7a1603f1e0948ca0cab011987f616e7296167;
 python -c 'import pandas; print(pandas.__version__)'; fi
   - conda list
+  - pip install .
 
 script:
   # if we're doing the pandas tests and hence have pytest available, we can
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/CHANGES new/Pint-0.16.1/CHANGES
--- old/Pint-0.15/CHANGES       2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/CHANGES     2020-09-22 05:12:30.000000000 +0200
@@ -1,6 +1,23 @@
 Pint Changelog
 ==============
 
+0.16.1 (2020-09-22)
+-------------------
+
+- Fix unpickling, now it is using the APP_REGISTRY as expected.
+  (Issue #1175)
+
+0.16 (2020-09-13)
+-----------------
+
+- Fixed issue where performing an operation of a Quantity with certain units 
would perform an in-place
+  unit conversion that modified the operand in addition to the returned value 
(Issues #1102 & #1144)
+- Implements Logarithmic Units like dBm, dB or decade
+  (Issue #71, Thanks Dima Pustakhod, Clark Willison, Giorgio Signorello, 
Steven Casagrande, Jonathan Wheeler)
+- Drop dependency on setuptools pkg_resources to read package resources, using 
std lib importlib.resources instead.
+  (Issue #1080)
+
+
 0.15 (2020-08-22)
 -----------------
 
@@ -16,6 +33,8 @@
 - Fixed right operand power for dimensionless Quantity to reflect numpy 
behavior. (Issue #1136)
 - Eliminated warning when setting a masked value on an underlying MaskedArray.
 - Add `sort` option to `formatting.formatter` to permit disabling sorting of 
component units in format string
+- Implements Logarithmic Units like dBm, dB or decade
+  (Issue #71, Thanks Dima Pustakhod, Giorgio Signorello, Jonathan Wheeler)
 
 
 0.14 (2020-07-01)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/MANIFEST.in new/Pint-0.16.1/MANIFEST.in
--- old/Pint-0.15/MANIFEST.in   2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/MANIFEST.in 2020-09-22 05:12:30.000000000 +0200
@@ -1,4 +1,4 @@
-include AUTHORS CHANGES LICENSE README.rst BADGES.rst version.txt 
readthedocs.yml .coveragerc
+include AUTHORS CHANGES LICENSE README.rst BADGES.rst version.txt .coveragerc 
.readthedocs.yml
 recursive-include pint *
 recursive-include docs *
 recursive-include bench *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/PKG-INFO new/Pint-0.16.1/PKG-INFO
--- old/Pint-0.15/PKG-INFO      2020-08-22 21:22:44.000000000 +0200
+++ new/Pint-0.16.1/PKG-INFO    2020-09-22 05:12:31.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: Pint
-Version: 0.15
+Version: 0.16.1
 Summary: Physical quantities module
 Home-page: https://github.com/hgrecco/pint
 Author: Hernan E. Grecco
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/Pint.egg-info/PKG-INFO 
new/Pint-0.16.1/Pint.egg-info/PKG-INFO
--- old/Pint-0.15/Pint.egg-info/PKG-INFO        2020-08-22 21:22:43.000000000 
+0200
+++ new/Pint-0.16.1/Pint.egg-info/PKG-INFO      2020-09-22 05:12:31.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: Pint
-Version: 0.15
+Version: 0.16.1
 Summary: Physical quantities module
 Home-page: https://github.com/hgrecco/pint
 Author: Hernan E. Grecco
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/Pint.egg-info/SOURCES.txt 
new/Pint-0.16.1/Pint.egg-info/SOURCES.txt
--- old/Pint-0.15/Pint.egg-info/SOURCES.txt     2020-08-22 21:22:43.000000000 
+0200
+++ new/Pint-0.16.1/Pint.egg-info/SOURCES.txt   2020-09-22 05:12:31.000000000 
+0200
@@ -1,5 +1,6 @@
 .coveragerc
 .gitignore
+.readthedocs.yml
 .travis.yml
 AUTHORS
 BADGES.rst
@@ -8,7 +9,6 @@
 MANIFEST.in
 README.rst
 pyproject.toml
-readthedocs.yml
 setup.cfg
 setup.py
 Pint.egg-info/PKG-INFO
@@ -31,6 +31,7 @@
 docs/faq.rst
 docs/getting.rst
 docs/index.rst
+docs/log_units.rst
 docs/make.bat
 docs/measurement.rst
 docs/nonmult.rst
@@ -94,6 +95,7 @@
 pint/testsuite/test_formatter.py
 pint/testsuite/test_infer_base_unit.py
 pint/testsuite/test_issues.py
+pint/testsuite/test_log_units.py
 pint/testsuite/test_matplotlib.py
 pint/testsuite/test_measurement.py
 pint/testsuite/test_non_int.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/Pint.egg-info/requires.txt 
new/Pint-0.16.1/Pint.egg-info/requires.txt
--- old/Pint-0.15/Pint.egg-info/requires.txt    2020-08-22 21:22:43.000000000 
+0200
+++ new/Pint-0.16.1/Pint.egg-info/requires.txt  2020-09-22 05:12:31.000000000 
+0200
@@ -1,6 +1,8 @@
-setuptools
 packaging
 
+[:python_version < "3.7"]
+importlib-resources
+
 [:python_version < "3.8"]
 importlib-metadata
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/docs/index.rst 
new/Pint-0.16.1/docs/index.rst
--- old/Pint-0.15/docs/index.rst        2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/docs/index.rst      2020-09-22 05:12:30.000000000 +0200
@@ -122,6 +122,7 @@
     defining-quantities
     numpy
     nonmult
+    log_units
     wrapping
     plotting
     serialization
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/docs/log_units.rst 
new/Pint-0.16.1/docs/log_units.rst
--- old/Pint-0.15/docs/log_units.rst    1970-01-01 01:00:00.000000000 +0100
+++ new/Pint-0.16.1/docs/log_units.rst  2020-09-22 05:12:30.000000000 +0200
@@ -0,0 +1,127 @@
+.. _log_units:
+
+
+Logarithmic Units
+=================
+
+.. warning::
+
+    Support for logarithmic units in Pint is currently in Beta. Please take
+    careful note of the information below, particularly around `compound log 
units`_
+    to avoid calculation errors. Bug reports and pull requests are always
+    welcome, please see :doc:`contributing` for more information on
+    how you can help improve this feature (and Pint in general).
+
+Pint supports some logarithmic units, including `dB`, `dBm`, `octave`, and 
`decade`
+as well as some conversions between them and their base units where applicable.
+These units behave much like those described in :ref:`nonmult`, so many of
+the recommendations there apply here as well.
+
+Setting up the ``UnitRegistry()``
+---------------------------------
+
+Many of the examples below will fail without supplying the
+``autoconvert_offset_to_baseunit=True`` flag. To use logarithmic units,
+intialize your ``UnitRegistry()`` like so:
+
+.. doctest::
+
+    >>> from pint import UnitRegistry
+    >>> ureg = UnitRegistry(autoconvert_offset_to_baseunit=True)
+    >>> Q_ = ureg.Quantity
+
+If you can't pass that flag you will need to define all logarithmic units
+:ref:`using the Quantity() constructor<Using the constructor>`, and you will
+be restricted in the kinds of operations you can do without explicitly calling
+`.to_base_units()` first.
+
+Defining log quantities
+-----------------------
+
+After you've set up your ``UnitRegistry()`` with the ``autoconvert...`` flag,
+you can define simple logarithmic quantities like most others:
+
+.. doctest::
+
+    >>> 20.0 * ureg.dBm
+    <Quantity(20.0, 'decibelmilliwatt')>
+    >>> ureg('20.0 dBm')
+    <Quantity(20.0, 'decibelmilliwatt')>
+    >>> ureg('20 dB')
+    <Quantity(20, 'decibel')>
+
+
+Converting to and from base units
+---------------------------------
+
+Get a sense of how logarithmic units are handled by using the `.to()` and
+`.to_base_units()` methods:
+
+.. doctest::
+
+    >>> ureg('20 dBm').to('mW')
+    <Quantity(100.0, 'milliwatt')>
+    >>> ureg('20 dB').to_base_units()
+    <Quantity(100.0, 'dimensionless')>
+
+.. note::
+
+    Notice in the above example how the `dB` unit is defined for
+    power quantities (10*log(p/p0)) not field (amplitude) quantities
+    (20*log(v/v0)). Take care that you're only using it to multiply power
+    levels, and not e.g. Voltages.
+
+Convert back from a base unit to a logarithmic unit using the `.to()` method:
+
+.. doctest::
+
+    >>> (100.0 * ureg('mW')).to('dBm')
+    <Quantity(20.0, 'decibelmilliwatt')>
+    >>> shift = Q_(4, '')
+    >>> shift
+    <Quantity(4, 'dimensionless')>
+    >>> shift.to('octave')
+    <Quantity(2.0, 'octave')>
+
+Compound log units
+------------------
+
+.. warning::
+
+    Support for compound logarithmic units is not comprehensive. The following
+    examples work, but many others will not. Consider converting the 
logarithmic
+    portion to base units before adding more units.
+
+Pint sometimes works with mixtures of logarithmic and other units. Below is an
+example of computing RMS noise from a noise density and a bandwidth:
+
+.. doctest::
+
+    >>> noise_density = -161.0 * ureg.dBm / ureg.Hz
+    >>> bandwidth = 10.0 * ureg.kHz
+    >>> noise_power = noise_density * bandwidth
+    >>> noise_power.to('dBm')
+    <Quantity(-121.0, 'decibelmilliwatt')>
+    >>> noise_power.to('mW')
+    <Quantity(7.94328235e-13, 'milliwatt')>
+
+There are still issues with parsing compound units, so for now the following
+will not work:
+
+.. doctest::
+
+    >>> -161.0 * ureg('dBm/Hz') == (-161.0 * ureg.dBm / ureg.Hz)
+    False
+
+But this will:
+
+.. doctest::
+
+    >>> ureg('-161.0 dBm/Hz') == (-161.0 * ureg.dBm / ureg.Hz)
+    True
+    >>> Q_(-161.0, 'dBm') / ureg.Hz == (-161.0 * ureg.dBm / ureg.Hz)
+    True
+
+To begin using this feature while avoiding problems, define logarithmic units
+as single-unit quantities and convert them to their base units as quickly as
+possible.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/docs/tutorial.rst 
new/Pint-0.16.1/docs/tutorial.rst
--- old/Pint-0.15/docs/tutorial.rst     2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/docs/tutorial.rst   2020-09-22 05:12:30.000000000 +0200
@@ -431,7 +431,7 @@
 The best way to do this is by instantiating the registry in a single place. For
 example, you can add the following code to your package ``__init__.py``
 
-.. code-block::
+.. code-block:: python
 
    from pint import UnitRegistry
    ureg = UnitRegistry()
@@ -440,7 +440,7 @@
 
 Then in ``yourmodule.py`` the code would be
 
-.. code-block::
+.. code-block:: python
 
    from . import ureg, Q_
 
@@ -450,7 +450,7 @@
 If you are pickling and unplicking Quantities within your project, you should
 also define the registry as the application registry
 
-.. code-block::
+.. code-block:: python
 
    from pint import UnitRegistry, set_application_registry
    ureg = UnitRegistry()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/__init__.py 
new/Pint-0.16.1/pint/__init__.py
--- old/Pint-0.15/pint/__init__.py      2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/__init__.py    2020-09-22 05:12:30.000000000 +0200
@@ -14,9 +14,10 @@
 import sys
 
 from .context import Context
-from .errors import (
+from .errors import (  # noqa: F401
     DefinitionSyntaxError,
     DimensionalityError,
+    LogarithmicUnitCalculusError,
     OffsetUnitCalculusError,
     RedefinitionError,
     UndefinedUnitError,
@@ -88,6 +89,24 @@
     return cls(*args)
 
 
+def _unpickle_quantity(cls, *args):
+    """Rebuild quantity upon unpickling using the application registry.
+    """
+    return _unpickle(_APP_REGISTRY.Quantity, *args)
+
+
+def _unpickle_unit(cls, *args):
+    """Rebuild unit upon unpickling using the application registry.
+    """
+    return _unpickle(_APP_REGISTRY.Unit, *args)
+
+
+def _unpickle_measurement(cls, *args):
+    """Rebuild measurement upon unpickling using the application registry.
+    """
+    return _unpickle(_APP_REGISTRY.Measurement, *args)
+
+
 def set_application_registry(registry):
     """Set the application registry, which is used for unpickling operations
     and when invoking pint.Quantity or pint.Unit directly.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/compat.py 
new/Pint-0.16.1/pint/compat.py
--- old/Pint-0.15/pint/compat.py        2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/compat.py      2020-09-22 05:12:30.000000000 +0200
@@ -127,6 +127,14 @@
 except ImportError:
     HAS_BABEL = False
 
+# Defines Logarithm and Exponential for Logarithmic Converter
+if HAS_NUMPY:
+    from numpy import exp  # noqa: F401
+    from numpy import log  # noqa: F401
+else:
+    from math import exp  # noqa: F401
+    from math import log  # noqa: F401
+
 if not HAS_BABEL:
     babel_parse = babel_units = missing_dependency("Babel")  # noqa: F811
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/constants_en.txt 
new/Pint-0.16.1/pint/constants_en.txt
--- old/Pint-0.15/pint/constants_en.txt 2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/constants_en.txt       2020-09-22 05:12:30.000000000 
+0200
@@ -13,6 +13,7 @@
 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
 wien_u = 2.8214393721220788934031913302944851953458817440731      # solution 
to (u-3)*exp(u)+3 = 0 => u = W(3/exp(3))+3
+eulers_number = 2.71828182845904523536028747135266249775724709369995
 
 #### DEFINED EXACT CONSTANTS ####
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/converters.py 
new/Pint-0.16.1/pint/converters.py
--- old/Pint-0.15/pint/converters.py    2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/converters.py  2020-09-22 05:12:30.000000000 +0200
@@ -9,10 +9,19 @@
 """
 
 
+from .compat import HAS_NUMPY, exp, log  # noqa: F401
+
+
 class Converter:
     """Base class for value converters."""
 
-    is_multiplicative = True
+    @property
+    def is_multiplicative(self):
+        return True
+
+    @property
+    def is_logarithmic(self):
+        return False
 
     def to_reference(self, value, inplace=False):
         return value
@@ -24,8 +33,6 @@
 class ScaleConverter(Converter):
     """A linear transformation."""
 
-    is_multiplicative = True
-
     def __init__(self, scale):
         self.scale = scale
 
@@ -74,3 +81,81 @@
             value = (value - self.offset) / self.scale
 
         return value
+
+
+class LogarithmicConverter(Converter):
+    """ Converts between linear units and logarithmic units, such as dB, 
octave, neper or pH.
+    Q_log = logfactor * log( Q_lin / scale ) / log(log_base)
+
+    Parameters
+    ----------
+    scale : float
+        unit of reference at denominator for logarithmic unit conversion
+    logbase : float
+        base of logarithm used in the logarithmic unit conversion
+    logfactor : float
+        factor multupled to logarithm for unit conversion
+    inplace : bool
+        controls if computation is done in place
+    """
+
+    def __init__(self, scale, logbase, logfactor):
+        """
+        Parameters
+        ----------
+        scale : float
+            unit of reference at denominator inside logarithm for unit 
conversion
+        logbase: float
+            base of logarithm used in unit conversion
+        logfactor: float
+            factor multiplied to logarithm for unit conversion
+        """
+
+        self.scale = scale
+        self.logbase = logbase
+        self.logfactor = logfactor
+
+    @property
+    def is_multiplicative(self):
+        return False
+
+    @property
+    def is_logarithmic(self):
+        return True
+
+    def from_reference(self, value, inplace=False):
+        """Converts value from the reference unit to the logarithmic unit
+
+            dBm   <------   mW
+            y dBm = 10 log10( x / 1mW )
+        """
+        if inplace:
+            value /= self.scale
+            if HAS_NUMPY:
+                log(value, value)
+            else:
+                value = log(value)
+            value *= self.logfactor / log(self.logbase)
+        else:
+            value = self.logfactor * log(value / self.scale) / 
log(self.logbase)
+
+        return value
+
+    def to_reference(self, value, inplace=False):
+        """Converts value to the reference unit from the logarithmic unit
+
+            dBm   ------>   mW
+            y dBm = 10 log10( x / 1mW )
+        """
+        if inplace:
+            value /= self.logfactor
+            value *= log(self.logbase)
+            if HAS_NUMPY:
+                exp(value, value)
+            else:
+                value = exp(value)
+            value *= self.scale
+        else:
+            value = self.scale * exp(log(self.logbase) * (value / 
self.logfactor))
+
+        return value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/default_en.txt 
new/Pint-0.16.1/pint/default_en.txt
--- old/Pint-0.15/pint/default_en.txt   2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/default_en.txt 2020-09-22 05:12:30.000000000 +0200
@@ -108,7 +108,6 @@
 mole = [substance] = mol
 kelvin = [temperature]; offset: 0 = K = degK = ??K = degree_Kelvin = degreeK  
# older names supported for compatibility
 radian = [] = rad
-neper = [] = Np
 bit = []
 count = []
 
@@ -136,13 +135,13 @@
 steradian = radian ** 2 = sr
 square_degree = (?? / 180) ** 2 * sr = sq_deg = sqdeg
 
-# Logarithmic ratio
-bel = 0.5 * ln10 * neper
-
 # Information
-byte = 8 * bit = B = octet
 baud = bit / second = Bd = bps
 
+byte = 8 * bit = B = octet
+# byte = 8 * bit = _ = octet
+## NOTE: B (byte) symbol can conflict with Bell
+
 # Length
 angstrom = 1e-10 * meter = ?? = ??ngstr??m = ???
 micron = micrometer = ??
@@ -174,7 +173,10 @@
 fortnight = 2 * week
 year = 365.25 * day = a = yr = julian_year
 month = year / 12
-decade = 10 * year
+
+# decade = 10 * year
+## NOTE: decade [time] can conflict with decade [dimensionless]
+
 century = 100 * year = _ = centuries
 millennium = 1e3 * year = _ = millennia
 eon = 1e9 * year
@@ -308,6 +310,7 @@
 inch_H2O_60F = inch * water_60F * g_0
 foot_H2O = foot * water * g_0 = ftH2O = feet_H2O
 centimeter_H2O = centimeter * water * g_0 = cmH2O = cm_H2O
+sound_pressure_level = 20e-6 * pascal = SPL
 
 # Torque
 [torque] = [force] * [length]
@@ -470,6 +473,26 @@
 bohr_magneton = e * hbar / (2 * m_e) = ??_B = mu_B
 nuclear_magneton = e * hbar / (2 * m_p) = ??_N = mu_N
 
+# Logaritmic Unit Definition
+#  Unit = scale; logbase; logfactor 
+#  x_dB = [logfactor] * log( x_lin / [scale] ) / log( [logbase] )
+ 
+# Logaritmic Units of dimensionless quantity: [ 
https://en.wikipedia.org/wiki/Level_(logarithmic_quantity) ]
+
+decibelmilliwatt = 1e-3 watt; logbase: 10; logfactor: 10 = dBm
+decibelmicrowatt = 1e-6 watt; logbase: 10; logfactor: 10 = dBu
+
+decibel = 1 ; logbase: 10; logfactor: 10 = dB
+# bell = 1 ; logbase: 10; logfactor: = B
+## NOTE: B (Bell) symbol conflicts with byte
+
+decade = 1 ; logbase: 10; logfactor: 1
+## NOTE: decade [time] can conflict with decade [dimensionless]
+
+octave = 1 ; logbase: 2; logfactor: 1 = oct
+
+neper = 1 ; logbase: 2.71828182845904523536028747135266249775724709369995; 
logfactor: 0.5 = Np
+# neper = 1 ; logbase: eulers_number; logfactor: 0.5 = Np
 
 #### UNIT GROUPS ####
 # Mostly for length, area, volume, mass, force
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/definitions.py 
new/Pint-0.16.1/pint/definitions.py
--- old/Pint-0.15/pint/definitions.py   2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/definitions.py 2020-09-22 05:12:30.000000000 +0200
@@ -10,7 +10,7 @@
 
 from collections import namedtuple
 
-from .converters import OffsetConverter, ScaleConverter
+from .converters import LogarithmicConverter, OffsetConverter, ScaleConverter
 from .errors import DefinitionSyntaxError
 from .util import ParserHelper, UnitsContainer, _is_dim
 
@@ -120,6 +120,10 @@
     def is_multiplicative(self):
         return self._converter.is_multiplicative
 
+    @property
+    def is_logarithmic(self):
+        return self._converter.is_logarithmic
+
     @classmethod
     def from_string(cls, definition, non_int_type=float):
         """Parse a definition.
@@ -235,7 +239,7 @@
             definition = PreprocessedDefinition.from_string(definition)
 
         if ";" in definition.value:
-            [converter, modifiers] = definition.value.split(";", 2)
+            [converter, modifiers] = definition.value.split(";", 1)
 
             try:
                 modifiers = dict(
@@ -265,11 +269,23 @@
             )
         reference = UnitsContainer(converter)
 
-        if modifiers.get("offset", 0) != 0:
-            converter = OffsetConverter(converter.scale, modifiers["offset"])
-        else:
+        if not modifiers:
             converter = ScaleConverter(converter.scale)
 
+        elif "offset" in modifiers:
+            if modifiers.get("offset", 0.0) != 0.0:
+                converter = OffsetConverter(converter.scale, 
modifiers["offset"])
+            else:
+                converter = ScaleConverter(converter.scale)
+
+        elif "logbase" in modifiers and "logfactor" in modifiers:
+            converter = LogarithmicConverter(
+                converter.scale, modifiers["logbase"], modifiers["logfactor"]
+            )
+
+        else:
+            raise DefinitionSyntaxError("Unable to assing a converter to the 
unit")
+
         return cls(
             definition.name,
             definition.symbol,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/errors.py 
new/Pint-0.16.1/pint/errors.py
--- old/Pint-0.15/pint/errors.py        2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/errors.py      2020-09-22 05:12:30.000000000 +0200
@@ -8,6 +8,9 @@
     :license: BSD, see LICENSE for more details.
 """
 
+OFFSET_ERROR_DOCS_HTML = "https://pint.readthedocs.io/en/latest/nonmult.html";
+LOG_ERROR_DOCS_HTML = "https://pint.readthedocs.io/en/latest/nonmult.html";
+
 
 def _file_prefix(filename=None, lineno=None):
     if filename and lineno is not None:
@@ -111,7 +114,22 @@
         return (
             "Ambiguous operation with offset unit (%s)."
             % ", ".join(str(u) for u in self.args)
-            + " See https://pint.readthedocs.io/en/latest/nonmult.html for 
guidance."
+            + " See "
+            + OFFSET_ERROR_DOCS_HTML
+            + " for guidance."
+        )
+
+
+class LogarithmicUnitCalculusError(PintTypeError):
+    """Raised on inappropriate operations with logarithmic units."""
+
+    def __str__(self):
+        return (
+            "Ambiguous operation with logarithmic unit (%s)."
+            % ", ".join(str(u) for u in self.args)
+            + " See "
+            + LOG_ERROR_DOCS_HTML
+            + " for guidance."
         )
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/measurement.py 
new/Pint-0.16.1/pint/measurement.py
--- old/Pint-0.15/pint/measurement.py   2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/measurement.py 2020-09-22 05:12:30.000000000 +0200
@@ -70,9 +70,9 @@
 
     def __reduce__(self):
         # See notes in Quantity.__reduce__
-        from . import _unpickle
+        from . import _unpickle_measurement
 
-        return _unpickle, (Measurement, self.magnitude, self._units)
+        return _unpickle_measurement, (Measurement, self.magnitude, 
self._units)
 
     def __repr__(self):
         return "<Measurement({}, {}, {})>".format(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/quantity.py 
new/Pint-0.16.1/pint/quantity.py
--- old/Pint-0.15/pint/quantity.py      2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/quantity.py    2020-09-22 05:12:30.000000000 +0200
@@ -192,11 +192,11 @@
         """Allow pickling quantities. Since UnitRegistries are not pickled, 
upon
         unpickling the new object is always attached to the application 
registry.
         """
-        from . import _unpickle
+        from . import _unpickle_quantity
 
         # Note: type(self) would be a mistake as subclasses built by
         # build_quantity_class can't be pickled
-        return _unpickle, (Quantity, self.magnitude, self._units)
+        return _unpickle_quantity, (Quantity, self.magnitude, self._units)
 
     def __new__(cls, value, units=None):
         if is_upcast_type(type(value)):
@@ -1007,7 +1007,9 @@
                 units = self._units
             # If only self has a delta unit, other determines unit of result.
             elif self._get_delta_units() and not other._get_delta_units():
-                magnitude = op(self._convert_magnitude(other._units), 
other._magnitude)
+                magnitude = op(
+                    self._convert_magnitude_not_inplace(other._units), 
other._magnitude
+                )
                 units = other._units
             else:
                 units = self._units
@@ -1055,7 +1057,7 @@
             # Replace offset unit in other by the corresponding delta unit.
             # This is done to prevent a shift by offset in the to()-call.
             tu = other._units.rename(other_non_mul_unit, "delta_" + 
other_non_mul_unit)
-            magnitude = op(self._convert_magnitude(tu), other._magnitude)
+            magnitude = op(self._convert_magnitude_not_inplace(tu), 
other._magnitude)
             units = other._units
         else:
             raise OffsetUnitCalculusError(self._units, other._units)
@@ -1542,7 +1544,11 @@
                         raise OffsetUnitCalculusError(self._units)
 
             if self.dimensionless:
-                return eq(self._convert_magnitude(self.UnitsContainer()), 
other, False)
+                return eq(
+                    self._convert_magnitude_not_inplace(self.UnitsContainer()),
+                    other,
+                    False,
+                )
 
             return bool_result(False)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/registry.py 
new/Pint-0.16.1/pint/registry.py
--- old/Pint-0.15/pint/registry.py      2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/registry.py    2020-09-22 05:12:30.000000000 +0200
@@ -40,18 +40,16 @@
 import os
 import re
 from collections import ChainMap, defaultdict
-from contextlib import closing, contextmanager
+from contextlib import contextmanager
 from decimal import Decimal
 from fractions import Fraction
 from io import StringIO
 from tokenize import NAME, NUMBER
 
-import pkg_resources
-
 from . import registry_helpers, systems
 from .compat import babel_parse, tokenizer
 from .context import Context, ContextChain
-from .converters import ScaleConverter
+from .converters import LogarithmicConverter, ScaleConverter
 from .definitions import (
     AliasDefinition,
     Definition,
@@ -81,6 +79,13 @@
     to_units_container,
 )
 
+try:
+    import importlib.resources as importlib_resources
+except ImportError:
+    # Backport for Python < 3.7
+    import importlib_resources
+
+
 _BLOCK_RE = re.compile(r" |\(")
 
 
@@ -531,8 +536,7 @@
         if isinstance(file, str):
             try:
                 if is_resource:
-                    with closing(pkg_resources.resource_stream(__name__, 
file)) as fp:
-                        rbytes = fp.read()
+                    rbytes = importlib_resources.read_binary(__package__, file)
                     return self.load_definitions(
                         StringIO(rbytes.decode("utf-8")), is_resource
                     )
@@ -1352,7 +1356,7 @@
             raise UndefinedUnitError(u)
 
     def _validate_and_extract(self, units):
-
+        # u is for unit, e is for exponent
         nonmult_units = [
             (u, e) for u, e in units.items() if not self._is_multiplicative(u)
         ]
@@ -1379,6 +1383,21 @@
 
         return None
 
+    def _add_ref_of_log_unit(self, offset_unit, all_units):
+
+        slct_unit = self._units[offset_unit]
+        if isinstance(slct_unit.converter, LogarithmicConverter):
+            # Extract reference unit
+            slct_ref = slct_unit.reference
+            # If reference unit is not dimensionless
+            if slct_ref != UnitsContainer():
+                # Extract reference unit
+                (u, e) = [(u, e) for u, e in slct_ref.items()].pop()
+                # Add it back to the unit list
+                return all_units.add(u, e)
+        # Otherwise, return the units unmodified
+        return all_units
+
     def _convert(self, value, src, dst, inplace=False):
         """Convert value from some source to destination units.
 
@@ -1434,10 +1453,14 @@
         if src_offset_unit:
             value = self._units[src_offset_unit].converter.to_reference(value, 
inplace)
             src = src.remove([src_offset_unit])
+            # Add reference unit for multiplicative section
+            src = self._add_ref_of_log_unit(src_offset_unit, src)
 
         # clean dst units from offset units
         if dst_offset_unit:
             dst = dst.remove([dst_offset_unit])
+            # Add reference unit for multiplicative section
+            dst = self._add_ref_of_log_unit(dst_offset_unit, dst)
 
         # Convert non multiplicative units to the dst.
         value = super()._convert(value, src, dst, inplace, False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/testsuite/test_converters.py 
new/Pint-0.16.1/pint/testsuite/test_converters.py
--- old/Pint-0.15/pint/testsuite/test_converters.py     2020-08-22 
21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/testsuite/test_converters.py   2020-09-22 
05:12:30.000000000 +0200
@@ -1,7 +1,12 @@
 import itertools
 
 from pint.compat import np
-from pint.converters import Converter, OffsetConverter, ScaleConverter
+from pint.converters import (
+    Converter,
+    LogarithmicConverter,
+    OffsetConverter,
+    ScaleConverter,
+)
 from pint.testsuite import BaseTestCase, helpers
 
 
@@ -9,19 +14,38 @@
     def test_converter(self):
         c = Converter()
         self.assertTrue(c.is_multiplicative)
+        self.assertFalse(c.is_logarithmic)
         self.assertTrue(c.to_reference(8))
         self.assertTrue(c.from_reference(8))
 
     def test_multiplicative_converter(self):
         c = ScaleConverter(20.0)
+        self.assertTrue(c.is_multiplicative)
+        self.assertFalse(c.is_logarithmic)
         self.assertEqual(c.from_reference(c.to_reference(100)), 100)
         self.assertEqual(c.to_reference(c.from_reference(100)), 100)
 
     def test_offset_converter(self):
         c = OffsetConverter(20.0, 2)
+        self.assertFalse(c.is_multiplicative)
+        self.assertFalse(c.is_logarithmic)
         self.assertEqual(c.from_reference(c.to_reference(100)), 100)
         self.assertEqual(c.to_reference(c.from_reference(100)), 100)
 
+    def test_log_converter(self):
+        c = LogarithmicConverter(scale=1, logbase=10, logfactor=1)
+        self.assertFalse(c.is_multiplicative)
+        self.assertTrue(c.is_logarithmic)
+        self.assertAlmostEqual(c.to_reference(0), 1)
+        self.assertAlmostEqual(c.to_reference(1), 10)
+        self.assertAlmostEqual(c.to_reference(2), 100)
+        self.assertAlmostEqual(c.from_reference(1), 0)
+        self.assertAlmostEqual(c.from_reference(10), 1)
+        self.assertAlmostEqual(c.from_reference(100), 2)
+        arb_value = 20.0
+        self.assertAlmostEqual(c.from_reference(c.to_reference(arb_value)), 
arb_value)
+        self.assertAlmostEqual(c.to_reference(c.from_reference(arb_value)), 
arb_value)
+
     @helpers.requires_numpy()
     def test_converter_inplace(self):
         for c in (ScaleConverter(20.0), OffsetConverter(20.0, 2)):
@@ -35,3 +59,24 @@
                 r = fun(a, inplace)
                 np.testing.assert_allclose(r, ac)
                 comp(a, r)
+
+    @helpers.requires_numpy()
+    def test_log_converter_inplace(self):
+        arb_value = 3.14
+        c = LogarithmicConverter(scale=1, logbase=10, logfactor=1)
+
+        from_to = lambda value, inplace: c.from_reference(
+            c.to_reference(value, inplace), inplace
+        )
+
+        to_from = lambda value, inplace: c.to_reference(
+            c.from_reference(value, inplace), inplace
+        )
+
+        for fun, (inplace, comp) in itertools.product(
+            (from_to, to_from), ((True, self.assertIs), (False, 
self.assertIsNot))
+        ):
+            arb_array = arb_value * np.ones((1, 10))
+            result = fun(arb_array, inplace)
+            np.testing.assert_allclose(result, arb_array)
+            comp(arb_array, result)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/testsuite/test_definitions.py 
new/Pint-0.16.1/pint/testsuite/test_definitions.py
--- old/Pint-0.15/pint/testsuite/test_definitions.py    2020-08-22 
21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/testsuite/test_definitions.py  2020-09-22 
05:12:30.000000000 +0200
@@ -1,4 +1,4 @@
-from pint.converters import OffsetConverter, ScaleConverter
+from pint.converters import LogarithmicConverter, OffsetConverter, 
ScaleConverter
 from pint.definitions import (
     AliasDefinition,
     Definition,
@@ -94,6 +94,67 @@
             "degF = 9 / 5 * kelvin; offset: 255.372222 bla",
         )
 
+    def test_log_unit_definition(self):
+
+        x = Definition.from_string(
+            "decibelmilliwatt = 1e-3 watt; logbase: 10; logfactor: 10 = dBm"
+        )
+        self.assertIsInstance(x, UnitDefinition)
+        self.assertFalse(x.is_base)
+        self.assertIsInstance(x.converter, LogarithmicConverter)
+        self.assertEqual(x.converter.scale, 1e-3)
+        self.assertEqual(x.converter.logbase, 10)
+        self.assertEqual(x.converter.logfactor, 10)
+        self.assertEqual(x.reference, UnitsContainer(watt=1))
+
+        x = Definition.from_string("decibel = 1 ; logbase: 10; logfactor: 10 = 
dB")
+        self.assertIsInstance(x, UnitDefinition)
+        self.assertFalse(x.is_base)
+        self.assertIsInstance(x.converter, LogarithmicConverter)
+        self.assertEqual(x.converter.scale, 1)
+        self.assertEqual(x.converter.logbase, 10)
+        self.assertEqual(x.converter.logfactor, 10)
+        self.assertEqual(x.reference, UnitsContainer())
+
+        x = Definition.from_string("bell = 1 ; logbase: 10; logfactor: 1 = B")
+        self.assertIsInstance(x, UnitDefinition)
+        self.assertFalse(x.is_base)
+        self.assertIsInstance(x.converter, LogarithmicConverter)
+        self.assertEqual(x.converter.scale, 1)
+        self.assertEqual(x.converter.logbase, 10)
+        self.assertEqual(x.converter.logfactor, 1)
+        self.assertEqual(x.reference, UnitsContainer())
+
+        x = Definition.from_string("decade = 1 ; logbase: 10; logfactor: 1")
+        self.assertIsInstance(x, UnitDefinition)
+        self.assertFalse(x.is_base)
+        self.assertIsInstance(x.converter, LogarithmicConverter)
+        self.assertEqual(x.converter.scale, 1)
+        self.assertEqual(x.converter.logbase, 10)
+        self.assertEqual(x.converter.logfactor, 1)
+        self.assertEqual(x.reference, UnitsContainer())
+
+        eulersnumber = 2.71828182845904523536028747135266249775724709369995
+        x = Definition.from_string(
+            "neper = 1 ; logbase: %1.50f; logfactor: 0.5 = Np" % eulersnumber
+        )
+        self.assertIsInstance(x, UnitDefinition)
+        self.assertFalse(x.is_base)
+        self.assertIsInstance(x.converter, LogarithmicConverter)
+        self.assertEqual(x.converter.scale, 1)
+        self.assertEqual(x.converter.logbase, eulersnumber)
+        self.assertEqual(x.converter.logfactor, 0.5)
+        self.assertEqual(x.reference, UnitsContainer())
+
+        x = Definition.from_string("octave = 1 ; logbase: 2; logfactor: 1 = 
oct")
+        self.assertIsInstance(x, UnitDefinition)
+        self.assertFalse(x.is_base)
+        self.assertIsInstance(x.converter, LogarithmicConverter)
+        self.assertEqual(x.converter.scale, 1)
+        self.assertEqual(x.converter.logbase, 2)
+        self.assertEqual(x.converter.logfactor, 1)
+        self.assertEqual(x.reference, UnitsContainer())
+
     def test_dimension_definition(self):
         x = DimensionDefinition("[time]", "", (), None, is_base=True)
         self.assertTrue(x.is_base)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/testsuite/test_errors.py 
new/Pint-0.16.1/pint/testsuite/test_errors.py
--- old/Pint-0.15/pint/testsuite/test_errors.py 2020-08-22 21:22:43.000000000 
+0200
+++ new/Pint-0.16.1/pint/testsuite/test_errors.py       2020-09-22 
05:12:30.000000000 +0200
@@ -3,12 +3,14 @@
 from pint import (
     DefinitionSyntaxError,
     DimensionalityError,
+    LogarithmicUnitCalculusError,
     OffsetUnitCalculusError,
     Quantity,
     RedefinitionError,
     UndefinedUnitError,
     UnitRegistry,
 )
+from pint.errors import LOG_ERROR_DOCS_HTML, OFFSET_ERROR_DOCS_HTML
 from pint.testsuite import BaseTestCase
 
 
@@ -79,13 +81,34 @@
         self.assertEqual(
             str(ex),
             "Ambiguous operation with offset unit (kilogram). See "
-            "https://pint.readthedocs.io/en/latest/nonmult.html for guidance.",
+            + OFFSET_ERROR_DOCS_HTML
+            + " for guidance.",
         )
         ex = OffsetUnitCalculusError(Quantity("1 kg")._units, Quantity("1 
s")._units)
         self.assertEqual(
             str(ex),
             "Ambiguous operation with offset unit (kilogram, second). See "
-            "https://pint.readthedocs.io/en/latest/nonmult.html for guidance.",
+            + OFFSET_ERROR_DOCS_HTML
+            + " for guidance.",
+        )
+
+    def test_logarithmic_unit_calculus_error(self):
+        Quantity = UnitRegistry(autoconvert_offset_to_baseunit=True).Quantity
+        ex = LogarithmicUnitCalculusError(Quantity("1 dB")._units)
+        self.assertEqual(
+            str(ex),
+            "Ambiguous operation with logarithmic unit (decibel). See "
+            + LOG_ERROR_DOCS_HTML
+            + " for guidance.",
+        )
+        ex = LogarithmicUnitCalculusError(
+            Quantity("1 dB")._units, Quantity("1 octave")._units
+        )
+        self.assertEqual(
+            str(ex),
+            "Ambiguous operation with logarithmic unit (decibel, octave). See "
+            + LOG_ERROR_DOCS_HTML
+            + " for guidance.",
         )
 
     def test_pickle_definition_syntax_error(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/testsuite/test_issues.py 
new/Pint-0.16.1/pint/testsuite/test_issues.py
--- old/Pint-0.15/pint/testsuite/test_issues.py 2020-08-22 21:22:43.000000000 
+0200
+++ new/Pint-0.16.1/pint/testsuite/test_issues.py       2020-09-22 
05:12:30.000000000 +0200
@@ -5,7 +5,7 @@
 
 import pytest
 
-from pint import Context, DimensionalityError, UnitRegistry
+from pint import Context, DimensionalityError, UnitRegistry, 
get_application_registry
 from pint.compat import np
 from pint.testsuite import QuantityTestCase, helpers
 from pint.unit import UnitsContainer
@@ -520,7 +520,7 @@
 
         lunar_module_height = Q_(10, "m")
         t1 = calculate_time_to_fall(lunar_module_height)
-        print(t1)
+        # print(t1)
         self.assertAlmostEqual(t1, Q_(1.4285714285714286, "s"))
 
         moon_gravity = Q_(1.625, "m/s^2")
@@ -580,7 +580,7 @@
 
         @ureg.check("[length]", "[length]/[time]^2")
         def pendulum_period(length, G=Q_(1, "standard_gravity")):
-            print(length)
+            # print(length)
             return (2 * math.pi * (length / G) ** 0.5).to("s")
 
         length = Q_(1, ureg.m)
@@ -746,12 +746,43 @@
         ureg.enable_contexts("c3")
 
     @helpers.requires_numpy()
+    def test_issue1144_1102(self):
+        # Performing operations shouldn't modify the original objects
+        # Issue 1144
+        ddc = "delta_degree_Celsius"
+        q1 = ureg.Quantity([-287.78, -32.24, -1.94], ddc)
+        q2 = ureg.Quantity(70.0, "degree_Fahrenheit")
+        q1 - q2
+        assert all(q1 == ureg.Quantity([-287.78, -32.24, -1.94], ddc))
+        assert q2 == ureg.Quantity(70.0, "degree_Fahrenheit")
+        q2 - q1
+        assert all(q1 == ureg.Quantity([-287.78, -32.24, -1.94], ddc))
+        assert q2 == ureg.Quantity(70.0, "degree_Fahrenheit")
+        # Issue 1102
+        val = [30.0, 45.0, 60.0] * ureg.degree
+        val == 1
+        1 == val
+        assert all(val == ureg.Quantity([30.0, 45.0, 60.0], "degree"))
+        # Test for another bug identified by searching on "_convert_magnitude"
+        q2 = ureg.Quantity(3, "degree_Kelvin")
+        q1 - q2
+        assert all(q1 == ureg.Quantity([-287.78, -32.24, -1.94], ddc))
+
+    @helpers.requires_numpy()
     def test_issue_1136(self):
         assert (2 ** ureg.Quantity([2, 3], "") == 2 ** np.array([2, 3])).all()
 
         with pytest.raises(DimensionalityError):
             2 ** ureg.Quantity([2, 3], "m")
 
+    def test_issue1175(self):
+        import pickle
+
+        foo1 = get_application_registry().Quantity(1, "s")
+        foo2 = pickle.loads(pickle.dumps(foo1))
+        self.assertIsInstance(foo1, foo2.__class__)
+        self.assertIsInstance(foo2, foo1.__class__)
+
 
 if np is not None:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/testsuite/test_log_units.py 
new/Pint-0.16.1/pint/testsuite/test_log_units.py
--- old/Pint-0.15/pint/testsuite/test_log_units.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/Pint-0.16.1/pint/testsuite/test_log_units.py    2020-09-22 
05:12:30.000000000 +0200
@@ -0,0 +1,276 @@
+import math
+
+import pytest
+
+from pint import OffsetUnitCalculusError, UnitRegistry
+from pint.testsuite import QuantityTestCase
+from pint.unit import Unit, UnitsContainer
+
+
+@pytest.fixture(scope="module")
+def auto_ureg():
+    return UnitRegistry(autoconvert_offset_to_baseunit=True)
+
+
+@pytest.fixture(scope="module")
+def ureg():
+    return UnitRegistry()
+
+
+class TestLogarithmicQuantity(QuantityTestCase):
+
+    FORCE_NDARRAY = False
+
+    def test_log_quantity_creation(self):
+
+        # Following Quantity Creation Pattern
+        for args in (
+            (4.2, "dBm"),
+            (4.2, UnitsContainer(decibelmilliwatt=1)),
+            (4.2, self.ureg.dBm),
+        ):
+            x = self.Q_(*args)
+            self.assertEqual(x.magnitude, 4.2)
+            self.assertEqual(x.units, UnitsContainer(decibelmilliwatt=1))
+
+        x = self.Q_(self.Q_(4.2, "dBm"))
+        self.assertEqual(x.magnitude, 4.2)
+        self.assertEqual(x.units, UnitsContainer(decibelmilliwatt=1))
+
+        x = self.Q_(4.2, UnitsContainer(decibelmilliwatt=1))
+        y = self.Q_(x)
+        self.assertEqual(x.magnitude, y.magnitude)
+        self.assertEqual(x.units, y.units)
+        self.assertIsNot(x, y)
+
+        # Using multiplications for dB units requires autoconversion to 
baseunits
+        new_reg = UnitRegistry(autoconvert_offset_to_baseunit=True)
+        x = new_reg.Quantity("4.2 * dBm")
+        self.assertEqual(x.magnitude, 4.2)
+        self.assertEqual(x.units, UnitsContainer(decibelmilliwatt=1))
+
+        with self.capture_log() as buffer:
+            self.assertEqual(4.2 * new_reg.dBm, new_reg.Quantity(4.2, 2 * 
new_reg.dBm))
+            self.assertEqual(len(buffer), 1)
+
+    def test_log_convert(self):
+        # # 1 dB = 1/10 * bel
+        # self.assertQuantityAlmostEqual(self.Q_(1.0, 
"dB").to("dimensionless"), self.Q_(1, "bell") / 10)
+        # # Uncomment Bell unit in default_en.txt
+
+        # ## Test dB to dB units octave - decade
+        # 1 decade = log2(10) octave
+        self.assertQuantityAlmostEqual(
+            self.Q_(1.0, "decade"), self.Q_(math.log(10, 2), "octave")
+        )
+        # ## Test dB to dB units dBm - dBu
+        # 0 dBm = 1mW = 1e3 uW = 30 dBu
+        self.assertAlmostEqual(self.Q_(0.0, "dBm"), 
self.Q_(29.999999999999996, "dBu"))
+
+    def test_mix_regular_log_units(self):
+        # Test regular-logarithmic mixed definition, such as dB/km or dB/cm
+
+        # Multiplications and divisions with a mix of Logarithmic Units and 
regular Units is normally not possible.
+        # The reason is that dB are considered by pint like offset units.
+        # Multiplications and divisions that involve offset units are badly 
defined, so pint raises an error
+        with self.assertRaises(OffsetUnitCalculusError):
+            (-10.0 * self.ureg.dB) / (1 * self.ureg.cm)
+
+        # However, if the flag autoconvert_offset_to_baseunit=True is given to 
UnitRegistry, then pint converts the unit to base.
+        # With this flag on multiplications and divisions are now possible:
+        new_reg = UnitRegistry(autoconvert_offset_to_baseunit=True)
+        self.assertQuantityAlmostEqual(-10 * new_reg.dB / new_reg.cm, 0.1 / 
new_reg.cm)
+
+
+log_unit_names = [
+    "decibelmilliwatt",
+    "dBm",
+    "decibelmicrowatt",
+    "dBu",
+    "decibel",
+    "dB",
+    "decade",
+    "octave",
+    "oct",
+]
+
+
+@pytest.mark.parametrize("unit_name", log_unit_names)
+def test_unit_by_attribute(ureg, unit_name):
+    """Can the logarithmic units be accessed by attribute lookups?"""
+    unit = getattr(ureg, unit_name)
+    assert isinstance(unit, Unit)
+
+
+@pytest.mark.parametrize("unit_name", log_unit_names)
+def test_unit_parsing(ureg, unit_name):
+    """Can the logarithmic units be understood by the parser?"""
+    unit = ureg.parse_units(unit_name)
+    assert isinstance(unit, Unit)
+
+
+@pytest.mark.parametrize("mag", [1.0, 4.2])
+@pytest.mark.parametrize("unit_name", log_unit_names)
+def test_quantity_by_constructor(ureg, unit_name, mag):
+    """Can Quantity() objects be constructed using logarithmic units?"""
+    q = ureg.Quantity(mag, unit_name)
+    assert q.magnitude == pytest.approx(mag)
+    assert q.units == getattr(ureg, unit_name)
+
+
+@pytest.mark.parametrize("mag", [1.0, 4.2])
+@pytest.mark.parametrize("unit_name", log_unit_names)
+def test_quantity_by_multiplication(auto_ureg, unit_name, mag):
+    """Test that logarithmic units can be defined with multiplication
+
+    Requires setting `autoconvert_offset_to_baseunit` to True
+    """
+    unit = getattr(auto_ureg, unit_name)
+    q = mag * unit
+    assert q.magnitude == pytest.approx(mag)
+    assert q.units == unit
+
+
+@pytest.mark.parametrize(
+    "unit1,unit2",
+    [
+        ("decibelmilliwatt", "dBm"),
+        ("decibelmicrowatt", "dBu"),
+        ("decibel", "dB"),
+        ("octave", "oct"),
+    ],
+)
+def test_unit_equivalence(ureg, unit1, unit2):
+    """Are certain pairs of units equivalent?"""
+    assert getattr(ureg, unit1) == getattr(ureg, unit2)
+
+
+@pytest.mark.parametrize(
+    "db_value,scalar",
+    [
+        (0.0, 1.0),  # 0 dB == 1x
+        (-10.0, 0.1),  # -10 dB == 0.1x
+        (10.0, 10.0),
+        (30.0, 1e3),
+        (60.0, 1e6),
+    ],
+)
+def test_db_conversion(ureg, db_value, scalar):
+    """Test that a dB value can be converted to a scalar and back.
+    """
+    Q_ = ureg.Quantity
+    assert Q_(db_value, "dB").to("dimensionless").magnitude == 
pytest.approx(scalar)
+    assert Q_(scalar, "dimensionless").to("dB").magnitude == 
pytest.approx(db_value)
+
+
+@pytest.mark.parametrize(
+    "octave,scalar",
+    [
+        (2.0, 4.0),  # 2 octave == 4x
+        (1.0, 2.0),  # 1 octave == 2x
+        (0.0, 1.0),
+        (-1.0, 0.5),
+        (-2.0, 0.25),
+    ],
+)
+def test_octave_conversion(ureg, octave, scalar):
+    """Test that an octave can be converted to a scalar and back.
+    """
+    Q_ = ureg.Quantity
+    assert Q_(octave, "octave").to("dimensionless").magnitude == 
pytest.approx(scalar)
+    assert Q_(scalar, "dimensionless").to("octave").magnitude == 
pytest.approx(octave)
+
+
+@pytest.mark.parametrize(
+    "decade,scalar",
+    [
+        (2.0, 100.0),  # 2 decades == 100x
+        (1.0, 10.0),  # 1 octave == 2x
+        (0.0, 1.0),
+        (-1.0, 0.1),
+        (-2.0, 0.01),
+    ],
+)
+def test_decade_conversion(ureg, decade, scalar):
+    """Test that a decade can be converted to a scalar and back.
+    """
+    Q_ = ureg.Quantity
+    assert Q_(decade, "decade").to("dimensionless").magnitude == 
pytest.approx(scalar)
+    assert Q_(scalar, "dimensionless").to("decade").magnitude == 
pytest.approx(decade)
+
+
+@pytest.mark.parametrize(
+    "dbm_value,mw_value",
+    [
+        (0.0, 1.0),  # 0.0 dBm == 1.0 mW
+        (10.0, 10.0),
+        (20.0, 100.0),
+        (-10.0, 0.1),
+        (-20.0, 0.01),
+    ],
+)
+def test_dbm_mw_conversion(ureg, dbm_value, mw_value):
+    """Test dBm values can convert to mW and back.
+    """
+    Q_ = ureg.Quantity
+    assert Q_(dbm_value, "dBm").to("mW").magnitude == pytest.approx(mw_value)
+    assert Q_(mw_value, "mW").to("dBm").magnitude == pytest.approx(dbm_value)
+
+
+@pytest.mark.xfail
+def test_compound_log_unit_multiply_definition(auto_ureg):
+    """Check that compound log units can be defined using multiply.
+    """
+    Q_ = auto_ureg.Quantity
+    canonical_def = Q_(-161, "dBm") / auto_ureg.Hz
+    mult_def = -161 * auto_ureg("dBm/Hz")
+    assert mult_def == canonical_def
+
+
+@pytest.mark.xfail
+def test_compound_log_unit_quantity_definition(auto_ureg):
+    """Check that compound log units can be defined using ``Quantity()``.
+    """
+    Q_ = auto_ureg.Quantity
+    canonical_def = Q_(-161, "dBm") / auto_ureg.Hz
+    quantity_def = Q_(-161, "dBm/Hz")
+    assert quantity_def == canonical_def
+
+
+def test_compound_log_unit_parse_definition(auto_ureg):
+    Q_ = auto_ureg.Quantity
+    canonical_def = Q_(-161, "dBm") / auto_ureg.Hz
+    parse_def = auto_ureg("-161 dBm/Hz")
+    assert parse_def == canonical_def
+
+
+def test_compound_log_unit_parse_expr(auto_ureg):
+    """Check that compound log units can be defined using 
``parse_expression()``.
+    """
+    Q_ = auto_ureg.Quantity
+    canonical_def = Q_(-161, "dBm") / auto_ureg.Hz
+    parse_def = auto_ureg.parse_expression("-161 dBm/Hz")
+    assert canonical_def == parse_def
+
+
+@pytest.mark.xfail
+def test_dbm_db_addition(auto_ureg):
+    """Test a dB value can be added to a dBm and the answer is correct.
+    """
+    power = (5 * auto_ureg.dBm) + (10 * auto_ureg.dB)
+    assert power.to("dBm").magnitude == pytest.approx(15)
+
+
+@pytest.mark.xfail
+@pytest.mark.parametrize(
+    "freq1,octaves,freq2",
+    [(100, 2.0, 400), (50, 1.0, 100), (200, 0.0, 200),],  # noqa: E231
+)
+def test_frequency_octave_addition(auto_ureg, freq1, octaves, freq2):
+    """Test an Octave can be added to a frequency correctly
+    """
+    freq1 = freq1 * auto_ureg.Hz
+    shift = octaves * auto_ureg.Octave
+    new_freq = freq1 + shift
+    assert new_freq.units == freq1.units
+    assert new_freq.magnitude == pytest.approx(freq2)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/pint/unit.py new/Pint-0.16.1/pint/unit.py
--- old/Pint-0.15/pint/unit.py  2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/pint/unit.py        2020-09-22 05:12:30.000000000 +0200
@@ -28,9 +28,9 @@
 
     def __reduce__(self):
         # See notes in Quantity.__reduce__
-        from . import _unpickle
+        from . import _unpickle_unit
 
-        return _unpickle, (Unit, self._units)
+        return _unpickle_unit, (Unit, self._units)
 
     def __init__(self, units):
         super().__init__()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/readthedocs.yml 
new/Pint-0.16.1/readthedocs.yml
--- old/Pint-0.15/readthedocs.yml       2020-08-22 21:22:43.000000000 +0200
+++ new/Pint-0.16.1/readthedocs.yml     1970-01-01 01:00:00.000000000 +0100
@@ -1,12 +0,0 @@
-version: 2
-build:
-  image: latest
-sphinx:
-  configuration: docs/conf.py
-  fail_on_warning: false
-python:
-   version: 3.7
-   install:
-     - requirements: requirements_docs.txt
-     - method: pip
-       path: .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Pint-0.15/setup.cfg new/Pint-0.16.1/setup.cfg
--- old/Pint-0.15/setup.cfg     2020-08-22 21:22:44.000000000 +0200
+++ new/Pint-0.16.1/setup.cfg   2020-09-22 05:12:31.000000000 +0200
@@ -28,9 +28,9 @@
 include_package_data = True
 python_requires = >=3.6
 install_requires = 
-       setuptools
        packaging
        importlib-metadata; python_version < '3.8'
+       importlib-resources; python_version < '3.7'
 setup_requires = setuptools; setuptools_scm
 test_suite = pint.testsuite.testsuite
 scripts = pint/pint-convert

Reply via email to