The following code prints '1 dimensionless':
import pint
ureg=pint.UnitRegistry()
print(ureg(0.))
Why, Pint?
The following code prints '1 dimensionless':
import pint
ureg=pint.UnitRegistry()
print(ureg(0.))
Why, Pint?
"Calling" a UnitRegistry
object is equivalent to calling parse_expression
on it. parse_expression
expects to receive a str
, and it has a special case for the empty string, which is to return it as a Quantity(1)
(the 1 dimensionless
you see).
In this case, you happened to hit a minor flaw in the duck-typing: It expects a string, but doesn't actually verify that it received one. Then it converts any falsy value to Quantity(1)
with the code:
if not input_string:
return self.Quantity(1)
so any zero-valued number (or None
, or empty sequence, or other falsy thing) becomes Quantity(1)
. Had you passed it a truthy expression of an unexpected type, the parser would have gotten involved and raised an exception, but falsy values never even reach the parser.
I'm not clear on why the empty expression should be a Quantity(1)
, but the authors explicitly put that check in there, so it must have been intended.
In short, don't pass non-strings to the function. They'll fail silently when falsy, and raise an exception for anything else (when it assumes they're a str
and it tries to call str
methods on them).
looks like a bug/limitation in the package.
When passing an integer (different from 0) pint
crashes:
>>> ureg(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python34\lib\site-packages\pint\registry.py", line 837, in parse_expression
input_string = string_preprocessor(input_string)
File "C:\Python34\lib\site-packages\pint\util.py", line 579, in string_preprocessor
input_string = input_string.replace(",", "")
AttributeError: 'int' object has no attribute 'replace'
in registry.py
def parse_expression(self, input_string, case_sensitive=True, **values):
"""Parse a mathematical expression including units and return a quantity object.
Numerical constants can be specified as keyword arguments and will take precedence
over the names defined in the registry.
"""
if not input_string:
return self.Quantity(1)
input_string = string_preprocessor(input_string) # should not be called with something else than string
it crashes because the package tries to perform string operations on the non-string, where a string is expected. But the test is if not input_string
so 0.0
make pint
create a 1
class (or whatever that means), just like if you'd pass ""
. Passing 1
allows to reach the next line, which crashes.
It's just missing a type check, something like:
if not isinstance(input_string,str):
raise Exception("a string is required")