Giter Club home page Giter Club logo

pint's Introduction

Latest Version

Ruff

Ruff-Format

Documentation

License

Python Versions

CI

LINTER

Coverage

Pint: makes units easy

Pint is a Python package to define, operate and manipulate physical quantities: the product of a numerical value and a unit of measurement. It allows arithmetic operations between them and conversions from and to different units.

It is distributed with a comprehensive list of physical units, prefixes and constants. Due to its modular design, you can extend (or even rewrite!) the complete list without changing the source code. It supports a lot of numpy mathematical operations without monkey patching or wrapping numpy.

It has a complete test coverage. It runs in Python 3.9+ with no other dependency. It is licensed under BSD.

It is extremely easy and natural to use:

>>> import pint
>>> ureg = pint.UnitRegistry()
>>> 3 * ureg.meter + 4 * ureg.cm
<Quantity(3.04, 'meter')>

and you can make good use of numpy if you want:

>>> import numpy as np
>>> [3, 4] * ureg.meter + [4, 3] * ureg.cm
<Quantity([ 3.04  4.03], 'meter')>
>>> np.sum(_)
<Quantity(7.07, 'meter')>

Quick Installation

To install Pint, simply:

$ pip install pint

or utilizing conda, with the conda-forge channel:

$ conda install -c conda-forge pint

and then simply enjoy it!

Documentation

Full documentation is available at http://pint.readthedocs.org/

Command-line converter

A command-line script pint-convert provides a quick way to convert between units or get conversion factors.

Design principles

Although there are already a few very good Python packages to handle physical quantities, no one was really fitting my needs. Like most developers, I programmed Pint to scratch my own itches.

Unit parsing: prefixed and pluralized forms of units are recognized without explicitly defining them. In other words: as the prefix kilo and the unit meter are defined, Pint understands kilometers. This results in a much shorter and maintainable unit definition list as compared to other packages.

Standalone unit definitions: units definitions are loaded from a text file which is simple and easy to edit. Adding and changing units and their definitions does not involve changing the code.

Advanced string formatting: a quantity can be formatted into string using PEP 3101 syntax. Extended conversion flags are given to provide symbolic, LaTeX and pretty formatting. Unit name translation is available if Babel is installed.

Free to choose the numerical type: You can use any numerical type (fraction, float, decimal, numpy.ndarray, etc). NumPy is not required but supported.

Awesome NumPy integration: When you choose to use a NumPy ndarray, its methods and ufuncs are supported including automatic conversion of units. For example numpy.arccos(q) will require a dimensionless q and the units of the output quantity will be radian.

Uncertainties integration: transparently handles calculations with quantities with uncertainties (like 3.14±0.01 meter) via the uncertainties package.

Handle temperature: conversion between units with different reference points, like positions on a map or absolute temperature scales.

Dependency free: it depends only on Python and its standard library. It interacts with other packages like numpy and uncertainties if they are installed

Pandas integration: Thanks to Pandas Extension Types it is now possible to use Pint with Pandas. Operations on DataFrames and between columns are units aware, providing even more convenience for users of Pandas DataFrames. For full details, see the pint-pandas Jupyter notebook.

Pint is maintained by a community of scientists, programmers and enthusiasts 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

pint's People

Contributors

5igno avatar alexbodn avatar andrewgsavage avatar bors[bot] avatar carterbox avatar cgevans avatar clarkgwillison avatar crusaderky avatar dalito avatar dopplershift avatar emilienkofman avatar github-actions[bot] avatar hgrecco avatar hugovk avatar jellby avatar jni avatar jondoesntgit avatar jthielen avatar jturner314 avatar jules-ch avatar keewis avatar loganthomas avatar michaeltiemannosc avatar muggenhor avatar porcelainmouse avatar rec avatar rpmanser avatar ryanpdwyer avatar tovrstra avatar znicholls avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pint's Issues

Right-division broken in python 2.7 without __future__

In Python 2.7, if we try to divide a number by a quantity, an exception is raised:

>>> 1/ureg.m
...
TypeError: unsupported operand type(s) for /: 'int' and 'Quantity'

Importing division from future fixes this:

>>> from __future__ import division
>>> 1/ureg.m
<Quantity(1.0, '1 / meter')>

Looks like this can be fixed by just adding __rdiv__ = __rtruediv__ to the class definition of Quantity.

I'll submit a patch shortly.

Finding more compact representation of multiplicative dimensions (or units)

This issue is a follow up from Issue #13 focused in getting a simpler expression for dimensions and units. For example:

  • for [length] / [time] the function should return [speed]
  • for kilogram * meter / second ** 2 the function should return Newton

Comment from @r-barnes:

This can be done relatively easily, in principle; the search can be done in O(N) time.

  • Expand the dimenions of the search term to non-derived dimensions (area, length, time, &c).
  • Expand the list of derived dimensions to non-derived dimensions (area, length, &c).
  • Divide the search units by the derived units, so that terms cancel.
  • The resulting unit is then the derived unit multiplied by whatever search units did not cancel.
  • Choose the expression with the smallest number of terms, as you say.
  • But there may be ties, in which case there is not an unambiguous answer.

Single-number Quantities don't work with ufuncs

Quantity objects that contain a single number (as opposed to an array) are not compatible with numpy ufuncs. For example:

>>> np.sqrt( ureg.dimensionless )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: sqrt
>>> np.sqrt( [1] * ureg.dimensionless )
<Quantity([ 1.], 'dimensionless')>

This is in contrast to numpy itself whose ufuncs can apply to a single value:

>>> np.sqrt(4)
2.0

This makes using unit-ful single-value variables more cumbersome than it should be.

Conversion from bar to mbar failed [Bug]

Hi,

I noticed an issue with the unit bar for the pressure, it seems that the parser which detects the prefixex such as m- for milli- does not work in that case.

Here is an example I ran and the error code

Cheers

Bachibouzouk

Python 2.7.3 (default, Jul 5 2013, 08:52:38)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.

Imported NumPy 1.6.1, SciPy 0.9.0, Matplotlib 1.1.1rc
Type "scientific" for more details.

from pint import UnitRegistry
ureg=UnitRegistry()
P=ureg.bar
P.to('Pa')
<Quantity(100000.0, 'pascal')>
P.to('mPa')
<Quantity(100000000.0, 'millipascal')>
P.to('mbar')
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python2.7/dist-packages/Pint-0.3.dev0-py2.7.egg/pint/quantity.py", line 192, in to
ret.ito(other)
File "/usr/local/lib/python2.7/dist-packages/Pint-0.3.dev0-py2.7.egg/pint/quantity.py", line 175, in ito
other = self._REGISTRY.parse_units(other)
File "/usr/local/lib/python2.7/dist-packages/Pint-0.3.dev0-py2.7.egg/pint/unit.py", line 746, in parse_units
cname = self.get_name(name)
File "/usr/local/lib/python2.7/dist-packages/Pint-0.3.dev0-py2.7.egg/pint/unit.py", line 549, in get_name
symbol = self.get_symbol(name)
File "/usr/local/lib/python2.7/dist-packages/Pint-0.3.dev0-py2.7.egg/pint/unit.py", line 570, in get_symbol
return self._prefixes[prefix].symbol + self._units[unit_name].symbol
TypeError: coercing to Unicode: need string or buffer, NoneType found

Special casing 1 dimension in unit.convert() leads to confusing error

Firstly, pint is really great. I've been looking for a good units package for months - finally stumbled across pint and it's just what I was hoping for.

Not sure if this is a bug or an enhancement, but the special casing in line 637 of unit.convert() leads to very confusing error messages when performing valid unit conversions where the source units which are defined as a function of multiple units:

In [1]: import pint

In [2]: pint.__version__
Out[2]: '0.2'

In [3]: ureg = pint.UnitRegistry()

In [4]: ureg.define('molar = mole / liter = M')

In [5]: t = 4 * ureg['mM']

In [6]: t
Out[6]: <Quantity(4, 'millimolar')>

In [7]: t.to('mole / liter')

DimensionalityError                       Traceback (most recent call last)
<ipython-input-7-5efb6e276de9> in <module>()
----> 1 t.to('mole / liter')

/usr/local/lib/python2.7/dist-packages/pint/quantity.pyc in to(self, other)
    189         """
    190         ret = copy.copy(self)
--> 191         ret.ito(other)
    192         return ret
    193 

/usr/local/lib/python2.7/dist-packages/pint/quantity.pyc in ito(self, other)
    178             other = UnitsContainer(other)
    179 
--> 180         self._magnitude = self._REGISTRY.convert(self._magnitude, self._units, other)
    181         self._units = other
    182         return self

/usr/local/lib/python2.7/dist-packages/pint/unit.py in convert(self, value, src, dst)
    639                 raise DimensionalityError(src, dst,
    640                                           self.get_dimensionality(src),
--> 641                                           self.get_dimensionality(dst))
    642             src_unit, src_value = list(src.items())[0]
    643             src_unit = self._units[src_unit]

DimensionalityError: Cannot convert from 'millimolar' ([substance] / [length] ** 3) to 
'mole / liter'  ([substance] / [length] ** 3)

I'd naively expect that to work correctly. The workaround is to convert to molar rather than mol/L.

pint.pi_theorem exhibits undefined behaviour on Python 3.3.

When running TestPiTheorem.test_simple in a loop like this:

{ while python3.3 -m unittest -v pint.testsuite.test_pitheorem.TestPiTheorem.test_simple; do true; done } &> pitheorem.log

it runs successfully a few times, then fails like this:

test_simple (pint.testsuite.test_pitheorem.TestPiTheorem) ... WARNING 2013-04-30 21:27:15,379 pi_theorem 226 A non dimension was found and a registry was not provided. Assuming that it is a dimension name: 1 {'m': 1}.
WARNING 2013-04-30 21:27:15,380 pi_theorem 226 A non dimension was found and a registry was not provided. Assuming that it is a dimension name: 1 {'m': 1, 's': -1.0}.
WARNING 2013-04-30 21:27:15,380 pi_theorem 226 A non dimension was found and a registry was not provided. Assuming that it is a dimension name: 1 {'s': 1}.
WARNING 2013-04-30 21:27:15,381 pi_theorem 226 A non dimension was found and a registry was not provided. Assuming that it is a dimension name: 1 {'m': 1}.
WARNING 2013-04-30 21:27:15,381 pi_theorem 226 A non dimension was found and a registry was not provided. Assuming that it is a dimension name: 1 {'m': 1, 's': -2.0}.
WARNING 2013-04-30 21:27:15,382 pi_theorem 226 A non dimension was found and a registry was not provided. Assuming that it is a dimension name: 1 {'grams': 1}.
WARNING 2013-04-30 21:27:15,382 pi_theorem 226 A non dimension was found and a registry was not provided. Assuming that it is a dimension name: 1 {'s': 1}.
FAIL

======================================================================
FAIL: test_simple (pint.testsuite.test_pitheorem.TestPiTheorem)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./pint/testsuite/test_pitheorem.py", line 25, in test_simple
    [{'g': 1, 'T': 2, 'L': -1}])
AssertionError: Lists differ: [{'T': 2, 'g': 2, 'L': -2}] != [{'L': -1, 'g': 1, 'T': 2}]

First differing element 0:
{'T': 2, 'g': 2, 'L': -2}
{'L': -1, 'g': 1, 'T': 2}

- [{'L': -2, 'T': 2, 'g': 2}]
?         ^               ^

+ [{'L': -1, 'T': 2, 'g': 1}]
?         ^               ^


----------------------------------------------------------------------
Ran 1 test in 0.060s

FAILED (failures=1)

Looking at the left-hand-side (i.e. the returned value) I notice that every instance of this I see has the same error, i.e. L and T multiplied by 2 from what they should be.

Additionally I've only managed to reproduce this with Python 3.3, I've seen this on Travis-CI a few times as well for pull request #20, also with 3.3 only:

Unicode support

I have added percent and permille to my definitions via:

percent = [fraction]; offset: 0 = %
permille = percent / 10 = ‰

Those definitions are loaded without any errors.

When I parse percents like 100 %, this works as expected. However with 100 ‰, I get the following error:

  File "/var/atmiz/eggs/Pint-0.2-py2.7.egg/pint/quantity.py", line 88, in __new__
    inst._units = inst._REGISTRY.parse_units(units)
  File "/var/atmiz/eggs/Pint-0.2-py2.7.egg/pint/unit.py", line 723, in parse_units
    units = ParserHelper.from_string(input_string)
  File "/var/atmiz/eggs/Pint-0.2-py2.7.egg/pint/util.py", line 320, in from_string
    {'L_': cls})
  File "<string>", line 1
    �
    ^
SyntaxError: invalid syntax

Unpexected treatment of values like: "", None, {}, [], False, True

Without much knowing about the inner working I have the following code - which I assume other end users might end up doing something similar:

# convert to Quantity - we pass the value as is to Quantity and let it do the conversion any errors we catch
try:
    q = self.unitregistry.Quantity(value)
except Exception as e:
    raise ValidationError("Field '{0}' can not parse '{1}' of type '{2}' into a valid quantity. Underlying " \
                                  " pint module parsing exception is: '{3}'".format(self.attname, value, type(value), e))

However rather en exception Quanity parses into values that don't seem to make much sense, especially for the empty string - which is what I expected my code to bail out on - I would think if we can not parse into something logical we should throw some kind of Parse exception. Now if this is by design since magnitude can be anything than for consistency reasons u"" should not parse into 1 dimensionless but rather into "" dimensionless thoughts?

Debug Server at port: 5678
self.unitregistry.Quantity("")
1 dimensionless

self.unitregistry.Quantity(None)
None dimensionless

self.unitregistry.Quantity({})
{} dimensionless

self.unitregistry.Quantity("asdf")
Traceback (most recent call last):
  File "/srv/www/django/development.<hidden>/src/github-texer-pydevsrc/pydevsrc/pydevd_comm.py", line 752, in doIt
    result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec)
  File "/srv/www/django/development.<hidden>/src/github-texer-pydevsrc/pydevsrc/pydevd_vars.py", line 375, in evaluateExpression
    result = eval(compiled, updated_globals, frame.f_locals)
  File "<string>", line 1, in <module>
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/danielsokolowski-pint/pint/quantity.py", line 74, in __new__
    inst = cls._REGISTRY.parse_expression(value)
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/danielsokolowski-pint/pint/unit.py", line 800, in parse_expression
    raise UndefinedUnitError(unknown)
UndefinedUnitError: 'asdf' is not defined in the unit registry

self.unitregistry.Quantity(False)
False dimensionless
self.unitregistry.Quantity(True)
True dimensionless
self.unitregistry.Quantity(None)
None dimensionless

self.unitregistry.Quantity()
Traceback (most recent call last):
  File "/srv/www/django/development.<hidden>/src/github-texer-pydevsrc/pydevsrc/pydevd_comm.py", line 752, in doIt
    result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec)
  File "/srv/www/django/development.<hidden>/src/github-texer-pydevsrc/pydevsrc/pydevd_vars.py", line 375, in evaluateExpression
    result = eval(compiled, updated_globals, frame.f_locals)
  File "<string>", line 1, in <module>
TypeError: __new__() takes at least 2 arguments (1 given)

import error (python2.6.5)

Hi,

I wanted to try your module, but it failed at importing it.
Here the call stack :

Python 2.6.5 (r265:79063, Nov 12 2010, 00:45:29)
[GCC 4.4.4 20100525 (Red Hat 4.4.4-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

import pint
Traceback (most recent call last):
File "", line 1, in
File "/home/user/py26/lib/python2.6/site-packages/pint/init.py", line 15, in
from .pint import UnitRegistry, DimensionalityError, UnitsContainer, UndefinedUnitError, logger, version
File "/home/user/py26/lib/python2.6/site-packages/pint/pint.py", line 464
conv.update({alias: name for alias in aliases})
^
SyntaxError: invalid syntax

The ^ symbol show the for statement.

Thanks in advance if you could check the problem.

IPython completion error

Running this with Python 3.3:

import pint
ureg = pint.unit.UnitRegistry()
ureg.<TAB>

Gives:

In [21]: ureg.Traceback (most recent call last):
  File "/home/ale/Programs/my-python3-env/lib/python3.3/site-packages/IPython/core/completer.py", line 855, in complete
    self.matches.extend(matcher(text))
  File "/home/ale/Programs/my-python3-env/lib/python3.3/site-packages/IPython/core/completer.py", line 648, in python_matches
    matches = self.attr_matches(text)
  File "/home/ale/Programs/my-python3-env/lib/python3.3/site-packages/IPython/core/completer.py", line 365, in attr_matches
    words = dir2(obj)
  File "/home/ale/Programs/my-python3-env/lib/python3.3/site-packages/IPython/utils/dir2.py", line 61, in dir2
    if hasattr(obj, attr):
  File "/home/ale/Programs/my-python3-env/lib/python3.3/site-packages/pint/unit.py", line 424, in __getattr__
    return self.Quantity(1, item)
  File "/home/ale/Programs/my-python3-env/lib/python3.3/site-packages/pint/quantity.py", line 88, in __new__
    inst._units = inst._REGISTRY.parse_units(units)
  File "/home/ale/Programs/my-python3-env/lib/python3.3/site-packages/pint/unit.py", line 730, in parse_units
    cname = self.get_name(name)
  File "/home/ale/Programs/my-python3-env/lib/python3.3/site-packages/pint/unit.py", line 523, in get_name
    raise UndefinedUnitError(name_or_alias)
pint.unit.UndefinedUnitError: 'trait_names' is not defined in the unit registry

If you suspect this is an IPython bug, please report it at:
    https://github.com/ipython/ipython/issues
or send an email to the mailing list at [email protected]

You can print a more detailed traceback right now with "%tb", or use "%debug"
to interactively debug it.

Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
    %config Application.verbose_crash=True

Roadmap for v0.2

This is the roadmap for v0.2 (expected late March 2013)::

  1. Measurements (value +/- uncertainties). Initial work in 4441b8a
    • A new class (Measurement).
    • Error propagation of addition, product and power.
    • Format to string. repr, str, pretty and latex.
  2. Buckingahm Pi theorem. Initial work in 293bd23
    • Determination of dimensionless quantities based on units, dimensions or quantities.
  3. Temperature units
    • DegC, DegF, DegK, DegR for Celsius, Fahrenheit, Kelvin and Rankine.
    • Delta version for use in multiplicative units (e.g. DeltaDegC).
    • Smart selection of Delta version based on context.
    • Meaningful error messages for unsupported operations.

We are open for suggestions.

iter() called on single-value Quantity returns bogus iterator

I'm not sure if this is a true 'bug', but I think changing this would improve interoperability.

Calling iter() on a single-value Quantity returns an iterator without error, yet said iterator raises a TypeError exception when one tries to iterate through it. For example:

>>> it = iter(ureg.m)
>>> it.next()
...
TypeError: Neither Quantity object nor its magnitude (1)supports indexing

Instead, the call to iter() itself should fail, as with ints and in numpy:

>>> iter(1)
...
TypeError: 'int' object is not iterable
>>> iter(np.array(1))
...
TypeError: iteration over a 0-d array

A call to iter() is sometimes used to check if an object is iterable before being looped over, e.g. in Matplotlib. Arguably such code could be improved, but I see no harm in making this change to Pint to fix the issue.

My proposed solution is to add an __iter__() method to the Quantity class:

def __iter__(self):
    it_mag = iter(self.magnitude)
    return iter((self.__class__(mag, self._units) for mag in it_mag))

There might be better ways to do this, but it seems to work fine. If desired, the exception could be caught and re-raised with a new Pint-specific error message.

Comprehensive NumPy Testing

None of the python units packages currently has a comprehensive testing suite for NumPy operations. A testing suite for ufuncs and common numpy methods is needed.

Pint always uses floor division

Around line 928 of pint.py, normal division is defined as floor division:
div = floordiv

Is there a reason div was not implemented?

Thanks.

Printing Fractional Exponents Less than 1

Whenever you create a unit with a fractional exponent less than one, it is printed as if the exponent is negative. However, the internal representation of the units is still correct. Consider the following examples:

>>> ureg['m^0.5']                      # 0.5 < 1
<Quantity(1.0, '1 / meter ** 0.5')>    # The printing indicates m^-0.5
>>> ureg['m^0.5'].units
<UnitsContainer({'meter': 0.5})>       # But the internal representation is fine

>>> ureg['m^-0.5']
<Quantity(1.0, '1 / meter ** 0.5')>    # Notice the same printing as above
>>> ureg['m^-0.5'].units
<UnitsContainer({'meter': -0.5})>

>>> ureg['m^0.5'] * ureg['m^-0.5']
<Quantity(1.0, 'dimensionless')>       # This is still correct

>>> ureg['m^1.1']
<Quantity(1.0, 'meter ** 1.1')>        # 1.1 > 1, correct printing
>>> ureg['m^0.9']
<Quantity(1.0, '1 / meter ** 0.9')>    # 0.9 < 1, printing as if -0.9

Contexts: a new feature to simplify common conversions in specialized situations

`If you work in certain topics, you usually need to convert from certain units to others based some pre-established relationships.

For example, you are working with EM fields in vacuum and you need to transform wavelength to frequency. If you try this:

>>> q = 500 * ureg.nm
>>> q.to('Hz') 
Traceback (most recent call last):
...
pint.unit.DimensionalityError: Cannot convert from 'nanometer' ([length]) to 'hertz' (1 / [time])

You need to use the relation wavelength = speed_of_light * frequency.

>>> (ureg.speed_of_light / q).to('Hz')
<Quantity(5.99584916e+14, 'hertz')>

The plan is to provide a context (abbreviated ctx) to facilitate this:

>>> q.to('Hz', ctx='m = c * s')
<Quantity(5.99584916e+14, 'hertz')>

or alternative as a context manager:

>>> with ureg.ctx('m = c * s'):
>>>     q.to('Hz')
<Quantity(5.99584916e+14, 'hertz')>

Some context will be predefined in the definitions file. The proposed syntax is:

@context spectroscopy = sp
    m = c * s

which then can be used as:

>>> q.to('Hz', ctx='spectroscopy')
<Quantity(5.99584916e+14, 'hertz')>

or with the abbreviated form:

>>> q.to('Hz', ctx='sp')
<Quantity(5.99584916e+14, 'hertz')>

You can define multiple relations in a single context (one per line in the definition file or in an tuple when you define it in situ)

Open points:

  • naming: Alternative names for ctx are: context, using
  • definitions: Maybe is clearer to define contexts with dimensions.
    eg: [length] = c * [time]

Multiple UnitRegistry instances share defined units

Based on the documentation of the UnitRegistry I would expect to be able to instantiate the registry without knowledge of any units. However, the following case already fails to adhere to this description:

from pint import UnitRegistry
q = UnitRegistry(filename=None)
print(q.meter)

As far as I can determine, this is due to the UnitRegistry class sharing the _UNITS, _PREFIXES and _SUFFIXES members across instances.

Is this the intended behaviour? (Because I wanted to create a system of units unrelated to the default system, which is a tad difficult if you get all the bagage for free...)

Resolving common names(, or not)

It would be nice if there was on option to retain the given name when defining units.

Specifically, it would be nice if you could define distances in metric units without them being "corrected" to the US-only spelling of metre.

Such an option would also be make it far simpler(IMO) to work with abbreviated names. You could just use ureg.km/ureg.h in definitions and %s to display, instead of having to use the ~ modifier in all your display code.

Thanks,

James


While I have your attention I'm curious where the work_year definition comes from, and I can't seem to find a definition with Google. Any hints?

Full support for uncertainties

It would be nice to have full support for uncertainties (including correlations, all mathematical functions, etc.).

Maybe you could make use of the (pure Python) module I wrote for this (uncertainties).

Dimensionless Quantities behave unexpectedly with some math functions

This behavior applies to both numpy and python standard mathematical functions. Firstly, np.sqrt behaves as expected (provided you work around issue #44 ), while math.sqrt first exhibits the issue:

>>> np.sqrt( [1] * ureg.m/ureg.cm )
<Quantity([ 1.], '1 / centimeter ** 0.5 / meter ** 0.5')>
>>> _.to('')
<Quantity([ 10.], 'dimensionless')>
>>> math.sqrt( 1 * ureg.m/ureg.cm )
1.0

In the first case, units are retained, so the dimensionless quantity stays correct. However, in the second case I believe the quantity is cast to a float by directly taking the magnitude, which is 1.0 (in units of m/cm) rather than (the truly dimensionless) 100, which is expected.

When casting a dimensionless Quantity to a float, the most sensible float value is the value of the 'true' dimensionless number. Otherwise you get extremely unintuitive results such as

>>> float(ureg.V/ureg.mV)
1.0

Furthermore, this requires an ugly and cumbersome workaround to work as expected.

>>> float( (ureg.V/ureg.mV).to('') )
1000.0

Simply not using python's math module isn't a solution, since similar issues can be found with when using numpy as in np.sin():

>>> np.sin( [np.pi/2] * ureg.m/ureg.m )
<Quantity([ 1.], 'dimensionless')>
>>> np.sin( [np.pi/2] * ureg.cm/ureg.m )
<Quantity([ 1.], 'dimensionless')>
>>> np.sin( ([np.pi/2] * ureg.cm/ureg.m).to('') )
<Quantity([ 0.01570732], 'dimensionless')>

Interestingly, np.arccos() seems to work as expected:

>>> np.arccos( [1] * ureg.m/ureg.m )
<Quantity([ 0.], 'radian')>
>>> np.arccos( [1] * ureg.cm/ureg.m )
<Quantity([ 1.56079616], 'radian')>

Multiplication of 'dimensionless' values unexpected outcome?

What kind of physical measurement is a 100 kilogram that is dimensionless?

>> Q_(100) * UnitRegistry()['kg'] == Q_('100 kg')
False
>>> 100 * UnitRegistry()['kg'] == Q_('100 kg')
True
>>> Q_(100) * UnitRegistry()['kg']
<Quantity(100 kilogram, 'dimensionless')>
>>> UnitRegistry()['100 kg']
<Quantity(100, 'kilogram')>

I humbly think pint is broken by design...but please correct me.

Decorator for numeric functions that require values in specific units.

Implemente a decorator
Add decorate method to registry to be used in the following way:

from pint import UnitRegistry
ureg = UnitRegistry()

@ureg.decorate(args=['meter', 'second'], ret='joule')
def func(length, time):
     # Some calculation that takes values in meters and seconds
     return value

print(func(500 * ureg.nanometer, 6 ureg.hour))
8 joule

Minor website typos

I've come across a few typos/issues on the readthedocs website and thought I'd point them out.

First, the "Code in GitHub" link on the left sidebar mistakenly points to Lantz, not Pint.

Second, in the PDF documentation, the link for the "Units" package on page 19 appears to be dead. It looks like the bitbucket page for the project can be found here: https://bitbucket.org/adonohue/units/

Dimensionless Quantities behave unexpectedly when added to 'raw' numbers

This issue is similar to issue #45 (thanks for fixing that, btw).

When dimensionless Quantities are added to 'raw' number types (int, float, np.float64, etc.), the number seems to be added directly to the magnitude of the Quantity rather than being properly converted to the Quantity's special 'unitless' units. For example:

>>> (ureg.km/ureg.m + 1).to('')
<Quantity(2000.0, 'dimensionless')>    # Wrong
>>> (ureg.km/ureg.m).to('') + 1
<Quantity(1001.0, 'dimensionless')>    # Correct

Interpreting space between numbers as something other than a multiplier

Hi,

Great package! Very useful. Thanks for that.

I observed that when the parser is input something like '2 1/2 in', it doesn't parse it as 2.5 inch but as 1 inch because the space between 2 and 1/2 is interpreted as a multiplication.

In [2]: ureg = UnitRegistry()
In [3]: ureg.Quantity('2 1/2 in')
Out[3]: <Quantity(1.0, 'inch')>

Is there any workaround for this? I can understand this being the default behavior, but is there any override that is possible?

Pavan

Import directive to include a definitions file in another.

Support an import directive in definitions file that allows to include one definition file in another:

The proposed syntax is similar to css:

@import <path to a definition file (absolute or relative to the current path)>

For example, to include constants_en.txt

# Same folder
@import constants_en.txt
# Parent folder
@import ../constants_en.txt
# Absolute path
@import /path/to/constants_en.txt

Semantics

  • The definitions in the imported filed are added to the registry when the @import statement is found
  • Path are written in unix style

ImportError: No module named 'pkg_resources'

After installing using "python setup.py install" and entering "from pint import UnitRegistry" into Python GUI, I get ImportError: No module named 'pkg_resources'". Where and how do I get or find pkg_resources? I am running windows 7, 64-bit, Python 3.3.1.

AttributeError: 'int' object has no attribute '_Quantity__handling'

Expected result below ought to be '100 dimensionless'.

self.unitregistry.Quantity(100)
100 dimensionless
self.unitregistry.Quantity('100')
Traceback (most recent call last):
  File "/srv/www/django/development.<hidden>/src/github-texer-pydevsrc/pydevsrc/pydevd_comm.py", line 752, in doIt
    result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec)
  File "/srv/www/django/development.<hidden>/src/github-texer-pydevsrc/pydevsrc/pydevd_vars.py", line 375, in evaluateExpression
    result = eval(compiled, updated_globals, frame.f_locals)
  File "<string>", line 1, in <module>
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/danielsokolowski-pint/pint/quantity.py", line 96, in __new__
    inst.__handling = None
AttributeError: 'int' object has no attribute '_Quantity__handling'
self.unitregistry.Quantity(100.00)
100.0 dimensionless
self.unitregistry.Quantity(Decimal('100'))
100 dimensionless

Perhaps consider putting 'beta' status back onto the package, this is not production ready.

Pretty Printing Fractional Exponential Units

I have found what I think is a bug, and an opportunity to both fix the bug and enhance Pint.

Whenever a quantity is defined with a fractional exponent in a unit, the exponent is converted to a decimal representation, which is all well and good. However, when pretty printing, the decimal point is not superscripted with the rest of the exponent. For example:

>>> x = ureg['s**(3/2)']

>>> x.units  # 3/2 converted to 1.5
<UnitsContainer({'second': 1.5})>

>>> "{:P~}".format(x)  # Exponent becomes ¹.⁵
'1.0 s¹.⁵'

A solution could be to keep fractional representations in fractional form, and use the unicode fraction slash character (U+2044 = ⁄ ) to compose arbitrary fractions with subscript and superscript numbers. It would be nice for the above example to evaluate to:

>>> "{:P~}".format(x)
'1.0 s³⁄₂'

The ³⁄₂ is a superscript 3, a fraction slash, and a subscript 2.

I don't know how feasible this is. Certainly, getting the decimal in the exponent would be great, but I don't know of a superscript decimal unicode character. I also don't know if storing fractions would be too much trouble for the rest of the system.

I can try to tackle this myself unless someone has an easy solution.

Add angular frequency

Adding angular frequency to the default unit definition could be useful:

hertz = 2 * pi * radian / second

Support significant digits in string representation of Measurements

Currently the value and error of a Measurement are formatted separately into string following the standard number formatting. The value should be formatted according to the error and an specified significant digits argument.

The proposed syntax is:

>>> m = Q_(8, 's').plus_minus(.21)
>>> '{:s}'.format(m) # defaults to 2 significant digits
(8.00 +/- .21) s
>>> '{:s1}'.format(m)
(8.0 +/- .2) s
>>> '{:s2}'.format(m)
(8.00 +/- .21) s

The same for r, l, p (representation, latex and pretty) formatting.

Temperature conversions are incorrect

>>> from pint import UnitRegistry
>>> ureg = UnitRegistry()
>>> Q_ = ureg.Quantity
>>> Q_('0 * degK').to('degC')
<Quantity(0.0, 'degC')>
>>> Q_('0 * degC').to('degF')
<Quantity(0.0, 'degF')>
>>> Q_('100 * degC').to('degF')
<Quantity(55.55555555555556, 'degF')>
>>> Q_('212 * degF').to('degC')
<Quantity(381.6, 'degC')>

It seems like the "offset" parameter in the definition file is being ignored. The test_offset method in test_pint.py is decorated with unittest.expectedFailure.

How are dimensionless numbers handled?

I was experimenting with pint, and I wanted to scale a length by another length. I expected to get a dimensionless number, and I kind of did, but not the one I expected! the units on the result were mixed, and the magnitude was not what I expected. Is there some trick to get the right magnitude of a dimensionless number?

from pint import UnitRegistry
u = UnitRegistry()

distance = 24.0 * u.meter

dd = distance / (2*u.ft)
print dd, dd.magnitude

print 1_u.meter / 1_u.cm

+END_SRC

+RESULTS:

: 12.0 meter / foot 12.0
: 1.0 centimeter * meter

pint.util:Exception

Fantastic package!


platform: Windows 7
Python 2.7.5 (WinPython-32bit-2.7.5.1)
Pint version from github: 24842ad5dc85d08ea569014d3dcd81172973e204

>>> from pint import UnitRegistry
>>> ureg = UnitRegistry()

ERROR:pint.util:Exception: Cannot add 'fine_structure_constant =  7.2973525698e-3' 'float' object has no attribute 'keys'

TypeError: unsupported operand type(s) for *: 'float' and 'Decimal'

I have only traced the bug on surface so I do not understand why this method is called UnitRegistry.convert(...). In a nut shell, using Decimal magnitude as opposed to float causes this method to fail as it tried to multiply Decimal and floats together - below is the stack trace.

>>> Offer(product=Product.objects.get(pk=1), amount_min='1000 kg', user=User.objects.get(pk=1), company=Company.objects.get(pk=1)).full_clean()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-ticket_20625-tailored/django/db/models/base.py", line 923, in full_clean
    self.clean_fields(exclude=exclude)
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-ticket_20625-tailored/django/db/models/base.py", line 965, in clean_fields
    setattr(self, f.attname, f.clean(raw_value, self))
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-ticket_20625-tailored/django/db/models/fields/__init__.py", line 256, in clean
    self.run_validators(value)
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-ticket_20625-tailored/django/db/models/fields/__init__.py", line 202, in run_validators
    if value in self.empty_values:
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/danielsokolowski-pint/pint/quantity.py", line 347, in __eq__
    return self.dimensionless and _eq(self.magnitude, other)
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/danielsokolowski-pint/pint/quantity.py", line 153, in dimensionless
    tmp = copy.copy(self).to_base_units()
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/danielsokolowski-pint/pint/quantity.py", line 210, in to_base_units
    ret.ito_base_units()
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/danielsokolowski-pint/pint/quantity.py", line 201, in ito_base_units
    self._magnitude = self._REGISTRY.convert(self._magnitude, self._units, other)
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/danielsokolowski-pint/pint/unit.py", line 674, in convert
    # Clone and put on Python path: https://github.com/tenXer/PyDevSrc, place this in your settings_development.py, and place your 'break' points in Eclipse
TypeError: unsupported operand type(s) for *: 'float' and 'Decimal'

Manual PYTHONPATH based Git clone install errors on __init__

Rather then system wide installs I prefer to required place code within the project root. This accomplished by auto appending 'pint' to the python path environment variable - in a similar fashion to what PIP but with less gotchas. Such install barfs as follows during the 'pint.init' parsing:

 File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/__init__.py", line 9, in <module>
    import pint
  File "/srv/www/django/development.<hidden>/src/github-danielsokolowski-django-unitofmeasure/unitofmeasure/hgrecco-pint/pint/__init__.py", line 19, in <module>
    __version__ = pkg_resources.get_distribution('pint').version
  File "build/bdist.linux-i686/egg/pkg_resources.py", line 339, in get_distribution
  File "build/bdist.linux-i686/egg/pkg_resources.py", line 212, in get_provider
  File "build/bdist.linux-i686/egg/pkg_resources.py", line 695, in require
  File "build/bdist.linux-i686/egg/pkg_resources.py", line 594, in resolve
pkg_resources.DistributionNotFound: pint

This is caused by following line 19@init.py:

__version__ = pkg_resources.get_distribution('pint').version

Proposed patch to follow shortly.

Some dimensionless comparisons fail with maximum recursion exception

I have a very strange problem with pint 0.2.1:

>>> from pint import UnitRegistry
>>> q = UnitRegistry()
>>> d = 1 * q.dimensionless
>>> d < 1
True
>>> d > 1
RuntimeError: maximum recursion depth exceeded while calling a Python object
>>> d <= 1
RuntimeError: maximum recursion depth exceeded while calling a Python object
>>> d >= 1
True

I can come up with workarounds but it's really a problem in pint.

Issue with no constants_en.txt unpacked (Python3.3 Windows 7)

Hi,
After installing pint on a Windows 7 machine, I get an error on import:

Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600 32 bit (In
tel)] on win32
Type "help", "copyright", "credits" or "license" for more information.

import pint
Traceback (most recent call last):
File "", line 1, in
File "", line 1567, in find_and_load
File "", line 1534, in find_and_load_unlocked
File "c:\python33\lib\site-packages\pint-0.4.dev0-py3.3.egg\pint__init
.py",
line 22, in
File "c:\python33\lib\site-packages\pint-0.4.dev0-py3.3.egg\pint\unit.py", lin
e 417, in init
File "c:\python33\lib\site-packages\pint-0.4.dev0-py3.3.egg\pint\unit.py", lin
e 492, in load_definitions
File "c:\python33\lib\site-packages\pint-0.4.dev0-py3.3.egg\pint\unit.py", lin
e 504, in load_definitions
File "c:\python33\lib\site-packages\pint-0.4.dev0-py3.3.egg\pint\unit.py", lin
e 491, in load_definitions
FileNotFoundError: [Errno 2] No such file or directory: 'C:\Users\dkaufman\Ap
pData\Roaming\Python-Eggs\pint-0.4.dev0-py3.3.egg-tmp\pint\constants_en.txt
'
For some reason, it seems that upon import, defaults_en.txt gets unpacked, but not constants_en.txt

Thanks,
Duane

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.