hgrecco / pint

Operate and manipulate physical quantities in Python
http://pint.readthedocs.org/
Other
2.36k stars 466 forks source link

pint.Quantity.units / pint.Unit fails #2046

Open peter-goldstein opened 3 weeks ago

peter-goldstein commented 3 weeks ago

Steps to reproduce:

a = pint.Quantity(1, "L").units
b = pint.Unit("mL")
c = a / b

Expected behavior: c is a dimensionless unit representing 1000

Actual behavior: AttributeError: 'PlainUnit' object has no attribute '_get_non_multiplicative_units'


The offending line is in pint/facets/plain/quantity.py:999:

no_offset_units_other = len(other._get_non_multiplicative_units())

other does not have this method, because other is a Unit, and not a NonMultiplicativeQuantity. It looks like the bug is coming from quantity.py:989:

if isinstance(other, self._REGISTRY.Unit):
    other = 1 * other

This is evaluating to False, so other is remaining a Unit rather than being converted to a Quantity. I suspect this isn't quite the right logic for this conditional. I believe the intention is "is this item a Unit and attached to the same registry I am," but what it is actually checking is, "was this item constructed as an instance of my registry's inner class called Unit."


(Unnecessary) detail:

andrewgsavage commented 3 weeks ago

I'd expect to get c = Quantity(1000, "dimensionless")

Looks like you're most of the way there, I'd change that to if isinstance(other, self._REGISTRY.Unit) or (isinstance(other, Unit) and self._REGISTRY==other._REGISTRY): A PR with a fix is welcomed. the only other place I see an isinstance check with a Unit is L918 in quantity.py so change that too.