Embedded the Pint library for units with the other libraries.

This commit is contained in:
Jeremy Mack Wright 2015-10-26 16:38:24 -04:00
parent 3e00cf6ffe
commit 8f36ee4fac
28 changed files with 9377 additions and 2 deletions

View File

@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
"""
pint
~~~~
Pint is Python module/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.
:copyright: (c) 2012 by Hernan E. Grecco.
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import subprocess
import pkg_resources
from .formatting import formatter
from .unit import (UnitRegistry, DimensionalityError, OffsetUnitCalculusError,
UndefinedUnitError, LazyRegistry)
from .util import pi_theorem, logger
from .context import Context
try: # pragma: no cover
__version__ = pkg_resources.get_distribution('pint').version
except: # pragma: no cover
# we seem to have a local copy not installed without setuptools
# so the reported version will be unknown
__version__ = "unknown"
#: A Registry with the default units and constants.
_DEFAULT_REGISTRY = LazyRegistry()
#: Registry used for unpickling operations.
_APP_REGISTRY = _DEFAULT_REGISTRY
def _build_quantity(value, units):
"""Build Quantity using the Application registry.
Used only for unpickling operations.
"""
global _APP_REGISTRY
return _APP_REGISTRY.Quantity(value, units)
def set_application_registry(registry):
"""Set the application registry which is used for unpickling operations.
:param registry: a UnitRegistry instance.
"""
assert isinstance(registry, UnitRegistry)
global _APP_REGISTRY
logger.debug('Changing app registry from %r to %r.', _APP_REGISTRY, registry)
_APP_REGISTRY = registry
def _run_pyroma(data): # pragma: no cover
"""Run pyroma (used to perform checks before releasing a new version).
"""
import sys
from zest.releaser.utils import ask
if not ask("Run pyroma on the package before uploading?"):
return
try:
from pyroma import run
result = run(data['tagdir'])
if result != 10:
if not ask("Continue?"):
sys.exit(1)
except ImportError:
if not ask("pyroma not available. Continue?"):
sys.exit(1)
def _check_travis(data): # pragma: no cover
"""Check if Travis reports that everything is ok.
(used to perform checks before releasing a new version).
"""
import json
import sys
from zest.releaser.utils import system, ask
if not ask('Check with Travis before releasing?'):
return
try:
# Python 3
from urllib.request import urlopen
def get(url):
return urlopen(url).read().decode('utf-8')
except ImportError:
# Python 2
from urllib2 import urlopen
def get(url):
return urlopen(url).read()
url = 'https://api.github.com/repos/%s/%s/status/%s'
username = 'hgrecco'
repo = 'pint'
commit = system('git rev-parse HEAD')
try:
result = json.loads(get(url % (username, repo, commit)))['state']
print('Travis says: %s' % result)
if result != 'success':
if not ask('Do you want to continue anyway?', default=False):
sys.exit(1)
except Exception:
print('Could not determine the commit state with Travis.')
if ask('Do you want to continue anyway?', default=False):
sys.exit(1)
def test():
"""Run all tests.
:return: a :class:`unittest.TestResult` object
"""
from .testsuite import run
return run()

View File

@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
"""
pint.compat
~~~~~~~~~~~
Compatibility layer.
:copyright: 2013 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import division, unicode_literals, print_function, absolute_import
import sys
import tokenize
from numbers import Number
from decimal import Decimal
PYTHON3 = sys.version >= '3'
if PYTHON3:
from io import BytesIO
string_types = str
tokenizer = lambda input_string: tokenize.tokenize(BytesIO(input_string.encode('utf-8')).readline)
def u(x):
return x
maketrans = str.maketrans
long_type = int
else:
from StringIO import StringIO
string_types = basestring
tokenizer = lambda input_string: tokenize.generate_tokens(StringIO(input_string).readline)
import codecs
def u(x):
return codecs.unicode_escape_decode(x)[0]
maketrans = lambda f, t: dict((ord(a), b) for a, b in zip(f, t))
long_type = long
if sys.version_info < (2, 7):
try:
import unittest2 as unittest
except ImportError:
raise Exception("Testing Pint in Python 2.6 requires package 'unittest2'")
else:
import unittest
try:
from collections import Chainmap
except ImportError:
from .chainmap import ChainMap
try:
from collections import TransformDict
except ImportError:
from .transformdict import TransformDict
try:
from functools import lru_cache
except ImportError:
from .lrucache import lru_cache
try:
from logging import NullHandler
except ImportError:
from .nullhandler import NullHandler
try:
import numpy as np
from numpy import ndarray
HAS_NUMPY = True
NUMPY_VER = np.__version__
NUMERIC_TYPES = (Number, Decimal, ndarray, np.number)
def _to_magnitude(value, force_ndarray=False):
if isinstance(value, (dict, bool)) or value is None:
raise TypeError('Invalid magnitude for Quantity: {0!r}'.format(value))
elif isinstance(value, string_types) and value == '':
raise ValueError('Quantity magnitude cannot be an empty string.')
elif isinstance(value, (list, tuple)):
return np.asarray(value)
if force_ndarray:
return np.asarray(value)
return value
except ImportError:
np = None
class ndarray(object):
pass
HAS_NUMPY = False
NUMPY_VER = '0'
NUMERIC_TYPES = (Number, Decimal)
def _to_magnitude(value, force_ndarray=False):
if isinstance(value, (dict, bool)) or value is None:
raise TypeError('Invalid magnitude for Quantity: {0!r}'.format(value))
elif isinstance(value, string_types) and value == '':
raise ValueError('Quantity magnitude cannot be an empty string.')
elif isinstance(value, (list, tuple)):
raise TypeError('lists and tuples are valid magnitudes for '
'Quantity only when NumPy is present.')
return value
try:
from uncertainties import ufloat
HAS_UNCERTAINTIES = True
except ImportError:
ufloat = None
HAS_UNCERTAINTIES = False

View File

@ -0,0 +1,153 @@
# -*- coding: utf-8 -*-
"""
pint.compat.chainmap
~~~~~~~~~~~~~~~~~~~~
Taken from the Python 3.3 source code.
:copyright: 2013, PSF
:license: PSF License
"""
from __future__ import division, unicode_literals, print_function, absolute_import
import sys
from collections import MutableMapping
if sys.version_info < (3, 0):
from thread import get_ident
elif sys.version_info < (3, 3):
from _thread import get_ident
else:
from threading import get_ident
def _recursive_repr(fillvalue='...'):
'Decorator to make a repr function return fillvalue for a recursive call'
def decorating_function(user_function):
repr_running = set()
def wrapper(self):
key = id(self), get_ident()
if key in repr_running:
return fillvalue
repr_running.add(key)
try:
result = user_function(self)
finally:
repr_running.discard(key)
return result
# Can't use functools.wraps() here because of bootstrap issues
wrapper.__module__ = getattr(user_function, '__module__')
wrapper.__doc__ = getattr(user_function, '__doc__')
wrapper.__name__ = getattr(user_function, '__name__')
wrapper.__annotations__ = getattr(user_function, '__annotations__', {})
return wrapper
return decorating_function
class ChainMap(MutableMapping):
''' A ChainMap groups multiple dicts (or other mappings) together
to create a single, updateable view.
The underlying mappings are stored in a list. That list is public and can
accessed or updated using the *maps* attribute. There is no other state.
Lookups search the underlying mappings successively until a key is found.
In contrast, writes, updates, and deletions only operate on the first
mapping.
'''
def __init__(self, *maps):
'''Initialize a ChainMap by setting *maps* to the given mappings.
If no mappings are provided, a single empty dictionary is used.
'''
self.maps = list(maps) or [{}] # always at least one map
def __missing__(self, key):
raise KeyError(key)
def __getitem__(self, key):
for mapping in self.maps:
try:
return mapping[key] # can't use 'key in mapping' with defaultdict
except KeyError:
pass
return self.__missing__(key) # support subclasses that define __missing__
def get(self, key, default=None):
return self[key] if key in self else default
def __len__(self):
return len(set().union(*self.maps)) # reuses stored hash values if possible
def __iter__(self):
return iter(set().union(*self.maps))
def __contains__(self, key):
return any(key in m for m in self.maps)
def __bool__(self):
return any(self.maps)
@_recursive_repr()
def __repr__(self):
return '{0.__class__.__name__}({1})'.format(
self, ', '.join(map(repr, self.maps)))
@classmethod
def fromkeys(cls, iterable, *args):
'Create a ChainMap with a single dict created from the iterable.'
return cls(dict.fromkeys(iterable, *args))
def copy(self):
'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]'
return self.__class__(self.maps[0].copy(), *self.maps[1:])
__copy__ = copy
def new_child(self, m=None): # like Django's _Context.push()
'''
New ChainMap with a new map followed by all previous maps. If no
map is provided, an empty dict is used.
'''
if m is None:
m = {}
return self.__class__(m, *self.maps)
@property
def parents(self): # like Django's _Context.pop()
'New ChainMap from maps[1:].'
return self.__class__(*self.maps[1:])
def __setitem__(self, key, value):
self.maps[0][key] = value
def __delitem__(self, key):
try:
del self.maps[0][key]
except KeyError:
raise KeyError('Key not found in the first mapping: {!r}'.format(key))
def popitem(self):
'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.'
try:
return self.maps[0].popitem()
except KeyError:
raise KeyError('No keys found in the first mapping.')
def pop(self, key, *args):
'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].'
try:
return self.maps[0].pop(key, *args)
except KeyError:
raise KeyError('Key not found in the first mapping: {!r}'.format(key))
def clear(self):
'Clear maps[0], leaving maps[1:] intact.'
self.maps[0].clear()

View File

@ -0,0 +1,177 @@
# -*- coding: utf-8 -*-
"""
pint.compat.lrucache
~~~~~~~~~~~~~~~~~~~~
LRU (least recently used) cache backport.
From https://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python-33s-lru-cache/
:copyright: 2004, Raymond Hettinger,
:license: MIT License
"""
from collections import namedtuple
from functools import update_wrapper
from threading import RLock
_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
class _HashedSeq(list):
__slots__ = 'hashvalue'
def __init__(self, tup, hash=hash):
self[:] = tup
self.hashvalue = hash(tup)
def __hash__(self):
return self.hashvalue
def _make_key(args, kwds, typed,
kwd_mark = (object(),),
fasttypes = set((int, str, frozenset, type(None))),
sorted=sorted, tuple=tuple, type=type, len=len):
'Make a cache key from optionally typed positional and keyword arguments'
key = args
if kwds:
sorted_items = sorted(kwds.items())
key += kwd_mark
for item in sorted_items:
key += item
if typed:
key += tuple(type(v) for v in args)
if kwds:
key += tuple(type(v) for k, v in sorted_items)
elif len(key) == 1 and type(key[0]) in fasttypes:
return key[0]
return _HashedSeq(key)
def lru_cache(maxsize=100, typed=False):
"""Least-recently-used cache decorator.
If *maxsize* is set to None, the LRU features are disabled and the cache
can grow without bound.
If *typed* is True, arguments of different types will be cached separately.
For example, f(3.0) and f(3) will be treated as distinct calls with
distinct results.
Arguments to the cached function must be hashable.
View the cache statistics named tuple (hits, misses, maxsize, currsize) with
f.cache_info(). Clear the cache and statistics with f.cache_clear().
Access the underlying function with f.__wrapped__.
See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
"""
# Users should only access the lru_cache through its public API:
# cache_info, cache_clear, and f.__wrapped__
# The internals of the lru_cache are encapsulated for thread safety and
# to allow the implementation to change (including a possible C version).
def decorating_function(user_function):
cache = dict()
stats = [0, 0] # make statistics updateable non-locally
HITS, MISSES = 0, 1 # names for the stats fields
make_key = _make_key
cache_get = cache.get # bound method to lookup key or return None
_len = len # localize the global len() function
lock = RLock() # because linkedlist updates aren't threadsafe
root = [] # root of the circular doubly linked list
root[:] = [root, root, None, None] # initialize by pointing to self
nonlocal_root = [root] # make updateable non-locally
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields
if maxsize == 0:
def wrapper(*args, **kwds):
# no caching, just do a statistics update after a successful call
result = user_function(*args, **kwds)
stats[MISSES] += 1
return result
elif maxsize is None:
def wrapper(*args, **kwds):
# simple caching without ordering or size limit
key = make_key(args, kwds, typed)
result = cache_get(key, root) # root used here as a unique not-found sentinel
if result is not root:
stats[HITS] += 1
return result
result = user_function(*args, **kwds)
cache[key] = result
stats[MISSES] += 1
return result
else:
def wrapper(*args, **kwds):
# size limited caching that tracks accesses by recency
key = make_key(args, kwds, typed) if kwds or typed else args
with lock:
link = cache_get(key)
if link is not None:
# record recent use of the key by moving it to the front of the list
root, = nonlocal_root
link_prev, link_next, key, result = link
link_prev[NEXT] = link_next
link_next[PREV] = link_prev
last = root[PREV]
last[NEXT] = root[PREV] = link
link[PREV] = last
link[NEXT] = root
stats[HITS] += 1
return result
result = user_function(*args, **kwds)
with lock:
root, = nonlocal_root
if key in cache:
# getting here means that this same key was added to the
# cache while the lock was released. since the link
# update is already done, we need only return the
# computed result and update the count of misses.
pass
elif _len(cache) >= maxsize:
# use the old root to store the new key and result
oldroot = root
oldroot[KEY] = key
oldroot[RESULT] = result
# empty the oldest link and make it the new root
root = nonlocal_root[0] = oldroot[NEXT]
oldkey = root[KEY]
oldvalue = root[RESULT]
root[KEY] = root[RESULT] = None
# now update the cache dictionary for the new links
del cache[oldkey]
cache[key] = oldroot
else:
# put result in a new link at the front of the list
last = root[PREV]
link = [last, root, key, result]
last[NEXT] = root[PREV] = cache[key] = link
stats[MISSES] += 1
return result
def cache_info():
"""Report cache statistics"""
with lock:
return _CacheInfo(stats[HITS], stats[MISSES], maxsize, len(cache))
def cache_clear():
"""Clear the cache and cache statistics"""
with lock:
cache.clear()
root = nonlocal_root[0]
root[:] = [root, root, None, None]
stats[:] = [0, 0]
wrapper.__wrapped__ = user_function
wrapper.cache_info = cache_info
wrapper.cache_clear = cache_clear
return update_wrapper(wrapper, user_function)
return decorating_function

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
"""
pint.compat.nullhandler
~~~~~~~~~~~~~~~~~~~~~~~
Taken from the Python 2.7 source code.
:copyright: 2013, PSF
:license: PSF License
"""
import logging
class NullHandler(logging.Handler):
"""
This handler does nothing. It's intended to be used to avoid the
"No handlers could be found for logger XXX" one-off warning. This is
important for library code, which may contain code to log events. If a user
of the library does not configure logging, the one-off warning might be
produced; to avoid this, the library developer simply needs to instantiate
a NullHandler and add it to the top-level logger of the library module or
package.
"""
def handle(self, record):
pass
def emit(self, record):
pass
def createLock(self):
self.lock = None

View File

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
"""
pint.compat.transformdict
~~~~~~~~~~~~~~~~~~~~~~~~~
Taken from the Python 3.4 source code.
:copyright: 2013, PSF
:license: PSF License
"""
from collections import MutableMapping
_sentinel = object()
class TransformDict(MutableMapping):
'''Dictionary that calls a transformation function when looking
up keys, but preserves the original keys.
>>> d = TransformDict(str.lower)
>>> d['Foo'] = 5
>>> d['foo'] == d['FOO'] == d['Foo'] == 5
True
>>> set(d.keys())
{'Foo'}
'''
__slots__ = ('_transform', '_original', '_data')
def __init__(self, transform, init_dict=None, **kwargs):
'''Create a new TransformDict with the given *transform* function.
*init_dict* and *kwargs* are optional initializers, as in the
dict constructor.
'''
if not callable(transform):
raise TypeError("expected a callable, got %r" % transform.__class__)
self._transform = transform
# transformed => original
self._original = {}
self._data = {}
if init_dict:
self.update(init_dict)
if kwargs:
self.update(kwargs)
def getitem(self, key):
'D.getitem(key) -> (stored key, value)'
transformed = self._transform(key)
original = self._original[transformed]
value = self._data[transformed]
return original, value
@property
def transform_func(self):
"This TransformDict's transformation function"
return self._transform
# Minimum set of methods required for MutableMapping
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._original.values())
def __getitem__(self, key):
return self._data[self._transform(key)]
def __setitem__(self, key, value):
transformed = self._transform(key)
self._data[transformed] = value
self._original.setdefault(transformed, key)
def __delitem__(self, key):
transformed = self._transform(key)
del self._data[transformed]
del self._original[transformed]
# Methods overriden to mitigate the performance overhead.
def clear(self):
'D.clear() -> None. Remove all items from D.'
self._data.clear()
self._original.clear()
def __contains__(self, key):
return self._transform(key) in self._data
def get(self, key, default=None):
'D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.'
return self._data.get(self._transform(key), default)
def pop(self, key, default=_sentinel):
'''D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised.
'''
transformed = self._transform(key)
if default is _sentinel:
del self._original[transformed]
return self._data.pop(transformed)
else:
self._original.pop(transformed, None)
return self._data.pop(transformed, default)
def popitem(self):
'''D.popitem() -> (k, v), remove and return some (key, value) pair
as a 2-tuple; but raise KeyError if D is empty.
'''
transformed, value = self._data.popitem()
return self._original.pop(transformed), value
# Other methods
def copy(self):
'D.copy() -> a shallow copy of D'
other = self.__class__(self._transform)
other._original = self._original.copy()
other._data = self._data.copy()
return other
__copy__ = copy
def __getstate__(self):
return (self._transform, self._data, self._original)
def __setstate__(self, state):
self._transform, self._data, self._original = state
def __repr__(self):
try:
equiv = dict(self)
except TypeError:
# Some keys are unhashable, fall back on .items()
equiv = list(self.items())
return '%s(%r, %s)' % (self.__class__.__name__,
self._transform, repr(equiv))

View File

@ -0,0 +1,51 @@
# Default Pint constants definition file
# Based on the International System of Units
# Language: english
# Source: http://physics.nist.gov/cuu/Constants/Table/allascii.txt
# :copyright: 2013 by Pint Authors, see AUTHORS for more details.
speed_of_light = 299792458 * meter / second = c
standard_gravity = 9.806650 * meter / second ** 2 = g_0 = g_n = gravity
vacuum_permeability = 4 * pi * 1e-7 * newton / ampere ** 2 = mu_0 = magnetic_constant
vacuum_permittivity = 1 / (mu_0 * c **2 ) = epsilon_0 = electric_constant
Z_0 = mu_0 * c = impedance_of_free_space = characteristic_impedance_of_vacuum
# 0.000 000 29 e-34
planck_constant = 6.62606957e-34 J s = h
hbar = planck_constant / (2 * pi) = ħ
# 0.000 80 e-11
newtonian_constant_of_gravitation = 6.67384e-11 m^3 kg^-1 s^-2
# 0.000 000 035 e-19
# elementary_charge = 1.602176565e-19 C = e
# 0.000 0075
molar_gas_constant = 8.3144621 J mol^-1 K^-1 = R
# 0.000 000 0024 e-3
fine_structure_constant = 7.2973525698e-3
# 0.000 000 27 e23
avogadro_number = 6.02214129e23 mol^-1 =N_A
# 0.000 0013 e-23
boltzmann_constant = 1.3806488e-23 J K^-1 = k
# 0.000 021 e-8
stefan_boltzmann_constant = 5.670373e-8 W m^-2 K^-4 = σ
# 0.000 0053 e10
wien_frequency_displacement_law_constant = 5.8789254e10 Hz K^-1
# 0.000 055
rydberg_constant = 10973731.568539 m^-1
# 0.000 000 40 e-31
electron_mass = 9.10938291e-31 kg = m_e
# 0.000 000 074 e-27
neutron_mass = 1.674927351e-27 kg = m_n
# 0.000 000 074 e-27
proton_mass = 1.672621777e-27 kg = m_p

View File

@ -0,0 +1,246 @@
# -*- coding: utf-8 -*-
"""
pint.context
~~~~~~~~~~~~
Functions and classes related to context definitions and application.
:copyright: 2013 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import division, unicode_literals, print_function, absolute_import
import re
from collections import defaultdict
import weakref
from .compat import ChainMap
from .util import ParserHelper, string_types
#: Regex to match the header parts of a context.
_header_re = re.compile('@context\s*(?P<defaults>\(.*\))?\s+(?P<name>\w+)\s*(=(?P<aliases>.*))*')
#: Regex to match variable names in an equation.
_varname_re = re.compile('[A-Za-z_][A-Za-z0-9_]*')
def _freeze(d):
"""Return a hashable view of dict.
"""
if isinstance(d, string_types):
d = ParserHelper.from_string(d)
if isinstance(d, frozenset):
return d
return frozenset(d.items())
def _expression_to_function(eq):
def func(ureg, value, **kwargs):
return ureg.parse_expression(eq, value=value, **kwargs)
return func
class Context(object):
"""A specialized container that defines transformation functions from
one dimension to another. Each Dimension are specified using a UnitsContainer.
Simple transformation are given with a function taking a single parameter.
>>> timedim = UnitsContainer({'[time]': 1})
>>> spacedim = UnitsContainer({'[length]': 1})
>>> def f(time):
... 'Time to length converter'
... return 3. * time
>>> c = Context()
>>> c.add_transformation(timedim, spacedim, f)
>>> c.transform(timedim, spacedim, 2)
6
Conversion functions may take optional keyword arguments and the context can
have default values for these arguments.
>>> def f(time, n):
... 'Time to length converter, n is the index of refraction of the material'
... return 3. * time / n
>>> c = Context(n=3)
>>> c.add_transformation(timedim, spacedim, f)
>>> c.transform(timedim, spacedim, 2)
2
"""
def __init__(self, name, aliases=(), defaults=None):
self.name = name
self.aliases = aliases
#: Maps (src, dst) -> transformation function
self.funcs = {}
#: Maps defaults variable names to values
self.defaults = defaults or {}
#: Maps (src, dst) -> self
#: Used as a convenience dictionary to be composed by ContextChain
self.relation_to_context = weakref.WeakValueDictionary()
@classmethod
def from_context(cls, context, **defaults):
"""Creates a new context that shares the funcs dictionary with the original
context. The default values are copied from the original context and updated
with the new defaults.
If defaults is empty, return the same context.
"""
if defaults:
newdef = dict(context.defaults, **defaults)
c = cls(context.name, context.aliases, newdef)
c.funcs = context.funcs
for edge in context.funcs.keys():
c.relation_to_context[edge] = c
return c
return context
@classmethod
def from_lines(cls, lines, to_base_func=None):
header, lines = lines[0], lines[1:]
r = _header_re.search(header)
name = r.groupdict()['name'].strip()
aliases = r.groupdict()['aliases']
if aliases:
aliases = tuple(a.strip() for a in r.groupdict()['aliases'].split('='))
else:
aliases = ()
defaults = r.groupdict()['defaults']
if defaults:
def to_num(val):
val = complex(val)
if not val.imag:
return val.real
return val
try:
_txt = defaults
defaults = (part.split('=') for part in defaults.strip('()').split(','))
defaults = dict((str(k).strip(), to_num(v))
for k, v in defaults)
except (ValueError, TypeError):
raise ValueError('Could not parse Context definition defaults: %s', _txt)
ctx = cls(name, aliases, defaults)
else:
ctx = cls(name, aliases)
names = set()
for line in lines:
line = line.strip()
if not line or line.startswith('#'):
continue
rel, eq = line.split(':')
names.update(_varname_re.findall(eq))
func = _expression_to_function(eq)
if '<->' in rel:
src, dst = (ParserHelper.from_string(s) for s in rel.split('<->'))
if to_base_func:
src = to_base_func(src)
dst = to_base_func(dst)
ctx.add_transformation(src, dst, func)
ctx.add_transformation(dst, src, func)
elif '->' in rel:
src, dst = (ParserHelper.from_string(s) for s in rel.split('->'))
if to_base_func:
src = to_base_func(src)
dst = to_base_func(dst)
ctx.add_transformation(src, dst, func)
else:
raise ValueError('Relationships must be specified with <-> or ->.')
if defaults:
missing_pars = set(defaults.keys()).difference(set(names))
if missing_pars:
raise ValueError('Context parameters {0} not found in any equation.'.format(missing_pars))
return ctx
def add_transformation(self, src, dst, func):
"""Add a transformation function to the context.
"""
_key = self.__keytransform__(src, dst)
self.funcs[_key] = func
self.relation_to_context[_key] = self
def remove_transformation(self, src, dst):
"""Add a transformation function to the context.
"""
_key = self.__keytransform__(src, dst)
del self.funcs[_key]
del self.relation_to_context[_key]
@staticmethod
def __keytransform__(src, dst):
return _freeze(src), _freeze(dst)
def transform(self, src, dst, registry, value):
"""Transform a value.
"""
_key = self.__keytransform__(src, dst)
return self.funcs[_key](registry, value, **self.defaults)
class ContextChain(ChainMap):
"""A specialized ChainMap for contexts that simplifies finding rules
to transform from one dimension to another.
"""
def __init__(self, *args, **kwargs):
super(ContextChain, self).__init__(*args, **kwargs)
self._graph = None
self._contexts = []
def insert_contexts(self, *contexts):
"""Insert one or more contexts in reversed order the chained map.
(A rule in last context will take precedence)
To facilitate the identification of the context with the matching rule,
the *relation_to_context* dictionary of the context is used.
"""
self._contexts.insert(0, contexts)
self.maps = [ctx.relation_to_context for ctx in reversed(contexts)] + self.maps
self._graph = None
def remove_contexts(self, n):
"""Remove the last n inserted contexts from the chain.
"""
self._contexts = self._contexts[n:]
self.maps = self.maps[n:]
self._graph = None
@property
def defaults(self):
if self:
return list(self.maps[0].values())[0].defaults
return {}
@property
def graph(self):
"""The graph relating
"""
if self._graph is None:
self._graph = defaultdict(set)
for fr_, to_ in self:
self._graph[fr_].add(to_)
return self._graph
def transform(self, src, dst, registry, value):
"""Transform the value, finding the rule in the chained context.
(A rule in last context will take precedence)
:raises: KeyError if the rule is not found.
"""
return self[(src, dst)].transform(src, dst, registry, value)

View File

@ -0,0 +1,350 @@
# Default Pint units definition file
# Based on the International System of Units
# Language: english
# :copyright: 2013 by Pint Authors, see AUTHORS for more details.
# decimal prefixes
yocto- = 1e-24 = y-
zepto- = 1e-21 = z-
atto- = 1e-18 = a-
femto- = 1e-15 = f-
pico- = 1e-12 = p-
nano- = 1e-9 = n-
micro- = 1e-6 = u- = µ-
milli- = 1e-3 = m-
centi- = 1e-2 = c-
deci- = 1e-1 = d-
deca- = 1e+1 = da-
hecto- = 1e2 = h-
kilo- = 1e3 = k-
mega- = 1e6 = M-
giga- = 1e9 = G-
tera- = 1e12 = T-
peta- = 1e15 = P-
exa- = 1e18 = E-
zetta- = 1e21 = Z-
yotta- = 1e24 = Y-
# binary_prefixes
kibi- = 2**10 = Ki-
mebi- = 2**20 = Mi-
gibi- = 2**30 = Gi-
tebi- = 2**40 = Ti-
pebi- = 2**50 = Pi-
exbi- = 2**60 = Ei-
zebi- = 2**70 = Zi-
yobi- = 2**80 = Yi-
# reference
meter = [length] = m = metre
second = [time] = s = sec
ampere = [current] = A = amp
candela = [luminosity] = cd = candle
gram = [mass] = g
mole = [substance] = mol
kelvin = [temperature]; offset: 0 = K = degK
radian = [] = rad
bit = []
count = []
@import constants_en.txt
# acceleration
[acceleration] = [length] / [time] ** 2
# Angle
turn = 2 * pi * radian = revolution = cycle = circle
degree = pi / 180 * radian = deg = arcdeg = arcdegree = angular_degree
arcminute = arcdeg / 60 = arcmin = arc_minute = angular_minute
arcsecond = arcmin / 60 = arcsec = arc_second = angular_second
steradian = radian ** 2 = sr
# Area
[area] = [length] ** 2
are = 100 * m**2
barn = 1e-28 * m ** 2 = b
cmil = 5.067075e-10 * m ** 2 = circular_mils
darcy = 9.869233e-13 * m ** 2
acre = 4046.8564224 * m ** 2 = international_acre
US_survey_acre = 160 * rod ** 2
# EM
esu = 1 * erg**0.5 * centimeter**0.5 = statcoulombs = statC = franklin = Fr
esu_per_second = 1 * esu / second = statampere
ampere_turn = 1 * A
gilbert = 10 / (4 * pi ) * ampere_turn
coulomb = ampere * second = C
volt = joule / coulomb = V
farad = coulomb / volt = F
ohm = volt / ampere = Ω
siemens = ampere / volt = S = mho
weber = volt * second = Wb
tesla = weber / meter ** 2 = T
henry = weber / ampere = H
elementary_charge = 1.602176487e-19 * coulomb = e
chemical_faraday = 9.64957e4 * coulomb
physical_faraday = 9.65219e4 * coulomb
faraday = 96485.3399 * coulomb = C12_faraday
gamma = 1e-9 * tesla
gauss = 1e-4 * tesla
maxwell = 1e-8 * weber = mx
oersted = 1000 / (4 * pi) * A / m = Oe
statfarad = 1.112650e-12 * farad = statF = stF
stathenry = 8.987554e11 * henry = statH = stH
statmho = 1.112650e-12 * siemens = statS = stS
statohm = 8.987554e11 * ohm
statvolt = 2.997925e2 * volt = statV = stV
unit_pole = 1.256637e-7 * weber
# Energy
[energy] = [force] * [length]
joule = newton * meter = J
erg = dyne * centimeter
btu = 1.05505585262e3 * joule = Btu = BTU = british_thermal_unit
eV = 1.60217653e-19 * J = electron_volt
thm = 100000 * BTU = therm = EC_therm
cal = 4.184 * joule = calorie = thermochemical_calorie
international_steam_table_calorie = 4.1868 * joule
ton_TNT = 4.184e9 * joule = tTNT
US_therm = 1.054804e8 * joule
watt_hour = watt * hour = Wh = watthour
E_h = 4.35974394e-18 * joule = hartree = hartree_energy
# Force
[force] = [mass] * [acceleration]
newton = kilogram * meter / second ** 2 = N
dyne = gram * centimeter / second ** 2 = dyn
force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond
force_gram = g_0 * gram = gf = gram_force
force_ounce = g_0 * ounce = ozf = ounce_force
force_pound = g_0 * lb = lbf = pound_force
force_ton = 2000 * force_pound = ton_force
poundal = lb * feet / second ** 2 = pdl
kip = 1000*lbf
# Frequency
[frequency] = 1 / [time]
hertz = 1 / second = Hz = rps
revolutions_per_minute = revolution / minute = rpm
counts_per_second = count / second = cps
# Heat
#RSI = degK * meter ** 2 / watt
#clo = 0.155 * RSI = clos
#R_value = foot ** 2 * degF * hour / btu
# Information
byte = 8 * bit = Bo = octet
baud = bit / second = Bd = bps
# Length
angstrom = 1e-10 * meter = ångström = Å
inch = 2.54 * centimeter = in = international_inch = inches = international_inches
foot = 12 * inch = ft = international_foot = feet = international_feet
mile = 5280 * foot = mi = international_mile
yard = 3 * feet = yd = international_yard
mil = inch / 1000 = thou
parsec = 3.08568025e16 * meter = pc
light_year = speed_of_light * julian_year = ly = lightyear
astronomical_unit = 149597870691 * meter = au
nautical_mile = 1.852e3 * meter = nmi
printers_point = 127 * millimeter / 360 = point
printers_pica = 12 * printers_point = pica
US_survey_foot = 1200 * meter / 3937
US_survey_yard = 3 * US_survey_foot
US_survey_mile = 5280 * US_survey_foot = US_statute_mile
rod = 16.5 * US_survey_foot = pole = perch
furlong = 660 * US_survey_foot
fathom = 6 * US_survey_foot
chain = 66 * US_survey_foot
barleycorn = inch / 3
arpentlin = 191.835 * feet
kayser = 1 / centimeter = wavenumber
# Mass
dram = oz / 16 = dr = avoirdupois_dram
ounce = 28.349523125 * gram = oz = avoirdupois_ounce
pound = 0.45359237 * kilogram = lb = avoirdupois_pound
stone = 14 * lb = st
carat = 200 * milligram
grain = 64.79891 * milligram = gr
long_hundredweight = 112 * lb
short_hundredweight = 100 * lb
metric_ton = 1000 * kilogram = t = tonne
pennyweight = 24 * gram = dwt
slug = 14.59390 * kilogram
troy_ounce = 480 * gram = toz = apounce = apothecary_ounce
troy_pound = 12 * toz = tlb = appound = apothecary_pound
drachm = 60 * gram = apdram = apothecary_dram
atomic_mass_unit = 1.660538782e-27 * kilogram = u = amu = dalton = Da
scruple = 20 * gram
bag = 94 * lb
ton = 2000 * lb = short_ton
# Textile
denier = gram / (9000 * meter)
tex = gram/ (1000 * meter)
dtex = decitex
# Power
[power] = [energy] / [time]
watt = joule / second = W = volt_ampere = VA
horsepower = 33000 * ft * lbf / min = hp = UK_horsepower = British_horsepower
boiler_horsepower = 33475 * btu / hour
metric_horsepower = 75 * force_kilogram * meter / second
electric_horsepower = 746 * watt
hydraulic_horsepower = 550 * feet * lbf / second
refrigeration_ton = 12000 * btu / hour = ton_of_refrigeration
# Pressure
[pressure] = [force] / [area]
Hg = gravity * 13.59510 * gram / centimeter ** 3 = mercury = conventional_mercury
mercury_60F = gravity * 13.5568 * gram / centimeter ** 3
H2O = gravity * 1000 * kilogram / meter ** 3 = h2o = water = conventional_water
water_4C = gravity * 999.972 * kilogram / meter ** 3 = water_39F
water_60F = gravity * 999.001 * kilogram / m ** 3
pascal = newton / meter ** 2 = Pa
bar = 100000 * pascal
atmosphere = 101325 * pascal = atm = standard_atmosphere
technical_atmosphere = kilogram * gravity / centimeter ** 2 = at
torr = atm / 760
psi = pound * gravity / inch ** 2 = pound_force_per_square_inch
ksi = kip / inch ** 2 = kip_per_square_inch
barye = 0.1 * newton / meter ** 2 = barie = barad = barrie = baryd = Ba
mmHg = millimeter * Hg = mm_Hg = millimeter_Hg = millimeter_Hg_0C
cmHg = centimeter * Hg = cm_Hg = centimeter_Hg
inHg = inch * Hg = in_Hg = inch_Hg = inch_Hg_32F
inch_Hg_60F = inch * mercury_60F
inch_H2O_39F = inch * water_39F
inch_H2O_60F = inch * water_60F
footH2O = ft * water
cmH2O = centimeter * water
foot_H2O = ft * water = ftH2O
standard_liter_per_minute = 1.68875 * Pa * m ** 3 / s = slpm = slm
# Radiation
Bq = Hz = becquerel
curie = 3.7e10 * Bq = Ci
rutherford = 1e6*Bq = rd = Rd
Gy = joule / kilogram = gray = Sv = sievert
rem = 1e-2 * sievert
rads = 1e-2 * gray
roentgen = 2.58e-4 * coulomb / kilogram
# Temperature
degC = kelvin; offset: 273.15 = celsius
degR = 5 / 9 * kelvin; offset: 0 = rankine
degF = 5 / 9 * kelvin; offset: 255.372222 = fahrenheit
# Time
minute = 60 * second = min
hour = 60 * minute = hr
day = 24 * hour
week = 7 * day
fortnight = 2 * week
year = 31556925.9747 * second
month = year/12
shake = 1e-8 * second
sidereal_day = day / 1.00273790935079524
sidereal_hour = sidereal_day/24
sidereal_minute=sidereal_hour/60
sidereal_second =sidereal_minute/60
sidereal_year = 366.25636042 * sidereal_day
sidereal_month = 27.321661 * sidereal_day
tropical_month = 27.321661 * day
synodic_month = 29.530589 * day = lunar_month
common_year = 365 * day
leap_year = 366 * day
julian_year = 365.25 * day
gregorian_year = 365.2425 * day
millenium = 1000 * year = millenia = milenia = milenium
eon = 1e9 * year
work_year = 2056 * hour
work_month = work_year/12
# Velocity
[speed] = [length] / [time]
knot = nautical_mile / hour = kt = knot_international = international_knot = nautical_miles_per_hour
mph = mile / hour = MPH
kph = kilometer / hour = KPH
# Viscosity
[viscosity] = [pressure] * [time]
poise = 1e-1 * Pa * second = P
stokes = 1e-4 * meter ** 2 / second = St
rhe = 10 / (Pa * s)
# Volume
[volume] = [length] ** 3
liter = 1e-3 * m ** 3 = l = L = litre
cc = centimeter ** 3 = cubic_centimeter
stere = meter ** 3
gross_register_ton = 100 * foot ** 3 = register_ton = GRT
acre_foot = acre * foot = acre_feet
board_foot = foot ** 2 * inch = FBM
bushel = 2150.42 * inch ** 3 = bu = US_bushel
dry_gallon = bushel / 8 = US_dry_gallon
dry_quart = dry_gallon / 4 = US_dry_quart
dry_pint = dry_quart / 2 = US_dry_pint
gallon = 231 * inch ** 3 = liquid_gallon = US_liquid_gallon
quart = gallon / 4 = liquid_quart = US_liquid_quart
pint = quart / 2 = pt = liquid_pint = US_liquid_pint
cup = pint / 2 = liquid_cup = US_liquid_cup
gill = cup / 2 = liquid_gill = US_liquid_gill
fluid_ounce = gill / 4 = floz = US_fluid_ounce = US_liquid_ounce
imperial_bushel = 36.36872 * liter = UK_bushel
imperial_gallon = imperial_bushel / 8 = UK_gallon
imperial_quart = imperial_gallon / 4 = UK_quart
imperial_pint = imperial_quart / 2 = UK_pint
imperial_cup = imperial_pint / 2 = UK_cup
imperial_gill = imperial_cup / 2 = UK_gill
imperial_floz = imperial_gill / 5 = UK_fluid_ounce = imperial_fluid_ounce
barrel = 42 * gallon = bbl
tablespoon = floz / 2 = tbsp = Tbsp = Tblsp = tblsp = tbs = Tbl
teaspoon = tablespoon / 3 = tsp
peck = bushel / 4 = pk
fluid_dram = floz / 8 = fldr = fluidram
firkin = barrel / 4
@context(n=1) spectroscopy = sp
# n index of refraction of the medium.
[length] <-> [frequency]: speed_of_light / n / value
[frequency] -> [energy]: planck_constant * value
[energy] -> [frequency]: value / planck_constant
@end
@context boltzmann
[temperature] -> [energy]: boltzmann_constant * value
[energy] -> [temperature]: value / boltzmann_constant
@end
@context(mw=0,volume=0,solvent_mass=0) chemistry = chem
# mw is the molecular weight of the species
# volume is the volume of the solution
# solvent_mass is the mass of solvent in the solution
# moles -> mass require the molecular weight
[substance] -> [mass]: value * mw
[mass] -> [substance]: value / mw
# moles/volume -> mass/volume and moles/mass -> mass / mass
# require the molecular weight
[substance] / [volume] -> [mass] / [volume]: value * mw
[mass] / [volume] -> [substance] / [volume]: value / mw
[substance] / [mass] -> [mass] / [mass]: value * mw
[mass] / [mass] -> [substance] / [mass]: value / mw
# moles/volume -> moles requires the solution volume
[substance] / [volume] -> [substance]: value * volume
[substance] -> [substance] / [volume]: value / volume
# moles/mass -> moles requires the solvent (usually water) mass
[substance] / [mass] -> [substance]: value * solvent_mass
[substance] -> [substance] / [mass]: value / solvent_mass
# moles/mass -> moles/volume require the solvent mass and the volume
[substance] / [mass] -> [substance]/[volume]: value * solvent_mass / volume
[substance] / [volume] -> [substance] / [mass]: value / solvent_mass * volume
@end

View File

@ -0,0 +1,197 @@
# -*- coding: utf-8 -*-
"""
pint.formatter
~~~~~~~~~~~~~~
Format units for pint.
:copyright: 2013 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import division, unicode_literals, print_function, absolute_import
import re
__JOIN_REG_EXP = re.compile("\{\d*\}")
def _join(fmt, iterable):
"""Join an iterable with the format specified in fmt.
The format can be specified in two ways:
- PEP3101 format with two replacement fields (eg. '{0} * {1}')
- The concatenating string (eg. ' * ')
"""
if not iterable:
return ''
if not __JOIN_REG_EXP.search(fmt):
return fmt.join(iterable)
miter = iter(iterable)
first = next(miter)
for val in miter:
ret = fmt.format(first, val)
first = ret
return first
_PRETTY_EXPONENTS = '⁰¹²³⁴⁵⁶⁷⁸⁹'
def _pretty_fmt_exponent(num):
"""Format an number into a pretty printed exponent.
"""
# TODO: Will not work for decimals
ret = '{0:n}'.format(num).replace('-', '')
for n in range(10):
ret = ret.replace(str(n), _PRETTY_EXPONENTS[n])
return ret
#: _FORMATS maps format specifications to the corresponding argument set to
#: formatter().
_FORMATS = {
'P': { # Pretty format.
'as_ratio': True,
'single_denominator': False,
'product_fmt': '·',
'division_fmt': '/',
'power_fmt': '{0}{1}',
'parentheses_fmt': '({0})',
'exp_call': _pretty_fmt_exponent,
},
'L': { # Latex format.
'as_ratio': True,
'single_denominator': True,
'product_fmt': r' \cdot ',
'division_fmt': r'\frac[{0}][{1}]',
'power_fmt': '{0}^[{1}]',
'parentheses_fmt': r'\left({0}\right)',
},
'H': { # HTML format.
'as_ratio': True,
'single_denominator': True,
'product_fmt': r' ',
'division_fmt': r'{0}/{1}',
'power_fmt': '{0}<sup>{1}</sup>',
'parentheses_fmt': r'({0})',
},
'': { # Default format.
'as_ratio': True,
'single_denominator': False,
'product_fmt': ' * ',
'division_fmt': ' / ',
'power_fmt': '{0} ** {1}',
'parentheses_fmt': r'({0})',
},
'C': { # Compact format.
'as_ratio': True,
'single_denominator': False,
'product_fmt': '*', # TODO: Should this just be ''?
'division_fmt': '/',
'power_fmt': '{0}**{1}',
'parentheses_fmt': r'({0})',
},
}
def formatter(items, as_ratio=True, single_denominator=False,
product_fmt=' * ', division_fmt=' / ', power_fmt='{0} ** {1}',
parentheses_fmt='({0})', exp_call=lambda x: '{0:n}'.format(x)):
"""Format a list of (name, exponent) pairs.
:param items: a list of (name, exponent) pairs.
:param as_ratio: True to display as ratio, False as negative powers.
:param single_denominator: all with terms with negative exponents are
collected together.
:param product_fmt: the format used for multiplication.
:param division_fmt: the format used for division.
:param power_fmt: the format used for exponentiation.
:param parentheses_fmt: the format used for parenthesis.
:return: the formula as a string.
"""
if not items:
return ''
if as_ratio:
fun = lambda x: exp_call(abs(x))
else:
fun = exp_call
pos_terms, neg_terms = [], []
for key, value in sorted(items):
if value == 1:
pos_terms.append(key)
elif value > 0:
pos_terms.append(power_fmt.format(key, fun(value)))
elif value == -1 and as_ratio:
neg_terms.append(key)
else:
neg_terms.append(power_fmt.format(key, fun(value)))
if not as_ratio:
# Show as Product: positive * negative terms ** -1
return _join(product_fmt, pos_terms + neg_terms)
# Show as Ratio: positive terms / negative terms
pos_ret = _join(product_fmt, pos_terms) or '1'
if not neg_terms:
return pos_ret
if single_denominator:
neg_ret = _join(product_fmt, neg_terms)
if len(neg_terms) > 1:
neg_ret = parentheses_fmt.format(neg_ret)
else:
neg_ret = _join(division_fmt, neg_terms)
return _join(division_fmt, [pos_ret, neg_ret])
# Extract just the type from the specification mini-langage: see
# http://docs.python.org/2/library/string.html#format-specification-mini-language
# We also add uS for uncertainties.
_BASIC_TYPES = frozenset('bcdeEfFgGnosxX%uS')
_KNOWN_TYPES = frozenset(_FORMATS.keys())
def _parse_spec(spec):
result = ''
for ch in reversed(spec):
if ch == '~' or ch in _BASIC_TYPES:
continue
elif ch in _KNOWN_TYPES:
if result:
raise ValueError("expected ':' after format specifier")
else:
result = ch
elif ch.isalpha():
raise ValueError("Unknown conversion specified " + ch)
else:
break
return result
def format_unit(unit, spec):
if not unit:
return 'dimensionless'
spec = _parse_spec(spec)
fmt = _FORMATS[spec]
result = formatter(unit.items(), **fmt)
if spec == 'L':
result = result.replace('[', '{').replace(']', '}')
return result
def remove_custom_flags(spec):
for flag in _FORMATS.keys():
if flag:
spec = spec.replace(flag, '')
return spec

View File

@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
"""
pint.measurement
~~~~~~~~~~~~~~~~
:copyright: 2013 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import division, unicode_literals, print_function, absolute_import
from .compat import ufloat
from .formatting import _FORMATS
MISSING = object()
class _Measurement(object):
"""Implements a class to describe a quantity with uncertainty.
:param value: The most likely value of the measurement.
:type value: Quantity or Number
:param error: The error or uncertainty of the measurement.
:type error: Quantity or Number
"""
def __new__(cls, value, error, units=MISSING):
if units is MISSING:
try:
value, units = value.magnitude, value.units
except AttributeError:
try:
value, error, units = value.nominal_value, value.std_dev, error
except AttributeError:
units = ''
try:
error = error.to(units).magnitude
except AttributeError:
pass
inst = super(_Measurement, cls).__new__(cls, ufloat(value, error), units)
if error < 0:
raise ValueError('The magnitude of the error cannot be negative'.format(value, error))
return inst
@property
def value(self):
return self._REGISTRY.Quantity(self.magnitude.nominal_value, self.units)
@property
def error(self):
return self._REGISTRY.Quantity(self.magnitude.std_dev, self.units)
@property
def rel(self):
return float(abs(self.magnitude.std_dev / self.magnitude.nominal_value))
def __repr__(self):
return "<Measurement({0:.2f}, {1:.2f}, {2})>".format(self.magnitude.nominal_value,
self.magnitude.std_dev,
self.units)
def __str__(self):
return '{0}'.format(self)
def __format__(self, spec):
if 'L' in spec:
newpm = pm = r' \pm '
pars = _FORMATS['L']['parentheses_fmt']
elif 'P' in spec:
newpm = pm = '±'
pars = _FORMATS['P']['parentheses_fmt']
else:
newpm = pm = '+/-'
pars = _FORMATS['']['parentheses_fmt']
if 'C' in spec:
sp = ''
newspec = spec.replace('C', '')
pars = _FORMATS['C']['parentheses_fmt']
else:
sp = ' '
newspec = spec
if 'H' in spec:
newpm = '&plusmn;'
newspec = spec.replace('H', '')
pars = _FORMATS['H']['parentheses_fmt']
mag = format(self.magnitude, newspec).replace(pm, sp + newpm + sp)
if 'L' in newspec and 'S' in newspec:
mag = mag.replace('(', r'\left(').replace(')', r'\right)')
if 'uS' in newspec or 'ue' in newspec or 'u%' in newspec:
return mag + ' ' + format(self.units, spec)
else:
return pars.format(mag) + ' ' + format(self.units, spec)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
import os
import logging
from contextlib import contextmanager
from pint.compat import ndarray, unittest, np
from pint import logger, UnitRegistry
from pint.quantity import _Quantity
from logging.handlers import BufferingHandler
class TestHandler(BufferingHandler):
def __init__(self, only_warnings=False):
# BufferingHandler takes a "capacity" argument
# so as to know when to flush. As we're overriding
# shouldFlush anyway, we can set a capacity of zero.
# You can call flush() manually to clear out the
# buffer.
self.only_warnings = only_warnings
BufferingHandler.__init__(self, 0)
def shouldFlush(self):
return False
def emit(self, record):
if self.only_warnings and record.level != logging.WARNING:
return
self.buffer.append(record.__dict__)
class BaseTestCase(unittest.TestCase):
CHECK_NO_WARNING = True
@contextmanager
def capture_log(self, level=logging.DEBUG):
th = TestHandler()
th.setLevel(level)
logger.addHandler(th)
if self._test_handler is not None:
l = len(self._test_handler.buffer)
yield th.buffer
if self._test_handler is not None:
self._test_handler.buffer = self._test_handler.buffer[:l]
def setUp(self):
self._test_handler = None
if self.CHECK_NO_WARNING:
self._test_handler = th = TestHandler()
th.setLevel(logging.WARNING)
logger.addHandler(th)
def tearDown(self):
if self._test_handler is not None:
buf = self._test_handler.buffer
l = len(buf)
msg = '\n'.join(record.get('msg', str(record)) for record in buf)
self.assertEqual(l, 0, msg='%d warnings raised.\n%s' % (l, msg))
class QuantityTestCase(BaseTestCase):
FORCE_NDARRAY = False
@classmethod
def setUpClass(cls):
cls.ureg = UnitRegistry(force_ndarray=cls.FORCE_NDARRAY)
cls.Q_ = cls.ureg.Quantity
def _get_comparable_magnitudes(self, first, second, msg):
if isinstance(first, _Quantity) and isinstance(second, _Quantity):
second = second.to(first)
self.assertEqual(first.units, second.units, msg=msg + 'Units are not equal.')
m1, m2 = first.magnitude, second.magnitude
elif isinstance(first, _Quantity):
self.assertTrue(first.dimensionless, msg=msg + 'The first is not dimensionless.')
first = first.to('')
m1, m2 = first.magnitude, second
elif isinstance(second, _Quantity):
self.assertTrue(second.dimensionless, msg=msg + 'The second is not dimensionless.')
second = second.to('')
m1, m2 = first, second.magnitude
else:
m1, m2 = first, second
return m1, m2
def assertQuantityEqual(self, first, second, msg=None):
if msg is None:
msg = 'Comparing %r and %r. ' % (first, second)
m1, m2 = self._get_comparable_magnitudes(first, second, msg)
if isinstance(m1, ndarray) or isinstance(m2, ndarray):
np.testing.assert_array_equal(m1, m2, err_msg=msg)
else:
unittest.TestCase.assertEqual(self, m1, m2, msg)
def assertQuantityAlmostEqual(self, first, second, rtol=1e-07, atol=0, msg=None):
if msg is None:
msg = 'Comparing %r and %r. ' % (first, second)
m1, m2 = self._get_comparable_magnitudes(first, second, msg)
if isinstance(m1, ndarray) or isinstance(m2, ndarray):
np.testing.assert_allclose(m1, m2, rtol=rtol, atol=atol, err_msg=msg)
else:
self.assertLessEqual(abs(m1 - m2), atol + rtol * abs(m2))
def testsuite():
"""A testsuite that has all the pint tests.
"""
return unittest.TestLoader().discover(os.path.dirname(__file__))
def main():
"""Runs the testsuite as command line application.
"""
try:
unittest.main()
except Exception as e:
print('Error: %s' % e)
def run():
"""Run all tests.
:return: a :class:`unittest.TestResult` object
"""
test_runner = unittest.TextTestRunner()
return test_runner.run(testsuite())

View File

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
from pint.compat import unittest, HAS_NUMPY, HAS_UNCERTAINTIES, NUMPY_VER, PYTHON3
def requires_numpy18():
return unittest.skipUnless(NUMPY_VER >= '1.8', 'Requires NumPy >= 1.8')
def requires_numpy():
return unittest.skipUnless(HAS_NUMPY, 'Requires NumPy')
def requires_not_numpy():
return unittest.skipIf(HAS_NUMPY, 'Requires NumPy is not installed.')
def requires_uncertainties():
return unittest.skipUnless(HAS_UNCERTAINTIES, 'Requires Uncertainties')
def requires_not_uncertainties():
return unittest.skipIf(HAS_UNCERTAINTIES, 'Requires Uncertainties is not installed.')
def requires_python2():
return unittest.skipIf(PYTHON3, 'Requires Python 2.X.')
def requires_python3():
return unittest.skipUnless(PYTHON3, 'Requires Python 3.X.')

View File

@ -0,0 +1,152 @@
# -*- coding: utf-8 -*-
#
# Adds Parameterized tests for Python's unittest module
#
# Code from: parameterizedtestcase, version: 0.1.0
# Homepage: https://github.com/msabramo/python_unittest_parameterized_test_case
# Author: Marc Abramowitz, email: marc@marc-abramowitz.com
# License: MIT
#
# Fixed for to work in Python 2 & 3 with "add_metaclass" decorator from six
# https://pypi.python.org/pypi/six
# Author: Benjamin Peterson
# License: MIT
#
# Use like this:
#
# from parameterizedtestcase import ParameterizedTestCase
#
# class MyTests(ParameterizedTestCase):
# @ParameterizedTestCase.parameterize(
# ("input", "expected_output"),
# [
# ("2+4", 6),
# ("3+5", 8),
# ("6*9", 54),
# ]
# )
# def test_eval(self, input, expected_output):
# self.assertEqual(eval(input), expected_output)
try:
import unittest2 as unittest
except ImportError: # pragma: no cover
import unittest
from functools import wraps
import collections
def add_metaclass(metaclass):
"""Class decorator for creating a class with a metaclass."""
def wrapper(cls):
orig_vars = cls.__dict__.copy()
orig_vars.pop('__dict__', None)
orig_vars.pop('__weakref__', None)
slots = orig_vars.get('__slots__')
if slots is not None:
if isinstance(slots, str):
slots = [slots]
for slots_var in slots:
orig_vars.pop(slots_var)
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper
def augment_method_docstring(method, new_class_dict, classname,
param_names, param_values, new_method):
param_assignments_str = '; '.join(
['%s = %s' % (k, v) for (k, v) in zip(param_names, param_values)])
extra_doc = "%s (%s.%s) [with %s] " % (
method.__name__, new_class_dict.get('__module__', '<module>'),
classname, param_assignments_str)
try:
new_method.__doc__ = extra_doc + new_method.__doc__
except TypeError: # Catches when new_method.__doc__ is None
new_method.__doc__ = extra_doc
class ParameterizedTestCaseMetaClass(type):
method_counter = {}
def __new__(meta, classname, bases, class_dict):
new_class_dict = {}
for attr_name, attr_value in list(class_dict.items()):
if isinstance(attr_value, collections.Callable) and hasattr(attr_value, 'param_names'):
# print("Processing attr_name = %r; attr_value = %r" % (
# attr_name, attr_value))
method = attr_value
param_names = attr_value.param_names
data = attr_value.data
func_name_format = attr_value.func_name_format
meta.process_method(
classname, method, param_names, data, new_class_dict,
func_name_format)
else:
new_class_dict[attr_name] = attr_value
return type.__new__(meta, classname, bases, new_class_dict)
@classmethod
def process_method(
cls, classname, method, param_names, data, new_class_dict,
func_name_format):
method_counter = cls.method_counter
for param_values in data:
new_method = cls.new_method(method, param_values)
method_counter[method.__name__] = \
method_counter.get(method.__name__, 0) + 1
case_data = dict(list(zip(param_names, param_values)))
case_data['func_name'] = method.__name__
case_data['case_num'] = method_counter[method.__name__]
new_method.__name__ = func_name_format.format(**case_data)
augment_method_docstring(
method, new_class_dict, classname,
param_names, param_values, new_method)
new_class_dict[new_method.__name__] = new_method
@classmethod
def new_method(cls, method, param_values):
@wraps(method)
def new_method(self):
return method(self, *param_values)
return new_method
@add_metaclass(ParameterizedTestCaseMetaClass)
class ParameterizedTestMixin(object):
@classmethod
def parameterize(cls, param_names, data,
func_name_format='{func_name}_{case_num:05d}'):
"""Decorator for parameterizing a test method - example:
@ParameterizedTestCase.parameterize(
("isbn", "expected_title"), [
("0262033844", "Introduction to Algorithms"),
("0321558146", "Campbell Essential Biology")])
"""
def decorator(func):
@wraps(func)
def newfunc(*arg, **kwargs):
return func(*arg, **kwargs)
newfunc.param_names = param_names
newfunc.data = data
newfunc.func_name_format = func_name_format
return newfunc
return decorator
@add_metaclass(ParameterizedTestCaseMetaClass)
class ParameterizedTestCase(unittest.TestCase, ParameterizedTestMixin):
pass

View File

@ -0,0 +1,632 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
import itertools
from collections import defaultdict
from pint import UnitRegistry
from pint.context import Context, _freeze
from pint.unit import UnitsContainer
from pint.testsuite import QuantityTestCase
def add_ctxs(ureg):
a, b = UnitsContainer({'[length]': 1}), UnitsContainer({'[time]': -1})
d = Context('lc')
d.add_transformation(a, b, lambda ureg, x: ureg.speed_of_light / x)
d.add_transformation(b, a, lambda ureg, x: ureg.speed_of_light / x)
ureg.add_context(d)
a, b = UnitsContainer({'[length]': 1}), UnitsContainer({'[current]': -1})
d = Context('ab')
d.add_transformation(a, b, lambda ureg, x: 1 / x)
d.add_transformation(b, a, lambda ureg, x: 1 / x)
ureg.add_context(d)
def add_arg_ctxs(ureg):
a, b = UnitsContainer({'[length]': 1}), UnitsContainer({'[time]': -1})
d = Context('lc')
d.add_transformation(a, b, lambda ureg, x, n: ureg.speed_of_light / x / n)
d.add_transformation(b, a, lambda ureg, x, n: ureg.speed_of_light / x / n)
ureg.add_context(d)
a, b = UnitsContainer({'[length]': 1}), UnitsContainer({'[current]': -1})
d = Context('ab')
d.add_transformation(a, b, lambda ureg, x: 1 / x)
d.add_transformation(b, a, lambda ureg, x: 1 / x)
ureg.add_context(d)
def add_argdef_ctxs(ureg):
a, b = UnitsContainer({'[length]': 1}), UnitsContainer({'[time]': -1})
d = Context('lc', defaults=dict(n=1))
assert d.defaults == dict(n=1)
d.add_transformation(a, b, lambda ureg, x, n: ureg.speed_of_light / x / n)
d.add_transformation(b, a, lambda ureg, x, n: ureg.speed_of_light / x / n)
ureg.add_context(d)
a, b = UnitsContainer({'[length]': 1}), UnitsContainer({'[current]': -1})
d = Context('ab')
d.add_transformation(a, b, lambda ureg, x: 1 / x)
d.add_transformation(b, a, lambda ureg, x: 1 / x)
ureg.add_context(d)
def add_sharedargdef_ctxs(ureg):
a, b = UnitsContainer({'[length]': 1}), UnitsContainer({'[time]': -1})
d = Context('lc', defaults=dict(n=1))
assert d.defaults == dict(n=1)
d.add_transformation(a, b, lambda ureg, x, n: ureg.speed_of_light / x / n)
d.add_transformation(b, a, lambda ureg, x, n: ureg.speed_of_light / x / n)
ureg.add_context(d)
a, b = UnitsContainer({'[length]': 1}), UnitsContainer({'[current]': 1})
d = Context('ab', defaults=dict(n=0))
d.add_transformation(a, b, lambda ureg, x, n: ureg.ampere * ureg.meter * n / x)
d.add_transformation(b, a, lambda ureg, x, n: ureg.ampere * ureg.meter * n / x)
ureg.add_context(d)
class TestContexts(QuantityTestCase):
def test_freeze(self):
self.assertEqual(_freeze('meter'), frozenset([('meter', 1)]))
self.assertEqual(_freeze('meter/second'), frozenset((('meter', 1), ('second', -1))))
x = frozenset((('meter', 1)))
self.assertIs(_freeze(x), x)
self.assertEqual(_freeze({'meter': 1}),
frozenset([('meter', 1)]))
self.assertEqual(_freeze({'meter': -1, 'second': -1}),
frozenset((('meter', -1), ('second', -1))))
def test_known_context(self):
ureg = UnitRegistry()
add_ctxs(ureg)
with ureg.context('lc'):
self.assertTrue(ureg._active_ctx)
self.assertTrue(ureg._active_ctx.graph)
self.assertFalse(ureg._active_ctx)
self.assertFalse(ureg._active_ctx.graph)
with ureg.context('lc', n=1):
self.assertTrue(ureg._active_ctx)
self.assertTrue(ureg._active_ctx.graph)
self.assertFalse(ureg._active_ctx)
self.assertFalse(ureg._active_ctx.graph)
def test_known_context_enable(self):
ureg = UnitRegistry()
add_ctxs(ureg)
ureg.enable_contexts('lc')
self.assertTrue(ureg._active_ctx)
self.assertTrue(ureg._active_ctx.graph)
ureg.disable_contexts(1)
self.assertFalse(ureg._active_ctx)
self.assertFalse(ureg._active_ctx.graph)
ureg.enable_contexts('lc', n=1)
self.assertTrue(ureg._active_ctx)
self.assertTrue(ureg._active_ctx.graph)
ureg.disable_contexts(1)
self.assertFalse(ureg._active_ctx)
self.assertFalse(ureg._active_ctx.graph)
def test_graph(self):
ureg = UnitRegistry()
add_ctxs(ureg)
l = _freeze({'[length]': 1.})
t = _freeze({'[time]': -1.})
c = _freeze({'[current]': -1.})
g_sp = defaultdict(set)
g_sp.update({l: set((t,)),
t: set((l,))})
g_ab = defaultdict(set)
g_ab.update({l: set((c,)),
c: set((l,))})
g = defaultdict(set)
g.update({l: set((t, c)),
t: set((l,)),
c: set((l,))})
with ureg.context('lc'):
self.assertEqual(ureg._active_ctx.graph, g_sp)
with ureg.context('lc', n=1):
self.assertEqual(ureg._active_ctx.graph, g_sp)
with ureg.context('ab'):
self.assertEqual(ureg._active_ctx.graph, g_ab)
with ureg.context('lc'):
with ureg.context('ab'):
self.assertEqual(ureg._active_ctx.graph, g)
with ureg.context('ab'):
with ureg.context('lc'):
self.assertEqual(ureg._active_ctx.graph, g)
with ureg.context('lc', 'ab'):
self.assertEqual(ureg._active_ctx.graph, g)
with ureg.context('ab', 'lc'):
self.assertEqual(ureg._active_ctx.graph, g)
def test_graph_enable(self):
ureg = UnitRegistry()
add_ctxs(ureg)
l = _freeze({'[length]': 1.})
t = _freeze({'[time]': -1.})
c = _freeze({'[current]': -1.})
g_sp = defaultdict(set)
g_sp.update({l: set((t,)),
t: set((l,))})
g_ab = defaultdict(set)
g_ab.update({l: set((c,)),
c: set((l,))})
g = defaultdict(set)
g.update({l: set((t, c)),
t: set((l,)),
c: set((l,))})
ureg.enable_contexts('lc')
self.assertEqual(ureg._active_ctx.graph, g_sp)
ureg.disable_contexts(1)
ureg.enable_contexts('lc', n=1)
self.assertEqual(ureg._active_ctx.graph, g_sp)
ureg.disable_contexts(1)
ureg.enable_contexts('ab')
self.assertEqual(ureg._active_ctx.graph, g_ab)
ureg.disable_contexts(1)
ureg.enable_contexts('lc')
ureg.enable_contexts('ab')
self.assertEqual(ureg._active_ctx.graph, g)
ureg.disable_contexts(2)
ureg.enable_contexts('ab')
ureg.enable_contexts('lc')
self.assertEqual(ureg._active_ctx.graph, g)
ureg.disable_contexts(2)
ureg.enable_contexts('lc', 'ab')
self.assertEqual(ureg._active_ctx.graph, g)
ureg.disable_contexts(2)
ureg.enable_contexts('ab', 'lc')
self.assertEqual(ureg._active_ctx.graph, g)
ureg.disable_contexts(2)
def test_known_nested_context(self):
ureg = UnitRegistry()
add_ctxs(ureg)
with ureg.context('lc'):
x = dict(ureg._active_ctx)
y = dict(ureg._active_ctx.graph)
self.assertTrue(ureg._active_ctx)
self.assertTrue(ureg._active_ctx.graph)
with ureg.context('ab'):
self.assertTrue(ureg._active_ctx)
self.assertTrue(ureg._active_ctx.graph)
self.assertNotEqual(x, ureg._active_ctx)
self.assertNotEqual(y, ureg._active_ctx.graph)
self.assertEqual(x, ureg._active_ctx)
self.assertEqual(y, ureg._active_ctx.graph)
self.assertFalse(ureg._active_ctx)
self.assertFalse(ureg._active_ctx.graph)
def test_unknown_context(self):
ureg = UnitRegistry()
add_ctxs(ureg)
try:
with ureg.context('la'):
pass
except KeyError as e:
value = True
except Exception as e:
value = False
self.assertTrue(value)
self.assertFalse(ureg._active_ctx)
self.assertFalse(ureg._active_ctx.graph)
def test_unknown_nested_context(self):
ureg = UnitRegistry()
add_ctxs(ureg)
with ureg.context('lc'):
x = dict(ureg._active_ctx)
y = dict(ureg._active_ctx.graph)
try:
with ureg.context('la'):
pass
except KeyError as e:
value = True
except Exception as e:
value = False
self.assertTrue(value)
self.assertEqual(x, ureg._active_ctx)
self.assertEqual(y, ureg._active_ctx.graph)
self.assertFalse(ureg._active_ctx)
self.assertFalse(ureg._active_ctx.graph)
def test_one_context(self):
ureg = UnitRegistry()
add_ctxs(ureg)
q = 500 * ureg.meter
s = (ureg.speed_of_light / q).to('Hz')
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc'):
self.assertEqual(q.to('Hz'), s)
self.assertRaises(ValueError, q.to, 'Hz')
def test_multiple_context(self):
ureg = UnitRegistry()
add_ctxs(ureg)
q = 500 * ureg.meter
s = (ureg.speed_of_light / q).to('Hz')
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc', 'ab'):
self.assertEqual(q.to('Hz'), s)
self.assertRaises(ValueError, q.to, 'Hz')
def test_nested_context(self):
ureg = UnitRegistry()
add_ctxs(ureg)
q = 500 * ureg.meter
s = (ureg.speed_of_light / q).to('Hz')
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc'):
self.assertEqual(q.to('Hz'), s)
with ureg.context('ab'):
self.assertEqual(q.to('Hz'), s)
self.assertEqual(q.to('Hz'), s)
with ureg.context('ab'):
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc'):
self.assertEqual(q.to('Hz'), s)
self.assertRaises(ValueError, q.to, 'Hz')
def test_context_with_arg(self):
ureg = UnitRegistry()
add_arg_ctxs(ureg)
q = 500 * ureg.meter
s = (ureg.speed_of_light / q).to('Hz')
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc', n=1):
self.assertEqual(q.to('Hz'), s)
with ureg.context('ab'):
self.assertEqual(q.to('Hz'), s)
self.assertEqual(q.to('Hz'), s)
with ureg.context('ab'):
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc', n=1):
self.assertEqual(q.to('Hz'), s)
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc'):
self.assertRaises(TypeError, q.to, 'Hz')
def test_enable_context_with_arg(self):
ureg = UnitRegistry()
add_arg_ctxs(ureg)
q = 500 * ureg.meter
s = (ureg.speed_of_light / q).to('Hz')
self.assertRaises(ValueError, q.to, 'Hz')
ureg.enable_contexts('lc', n=1)
self.assertEqual(q.to('Hz'), s)
ureg.enable_contexts('ab')
self.assertEqual(q.to('Hz'), s)
self.assertEqual(q.to('Hz'), s)
ureg.disable_contexts(1)
ureg.disable_contexts(1)
ureg.enable_contexts('ab')
self.assertRaises(ValueError, q.to, 'Hz')
ureg.enable_contexts('lc', n=1)
self.assertEqual(q.to('Hz'), s)
ureg.disable_contexts(1)
self.assertRaises(ValueError, q.to, 'Hz')
ureg.disable_contexts(1)
ureg.enable_contexts('lc')
self.assertRaises(TypeError, q.to, 'Hz')
ureg.disable_contexts(1)
def test_context_with_arg_def(self):
ureg = UnitRegistry()
add_argdef_ctxs(ureg)
q = 500 * ureg.meter
s = (ureg.speed_of_light / q).to('Hz')
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc'):
self.assertEqual(q.to('Hz'), s)
with ureg.context('ab'):
self.assertEqual(q.to('Hz'), s)
self.assertEqual(q.to('Hz'), s)
with ureg.context('ab'):
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc'):
self.assertEqual(q.to('Hz'), s)
self.assertRaises(ValueError, q.to, 'Hz')
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc', n=2):
self.assertEqual(q.to('Hz'), s / 2)
with ureg.context('ab'):
self.assertEqual(q.to('Hz'), s / 2)
self.assertEqual(q.to('Hz'), s / 2)
with ureg.context('ab'):
self.assertRaises(ValueError, q.to, 'Hz')
with ureg.context('lc', n=2):
self.assertEqual(q.to('Hz'), s / 2)
self.assertRaises(ValueError, q.to, 'Hz')
def test_context_with_sharedarg_def(self):
ureg = UnitRegistry()
add_sharedargdef_ctxs(ureg)
q = 500 * ureg.meter
s = (ureg.speed_of_light / q).to('Hz')
u = (1 / 500) * ureg.ampere
with ureg.context('lc'):
self.assertEqual(q.to('Hz'), s)
with ureg.context('ab'):
self.assertEqual(q.to('ampere'), u)
with ureg.context('ab'):
self.assertEqual(q.to('ampere'), 0 * u)
with ureg.context('lc'):
self.assertRaises(ZeroDivisionError, ureg.Quantity.to, q, 'Hz')
with ureg.context('lc', n=2):
self.assertEqual(q.to('Hz'), s / 2)
with ureg.context('ab'):
self.assertEqual(q.to('ampere'), 2 * u)
with ureg.context('ab', n=3):
self.assertEqual(q.to('ampere'), 3 * u)
with ureg.context('lc'):
self.assertEqual(q.to('Hz'), s / 3)
with ureg.context('lc', n=2):
self.assertEqual(q.to('Hz'), s / 2)
with ureg.context('ab', n=4):
self.assertEqual(q.to('ampere'), 4 * u)
with ureg.context('ab', n=3):
self.assertEqual(q.to('ampere'), 3 * u)
with ureg.context('lc', n=6):
self.assertEqual(q.to('Hz'), s / 6)
def _test_ctx(self, ctx):
ureg = UnitRegistry()
q = 500 * ureg.meter
s = (ureg.speed_of_light / q).to('Hz')
nctx = len(ureg._contexts)
self.assertNotIn(ctx.name, ureg._contexts)
ureg.add_context(ctx)
self.assertIn(ctx.name, ureg._contexts)
self.assertEqual(len(ureg._contexts), nctx + 1 + len(ctx.aliases))
with ureg.context(ctx.name):
self.assertEqual(q.to('Hz'), s)
self.assertEqual(s.to('meter'), q)
ureg.remove_context(ctx.name)
self.assertNotIn(ctx.name, ureg._contexts)
self.assertEqual(len(ureg._contexts), nctx)
def test_parse_invalid(self):
s = ['@context longcontextname',
'[length] = 1 / [time]: c / value',
'1 / [time] = [length]: c / value']
self.assertRaises(ValueError, Context.from_lines, s)
def test_parse_simple(self):
a = Context.__keytransform__(UnitsContainer({'[time]': -1}), UnitsContainer({'[length]': 1}))
b = Context.__keytransform__(UnitsContainer({'[length]': 1}), UnitsContainer({'[time]': -1}))
s = ['@context longcontextname',
'[length] -> 1 / [time]: c / value',
'1 / [time] -> [length]: c / value']
c = Context.from_lines(s)
self.assertEqual(c.name, 'longcontextname')
self.assertEqual(c.aliases, ())
self.assertEqual(c.defaults, {})
self.assertEqual(set(c.funcs.keys()), set((a, b)))
self._test_ctx(c)
s = ['@context longcontextname = lc',
'[length] <-> 1 / [time]: c / value']
c = Context.from_lines(s)
self.assertEqual(c.name, 'longcontextname')
self.assertEqual(c.aliases, ('lc', ))
self.assertEqual(c.defaults, {})
self.assertEqual(set(c.funcs.keys()), set((a, b)))
self._test_ctx(c)
s = ['@context longcontextname = lc = lcn',
'[length] <-> 1 / [time]: c / value']
c = Context.from_lines(s)
self.assertEqual(c.name, 'longcontextname')
self.assertEqual(c.aliases, ('lc', 'lcn', ))
self.assertEqual(c.defaults, {})
self.assertEqual(set(c.funcs.keys()), set((a, b)))
self._test_ctx(c)
def test_parse_auto_inverse(self):
a = Context.__keytransform__(UnitsContainer({'[time]': -1.}), UnitsContainer({'[length]': 1.}))
b = Context.__keytransform__(UnitsContainer({'[length]': 1.}), UnitsContainer({'[time]': -1.}))
s = ['@context longcontextname',
'[length] <-> 1 / [time]: c / value']
c = Context.from_lines(s)
self.assertEqual(c.defaults, {})
self.assertEqual(set(c.funcs.keys()), set((a, b)))
self._test_ctx(c)
def test_parse_define(self):
a = Context.__keytransform__(UnitsContainer({'[time]': -1}), UnitsContainer({'[length]': 1.}))
b = Context.__keytransform__(UnitsContainer({'[length]': 1}), UnitsContainer({'[time]': -1.}))
s = ['@context longcontextname',
'[length] <-> 1 / [time]: c / value']
c = Context.from_lines(s)
self.assertEqual(c.defaults, {})
self.assertEqual(set(c.funcs.keys()), set((a, b)))
self._test_ctx(c)
def test_parse_parameterized(self):
a = Context.__keytransform__(UnitsContainer({'[time]': -1.}), UnitsContainer({'[length]': 1.}))
b = Context.__keytransform__(UnitsContainer({'[length]': 1.}), UnitsContainer({'[time]': -1.}))
s = ['@context(n=1) longcontextname',
'[length] <-> 1 / [time]: n * c / value']
c = Context.from_lines(s)
self.assertEqual(c.defaults, {'n': 1})
self.assertEqual(set(c.funcs.keys()), set((a, b)))
self._test_ctx(c)
s = ['@context(n=1, bla=2) longcontextname',
'[length] <-> 1 / [time]: n * c / value / bla']
c = Context.from_lines(s)
self.assertEqual(c.defaults, {'n': 1, 'bla': 2})
self.assertEqual(set(c.funcs.keys()), set((a, b)))
# If the variable is not present in the definition, then raise an error
s = ['@context(n=1) longcontextname',
'[length] <-> 1 / [time]: c / value']
self.assertRaises(ValueError, Context.from_lines, s)
def test_warnings(self):
ureg = UnitRegistry()
with self.capture_log() as buffer:
add_ctxs(ureg)
d = Context('ab')
ureg.add_context(d)
self.assertEqual(len(buffer), 1)
self.assertIn("ab", str(buffer[-1]))
d = Context('ab1', aliases=('ab',))
ureg.add_context(d)
self.assertEqual(len(buffer), 2)
self.assertIn("ab", str(buffer[-1]))
class TestDefinedContexts(QuantityTestCase):
FORCE_NDARRAY = False
def test_defined(self):
ureg = self.ureg
with ureg.context('sp'):
pass
a = Context.__keytransform__(UnitsContainer({'[time]': -1.}), UnitsContainer({'[length]': 1.}))
b = Context.__keytransform__(UnitsContainer({'[length]': 1.}), UnitsContainer({'[time]': -1.}))
self.assertIn(a, ureg._contexts['sp'].funcs)
self.assertIn(b, ureg._contexts['sp'].funcs)
with ureg.context('sp'):
self.assertIn(a, ureg._active_ctx)
self.assertIn(b, ureg._active_ctx)
def test_spectroscopy(self):
ureg = self.ureg
eq = (532. * ureg.nm, 563.5 * ureg.terahertz, 2.33053 * ureg.eV)
with ureg.context('sp'):
from pint.util import find_shortest_path
for a, b in itertools.product(eq, eq):
for x in range(2):
if x == 1:
a = a.to_base_units()
b = b.to_base_units()
da, db = Context.__keytransform__(a.dimensionality,
b.dimensionality)
p = find_shortest_path(ureg._active_ctx.graph, da, db)
self.assertTrue(p)
msg = '{0} <-> {1}'.format(a, b)
# assertAlmostEqualRelError converts second to first
self.assertQuantityAlmostEqual(b, a, rtol=0.01, msg=msg)
for a, b in itertools.product(eq, eq):
self.assertQuantityAlmostEqual(a.to(b.units, 'sp'), b, rtol=0.01)

View File

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
from pint import formatting as fmt
from pint.testsuite import QuantityTestCase
class TestFormatter(QuantityTestCase):
def test_join(self):
for empty in (tuple(), []):
self.assertEqual(fmt._join('s', empty), '')
self.assertEqual(fmt._join('*', '1 2 3'.split()), '1*2*3')
self.assertEqual(fmt._join('{0}*{1}', '1 2 3'.split()), '1*2*3')
def test_formatter(self):
self.assertEqual(fmt.formatter(dict().items()), '')
self.assertEqual(fmt.formatter(dict(meter=1).items()), 'meter')
self.assertEqual(fmt.formatter(dict(meter=-1).items()), '1 / meter')
self.assertEqual(fmt.formatter(dict(meter=-1).items(), as_ratio=False), 'meter ** -1')
self.assertEqual(fmt.formatter(dict(meter=-1, second=-1).items(), as_ratio=False),
'meter ** -1 * second ** -1')
self.assertEqual(fmt.formatter(dict(meter=-1, second=-1).items()),
'1 / meter / second')
self.assertEqual(fmt.formatter(dict(meter=-1, second=-1).items(), single_denominator=True),
'1 / (meter * second)')
self.assertEqual(fmt.formatter(dict(meter=-1, second=-2).items()),
'1 / meter / second ** 2')
self.assertEqual(fmt.formatter(dict(meter=-1, second=-2).items(), single_denominator=True),
'1 / (meter * second ** 2)')
def test_parse_spec(self):
self.assertEqual(fmt._parse_spec(''), '')
self.assertEqual(fmt._parse_spec(''), '')
self.assertRaises(ValueError, fmt._parse_spec, 'W')
self.assertRaises(ValueError, fmt._parse_spec, 'PL')
def test_format_unit(self):
self.assertEqual(fmt.format_unit('', 'C'), 'dimensionless')
self.assertRaises(ValueError, fmt.format_unit, 'm', 'W')

View File

@ -0,0 +1,473 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
import math
from pint import UnitRegistry
from pint.unit import UnitsContainer
from pint.util import ParserHelper
from pint.compat import np, unittest, long_type
from pint.testsuite import QuantityTestCase, helpers
class TestIssues(QuantityTestCase):
FORCE_NDARRAY = False
def setup(self):
self.ureg.autoconvert_offset_to_baseunit = False
@unittest.expectedFailure
def test_issue25(self):
x = ParserHelper.from_string('10 %')
self.assertEqual(x, ParserHelper(10, {'%': 1}))
x = ParserHelper.from_string('10 ‰')
self.assertEqual(x, ParserHelper(10, {'': 1}))
ureg = UnitRegistry()
ureg.define('percent = [fraction]; offset: 0 = %')
ureg.define('permille = percent / 10 = ‰')
x = ureg.parse_expression('10 %')
self.assertEqual(x, ureg.Quantity(10, {'%': 1}))
y = ureg.parse_expression('10 ‰')
self.assertEqual(y, ureg.Quantity(10, {'': 1}))
self.assertEqual(x.to(''), ureg.Quantity(1, {'': 1}))
def test_issue29(self):
ureg = UnitRegistry()
ureg.define('molar = mole / liter = M')
t = 4 * ureg('mM')
self.assertEqual(t.magnitude, 4)
self.assertEqual(t.units, UnitsContainer(millimolar=1))
self.assertEqual(t.to('mole / liter'), 4e-3 * ureg('M'))
def test_issue52(self):
u1 = UnitRegistry()
u2 = UnitRegistry()
q1 = u1.meter
q2 = u2.meter
import operator as op
for fun in (op.add, op.iadd,
op.sub, op.isub,
op.mul, op.imul,
op.floordiv, op.ifloordiv,
op.truediv, op.itruediv):
self.assertRaises(ValueError, fun, q1, q2)
def test_issue54(self):
ureg = UnitRegistry()
self.assertEqual((ureg.km/ureg.m + 1).magnitude, 1001)
def test_issue54_related(self):
ureg = UnitRegistry()
self.assertEqual(ureg.km/ureg.m, 1000)
self.assertEqual(1000, ureg.km/ureg.m)
self.assertLess(900, ureg.km/ureg.m)
self.assertGreater(1100, ureg.km/ureg.m)
def test_issue61(self):
ureg = UnitRegistry()
Q_ = ureg.Quantity
for value in ({}, {'a': 3}, None):
self.assertRaises(TypeError, Q_, value)
self.assertRaises(TypeError, Q_, value, 'meter')
self.assertRaises(ValueError, Q_, '', 'meter')
self.assertRaises(ValueError, Q_, '')
@helpers.requires_not_numpy()
def test_issue61_notNP(self):
ureg = UnitRegistry()
Q_ = ureg.Quantity
for value in ([1, 2, 3], (1, 2, 3)):
self.assertRaises(TypeError, Q_, value)
self.assertRaises(TypeError, Q_, value, 'meter')
def test_issue66(self):
ureg = UnitRegistry()
self.assertEqual(ureg.get_dimensionality(UnitsContainer({'[temperature]': 1})),
UnitsContainer({'[temperature]': 1}))
self.assertEqual(ureg.get_dimensionality(ureg.kelvin.units),
UnitsContainer({'[temperature]': 1}))
self.assertEqual(ureg.get_dimensionality(ureg.degC.units),
UnitsContainer({'[temperature]': 1}))
def test_issue66b(self):
ureg = UnitRegistry()
self.assertEqual(ureg.get_base_units(ureg.kelvin.units),
(1.0, UnitsContainer({'kelvin': 1})))
self.assertEqual(ureg.get_base_units(ureg.degC.units),
(1.0, UnitsContainer({'kelvin': 1})))
def test_issue69(self):
ureg = UnitRegistry()
q = ureg('m').to(ureg('in'))
self.assertEqual(q, ureg('m').to('in'))
@helpers.requires_uncertainties()
def test_issue77(self):
ureg = UnitRegistry()
acc = (5.0 * ureg('m/s/s')).plus_minus(0.25)
tim = (37.0 * ureg('s')).plus_minus(0.16)
dis = acc * tim ** 2 / 2
self.assertEqual(dis.value, acc.value * tim.value ** 2 / 2)
def test_issue85(self):
ureg = UnitRegistry()
T = 4. * ureg.kelvin
m = 1. * ureg.amu
va = 2. * ureg.k * T / m
try:
va.to_base_units()
except:
self.assertTrue(False, 'Error while trying to get base units for {}'.format(va))
boltmk = 1.3806488e-23*ureg.J/ureg.K
vb = 2. * boltmk * T / m
self.assertQuantityAlmostEqual(va.to_base_units(), vb.to_base_units())
def test_issue86(self):
ureg = self.ureg
ureg.autoconvert_offset_to_baseunit = True
def parts(q):
return q.magnitude, q.units
q1 = 10. * ureg.degC
q2 = 10. * ureg.kelvin
k1 = q1.to_base_units()
q3 = 3. * ureg.meter
q1m, q1u = parts(q1)
q2m, q2u = parts(q2)
q3m, q3u = parts(q3)
k1m, k1u = parts(k1)
self.assertEqual(parts(q2 * q3), (q2m * q3m, q2u * q3u))
self.assertEqual(parts(q2 / q3), (q2m / q3m, q2u / q3u))
self.assertEqual(parts(q3 * q2), (q3m * q2m, q3u * q2u))
self.assertEqual(parts(q3 / q2), (q3m / q2m, q3u / q2u))
self.assertEqual(parts(q2 ** 1), (q2m ** 1, q2u ** 1))
self.assertEqual(parts(q2 ** -1), (q2m ** -1, q2u ** -1))
self.assertEqual(parts(q2 ** 2), (q2m ** 2, q2u ** 2))
self.assertEqual(parts(q2 ** -2), (q2m ** -2, q2u ** -2))
self.assertEqual(parts(q1 * q3), (k1m * q3m, k1u * q3u))
self.assertEqual(parts(q1 / q3), (k1m / q3m, k1u / q3u))
self.assertEqual(parts(q3 * q1), (q3m * k1m, q3u * k1u))
self.assertEqual(parts(q3 / q1), (q3m / k1m, q3u / k1u))
self.assertEqual(parts(q1 ** -1), (k1m ** -1, k1u ** -1))
self.assertEqual(parts(q1 ** 2), (k1m ** 2, k1u ** 2))
self.assertEqual(parts(q1 ** -2), (k1m ** -2, k1u ** -2))
def test_issues86b(self):
ureg = self.ureg
T1 = 200. * ureg.degC
T2 = T1.to(ureg.kelvin)
m = 132.9054519 * ureg.amu
v1 = 2 * ureg.k * T1 / m
v2 = 2 * ureg.k * T2 / m
self.assertQuantityAlmostEqual(v1, v2)
self.assertQuantityAlmostEqual(v1, v2.to_base_units())
self.assertQuantityAlmostEqual(v1.to_base_units(), v2)
self.assertQuantityAlmostEqual(v1.to_base_units(), v2.to_base_units())
@unittest.expectedFailure
def test_issue86c(self):
ureg = self.ureg
ureg.autoconvert_offset_to_baseunit = True
T = ureg.degC
T = 100. * T
self.assertQuantityAlmostEqual(ureg.k*2*T, ureg.k*(2*T))
def test_issue93(self):
ureg = UnitRegistry()
self.assertIsInstance(ureg.meter.magnitude, int)
x = 5 * ureg.meter
self.assertIsInstance(x.magnitude, int)
y = 0.1 * ureg.meter
self.assertIsInstance(y.magnitude, float)
z = 5 * ureg.meter
self.assertIsInstance(z.magnitude, int)
z += y
self.assertIsInstance(z.magnitude, float)
self.assertQuantityAlmostEqual(x + y, 5.1 * ureg.meter)
self.assertQuantityAlmostEqual(z, 5.1 * ureg.meter)
def _test_issueXX(self):
ureg = UnitRegistry()
try:
ureg.convert(1, ureg.degC, ureg.kelvin * ureg.meter / ureg.nanometer)
except:
self.assertTrue(False,
'Error while trying to convert {} to {}'.format(ureg.degC, ureg.kelvin * ureg.meter / ureg.nanometer))
def test_issue121(self):
sh = (2, 1)
ureg = UnitRegistry()
z, v = 0, 2.
self.assertEqual(z + v * ureg.meter, v * ureg.meter)
self.assertEqual(z - v * ureg.meter, -v * ureg.meter)
self.assertEqual(v * ureg.meter + z, v * ureg.meter)
self.assertEqual(v * ureg.meter - z, v * ureg.meter)
self.assertEqual(sum([v * ureg.meter, v * ureg.meter]), 2 * v * ureg.meter)
def test_issue105(self):
ureg = UnitRegistry()
func = ureg.parse_unit_name
val = list(func('meter'))
self.assertEqual(list(func('METER')), [])
self.assertEqual(val, list(func('METER', False)))
for func in (ureg.get_name, ureg.parse_expression):
val = func('meter')
self.assertRaises(ValueError, func, 'METER')
self.assertEqual(val, func('METER', False))
def test_issue104(self):
ureg = UnitRegistry()
x = [ureg('1 meter'), ureg('1 meter'), ureg('1 meter')]
y = [ureg('1 meter')] * 3
def summer(values):
if not values:
return 0
total = values[0]
for v in values[1:]:
total += v
return total
self.assertQuantityAlmostEqual(summer(x), ureg.Quantity(3, 'meter'))
self.assertQuantityAlmostEqual(x[0], ureg.Quantity(1, 'meter'))
self.assertQuantityAlmostEqual(summer(y), ureg.Quantity(3, 'meter'))
self.assertQuantityAlmostEqual(y[0], ureg.Quantity(1, 'meter'))
def test_issue170(self):
Q_ = UnitRegistry().Quantity
q = Q_('1 kHz')/Q_('100 Hz')
iq = int(q)
self.assertEqual(iq, 10)
self.assertIsInstance(iq, int)
@helpers.requires_python2()
def test_issue170b(self):
Q_ = UnitRegistry().Quantity
q = Q_('1 kHz')/Q_('100 Hz')
iq = long(q)
self.assertEqual(iq, long(10))
self.assertIsInstance(iq, long)
@helpers.requires_numpy()
class TestIssuesNP(QuantityTestCase):
FORCE_NDARRAY = False
@unittest.expectedFailure
def test_issue37(self):
x = np.ma.masked_array([1, 2, 3], mask=[True, True, False])
ureg = UnitRegistry()
q = ureg.meter * x
self.assertIsInstance(q, ureg.Quantity)
np.testing.assert_array_equal(q.magnitude, x)
self.assertEqual(q.units, ureg.meter.units)
q = x * ureg.meter
self.assertIsInstance(q, ureg.Quantity)
np.testing.assert_array_equal(q.magnitude, x)
self.assertEqual(q.units, ureg.meter.units)
m = np.ma.masked_array(2 * np.ones(3,3))
qq = q * m
self.assertIsInstance(qq, ureg.Quantity)
np.testing.assert_array_equal(qq.magnitude, x * m)
self.assertEqual(qq.units, ureg.meter.units)
qq = m * q
self.assertIsInstance(qq, ureg.Quantity)
np.testing.assert_array_equal(qq.magnitude, x * m)
self.assertEqual(qq.units, ureg.meter.units)
@unittest.expectedFailure
def test_issue39(self):
x = np.matrix([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
ureg = UnitRegistry()
q = ureg.meter * x
self.assertIsInstance(q, ureg.Quantity)
np.testing.assert_array_equal(q.magnitude, x)
self.assertEqual(q.units, ureg.meter.units)
q = x * ureg.meter
self.assertIsInstance(q, ureg.Quantity)
np.testing.assert_array_equal(q.magnitude, x)
self.assertEqual(q.units, ureg.meter.units)
m = np.matrix(2 * np.ones(3,3))
qq = q * m
self.assertIsInstance(qq, ureg.Quantity)
np.testing.assert_array_equal(qq.magnitude, x * m)
self.assertEqual(qq.units, ureg.meter.units)
qq = m * q
self.assertIsInstance(qq, ureg.Quantity)
np.testing.assert_array_equal(qq.magnitude, x * m)
self.assertEqual(qq.units, ureg.meter.units)
def test_issue44(self):
ureg = UnitRegistry()
x = 4. * ureg.dimensionless
np.sqrt(x)
self.assertQuantityAlmostEqual(np.sqrt([4.] * ureg.dimensionless), [2.] * ureg.dimensionless)
self.assertQuantityAlmostEqual(np.sqrt(4. * ureg.dimensionless), 2. * ureg.dimensionless)
def test_issue45(self):
import math
ureg = UnitRegistry()
self.assertAlmostEqual(math.sqrt(4 * ureg.m/ureg.cm), math.sqrt(4 * 100))
self.assertAlmostEqual(float(ureg.V / ureg.mV), 1000.)
def test_issue45b(self):
ureg = UnitRegistry()
self.assertAlmostEqual(np.sin([np.pi/2] * ureg.m / ureg.m ), np.sin([np.pi/2] * ureg.dimensionless))
self.assertAlmostEqual(np.sin([np.pi/2] * ureg.cm / ureg.m ), np.sin([np.pi/2] * ureg.dimensionless * 0.01))
def test_issue50(self):
ureg = UnitRegistry()
Q_ = ureg.Quantity
self.assertEqual(Q_(100), 100 * ureg.dimensionless)
self.assertEqual(Q_('100'), 100 * ureg.dimensionless)
def test_issue62(self):
ureg = UnitRegistry()
m = ureg('m**0.5')
self.assertEqual(str(m.units), 'meter ** 0.5')
def test_issue74(self):
ureg = UnitRegistry()
v1 = np.asarray([1., 2., 3.])
v2 = np.asarray([3., 2., 1.])
q1 = v1 * ureg.ms
q2 = v2 * ureg.ms
np.testing.assert_array_equal(q1 < q2, v1 < v2)
np.testing.assert_array_equal(q1 > q2, v1 > v2)
np.testing.assert_array_equal(q1 <= q2, v1 <= v2)
np.testing.assert_array_equal(q1 >= q2, v1 >= v2)
q2s = np.asarray([0.003, 0.002, 0.001]) * ureg.s
v2s = q2s.to('ms').magnitude
np.testing.assert_array_equal(q1 < q2s, v1 < v2s)
np.testing.assert_array_equal(q1 > q2s, v1 > v2s)
np.testing.assert_array_equal(q1 <= q2s, v1 <= v2s)
np.testing.assert_array_equal(q1 >= q2s, v1 >= v2s)
def test_issue75(self):
ureg = UnitRegistry()
v1 = np.asarray([1., 2., 3.])
v2 = np.asarray([3., 2., 1.])
q1 = v1 * ureg.ms
q2 = v2 * ureg.ms
np.testing.assert_array_equal(q1 == q2, v1 == v2)
np.testing.assert_array_equal(q1 != q2, v1 != v2)
q2s = np.asarray([0.003, 0.002, 0.001]) * ureg.s
v2s = q2s.to('ms').magnitude
np.testing.assert_array_equal(q1 == q2s, v1 == v2s)
np.testing.assert_array_equal(q1 != q2s, v1 != v2s)
def test_issue93(self):
ureg = UnitRegistry()
self.assertIsInstance(ureg.meter.magnitude, int)
x = 5 * ureg.meter
self.assertIsInstance(x.magnitude, int)
y = 0.1 * ureg.meter
self.assertIsInstance(y.magnitude, float)
z = 5 * ureg.meter
self.assertIsInstance(z.magnitude, int)
z += y
self.assertIsInstance(z.magnitude, float)
self.assertQuantityAlmostEqual(x + y, 5.1 * ureg.meter)
self.assertQuantityAlmostEqual(z, 5.1 * ureg.meter)
def test_issue94(self):
ureg = UnitRegistry()
v1 = np.array([5, 5]) * ureg.meter
v2 = 0.1 * ureg.meter
v3 = np.array([5, 5]) * ureg.meter
v3 += v2
np.testing.assert_array_equal((v1 + v2).magnitude, np.array([5.1, 5.1]))
np.testing.assert_array_equal(v3.magnitude, np.array([5, 5]))
@helpers.requires_numpy18()
def test_issue121(self):
sh = (2, 1)
ureg = UnitRegistry()
z, v = 0, 2.
self.assertEqual(z + v * ureg.meter, v * ureg.meter)
self.assertEqual(z - v * ureg.meter, -v * ureg.meter)
self.assertEqual(v * ureg.meter + z, v * ureg.meter)
self.assertEqual(v * ureg.meter - z, v * ureg.meter)
self.assertEqual(sum([v * ureg.meter, v * ureg.meter]), 2 * v * ureg.meter)
z, v = np.zeros(sh), 2. * np.ones(sh)
self.assertQuantityEqual(z + v * ureg.meter, v * ureg.meter)
self.assertQuantityEqual(z - v * ureg.meter, -v * ureg.meter)
self.assertQuantityEqual(v * ureg.meter + z, v * ureg.meter)
self.assertQuantityEqual(v * ureg.meter - z, v * ureg.meter)
z, v = np.zeros((3, 1)), 2. * np.ones(sh)
for x, y in ((z, v),
(z, v * ureg.meter),
(v * ureg.meter, z)
):
try:
w = x + y
self.assertTrue(False, "ValueError not raised")
except ValueError:
pass
try:
w = x - y
self.assertTrue(False, "ValueError not raised")
except ValueError:
pass
def test_issue127(self):
q = [1., 2., 3., 4.] * self.ureg.meter
q[0] = np.nan
self.assertNotEqual(q[0], 1.)
self.assertTrue(math.isnan(q[0].magnitude))
q[1] = float('NaN')
self.assertNotEqual(q[1], 2.)
self.assertTrue(math.isnan(q[1].magnitude))
def test_issue171_real_imag(self):
qr = [1., 2., 3., 4.] * self.ureg.meter
qi = [4., 3., 2., 1.] * self.ureg.meter
q = qr + 1j * qi
self.assertQuantityEqual(q.real, qr)
self.assertQuantityEqual(q.imag, qi)
def test_issue171_T(self):
a = np.asarray([[1., 2., 3., 4.],[4., 3., 2., 1.]])
q1 = a * self.ureg.meter
q2 = a.T * self.ureg.meter
self.assertQuantityEqual(q1.T, q2)

View File

@ -0,0 +1,160 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
from pint.testsuite import QuantityTestCase, helpers
@helpers.requires_not_uncertainties()
class TestNotMeasurement(QuantityTestCase):
FORCE_NDARRAY = False
def test_instantiate(self):
M_ = self.ureg.Measurement
self.assertRaises(RuntimeError, M_, 4.0, 0.1, 's')
@helpers.requires_uncertainties()
class TestMeasurement(QuantityTestCase):
FORCE_NDARRAY = False
def test_simple(self):
M_ = self.ureg.Measurement
M_(4.0, 0.1, 's')
def test_build(self):
M_ = self.ureg.Measurement
v, u = self.Q_(4.0, 's'), self.Q_(.1, 's')
M_(v.magnitude, u.magnitude, 's')
ms = (M_(v.magnitude, u.magnitude, 's'),
M_(v, u.magnitude),
M_(v, u),
v.plus_minus(.1),
v.plus_minus(0.025, True),
v.plus_minus(u),)
for m in ms:
self.assertEqual(m.value, v)
self.assertEqual(m.error, u)
self.assertEqual(m.rel, m.error / abs(m.value))
def test_format(self):
v, u = self.Q_(4.0, 's ** 2'), self.Q_(.1, 's ** 2')
m = self.ureg.Measurement(v, u)
self.assertEqual(str(m), '(4.00 +/- 0.10) second ** 2')
self.assertEqual(repr(m), '<Measurement(4.00, 0.10, second ** 2)>')
#self.assertEqual('{:!s}'.format(m), '(4.00 +/- 0.10) second ** 2')
#self.assertEqual('{:!r}'.format(m), '<Measurement(4.0-, 0.10, second ** 2)>')
self.assertEqual('{0:P}'.format(m), '(4.00 ± 0.10) second²')
self.assertEqual('{0:L}'.format(m), r'\left(4.00 \pm 0.10\right) second^{2}')
self.assertEqual('{0:H}'.format(m), '(4.00 &plusmn; 0.10) second<sup>2</sup>')
self.assertEqual('{0:C}'.format(m), '(4.00+/-0.10) second**2')
self.assertEqual('{0:.1f}'.format(m), '(4.0 +/- 0.1) second ** 2')
self.assertEqual('{0:.1fP}'.format(m), '(4.0 ± 0.1) second²')
self.assertEqual('{0:.1fL}'.format(m), r'\left(4.0 \pm 0.1\right) second^{2}')
self.assertEqual('{0:.1fH}'.format(m), '(4.0 &plusmn; 0.1) second<sup>2</sup>')
self.assertEqual('{0:.1fC}'.format(m), '(4.0+/-0.1) second**2')
def test_format_paru(self):
v, u = self.Q_(0.20, 's ** 2'), self.Q_(0.01, 's ** 2')
m = self.ureg.Measurement(v, u)
self.assertEqual('{0:uS}'.format(m), '0.200(10) second ** 2')
self.assertEqual('{0:.3uS}'.format(m), '0.2000(100) second ** 2')
self.assertEqual('{0:.3uSP}'.format(m), '0.2000(100) second²')
self.assertEqual('{0:.3uSL}'.format(m), r'0.2000\left(100\right) second^{2}')
self.assertEqual('{0:.3uSH}'.format(m), '0.2000(100) second<sup>2</sup>')
self.assertEqual('{0:.3uSC}'.format(m), '0.2000(100) second**2')
def test_format_u(self):
v, u = self.Q_(0.20, 's ** 2'), self.Q_(0.01, 's ** 2')
m = self.ureg.Measurement(v, u)
self.assertEqual('{0:.3u}'.format(m), '(0.2000 +/- 0.0100) second ** 2')
self.assertEqual('{0:.3uP}'.format(m), '(0.2000 ± 0.0100) second²')
self.assertEqual('{0:.3uL}'.format(m), r'\left(0.2000 \pm 0.0100\right) second^{2}')
self.assertEqual('{0:.3uH}'.format(m), '(0.2000 &plusmn; 0.0100) second<sup>2</sup>')
self.assertEqual('{0:.3uC}'.format(m), '(0.2000+/-0.0100) second**2')
def test_format_percu(self):
self.test_format_perce()
v, u = self.Q_(0.20, 's ** 2'), self.Q_(0.01, 's ** 2')
m = self.ureg.Measurement(v, u)
self.assertEqual('{0:.1u%}'.format(m), '(20 +/- 1)% second ** 2')
self.assertEqual('{0:.1u%P}'.format(m), '(20 ± 1)% second²')
self.assertEqual('{0:.1u%L}'.format(m), r'\left(20 \pm 1\right) \% second^{2}')
self.assertEqual('{0:.1u%H}'.format(m), '(20 &plusmn; 1)% second<sup>2</sup>')
self.assertEqual('{0:.1u%C}'.format(m), '(20+/-1)% second**2')
def test_format_perce(self):
v, u = self.Q_(0.20, 's ** 2'), self.Q_(0.01, 's ** 2')
m = self.ureg.Measurement(v, u)
self.assertEqual('{0:.1ue}'.format(m), '(2.0 +/- 0.1)e-01 second ** 2')
self.assertEqual('{0:.1ueP}'.format(m), '(2.0 ± 0.1)×10⁻¹ second²')
self.assertEqual('{0:.1ueL}'.format(m), r'\left(2.0 \pm 0.1\right) \times 10^{-1} second^{2}')
self.assertEqual('{0:.1ueH}'.format(m), '(2.0 &plusmn; 0.1)e-01 second<sup>2</sup>')
self.assertEqual('{0:.1ueC}'.format(m), '(2.0+/-0.1)e-01 second**2')
def test_raise_build(self):
v, u = self.Q_(1.0, 's'), self.Q_(.1, 's')
o = self.Q_(.1, 'm')
M_ = self.ureg.Measurement
self.assertRaises(ValueError, M_, v, o)
self.assertRaises(ValueError, v.plus_minus, o)
self.assertRaises(ValueError, v.plus_minus, u, True)
def test_propagate_linear(self):
v1, u1 = self.Q_(8.0, 's'), self.Q_(.7, 's')
v2, u2 = self.Q_(5.0, 's'), self.Q_(.6, 's')
v2, u3 = self.Q_(-5.0, 's'), self.Q_(.6, 's')
m1 = v1.plus_minus(u1)
m2 = v2.plus_minus(u2)
m3 = v2.plus_minus(u3)
for factor, m in zip((3, -3, 3, -3), (m1, m3, m1, m3)):
r = factor * m
self.assertAlmostEqual(r.value.magnitude, factor * m.value.magnitude)
self.assertAlmostEqual(r.error.magnitude, abs(factor * m.error.magnitude))
self.assertEqual(r.value.units, m.value.units)
for ml, mr in zip((m1, m1, m1, m3), (m1, m2, m3, m3)):
r = ml + mr
self.assertAlmostEqual(r.value.magnitude, ml.value.magnitude + mr.value.magnitude)
self.assertAlmostEqual(r.error.magnitude,
ml.error.magnitude + mr.error.magnitude if ml is mr else
(ml.error.magnitude ** 2 + mr.error.magnitude ** 2) ** .5)
self.assertEqual(r.value.units, ml.value.units)
for ml, mr in zip((m1, m1, m1, m3), (m1, m2, m3, m3)):
r = ml - mr
self.assertAlmostEqual(r.value.magnitude, ml.value.magnitude - mr.value.magnitude)
self.assertAlmostEqual(r.error.magnitude,
0 if ml is mr else
(ml.error.magnitude ** 2 + mr.error.magnitude ** 2) ** .5)
self.assertEqual(r.value.units, ml.value.units)
def test_propagate_product(self):
v1, u1 = self.Q_(8.0, 's'), self.Q_(.7, 's')
v2, u2 = self.Q_(5.0, 's'), self.Q_(.6, 's')
v2, u3 = self.Q_(-5.0, 's'), self.Q_(.6, 's')
m1 = v1.plus_minus(u1)
m2 = v2.plus_minus(u2)
m3 = v2.plus_minus(u3)
m4 = (2.3 * self.ureg.meter).plus_minus(0.1)
m5 = (1.4 * self.ureg.meter).plus_minus(0.2)
for ml, mr in zip((m1, m1, m1, m3, m4), (m1, m2, m3, m3, m5)):
r = ml * mr
self.assertAlmostEqual(r.value.magnitude, ml.value.magnitude * mr.value.magnitude)
self.assertEqual(r.value.units, ml.value.units * mr.value.units)
for ml, mr in zip((m1, m1, m1, m3, m4), (m1, m2, m3, m3, m5)):
r = ml / mr
self.assertAlmostEqual(r.value.magnitude, ml.value.magnitude / mr.value.magnitude)
self.assertEqual(r.value.units, ml.value.units / mr.value.units)

View File

@ -0,0 +1,441 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
import copy
import operator as op
from pint import DimensionalityError
from pint.compat import np, unittest
from pint.testsuite import QuantityTestCase, helpers
from pint.testsuite.test_umath import TestUFuncs
@helpers.requires_numpy()
class TestNumpyMethods(QuantityTestCase):
FORCE_NDARRAY = True
@property
def q(self):
return [[1,2],[3,4]] * self.ureg.m
def test_tolist(self):
self.assertEqual(self.q.tolist(), [[1*self.ureg.m, 2*self.ureg.m], [3*self.ureg.m, 4*self.ureg.m]])
def test_sum(self):
self.assertEqual(self.q.sum(), 10*self.ureg.m)
self.assertQuantityEqual(self.q.sum(0), [4, 6]*self.ureg.m)
self.assertQuantityEqual(self.q.sum(1), [3, 7]*self.ureg.m)
def test_fill(self):
tmp = self.q
tmp.fill(6 * self.ureg.ft)
self.assertQuantityEqual(tmp, [[6, 6], [6, 6]] * self.ureg.ft)
tmp.fill(5 * self.ureg.m)
self.assertQuantityEqual(tmp, [[5, 5], [5, 5]] * self.ureg.m)
def test_reshape(self):
self.assertQuantityEqual(self.q.reshape([1,4]), [[1, 2, 3, 4]] * self.ureg.m)
def test_transpose(self):
self.assertQuantityEqual(self.q.transpose(), [[1, 3], [2, 4]] * self.ureg.m)
def test_flatten(self):
self.assertQuantityEqual(self.q.flatten(), [1, 2, 3, 4] * self.ureg.m)
def test_ravel(self):
self.assertQuantityEqual(self.q.ravel(), [1, 2, 3, 4] * self.ureg.m)
def test_squeeze(self):
self.assertQuantityEqual(
self.q.reshape([1,4]).squeeze(),
[1, 2, 3, 4] * self.ureg.m
)
def test_take(self):
self.assertQuantityEqual(self.q.take([0,1,2,3]), self.q.flatten())
def test_put(self):
q = [1., 2., 3., 4.] * self.ureg.m
q.put([0, 2], [10.,20.]*self.ureg.m)
self.assertQuantityEqual(q, [10., 2., 20., 4.]*self.ureg.m)
q = [1., 2., 3., 4.] * self.ureg.m
q.put([0, 2], [1., 2.]*self.ureg.mm)
self.assertQuantityEqual(q, [0.001, 2., 0.002, 4.]*self.ureg.m)
q = [1., 2., 3., 4.] * self.ureg.m / self.ureg.mm
q.put([0, 2], [1., 2.])
self.assertQuantityEqual(q, [0.001, 2., 0.002, 4.]*self.ureg.m/self.ureg.mm)
q = [1., 2., 3., 4.] * self.ureg.m
self.assertRaises(ValueError, q.put, [0, 2], [4., 6.] * self.ureg.J)
self.assertRaises(ValueError, q.put, [0, 2], [4., 6.])
def test_repeat(self):
self.assertQuantityEqual(self.q.repeat(2), [1,1,2,2,3,3,4,4]*self.ureg.m)
def test_sort(self):
q = [4, 5, 2, 3, 1, 6] * self.ureg.m
q.sort()
self.assertQuantityEqual(q, [1, 2, 3, 4, 5, 6] * self.ureg.m)
def test_argsort(self):
q = [1, 4, 5, 6, 2, 9] * self.ureg.MeV
np.testing.assert_array_equal(q.argsort(), [0, 4, 1, 2, 3, 5])
def test_diagonal(self):
q = [[1, 2, 3], [1, 2, 3], [1, 2, 3]] * self.ureg.m
self.assertQuantityEqual(q.diagonal(offset=1), [2, 3] * self.ureg.m)
def test_compress(self):
self.assertQuantityEqual(self.q.compress([False, True], axis=0),
[[3, 4]] * self.ureg.m)
self.assertQuantityEqual(self.q.compress([False, True], axis=1),
[[2], [4]] * self.ureg.m)
def test_searchsorted(self):
q = self.q.flatten()
np.testing.assert_array_equal(q.searchsorted([1.5, 2.5] * self.ureg.m),
[1, 2])
q = self.q.flatten()
self.assertRaises(ValueError, q.searchsorted, [1.5, 2.5])
def test_nonzero(self):
q = [1, 0, 5, 6, 0, 9] * self.ureg.m
np.testing.assert_array_equal(q.nonzero()[0], [0, 2, 3, 5])
def test_max(self):
self.assertEqual(self.q.max(), 4*self.ureg.m)
def test_argmax(self):
self.assertEqual(self.q.argmax(), 3)
def test_min(self):
self.assertEqual(self.q.min(), 1 * self.ureg.m)
def test_argmin(self):
self.assertEqual(self.q.argmin(), 0)
def test_ptp(self):
self.assertEqual(self.q.ptp(), 3 * self.ureg.m)
def test_clip(self):
self.assertQuantityEqual(
self.q.clip(max=2*self.ureg.m),
[[1, 2], [2, 2]] * self.ureg.m
)
self.assertQuantityEqual(
self.q.clip(min=3*self.ureg.m),
[[3, 3], [3, 4]] * self.ureg.m
)
self.assertQuantityEqual(
self.q.clip(min=2*self.ureg.m, max=3*self.ureg.m),
[[2, 2], [3, 3]] * self.ureg.m
)
self.assertRaises(ValueError, self.q.clip, self.ureg.J)
self.assertRaises(ValueError, self.q.clip, 1)
def test_round(self):
q = [1, 1.33, 5.67, 22] * self.ureg.m
self.assertQuantityEqual(q.round(0), [1, 1, 6, 22] * self.ureg.m)
self.assertQuantityEqual(q.round(-1), [0, 0, 10, 20] * self.ureg.m)
self.assertQuantityEqual(q.round(1), [1, 1.3, 5.7, 22] * self.ureg.m)
def test_trace(self):
self.assertEqual(self.q.trace(), (1+4) * self.ureg.m)
def test_cumsum(self):
self.assertQuantityEqual(self.q.cumsum(), [1, 3, 6, 10] * self.ureg.m)
def test_mean(self):
self.assertEqual(self.q.mean(), 2.5 * self.ureg.m)
def test_var(self):
self.assertEqual(self.q.var(), 1.25*self.ureg.m**2)
def test_std(self):
self.assertQuantityAlmostEqual(self.q.std(), 1.11803*self.ureg.m, rtol=1e-5)
def test_prod(self):
self.assertEqual(self.q.prod(), 24 * self.ureg.m**4)
def test_cumprod(self):
self.assertRaises(ValueError, self.q.cumprod)
self.assertQuantityEqual((self.q / self.ureg.m).cumprod(), [1, 2, 6, 24])
def test_integer_div(self):
a = [1] * self.ureg.m
b = [2] * self.ureg.m
c = a/b # Should be float division
self.assertEqual(c.magnitude[0], 0.5)
a /= b # Should be integer division
self.assertEqual(a.magnitude[0], 0)
def test_conj(self):
self.assertQuantityEqual((self.q*(1+1j)).conj(), self.q*(1-1j))
self.assertQuantityEqual((self.q*(1+1j)).conjugate(), self.q*(1-1j))
def test_getitem(self):
self.assertRaises(IndexError, self.q.__getitem__, (0,10))
self.assertQuantityEqual(self.q[0], [1,2]*self.ureg.m)
self.assertEqual(self.q[1,1], 4*self.ureg.m)
def test_setitem(self):
self.assertRaises(ValueError, self.q.__setitem__, (0,0), 1)
self.assertRaises(ValueError, self.q.__setitem__, (0,0), 1*self.ureg.J)
self.assertRaises(ValueError, self.q.__setitem__, 0, 1)
self.assertRaises(ValueError, self.q.__setitem__, 0, np.ndarray([1, 2]))
self.assertRaises(ValueError, self.q.__setitem__, 0, 1*self.ureg.J)
q = self.q.copy()
q[0] = 1*self.ureg.m
self.assertQuantityEqual(q, [[1,1],[3,4]]*self.ureg.m)
q = self.q.copy()
q.__setitem__(Ellipsis, 1*self.ureg.m)
self.assertQuantityEqual(q, [[1,1],[1,1]]*self.ureg.m)
q = self.q.copy()
q[:] = 1*self.ureg.m
self.assertQuantityEqual(q, [[1,1],[1,1]]*self.ureg.m)
# check and see that dimensionless num bers work correctly
q = [0,1,2,3]*self.ureg.dimensionless
q[0] = 1
self.assertQuantityEqual(q, np.asarray([1,1,2,3]))
q[0] = self.ureg.m/self.ureg.mm
self.assertQuantityEqual(q, np.asarray([1000, 1,2,3]))
q = [0.,1.,2.,3.] * self.ureg.m / self.ureg.mm
q[0] = 1.
self.assertQuantityEqual(q, [0.001,1,2,3]*self.ureg.m / self.ureg.mm)
def test_iterator(self):
for q, v in zip(self.q.flatten(), [1, 2, 3, 4]):
self.assertEqual(q, v * self.ureg.m)
def test_reversible_op(self):
"""
"""
x = self.q.magnitude
u = self.Q_(np.ones(x.shape))
self.assertQuantityEqual(x / self.q, u * x / self.q)
self.assertQuantityEqual(x * self.q, u * x * self.q)
self.assertQuantityEqual(x + u, u + x)
self.assertQuantityEqual(x - u, -(u - x))
def test_pickle(self):
import pickle
def pickle_test(q):
pq = pickle.loads(pickle.dumps(q))
np.testing.assert_array_equal(q.magnitude, pq.magnitude)
self.assertEqual(q.units, pq.units)
pickle_test([10,20]*self.ureg.m)
def test_equal(self):
x = self.q.magnitude
u = self.Q_(np.ones(x.shape))
self.assertQuantityEqual(u, u)
self.assertQuantityEqual(u == u, u.magnitude == u.magnitude)
self.assertQuantityEqual(u == 1, u.magnitude == 1)
@helpers.requires_numpy()
class TestNumpyNeedsSubclassing(TestUFuncs):
FORCE_NDARRAY = True
@property
def q(self):
return [1. ,2., 3., 4.] * self.ureg.J
@unittest.expectedFailure
def test_unwrap(self):
"""unwrap depends on diff
"""
self.assertQuantityEqual(np.unwrap([0,3*np.pi]*self.ureg.radians), [0,np.pi])
self.assertQuantityEqual(np.unwrap([0,540]*self.ureg.deg), [0,180]*self.ureg.deg)
@unittest.expectedFailure
def test_trapz(self):
"""Units are erased by asanyarray, Quantity does not inherit from NDArray
"""
self.assertQuantityEqual(np.trapz(self.q, dx=1*self.ureg.m), 7.5 * self.ureg.J*self.ureg.m)
@unittest.expectedFailure
def test_diff(self):
"""Units are erased by asanyarray, Quantity does not inherit from NDArray
"""
self.assertQuantityEqual(np.diff(self.q, 1), [1, 1, 1] * self.ureg.J)
@unittest.expectedFailure
def test_ediff1d(self):
"""Units are erased by asanyarray, Quantity does not inherit from NDArray
"""
self.assertQuantityEqual(np.ediff1d(self.q, 1 * self.ureg.J), [1, 1, 1] * self.ureg.J)
@unittest.expectedFailure
def test_fix(self):
"""Units are erased by asanyarray, Quantity does not inherit from NDArray
"""
self.assertQuantityEqual(np.fix(3.14 * self.ureg.m), 3.0 * self.ureg.m)
self.assertQuantityEqual(np.fix(3.0 * self.ureg.m), 3.0 * self.ureg.m)
self.assertQuantityEqual(
np.fix([2.1, 2.9, -2.1, -2.9] * self.ureg.m),
[2., 2., -2., -2.] * self.ureg.m
)
@unittest.expectedFailure
def test_gradient(self):
"""shape is a property not a function
"""
l = np.gradient([[1,1],[3,4]] * self.ureg.J, 1 * self.ureg.m)
self.assertQuantityEqual(l[0], [[2., 3.], [2., 3.]] * self.ureg.J / self.ureg.m)
self.assertQuantityEqual(l[1], [[0., 0.], [1., 1.]] * self.ureg.J / self.ureg.m)
@unittest.expectedFailure
def test_cross(self):
"""Units are erased by asarray, Quantity does not inherit from NDArray
"""
a = [[3,-3, 1]] * self.ureg.kPa
b = [[4, 9, 2]] * self.ureg.m**2
self.assertQuantityEqual(np.cross(a, b), [-15, -2, 39] * self.ureg.kPa * self.ureg.m**2)
@unittest.expectedFailure
def test_power(self):
"""This is not supported as different elements might end up with different units
eg. ([1, 1] * m) ** [2, 3]
Must force exponent to single value
"""
self._test2(np.power, self.q1,
(self.qless, np.asarray([1., 2, 3, 4])),
(self.q2, ),)
@unittest.expectedFailure
def test_ones_like(self):
"""Units are erased by emptyarra, Quantity does not inherit from NDArray
"""
self._test1(np.ones_like,
(self.q2, self.qs, self.qless, self.qi),
(),
2)
@unittest.skip
class TestBitTwiddlingUfuncs(TestUFuncs):
"""Universal functions (ufuncs) > Bittwiddling functions
http://docs.scipy.org/doc/numpy/reference/ufuncs.html#bittwiddlingfunctions
bitwise_and(x1, x2[, out]) Compute the bitwise AND of two arrays elementwise.
bitwise_or(x1, x2[, out]) Compute the bitwise OR of two arrays elementwise.
bitwise_xor(x1, x2[, out]) Compute the bitwise XOR of two arrays elementwise.
invert(x[, out]) Compute bitwise inversion, or bitwise NOT, elementwise.
left_shift(x1, x2[, out]) Shift the bits of an integer to the left.
right_shift(x1, x2[, out]) Shift the bits of an integer to the right.
"""
@property
def qless(self):
return np.asarray([1, 2, 3, 4], dtype=np.uint8) * self.ureg.dimensionless
@property
def qs(self):
return 8 * self.ureg.J
@property
def q1(self):
return np.asarray([1, 2, 3, 4], dtype=np.uint8) * self.ureg.J
@property
def q2(self):
return 2 * self.q1
@property
def qm(self):
return np.asarray([1, 2, 3, 4], dtype=np.uint8) * self.ureg.m
def test_bitwise_and(self):
self._test2(np.bitwise_and,
self.q1,
(self.q2, self.qs,),
(self.qm, ),
'same')
def test_bitwise_or(self):
self._test2(np.bitwise_or,
self.q1,
(self.q1, self.q2, self.qs, ),
(self.qm,),
'same')
def test_bitwise_xor(self):
self._test2(np.bitwise_xor,
self.q1,
(self.q1, self.q2, self.qs, ),
(self.qm, ),
'same')
def test_invert(self):
self._test1(np.invert,
(self.q1, self.q2, self.qs, ),
(),
'same')
def test_left_shift(self):
self._test2(np.left_shift,
self.q1,
(self.qless, 2),
(self.q1, self.q2, self.qs, ),
'same')
def test_right_shift(self):
self._test2(np.right_shift,
self.q1,
(self.qless, 2),
(self.q1, self.q2, self.qs, ),
'same')
class TestNDArrayQunatityMath(QuantityTestCase):
@helpers.requires_numpy()
def test_exponentiation_array_exp(self):
arr = np.array(range(3), dtype=np.float)
q = self.Q_(arr, None)
for op_ in [op.pow, op.ipow]:
q_cp = copy.copy(q)
self.assertRaises(DimensionalityError, op_, 2., q_cp)
arr_cp = copy.copy(arr)
arr_cp = copy.copy(arr)
q_cp = copy.copy(q)
self.assertRaises(DimensionalityError, op_, q_cp, arr_cp)
q_cp = copy.copy(q)
q2_cp = copy.copy(q)
self.assertRaises(DimensionalityError, op_, q_cp, q2_cp)
@unittest.expectedFailure
@helpers.requires_numpy()
def test_exponentiation_array_exp_2(self):
arr = np.array(range(3), dtype=np.float)
#q = self.Q_(copy.copy(arr), None)
q = self.Q_(copy.copy(arr), 'meter')
arr_cp = copy.copy(arr)
q_cp = copy.copy(q)
# this fails as expected since numpy 1.8.0 but...
self.assertRaises(DimensionalityError, op.pow, arr_cp, q_cp)
# ..not for op.ipow !
# q_cp is treated as if it is an array. The units are ignored.
# _Quantity.__ipow__ is never called
arr_cp = copy.copy(arr)
q_cp = copy.copy(q)
self.assertRaises(DimensionalityError, op.ipow, arr_cp, q_cp)

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
import itertools
from pint import pi_theorem
from pint.testsuite import QuantityTestCase
class TestPiTheorem(QuantityTestCase):
FORCE_NDARRAY = False
def test_simple(self):
# simple movement
with self.capture_log() as buffer:
self.assertEqual(pi_theorem({'V': 'm/s', 'T': 's', 'L': 'm'}),
[{'V': 1, 'T': 1, 'L': -1}])
# pendulum
self.assertEqual(pi_theorem({'T': 's', 'M': 'grams', 'L': 'm', 'g': 'm/s**2'}),
[{'g': 1, 'T': 2, 'L': -1}])
self.assertEqual(len(buffer), 7)
def test_inputs(self):
V = 'km/hour'
T = 'ms'
L = 'cm'
f1 = lambda x: x
f2 = lambda x: self.Q_(1, x)
f3 = lambda x: self.Q_(1, x).units
f4 = lambda x: self.Q_(1, x).dimensionality
fs = f1, f2, f3, f4
for fv, ft, fl in itertools.product(fs, fs, fs):
qv = fv(V)
qt = ft(T)
ql = ft(L)
self.assertEqual(self.ureg.pi_theorem({'V': qv, 'T': qt, 'L': ql}),
[{'V': 1.0, 'T': 1.0, 'L': -1.0}])

View File

@ -0,0 +1,995 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
import copy
import math
import operator as op
from pint import DimensionalityError, OffsetUnitCalculusError, UnitRegistry
from pint.unit import UnitsContainer
from pint.compat import string_types, PYTHON3, np, unittest
from pint.testsuite import QuantityTestCase, helpers
from pint.testsuite.parameterized import ParameterizedTestCase
class TestQuantity(QuantityTestCase):
FORCE_NDARRAY = False
def test_quantity_creation(self):
for args in ((4.2, 'meter'),
(4.2, UnitsContainer(meter=1)),
(4.2, self.ureg.meter),
('4.2*meter', ),
('4.2/meter**(-1)', ),
(self.Q_(4.2, 'meter'),)):
x = self.Q_(*args)
self.assertEqual(x.magnitude, 4.2)
self.assertEqual(x.units, UnitsContainer(meter=1))
x = self.Q_(4.2, UnitsContainer(length=1))
y = self.Q_(x)
self.assertEqual(x.magnitude, y.magnitude)
self.assertEqual(x.units, y.units)
self.assertIsNot(x, y)
x = self.Q_(4.2, None)
self.assertEqual(x.magnitude, 4.2)
self.assertEqual(x.units, UnitsContainer())
with self.capture_log() as buffer:
self.assertEqual(4.2 * self.ureg.meter, self.Q_(4.2, 2 * self.ureg.meter))
self.assertEqual(len(buffer), 1)
def test_quantity_bool(self):
self.assertTrue(self.Q_(1, None))
self.assertTrue(self.Q_(1, 'meter'))
self.assertFalse(self.Q_(0, None))
self.assertFalse(self.Q_(0, 'meter'))
def test_quantity_comparison(self):
x = self.Q_(4.2, 'meter')
y = self.Q_(4.2, 'meter')
z = self.Q_(5, 'meter')
j = self.Q_(5, 'meter*meter')
# identity for single object
self.assertTrue(x == x)
self.assertFalse(x != x)
# identity for multiple objects with same value
self.assertTrue(x == y)
self.assertFalse(x != y)
self.assertTrue(x <= y)
self.assertTrue(x >= y)
self.assertFalse(x < y)
self.assertFalse(x > y)
self.assertFalse(x == z)
self.assertTrue(x != z)
self.assertTrue(x < z)
self.assertTrue(z != j)
self.assertNotEqual(z, j)
self.assertEqual(self.Q_(0, 'meter'), self.Q_(0, 'centimeter'))
self.assertNotEqual(self.Q_(0, 'meter'), self.Q_(0, 'second'))
self.assertLess(self.Q_(10, 'meter'), self.Q_(5, 'kilometer'))
def test_quantity_comparison_convert(self):
self.assertEqual(self.Q_(1000, 'millimeter'), self.Q_(1, 'meter'))
self.assertEqual(self.Q_(1000, 'millimeter/min'), self.Q_(1000/60, 'millimeter/s'))
def test_quantity_repr(self):
x = self.Q_(4.2, UnitsContainer(meter=1))
self.assertEqual(str(x), '4.2 meter')
self.assertEqual(repr(x), "<Quantity(4.2, 'meter')>")
def test_quantity_format(self):
x = self.Q_(4.12345678, UnitsContainer(meter=2, kilogram=1, second=-1))
for spec, result in (('{0}', str(x)), ('{0!s}', str(x)), ('{0!r}', repr(x)),
('{0.magnitude}', str(x.magnitude)), ('{0.units}', str(x.units)),
('{0.magnitude!s}', str(x.magnitude)), ('{0.units!s}', str(x.units)),
('{0.magnitude!r}', repr(x.magnitude)), ('{0.units!r}', repr(x.units)),
('{0:.4f}', '{0:.4f} {1!s}'.format(x.magnitude, x.units)),
('{0:L}', r'4.12345678 \frac{kilogram \cdot meter^{2}}{second}'),
('{0:P}', '4.12345678 kilogram·meter²/second'),
('{0:H}', '4.12345678 kilogram meter<sup>2</sup>/second'),
('{0:C}', '4.12345678 kilogram*meter**2/second'),
('{0:~}', '4.12345678 kg * m ** 2 / s'),
('{0:L~}', r'4.12345678 \frac{kg \cdot m^{2}}{s}'),
('{0:P~}', '4.12345678 kg·m²/s'),
('{0:H~}', '4.12345678 kg m<sup>2</sup>/s'),
('{0:C~}', '4.12345678 kg*m**2/s'),
):
self.assertEqual(spec.format(x), result)
def test_default_formatting(self):
ureg = UnitRegistry()
x = ureg.Quantity(4.12345678, UnitsContainer(meter=2, kilogram=1, second=-1))
for spec, result in (('L', r'4.12345678 \frac{kilogram \cdot meter^{2}}{second}'),
('P', '4.12345678 kilogram·meter²/second'),
('H', '4.12345678 kilogram meter<sup>2</sup>/second'),
('C', '4.12345678 kilogram*meter**2/second'),
('~', '4.12345678 kg * m ** 2 / s'),
('L~', r'4.12345678 \frac{kg \cdot m^{2}}{s}'),
('P~', '4.12345678 kg·m²/s'),
('H~', '4.12345678 kg m<sup>2</sup>/s'),
('C~', '4.12345678 kg*m**2/s'),
):
ureg.default_format = spec
self.assertEqual('{0}'.format(x), result)
def test_to_base_units(self):
x = self.Q_('1*inch')
self.assertQuantityAlmostEqual(x.to_base_units(), self.Q_(0.0254, 'meter'))
x = self.Q_('1*inch*inch')
self.assertQuantityAlmostEqual(x.to_base_units(), self.Q_(0.0254 ** 2.0, 'meter*meter'))
x = self.Q_('1*inch/minute')
self.assertQuantityAlmostEqual(x.to_base_units(), self.Q_(0.0254 / 60., 'meter/second'))
def test_convert(self):
x = self.Q_('2*inch')
self.assertQuantityAlmostEqual(x.to('meter'), self.Q_(2. * 0.0254, 'meter'))
x = self.Q_('2*meter')
self.assertQuantityAlmostEqual(x.to('inch'), self.Q_(2. / 0.0254, 'inch'))
x = self.Q_('2*sidereal_second')
self.assertQuantityAlmostEqual(x.to('second'), self.Q_(1.994539133 , 'second'))
x = self.Q_('2.54*centimeter/second')
self.assertQuantityAlmostEqual(x.to('inch/second'), self.Q_(1, 'inch/second'))
x = self.Q_('2.54*centimeter')
self.assertQuantityAlmostEqual(x.to('inch').magnitude, 1)
self.assertQuantityAlmostEqual(self.Q_(2, 'second').to('millisecond').magnitude, 2000)
@helpers.requires_numpy()
def test_convert(self):
# Conversions with single units take a different codepath than
# Conversions with more than one unit.
src_dst1 = UnitsContainer(meter=1), UnitsContainer(inch=1)
src_dst2 = UnitsContainer(meter=1, second=-1), UnitsContainer(inch=1, minute=-1)
for src, dst in (src_dst1, src_dst2):
a = np.ones((3, 1))
ac = np.ones((3, 1))
q = self.Q_(a, src)
qac = self.Q_(ac, src).to(dst)
r = q.to(dst)
self.assertQuantityAlmostEqual(qac, r)
self.assertIsNot(r, q)
self.assertIsNot(r._magnitude, a)
def test_context_attr(self):
self.assertEqual(self.ureg.meter, self.Q_(1, 'meter'))
def test_both_symbol(self):
self.assertEqual(self.Q_(2, 'ms'), self.Q_(2, 'millisecond'))
self.assertEqual(self.Q_(2, 'cm'), self.Q_(2, 'centimeter'))
def test_dimensionless_units(self):
self.assertAlmostEqual(self.Q_(360, 'degree').to('radian').magnitude, 2 * math.pi)
self.assertAlmostEqual(self.Q_(2 * math.pi, 'radian'), self.Q_(360, 'degree'))
self.assertEqual(self.Q_(1, 'radian').dimensionality, UnitsContainer())
self.assertTrue(self.Q_(1, 'radian').dimensionless)
self.assertFalse(self.Q_(1, 'radian').unitless)
self.assertEqual(self.Q_(1, 'meter')/self.Q_(1, 'meter'), 1)
self.assertEqual((self.Q_(1, 'meter')/self.Q_(1, 'mm')).to(''), 1000)
def test_offset(self):
self.assertQuantityAlmostEqual(self.Q_(0, 'kelvin').to('kelvin'), self.Q_(0, 'kelvin'))
self.assertQuantityAlmostEqual(self.Q_(0, 'degC').to('kelvin'), self.Q_(273.15, 'kelvin'))
self.assertQuantityAlmostEqual(self.Q_(0, 'degF').to('kelvin'), self.Q_(255.372222, 'kelvin'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(100, 'kelvin').to('kelvin'), self.Q_(100, 'kelvin'))
self.assertQuantityAlmostEqual(self.Q_(100, 'degC').to('kelvin'), self.Q_(373.15, 'kelvin'))
self.assertQuantityAlmostEqual(self.Q_(100, 'degF').to('kelvin'), self.Q_(310.92777777, 'kelvin'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(0, 'kelvin').to('degC'), self.Q_(-273.15, 'degC'))
self.assertQuantityAlmostEqual(self.Q_(100, 'kelvin').to('degC'), self.Q_(-173.15, 'degC'))
self.assertQuantityAlmostEqual(self.Q_(0, 'kelvin').to('degF'), self.Q_(-459.67, 'degF'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(100, 'kelvin').to('degF'), self.Q_(-279.67, 'degF'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(32, 'degF').to('degC'), self.Q_(0, 'degC'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(100, 'degC').to('degF'), self.Q_(212, 'degF'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(54, 'degF').to('degC'), self.Q_(12.2222, 'degC'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(12, 'degC').to('degF'), self.Q_(53.6, 'degF'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(12, 'kelvin').to('degC'), self.Q_(-261.15, 'degC'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(12, 'degC').to('kelvin'), self.Q_(285.15, 'kelvin'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(12, 'kelvin').to('degR'), self.Q_(21.6, 'degR'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(12, 'degR').to('kelvin'), self.Q_(6.66666667, 'kelvin'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(12, 'degC').to('degR'), self.Q_(513.27, 'degR'), atol=0.01)
self.assertQuantityAlmostEqual(self.Q_(12, 'degR').to('degC'), self.Q_(-266.483333, 'degC'), atol=0.01)
def test_offset_delta(self):
self.assertQuantityAlmostEqual(self.Q_(0, 'delta_degC').to('kelvin'), self.Q_(0, 'kelvin'))
self.assertQuantityAlmostEqual(self.Q_(0, 'delta_degF').to('kelvin'), self.Q_(0, 'kelvin'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(100, 'kelvin').to('delta_degC'), self.Q_(100, 'delta_degC'))
self.assertQuantityAlmostEqual(self.Q_(100, 'kelvin').to('delta_degF'), self.Q_(180, 'delta_degF'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(100, 'delta_degF').to('kelvin'), self.Q_(55.55555556, 'kelvin'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(100, 'delta_degC').to('delta_degF'), self.Q_(180, 'delta_degF'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(100, 'delta_degF').to('delta_degC'), self.Q_(55.55555556, 'delta_degC'), rtol=0.01)
self.assertQuantityAlmostEqual(self.Q_(12.3, 'delta_degC').to('delta_degF'), self.Q_(22.14, 'delta_degF'), rtol=0.01)
def test_pickle(self):
import pickle
def pickle_test(q):
self.assertEqual(q, pickle.loads(pickle.dumps(q)))
pickle_test(self.Q_(32, ''))
pickle_test(self.Q_(2.4, ''))
pickle_test(self.Q_(32, 'm/s'))
pickle_test(self.Q_(2.4, 'm/s'))
class TestQuantityBasicMath(QuantityTestCase):
FORCE_NDARRAY = False
def _test_inplace(self, operator, value1, value2, expected_result, unit=None):
if isinstance(value1, string_types):
value1 = self.Q_(value1)
if isinstance(value2, string_types):
value2 = self.Q_(value2)
if isinstance(expected_result, string_types):
expected_result = self.Q_(expected_result)
if not unit is None:
value1 = value1 * unit
value2 = value2 * unit
expected_result = expected_result * unit
value1 = copy.copy(value1)
value2 = copy.copy(value2)
id1 = id(value1)
id2 = id(value2)
value1 = operator(value1, value2)
value2_cpy = copy.copy(value2)
self.assertQuantityAlmostEqual(value1, expected_result)
self.assertEqual(id1, id(value1))
self.assertQuantityAlmostEqual(value2, value2_cpy)
self.assertEqual(id2, id(value2))
def _test_not_inplace(self, operator, value1, value2, expected_result, unit=None):
if isinstance(value1, string_types):
value1 = self.Q_(value1)
if isinstance(value2, string_types):
value2 = self.Q_(value2)
if isinstance(expected_result, string_types):
expected_result = self.Q_(expected_result)
if not unit is None:
value1 = value1 * unit
value2 = value2 * unit
expected_result = expected_result * unit
id1 = id(value1)
id2 = id(value2)
value1_cpy = copy.copy(value1)
value2_cpy = copy.copy(value2)
result = operator(value1, value2)
self.assertQuantityAlmostEqual(expected_result, result)
self.assertQuantityAlmostEqual(value1, value1_cpy)
self.assertQuantityAlmostEqual(value2, value2_cpy)
self.assertNotEqual(id(result), id1)
self.assertNotEqual(id(result), id2)
def _test_quantity_add_sub(self, unit, func):
x = self.Q_(unit, 'centimeter')
y = self.Q_(unit, 'inch')
z = self.Q_(unit, 'second')
a = self.Q_(unit, None)
func(op.add, x, x, self.Q_(unit + unit, 'centimeter'))
func(op.add, x, y, self.Q_(unit + 2.54 * unit, 'centimeter'))
func(op.add, y, x, self.Q_(unit + unit / (2.54 * unit), 'inch'))
func(op.add, a, unit, self.Q_(unit + unit, None))
self.assertRaises(DimensionalityError, op.add, 10, x)
self.assertRaises(DimensionalityError, op.add, x, 10)
self.assertRaises(DimensionalityError, op.add, x, z)
func(op.sub, x, x, self.Q_(unit - unit, 'centimeter'))
func(op.sub, x, y, self.Q_(unit - 2.54 * unit, 'centimeter'))
func(op.sub, y, x, self.Q_(unit - unit / (2.54 * unit), 'inch'))
func(op.sub, a, unit, self.Q_(unit - unit, None))
self.assertRaises(DimensionalityError, op.sub, 10, x)
self.assertRaises(DimensionalityError, op.sub, x, 10)
self.assertRaises(DimensionalityError, op.sub, x, z)
def _test_quantity_iadd_isub(self, unit, func):
x = self.Q_(unit, 'centimeter')
y = self.Q_(unit, 'inch')
z = self.Q_(unit, 'second')
a = self.Q_(unit, None)
func(op.iadd, x, x, self.Q_(unit + unit, 'centimeter'))
func(op.iadd, x, y, self.Q_(unit + 2.54 * unit, 'centimeter'))
func(op.iadd, y, x, self.Q_(unit + unit / 2.54, 'inch'))
func(op.iadd, a, unit, self.Q_(unit + unit, None))
self.assertRaises(DimensionalityError, op.iadd, 10, x)
self.assertRaises(DimensionalityError, op.iadd, x, 10)
self.assertRaises(DimensionalityError, op.iadd, x, z)
func(op.isub, x, x, self.Q_(unit - unit, 'centimeter'))
func(op.isub, x, y, self.Q_(unit - 2.54, 'centimeter'))
func(op.isub, y, x, self.Q_(unit - unit / 2.54, 'inch'))
func(op.isub, a, unit, self.Q_(unit - unit, None))
self.assertRaises(DimensionalityError, op.sub, 10, x)
self.assertRaises(DimensionalityError, op.sub, x, 10)
self.assertRaises(DimensionalityError, op.sub, x, z)
def _test_quantity_mul_div(self, unit, func):
func(op.mul, unit * 10.0, '4.2*meter', '42*meter', unit)
func(op.mul, '4.2*meter', unit * 10.0, '42*meter', unit)
func(op.mul, '4.2*meter', '10*inch', '42*meter*inch', unit)
func(op.truediv, unit * 42, '4.2*meter', '10/meter', unit)
func(op.truediv, '4.2*meter', unit * 10.0, '0.42*meter', unit)
func(op.truediv, '4.2*meter', '10*inch', '0.42*meter/inch', unit)
def _test_quantity_imul_idiv(self, unit, func):
#func(op.imul, 10.0, '4.2*meter', '42*meter')
func(op.imul, '4.2*meter', 10.0, '42*meter', unit)
func(op.imul, '4.2*meter', '10*inch', '42*meter*inch', unit)
#func(op.truediv, 42, '4.2*meter', '10/meter')
func(op.itruediv, '4.2*meter', unit * 10.0, '0.42*meter', unit)
func(op.itruediv, '4.2*meter', '10*inch', '0.42*meter/inch', unit)
def _test_quantity_floordiv(self, unit, func):
func(op.floordiv, unit * 10.0, '4.2*meter', '2/meter', unit)
func(op.floordiv, '24*meter', unit * 10.0, '2*meter', unit)
func(op.floordiv, '10*meter', '4.2*inch', '2*meter/inch', unit)
def _test_quantity_ifloordiv(self, unit, func):
func(op.ifloordiv, 10.0, '4.2*meter', '2/meter', unit)
func(op.ifloordiv, '24*meter', 10.0, '2*meter', unit)
func(op.ifloordiv, '10*meter', '4.2*inch', '2*meter/inch', unit)
def _test_numeric(self, unit, ifunc):
self._test_quantity_add_sub(unit, self._test_not_inplace)
self._test_quantity_iadd_isub(unit, ifunc)
self._test_quantity_mul_div(unit, self._test_not_inplace)
self._test_quantity_imul_idiv(unit, ifunc)
self._test_quantity_floordiv(unit, self._test_not_inplace)
#self._test_quantity_ifloordiv(unit, ifunc)
def test_float(self):
self._test_numeric(1., self._test_not_inplace)
def test_fraction(self):
import fractions
self._test_numeric(fractions.Fraction(1, 1), self._test_not_inplace)
@helpers.requires_numpy()
def test_nparray(self):
self._test_numeric(np.ones((1, 3)), self._test_inplace)
def test_quantity_abs_round(self):
x = self.Q_(-4.2, 'meter')
y = self.Q_(4.2, 'meter')
# In Python 3+ round of x is delegated to x.__round__, instead of round(x.__float__)
# and therefore it can be properly implemented by Pint
for fun in (abs, op.pos, op.neg) + (round, ) if PYTHON3 else ():
zx = self.Q_(fun(x.magnitude), 'meter')
zy = self.Q_(fun(y.magnitude), 'meter')
rx = fun(x)
ry = fun(y)
self.assertEqual(rx, zx, 'while testing {0}'.format(fun))
self.assertEqual(ry, zy, 'while testing {0}'.format(fun))
self.assertIsNot(rx, zx, 'while testing {0}'.format(fun))
self.assertIsNot(ry, zy, 'while testing {0}'.format(fun))
def test_quantity_float_complex(self):
x = self.Q_(-4.2, None)
y = self.Q_(4.2, None)
z = self.Q_(1, 'meter')
for fun in (float, complex):
self.assertEqual(fun(x), fun(x.magnitude))
self.assertEqual(fun(y), fun(y.magnitude))
self.assertRaises(DimensionalityError, fun, z)
class TestDimensions(QuantityTestCase):
FORCE_NDARRAY = False
def test_get_dimensionality(self):
get = self.ureg.get_dimensionality
self.assertEqual(get('[time]'), UnitsContainer({'[time]': 1}))
self.assertEqual(get(UnitsContainer({'[time]': 1})), UnitsContainer({'[time]': 1}))
self.assertEqual(get('seconds'), UnitsContainer({'[time]': 1}))
self.assertEqual(get(UnitsContainer({'seconds': 1})), UnitsContainer({'[time]': 1}))
self.assertEqual(get('[speed]'), UnitsContainer({'[length]': 1, '[time]': -1}))
self.assertEqual(get('[acceleration]'), UnitsContainer({'[length]': 1, '[time]': -2}))
def test_dimensionality(self):
x = self.Q_(42, 'centimeter')
x.to_base_units()
x = self.Q_(42, 'meter*second')
self.assertEqual(x.dimensionality, UnitsContainer({'[length]': 1., '[time]': 1.}))
x = self.Q_(42, 'meter*second*second')
self.assertEqual(x.dimensionality, UnitsContainer({'[length]': 1., '[time]': 2.}))
x = self.Q_(42, 'inch*second*second')
self.assertEqual(x.dimensionality, UnitsContainer({'[length]': 1., '[time]': 2.}))
self.assertTrue(self.Q_(42, None).dimensionless)
self.assertFalse(self.Q_(42, 'meter').dimensionless)
self.assertTrue((self.Q_(42, 'meter') / self.Q_(1, 'meter')).dimensionless)
self.assertFalse((self.Q_(42, 'meter') / self.Q_(1, 'second')).dimensionless)
self.assertTrue((self.Q_(42, 'meter') / self.Q_(1, 'inch')).dimensionless)
class TestQuantityWithDefaultRegistry(TestDimensions):
@classmethod
def setUpClass(cls):
from pint import _DEFAULT_REGISTRY
cls.ureg = _DEFAULT_REGISTRY
cls.Q_ = cls.ureg.Quantity
class TestDimensionsWithDefaultRegistry(TestDimensions):
@classmethod
def setUpClass(cls):
from pint import _DEFAULT_REGISTRY
cls.ureg = _DEFAULT_REGISTRY
cls.Q_ = cls.ureg.Quantity
class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase):
def setup(self):
self.ureg.autoconvert_offset_to_baseunit = False
self.ureg.default_as_delta = True
additions = [
# --- input tuple -------------------- | -- expected result --
(((100, 'kelvin'), (10, 'kelvin')), (110, 'kelvin')),
(((100, 'kelvin'), (10, 'degC')), 'error'),
(((100, 'kelvin'), (10, 'degF')), 'error'),
(((100, 'kelvin'), (10, 'degR')), (105.56, 'kelvin')),
(((100, 'kelvin'), (10, 'delta_degC')), (110, 'kelvin')),
(((100, 'kelvin'), (10, 'delta_degF')), (105.56, 'kelvin')),
(((100, 'degC'), (10, 'kelvin')), 'error'),
(((100, 'degC'), (10, 'degC')), 'error'),
(((100, 'degC'), (10, 'degF')), 'error'),
(((100, 'degC'), (10, 'degR')), 'error'),
(((100, 'degC'), (10, 'delta_degC')), (110, 'degC')),
(((100, 'degC'), (10, 'delta_degF')), (105.56, 'degC')),
(((100, 'degF'), (10, 'kelvin')), 'error'),
(((100, 'degF'), (10, 'degC')), 'error'),
(((100, 'degF'), (10, 'degF')), 'error'),
(((100, 'degF'), (10, 'degR')), 'error'),
(((100, 'degF'), (10, 'delta_degC')), (118, 'degF')),
(((100, 'degF'), (10, 'delta_degF')), (110, 'degF')),
(((100, 'degR'), (10, 'kelvin')), (118, 'degR')),
(((100, 'degR'), (10, 'degC')), 'error'),
(((100, 'degR'), (10, 'degF')), 'error'),
(((100, 'degR'), (10, 'degR')), (110, 'degR')),
(((100, 'degR'), (10, 'delta_degC')), (118, 'degR')),
(((100, 'degR'), (10, 'delta_degF')), (110, 'degR')),
(((100, 'delta_degC'), (10, 'kelvin')), (110, 'kelvin')),
(((100, 'delta_degC'), (10, 'degC')), (110, 'degC')),
(((100, 'delta_degC'), (10, 'degF')), (190, 'degF')),
(((100, 'delta_degC'), (10, 'degR')), (190, 'degR')),
(((100, 'delta_degC'), (10, 'delta_degC')), (110, 'delta_degC')),
(((100, 'delta_degC'), (10, 'delta_degF')), (105.56, 'delta_degC')),
(((100, 'delta_degF'), (10, 'kelvin')), (65.56, 'kelvin')),
(((100, 'delta_degF'), (10, 'degC')), (65.56, 'degC')),
(((100, 'delta_degF'), (10, 'degF')), (110, 'degF')),
(((100, 'delta_degF'), (10, 'degR')), (110, 'degR')),
(((100, 'delta_degF'), (10, 'delta_degC')), (118, 'delta_degF')),
(((100, 'delta_degF'), (10, 'delta_degF')), (110, 'delta_degF')),
]
@ParameterizedTestCase.parameterize(("input", "expected_output"),
additions)
def test_addition(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = False
qin1, qin2 = input_tuple
q1, q2 = self.Q_(*qin1), self.Q_(*qin2)
# update input tuple with new values to have correct values on failure
input_tuple = q1, q2
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.add, q1, q2)
else:
expected = self.Q_(*expected)
self.assertEqual(op.add(q1, q2).units, expected.units)
self.assertQuantityAlmostEqual(op.add(q1, q2), expected,
atol=0.01)
@helpers.requires_numpy()
@ParameterizedTestCase.parameterize(("input", "expected_output"),
additions)
def test_inplace_addition(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = False
(q1v, q1u), (q2v, q2u) = input_tuple
# update input tuple with new values to have correct values on failure
input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u),
(np.array([q2v]*2, dtype=np.float), q2u))
Q_ = self.Q_
qin1, qin2 = input_tuple
q1, q2 = Q_(*qin1), Q_(*qin2)
q1_cp = copy.copy(q1)
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.iadd, q1_cp, q2)
else:
expected = np.array([expected[0]]*2, dtype=np.float), expected[1]
self.assertEqual(op.iadd(q1_cp, q2).units, Q_(*expected).units)
q1_cp = copy.copy(q1)
self.assertQuantityAlmostEqual(op.iadd(q1_cp, q2), Q_(*expected),
atol=0.01)
subtractions = [
(((100, 'kelvin'), (10, 'kelvin')), (90, 'kelvin')),
(((100, 'kelvin'), (10, 'degC')), (-183.15, 'kelvin')),
(((100, 'kelvin'), (10, 'degF')), (-160.93, 'kelvin')),
(((100, 'kelvin'), (10, 'degR')), (94.44, 'kelvin')),
(((100, 'kelvin'), (10, 'delta_degC')), (90, 'kelvin')),
(((100, 'kelvin'), (10, 'delta_degF')), (94.44, 'kelvin')),
(((100, 'degC'), (10, 'kelvin')), (363.15, 'delta_degC')),
(((100, 'degC'), (10, 'degC')), (90, 'delta_degC')),
(((100, 'degC'), (10, 'degF')), (112.22, 'delta_degC')),
(((100, 'degC'), (10, 'degR')), (367.59, 'delta_degC')),
(((100, 'degC'), (10, 'delta_degC')), (90, 'degC')),
(((100, 'degC'), (10, 'delta_degF')), (94.44, 'degC')),
(((100, 'degF'), (10, 'kelvin')), (541.67, 'delta_degF')),
(((100, 'degF'), (10, 'degC')), (50, 'delta_degF')),
(((100, 'degF'), (10, 'degF')), (90, 'delta_degF')),
(((100, 'degF'), (10, 'degR')), (549.67, 'delta_degF')),
(((100, 'degF'), (10, 'delta_degC')), (82, 'degF')),
(((100, 'degF'), (10, 'delta_degF')), (90, 'degF')),
(((100, 'degR'), (10, 'kelvin')), (82, 'degR')),
(((100, 'degR'), (10, 'degC')), (-409.67, 'degR')),
(((100, 'degR'), (10, 'degF')), (-369.67, 'degR')),
(((100, 'degR'), (10, 'degR')), (90, 'degR')),
(((100, 'degR'), (10, 'delta_degC')), (82, 'degR')),
(((100, 'degR'), (10, 'delta_degF')), (90, 'degR')),
(((100, 'delta_degC'), (10, 'kelvin')), (90, 'kelvin')),
(((100, 'delta_degC'), (10, 'degC')), (90, 'degC')),
(((100, 'delta_degC'), (10, 'degF')), (170, 'degF')),
(((100, 'delta_degC'), (10, 'degR')), (170, 'degR')),
(((100, 'delta_degC'), (10, 'delta_degC')), (90, 'delta_degC')),
(((100, 'delta_degC'), (10, 'delta_degF')), (94.44, 'delta_degC')),
(((100, 'delta_degF'), (10, 'kelvin')), (45.56, 'kelvin')),
(((100, 'delta_degF'), (10, 'degC')), (45.56, 'degC')),
(((100, 'delta_degF'), (10, 'degF')), (90, 'degF')),
(((100, 'delta_degF'), (10, 'degR')), (90, 'degR')),
(((100, 'delta_degF'), (10, 'delta_degC')), (82, 'delta_degF')),
(((100, 'delta_degF'), (10, 'delta_degF')), (90, 'delta_degF')),
]
@ParameterizedTestCase.parameterize(("input", "expected_output"),
subtractions)
def test_subtraction(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = False
qin1, qin2 = input_tuple
q1, q2 = self.Q_(*qin1), self.Q_(*qin2)
input_tuple = q1, q2
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.sub, q1, q2)
else:
expected = self.Q_(*expected)
self.assertEqual(op.sub(q1, q2).units, expected.units)
self.assertQuantityAlmostEqual(op.sub(q1, q2), expected,
atol=0.01)
# @unittest.expectedFailure
@helpers.requires_numpy()
@ParameterizedTestCase.parameterize(("input", "expected_output"),
subtractions)
def test_inplace_subtraction(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = False
(q1v, q1u), (q2v, q2u) = input_tuple
# update input tuple with new values to have correct values on failure
input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u),
(np.array([q2v]*2, dtype=np.float), q2u))
Q_ = self.Q_
qin1, qin2 = input_tuple
q1, q2 = Q_(*qin1), Q_(*qin2)
q1_cp = copy.copy(q1)
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.isub, q1_cp, q2)
else:
expected = np.array([expected[0]]*2, dtype=np.float), expected[1]
self.assertEqual(op.isub(q1_cp, q2).units, Q_(*expected).units)
q1_cp = copy.copy(q1)
self.assertQuantityAlmostEqual(op.isub(q1_cp, q2), Q_(*expected),
atol=0.01)
multiplications = [
(((100, 'kelvin'), (10, 'kelvin')), (1000, 'kelvin**2')),
(((100, 'kelvin'), (10, 'degC')), 'error'),
(((100, 'kelvin'), (10, 'degF')), 'error'),
(((100, 'kelvin'), (10, 'degR')), (1000, 'kelvin*degR')),
(((100, 'kelvin'), (10, 'delta_degC')), (1000, 'kelvin*delta_degC')),
(((100, 'kelvin'), (10, 'delta_degF')), (1000, 'kelvin*delta_degF')),
(((100, 'degC'), (10, 'kelvin')), 'error'),
(((100, 'degC'), (10, 'degC')), 'error'),
(((100, 'degC'), (10, 'degF')), 'error'),
(((100, 'degC'), (10, 'degR')), 'error'),
(((100, 'degC'), (10, 'delta_degC')), 'error'),
(((100, 'degC'), (10, 'delta_degF')), 'error'),
(((100, 'degF'), (10, 'kelvin')), 'error'),
(((100, 'degF'), (10, 'degC')), 'error'),
(((100, 'degF'), (10, 'degF')), 'error'),
(((100, 'degF'), (10, 'degR')), 'error'),
(((100, 'degF'), (10, 'delta_degC')), 'error'),
(((100, 'degF'), (10, 'delta_degF')), 'error'),
(((100, 'degR'), (10, 'kelvin')), (1000, 'degR*kelvin')),
(((100, 'degR'), (10, 'degC')), 'error'),
(((100, 'degR'), (10, 'degF')), 'error'),
(((100, 'degR'), (10, 'degR')), (1000, 'degR**2')),
(((100, 'degR'), (10, 'delta_degC')), (1000, 'degR*delta_degC')),
(((100, 'degR'), (10, 'delta_degF')), (1000, 'degR*delta_degF')),
(((100, 'delta_degC'), (10, 'kelvin')), (1000, 'delta_degC*kelvin')),
(((100, 'delta_degC'), (10, 'degC')), 'error'),
(((100, 'delta_degC'), (10, 'degF')), 'error'),
(((100, 'delta_degC'), (10, 'degR')), (1000, 'delta_degC*degR')),
(((100, 'delta_degC'), (10, 'delta_degC')), (1000, 'delta_degC**2')),
(((100, 'delta_degC'), (10, 'delta_degF')), (1000, 'delta_degC*delta_degF')),
(((100, 'delta_degF'), (10, 'kelvin')), (1000, 'delta_degF*kelvin')),
(((100, 'delta_degF'), (10, 'degC')), 'error'),
(((100, 'delta_degF'), (10, 'degF')), 'error'),
(((100, 'delta_degF'), (10, 'degR')), (1000, 'delta_degF*degR')),
(((100, 'delta_degF'), (10, 'delta_degC')), (1000, 'delta_degF*delta_degC')),
(((100, 'delta_degF'), (10, 'delta_degF')), (1000, 'delta_degF**2')),
]
@ParameterizedTestCase.parameterize(("input", "expected_output"),
multiplications)
def test_multiplication(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = False
qin1, qin2 = input_tuple
q1, q2 = self.Q_(*qin1), self.Q_(*qin2)
input_tuple = q1, q2
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.mul, q1, q2)
else:
expected = self.Q_(*expected)
self.assertEqual(op.mul(q1, q2).units, expected.units)
self.assertQuantityAlmostEqual(op.mul(q1, q2), expected,
atol=0.01)
@helpers.requires_numpy()
@ParameterizedTestCase.parameterize(("input", "expected_output"),
multiplications)
def test_inplace_multiplication(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = False
(q1v, q1u), (q2v, q2u) = input_tuple
# update input tuple with new values to have correct values on failure
input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u),
(np.array([q2v]*2, dtype=np.float), q2u))
Q_ = self.Q_
qin1, qin2 = input_tuple
q1, q2 = Q_(*qin1), Q_(*qin2)
q1_cp = copy.copy(q1)
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.imul, q1_cp, q2)
else:
expected = np.array([expected[0]]*2, dtype=np.float), expected[1]
self.assertEqual(op.imul(q1_cp, q2).units, Q_(*expected).units)
q1_cp = copy.copy(q1)
self.assertQuantityAlmostEqual(op.imul(q1_cp, q2), Q_(*expected),
atol=0.01)
divisions = [
(((100, 'kelvin'), (10, 'kelvin')), (10, '')),
(((100, 'kelvin'), (10, 'degC')), 'error'),
(((100, 'kelvin'), (10, 'degF')), 'error'),
(((100, 'kelvin'), (10, 'degR')), (10, 'kelvin/degR')),
(((100, 'kelvin'), (10, 'delta_degC')), (10, 'kelvin/delta_degC')),
(((100, 'kelvin'), (10, 'delta_degF')), (10, 'kelvin/delta_degF')),
(((100, 'degC'), (10, 'kelvin')), 'error'),
(((100, 'degC'), (10, 'degC')), 'error'),
(((100, 'degC'), (10, 'degF')), 'error'),
(((100, 'degC'), (10, 'degR')), 'error'),
(((100, 'degC'), (10, 'delta_degC')), 'error'),
(((100, 'degC'), (10, 'delta_degF')), 'error'),
(((100, 'degF'), (10, 'kelvin')), 'error'),
(((100, 'degF'), (10, 'degC')), 'error'),
(((100, 'degF'), (10, 'degF')), 'error'),
(((100, 'degF'), (10, 'degR')), 'error'),
(((100, 'degF'), (10, 'delta_degC')), 'error'),
(((100, 'degF'), (10, 'delta_degF')), 'error'),
(((100, 'degR'), (10, 'kelvin')), (10, 'degR/kelvin')),
(((100, 'degR'), (10, 'degC')), 'error'),
(((100, 'degR'), (10, 'degF')), 'error'),
(((100, 'degR'), (10, 'degR')), (10, '')),
(((100, 'degR'), (10, 'delta_degC')), (10, 'degR/delta_degC')),
(((100, 'degR'), (10, 'delta_degF')), (10, 'degR/delta_degF')),
(((100, 'delta_degC'), (10, 'kelvin')), (10, 'delta_degC/kelvin')),
(((100, 'delta_degC'), (10, 'degC')), 'error'),
(((100, 'delta_degC'), (10, 'degF')), 'error'),
(((100, 'delta_degC'), (10, 'degR')), (10, 'delta_degC/degR')),
(((100, 'delta_degC'), (10, 'delta_degC')), (10, '')),
(((100, 'delta_degC'), (10, 'delta_degF')), (10, 'delta_degC/delta_degF')),
(((100, 'delta_degF'), (10, 'kelvin')), (10, 'delta_degF/kelvin')),
(((100, 'delta_degF'), (10, 'degC')), 'error'),
(((100, 'delta_degF'), (10, 'degF')), 'error'),
(((100, 'delta_degF'), (10, 'degR')), (10, 'delta_degF/degR')),
(((100, 'delta_degF'), (10, 'delta_degC')), (10, 'delta_degF/delta_degC')),
(((100, 'delta_degF'), (10, 'delta_degF')), (10, '')),
]
@ParameterizedTestCase.parameterize(("input", "expected_output"),
divisions)
def test_truedivision(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = False
qin1, qin2 = input_tuple
q1, q2 = self.Q_(*qin1), self.Q_(*qin2)
input_tuple = q1, q2
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.truediv, q1, q2)
else:
expected = self.Q_(*expected)
self.assertEqual(op.truediv(q1, q2).units, expected.units)
self.assertQuantityAlmostEqual(op.truediv(q1, q2), expected,
atol=0.01)
@helpers.requires_numpy()
@ParameterizedTestCase.parameterize(("input", "expected_output"),
divisions)
def test_inplace_truedivision(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = False
(q1v, q1u), (q2v, q2u) = input_tuple
# update input tuple with new values to have correct values on failure
input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u),
(np.array([q2v]*2, dtype=np.float), q2u))
Q_ = self.Q_
qin1, qin2 = input_tuple
q1, q2 = Q_(*qin1), Q_(*qin2)
q1_cp = copy.copy(q1)
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.itruediv, q1_cp, q2)
else:
expected = np.array([expected[0]]*2, dtype=np.float), expected[1]
self.assertEqual(op.itruediv(q1_cp, q2).units, Q_(*expected).units)
q1_cp = copy.copy(q1)
self.assertQuantityAlmostEqual(op.itruediv(q1_cp, q2),
Q_(*expected), atol=0.01)
multiplications_with_autoconvert_to_baseunit = [
(((100, 'kelvin'), (10, 'degC')), (28315., 'kelvin**2')),
(((100, 'kelvin'), (10, 'degF')), (26092.78, 'kelvin**2')),
(((100, 'degC'), (10, 'kelvin')), (3731.5, 'kelvin**2')),
(((100, 'degC'), (10, 'degC')), (105657.42, 'kelvin**2')),
(((100, 'degC'), (10, 'degF')), (97365.20, 'kelvin**2')),
(((100, 'degC'), (10, 'degR')), (3731.5, 'kelvin*degR')),
(((100, 'degC'), (10, 'delta_degC')), (3731.5, 'kelvin*delta_degC')),
(((100, 'degC'), (10, 'delta_degF')), (3731.5, 'kelvin*delta_degF')),
(((100, 'degF'), (10, 'kelvin')), (3109.28, 'kelvin**2')),
(((100, 'degF'), (10, 'degC')), (88039.20, 'kelvin**2')),
(((100, 'degF'), (10, 'degF')), (81129.69, 'kelvin**2')),
(((100, 'degF'), (10, 'degR')), (3109.28, 'kelvin*degR')),
(((100, 'degF'), (10, 'delta_degC')), (3109.28, 'kelvin*delta_degC')),
(((100, 'degF'), (10, 'delta_degF')), (3109.28, 'kelvin*delta_degF')),
(((100, 'degR'), (10, 'degC')), (28315., 'degR*kelvin')),
(((100, 'degR'), (10, 'degF')), (26092.78, 'degR*kelvin')),
(((100, 'delta_degC'), (10, 'degC')), (28315., 'delta_degC*kelvin')),
(((100, 'delta_degC'), (10, 'degF')), (26092.78, 'delta_degC*kelvin')),
(((100, 'delta_degF'), (10, 'degC')), (28315., 'delta_degF*kelvin')),
(((100, 'delta_degF'), (10, 'degF')), (26092.78, 'delta_degF*kelvin')),
]
@ParameterizedTestCase.parameterize(
("input", "expected_output"),
multiplications_with_autoconvert_to_baseunit)
def test_multiplication_with_autoconvert(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = True
qin1, qin2 = input_tuple
q1, q2 = self.Q_(*qin1), self.Q_(*qin2)
input_tuple = q1, q2
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.mul, q1, q2)
else:
expected = self.Q_(*expected)
self.assertEqual(op.mul(q1, q2).units, expected.units)
self.assertQuantityAlmostEqual(op.mul(q1, q2), expected,
atol=0.01)
@helpers.requires_numpy()
@ParameterizedTestCase.parameterize(
("input", "expected_output"),
multiplications_with_autoconvert_to_baseunit)
def test_inplace_multiplication_with_autoconvert(self, input_tuple, expected):
self.ureg.autoconvert_offset_to_baseunit = True
(q1v, q1u), (q2v, q2u) = input_tuple
# update input tuple with new values to have correct values on failure
input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u),
(np.array([q2v]*2, dtype=np.float), q2u))
Q_ = self.Q_
qin1, qin2 = input_tuple
q1, q2 = Q_(*qin1), Q_(*qin2)
q1_cp = copy.copy(q1)
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.imul, q1_cp, q2)
else:
expected = np.array([expected[0]]*2, dtype=np.float), expected[1]
self.assertEqual(op.imul(q1_cp, q2).units, Q_(*expected).units)
q1_cp = copy.copy(q1)
self.assertQuantityAlmostEqual(op.imul(q1_cp, q2), Q_(*expected),
atol=0.01)
multiplications_with_scalar = [
(((10, 'kelvin'), 2), (20., 'kelvin')),
(((10, 'kelvin**2'), 2), (20., 'kelvin**2')),
(((10, 'degC'), 2), (20., 'degC')),
(((10, '1/degC'), 2), 'error'),
(((10, 'degC**0.5'), 2), 'error'),
(((10, 'degC**2'), 2), 'error'),
(((10, 'degC**-2'), 2), 'error'),
]
@ParameterizedTestCase.parameterize(
("input", "expected_output"), multiplications_with_scalar)
def test_multiplication_with_scalar(self, input_tuple, expected):
self.ureg.default_as_delta = False
in1, in2 = input_tuple
if type(in1) is tuple:
in1, in2 = self.Q_(*in1), in2
else:
in1, in2 = in1, self.Q_(*in2)
input_tuple = in1, in2 # update input_tuple for better tracebacks
if expected == 'error':
self.assertRaises(OffsetUnitCalculusError, op.mul, in1, in2)
else:
expected = self.Q_(*expected)
self.assertEqual(op.mul(in1, in2).units, expected.units)
self.assertQuantityAlmostEqual(op.mul(in1, in2), expected,
atol=0.01)
divisions_with_scalar = [ # without / with autoconvert to base unit
(((10, 'kelvin'), 2), [(5., 'kelvin'), (5., 'kelvin')]),
(((10, 'kelvin**2'), 2), [(5., 'kelvin**2'), (5., 'kelvin**2')]),
(((10, 'degC'), 2), ['error', 'error']),
(((10, 'degC**2'), 2), ['error', 'error']),
(((10, 'degC**-2'), 2), ['error', 'error']),
((2, (10, 'kelvin')), [(0.2, '1/kelvin'), (0.2, '1/kelvin')]),
((2, (10, 'degC')), ['error', (2/283.15, '1/kelvin')]),
((2, (10, 'degC**2')), ['error', 'error']),
((2, (10, 'degC**-2')), ['error', 'error']),
]
@ParameterizedTestCase.parameterize(
("input", "expected_output"), divisions_with_scalar)
def test_division_with_scalar(self, input_tuple, expected):
self.ureg.default_as_delta = False
in1, in2 = input_tuple
if type(in1) is tuple:
in1, in2 = self.Q_(*in1), in2
else:
in1, in2 = in1, self.Q_(*in2)
input_tuple = in1, in2 # update input_tuple for better tracebacks
expected_copy = expected[:]
for i, mode in enumerate([False, True]):
self.ureg.autoconvert_offset_to_baseunit = mode
if expected_copy[i] == 'error':
self.assertRaises(OffsetUnitCalculusError, op.truediv, in1, in2)
else:
expected = self.Q_(*expected_copy[i])
self.assertEqual(op.truediv(in1, in2).units, expected.units)
self.assertQuantityAlmostEqual(op.truediv(in1, in2), expected)
exponentiation = [ # resuls without / with autoconvert
(((10, 'degC'), 1), [(10, 'degC'), (10, 'degC')]),
(((10, 'degC'), 0.5), ['error', (283.15**0.5, 'kelvin**0.5')]),
(((10, 'degC'), 0), [(1., ''), (1., '')]),
(((10, 'degC'), -1), ['error', (1/(10+273.15), 'kelvin**-1')]),
(((10, 'degC'), -2), ['error', (1/(10+273.15)**2., 'kelvin**-2')]),
((( 0, 'degC'), -2), ['error', (1/(273.15)**2, 'kelvin**-2')]),
(((10, 'degC'), (2, '')), ['error', ((283.15)**2, 'kelvin**2')]),
(((10, 'degC'), (10, 'degK')), ['error', 'error']),
(((10, 'kelvin'), (2, '')), [(100., 'kelvin**2'), (100., 'kelvin**2')]),
(( 2, (2, 'kelvin')), ['error', 'error']),
(( 2, (500., 'millikelvin/kelvin')), [2**0.5, 2**0.5]),
(( 2, (0.5, 'kelvin/kelvin')), [2**0.5, 2**0.5]),
(((10, 'degC'), (500., 'millikelvin/kelvin')),
['error', (283.15**0.5, 'kelvin**0.5')]),
]
@ParameterizedTestCase.parameterize(
("input", "expected_output"), exponentiation)
def test_exponentiation(self, input_tuple, expected):
self.ureg.default_as_delta = False
in1, in2 = input_tuple
if type(in1) is tuple and type(in2) is tuple:
in1, in2 = self.Q_(*in1), self.Q_(*in2)
elif not type(in1) is tuple and type(in2) is tuple:
in2 = self.Q_(*in2)
else:
in1 = self.Q_(*in1)
input_tuple = in1, in2
expected_copy = expected[:]
for i, mode in enumerate([False, True]):
self.ureg.autoconvert_offset_to_baseunit = mode
if expected_copy[i] == 'error':
self.assertRaises((OffsetUnitCalculusError,
DimensionalityError), op.pow, in1, in2)
else:
if type(expected_copy[i]) is tuple:
expected = self.Q_(*expected_copy[i])
self.assertEqual(op.pow(in1, in2).units, expected.units)
else:
expected = expected_copy[i]
self.assertQuantityAlmostEqual(op.pow(in1, in2), expected)
@helpers.requires_numpy()
@ParameterizedTestCase.parameterize(
("input", "expected_output"), exponentiation)
def test_inplace_exponentiation(self, input_tuple, expected):
self.ureg.default_as_delta = False
in1, in2 = input_tuple
if type(in1) is tuple and type(in2) is tuple:
(q1v, q1u), (q2v, q2u) = in1, in2
in1 = self.Q_(*(np.array([q1v]*2, dtype=np.float), q1u))
in2 = self.Q_(q2v, q2u)
elif not type(in1) is tuple and type(in2) is tuple:
in2 = self.Q_(*in2)
else:
in1 = self.Q_(*in1)
input_tuple = in1, in2
expected_copy = expected[:]
for i, mode in enumerate([False, True]):
self.ureg.autoconvert_offset_to_baseunit = mode
in1_cp = copy.copy(in1)
if expected_copy[i] == 'error':
self.assertRaises((OffsetUnitCalculusError,
DimensionalityError), op.ipow, in1_cp, in2)
else:
if type(expected_copy[i]) is tuple:
expected = self.Q_(np.array([expected_copy[i][0]]*2,
dtype=np.float),
expected_copy[i][1])
self.assertEqual(op.ipow(in1_cp, in2).units, expected.units)
else:
expected = np.array([expected_copy[i]]*2, dtype=np.float)
in1_cp = copy.copy(in1)
self.assertQuantityAlmostEqual(op.ipow(in1_cp, in2), expected)

View File

@ -0,0 +1,676 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
from pint.compat import np
from pint.testsuite import QuantityTestCase, helpers
# Following http://docs.scipy.org/doc/numpy/reference/ufuncs.html
if np:
pi = np.pi
@helpers.requires_numpy()
class TestUFuncs(QuantityTestCase):
FORCE_NDARRAY = True
@property
def qless(self):
return np.asarray([1., 2., 3., 4.]) * self.ureg.dimensionless
@property
def qs(self):
return 8 * self.ureg.J
@property
def q1(self):
return np.asarray([1., 2., 3., 4.]) * self.ureg.J
@property
def q2(self):
return 2 * self.q1
@property
def qm(self):
return np.asarray([1., 2., 3., 4.]) * self.ureg.m
@property
def qi(self):
return np.asarray([1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j]) * self.ureg.m
def assertEqual(self, first, second, msg=None):
np.testing.assert_equal(first, second, msg)
def assertRaisesMsg(self, msg, ExcType, func, *args, **kwargs):
try:
func(*args, **kwargs)
self.assertFalse(True, msg='Exception {0} not raised {1}'.format(ExcType, msg))
except ExcType as e:
pass
except Exception as e:
self.assertFalse(True, msg='{0} not raised but {1}\n{2}'.format(ExcType, e, msg))
def _test1(self, func, ok_with, raise_with=(), output_units='same', results=None, rtol=1e-6):
"""Test function that takes a single argument and returns Quantity.
:param func: function callable.
:param ok_with: iterables of values that work fine.
:param raise_with: iterables of values that raise exceptions.
:param output_units: units to be used when building results.
'same': ok_with[n].units (default).
is float: ok_with[n].units ** output_units.
None: no output units, the result should be an ndarray.
Other value will be parsed as unit.
:param results: iterable of results.
If None, the result will be obtained by applying
func to each ok_with value
:param rtol: relative tolerance.
"""
if results is None:
results = [None, ] * len(ok_with)
for x1, res in zip(ok_with, results):
err_msg = 'At {0} with {1}'.format(func.__name__, x1)
if output_units == 'same':
ou = x1.units
elif isinstance(output_units, (int, float)):
ou = x1.units ** output_units
else:
ou = output_units
qm = func(x1)
if res is None:
res = func(x1.magnitude)
if ou is not None:
res = self.Q_(res, ou)
self.assertQuantityAlmostEqual(qm, res, rtol=rtol, msg=err_msg)
for x1 in raise_with:
self.assertRaisesMsg('At {0} with {1}'.format(func.__name__, x1),
ValueError, func, x1)
def _testn(self, func, ok_with, raise_with=(), results=None):
"""Test function that takes a single argument and returns and ndarray (not a Quantity)
:param func: function callable.
:param ok_with: iterables of values that work fine.
:param raise_with: iterables of values that raise exceptions.
:param results: iterable of results.
If None, the result will be obtained by applying
func to each ok_with value
"""
self._test1(func, ok_with, raise_with, output_units=None, results=results)
def _test1_2o(self, func, ok_with, raise_with=(), output_units=('same', 'same'),
results=None, rtol=1e-6):
"""Test functions that takes a single argument and return two Quantities.
:param func: function callable.
:param ok_with: iterables of values that work fine.
:param raise_with: iterables of values that raise exceptions.
:param output_units: tuple of units to be used when building the result tuple.
'same': ok_with[n].units (default).
is float: ok_with[n].units ** output_units.
None: no output units, the result should be an ndarray.
Other value will be parsed as unit.
:param results: iterable of results.
If None, the result will be obtained by applying
func to each ok_with value
:param rtol: relative tolerance.
"""
if results is None:
results = [None, ] * len(ok_with)
for x1, res in zip(ok_with, results):
err_msg = 'At {0} with {1}'.format(func.__name__, x1)
qms = func(x1)
if res is None:
res = func(x1.magnitude)
for ndx, (qm, re, ou) in enumerate(zip(qms, res, output_units)):
if ou == 'same':
ou = x1.units
elif isinstance(ou, (int, float)):
ou = x1.units ** ou
if ou is not None:
re = self.Q_(re, ou)
self.assertQuantityAlmostEqual(qm, re, rtol=rtol, msg=err_msg)
for x1 in raise_with:
self.assertRaisesMsg('At {0} with {1}'.format(func.__name__, x1),
ValueError, func, x1)
def _test2(self, func, x1, ok_with, raise_with=(), output_units='same', rtol=1e-6, convert2=True):
"""Test function that takes two arguments and return a Quantity.
:param func: function callable.
:param x1: first argument of func.
:param ok_with: iterables of values that work fine.
:param raise_with: iterables of values that raise exceptions.
:param output_units: units to be used when building results.
'same': x1.units (default).
'prod': x1.units * ok_with[n].units
'div': x1.units / ok_with[n].units
'second': x1.units * ok_with[n]
None: no output units, the result should be an ndarray.
Other value will be parsed as unit.
:param rtol: relative tolerance.
:param convert2: if the ok_with[n] should be converted to x1.units.
"""
for x2 in ok_with:
err_msg = 'At {0} with {1} and {2}'.format(func.__name__, x1, x2)
if output_units == 'same':
ou = x1.units
elif output_units == 'prod':
ou = x1.units * x2.units
elif output_units == 'div':
ou = x1.units / x2.units
elif output_units == 'second':
ou = x1.units ** x2
else:
ou = output_units
qm = func(x1, x2)
if convert2 and hasattr(x2, 'magnitude'):
m2 = x2.to(getattr(x1, 'units', '')).magnitude
else:
m2 = getattr(x2, 'magnitude', x2)
res = func(x1.magnitude, m2)
if ou is not None:
res = self.Q_(res, ou)
self.assertQuantityAlmostEqual(qm, res, rtol=rtol, msg=err_msg)
for x2 in raise_with:
self.assertRaisesMsg('At {0} with {1} and {2}'.format(func.__name__, x1, x2),
ValueError, func, x1, x2)
def _testn2(self, func, x1, ok_with, raise_with=()):
"""Test function that takes two arguments and return a ndarray.
:param func: function callable.
:param x1: first argument of func.
:param ok_with: iterables of values that work fine.
:param raise_with: iterables of values that raise exceptions.
"""
self._test2(func, x1, ok_with, raise_with, output_units=None)
@helpers.requires_numpy()
class TestMathUfuncs(TestUFuncs):
"""Universal functions (ufunc) > Math operations
http://docs.scipy.org/doc/numpy/reference/ufuncs.html#math-operations
add(x1, x2[, out]) Add arguments element-wise.
subtract(x1, x2[, out]) Subtract arguments, element-wise.
multiply(x1, x2[, out]) Multiply arguments element-wise.
divide(x1, x2[, out]) Divide arguments element-wise.
logaddexp(x1, x2[, out]) Logarithm of the sum of exponentiations of the inputs.
logaddexp2(x1, x2[, out]) Logarithm of the sum of exponentiations of the inputs in base-2.
true_divide(x1, x2[, out]) Returns a true division of the inputs, element-wise.
floor_divide(x1, x2[, out]) Return the largest integer smaller or equal to the division of the inputs.
negative(x[, out]) Returns an array with the negative of each element of the original array.
power(x1, x2[, out]) First array elements raised to powers from second array, element-wise. NOT IMPLEMENTED
remainder(x1, x2[, out]) Return element-wise remainder of division.
mod(x1, x2[, out]) Return element-wise remainder of division.
fmod(x1, x2[, out]) Return the element-wise remainder of division.
absolute(x[, out]) Calculate the absolute value element-wise.
rint(x[, out]) Round elements of the array to the nearest integer.
sign(x[, out]) Returns an element-wise indication of the sign of a number.
conj(x[, out]) Return the complex conjugate, element-wise.
exp(x[, out]) Calculate the exponential of all elements in the input array.
exp2(x[, out]) Calculate 2**p for all p in the input array.
log(x[, out]) Natural logarithm, element-wise.
log2(x[, out]) Base-2 logarithm of x.
log10(x[, out]) Return the base 10 logarithm of the input array, element-wise.
expm1(x[, out]) Calculate exp(x) - 1 for all elements in the array.
log1p(x[, out]) Return the natural logarithm of one plus the input array, element-wise.
sqrt(x[, out]) Return the positive square-root of an array, element-wise.
square(x[, out]) Return the element-wise square of the input.
reciprocal(x[, out]) Return the reciprocal of the argument, element-wise.
ones_like(x[, out]) Returns an array of ones with the same shape and type as a given array.
"""
def test_add(self):
self._test2(np.add,
self.q1,
(self.q2, self.qs),
(self.qm, ))
def test_subtract(self):
self._test2(np.subtract,
self.q1,
(self.q2, self.qs),
(self.qm, ))
def test_multiply(self):
self._test2(np.multiply,
self.q1,
(self.q2, self.qs), (),
'prod')
def test_divide(self):
self._test2(np.divide,
self.q1,
(self.q2, self.qs, self.qless),
(),
'div', convert2=False)
def test_logaddexp(self):
self._test2(np.logaddexp,
self.qless,
(self.qless, ),
(self.q1, ),
'')
def test_logaddexp2(self):
self._test2(np.logaddexp2,
self.qless,
(self.qless, ),
(self.q1, ),
'div')
def test_true_divide(self):
self._test2(np.true_divide,
self.q1,
(self.q2, self.qs, self.qless),
(),
'div', convert2=False)
def test_floor_divide(self):
self._test2(np.floor_divide,
self.q1,
(self.q2, self.qs, self.qless),
(),
'div', convert2=False)
def test_negative(self):
self._test1(np.negative,
(self.qless, self.q1),
())
def test_remainder(self):
self._test2(np.remainder,
self.q1,
(self.q2, self.qs, self.qless),
(),
'same', convert2=False)
def test_mod(self):
self._test2(np.mod,
self.q1,
(self.q2, self.qs, self.qless),
(),
'same', convert2=False)
def test_fmod(self):
self._test2(np.fmod,
self.q1,
(self.q2, self.qs, self.qless),
(),
'same', convert2=False)
def test_absolute(self):
self._test1(np.absolute,
(self.q2, self.qs, self.qless, self.qi),
(),
'same')
def test_rint(self):
self._test1(np.rint,
(self.q2, self.qs, self.qless, self.qi),
(),
'same')
def test_conj(self):
self._test1(np.conj,
(self.q2, self.qs, self.qless, self.qi),
(),
'same')
def test_exp(self):
self._test1(np.exp,
(self.qless, ),
(self.q1, ),
'')
def test_exp2(self):
self._test1(np.exp2,
(self.qless,),
(self.q1, ),
'')
def test_log(self):
self._test1(np.log,
(self.qless,),
(self.q1, ),
'')
def test_log2(self):
self._test1(np.log2,
(self.qless,),
(self.q1, ),
'')
def test_log10(self):
self._test1(np.log10,
(self.qless,),
(self.q1, ),
'')
def test_expm1(self):
self._test1(np.expm1,
(self.qless,),
(self.q1, ),
'')
def test_sqrt(self):
self._test1(np.sqrt,
(self.q2, self.qs, self.qless, self.qi),
(),
0.5)
def test_square(self):
self._test1(np.square,
(self.q2, self.qs, self.qless, self.qi),
(),
2)
def test_reciprocal(self):
self._test1(np.reciprocal,
(self.q2, self.qs, self.qless, self.qi),
(),
-1)
@helpers.requires_numpy()
class TestTrigUfuncs(TestUFuncs):
"""Universal functions (ufunc) > Trigonometric functions
http://docs.scipy.org/doc/numpy/reference/ufuncs.html#trigonometric-functions
sin(x[, out]) Trigonometric sine, element-wise.
cos(x[, out]) Cosine elementwise.
tan(x[, out]) Compute tangent element-wise.
arcsin(x[, out]) Inverse sine, element-wise.
arccos(x[, out]) Trigonometric inverse cosine, element-wise.
arctan(x[, out]) Trigonometric inverse tangent, element-wise.
arctan2(x1, x2[, out]) Element-wise arc tangent of x1/x2 choosing the quadrant correctly.
hypot(x1, x2[, out]) Given the legs of a right triangle, return its hypotenuse.
sinh(x[, out]) Hyperbolic sine, element-wise.
cosh(x[, out]) Hyperbolic cosine, element-wise.
tanh(x[, out]) Compute hyperbolic tangent element-wise.
arcsinh(x[, out]) Inverse hyperbolic sine elementwise.
arccosh(x[, out]) Inverse hyperbolic cosine, elementwise.
arctanh(x[, out]) Inverse hyperbolic tangent elementwise.
deg2rad(x[, out]) Convert angles from degrees to radians.
rad2deg(x[, out]) Convert angles from radians to degrees.
"""
def test_sin(self):
self._test1(np.sin, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless,
np.arange(0, pi/2, pi/4) * self.ureg.radian,
np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m
), (self.ureg.m, ), '', results=(None, None, np.sin(np.arange(0, pi/2, pi/4)*0.001)))
self._test1(np.sin, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees,
), results=(np.sin(np.arange(0, pi/2, pi/4)), ))
def test_cos(self):
self._test1(np.cos, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless,
np.arange(0, pi/2, pi/4) * self.ureg.radian,
np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m,
), (self.ureg.m, ), '',
results=(None,
None,
np.cos(np.arange(0, pi/2, pi/4)*0.001),
)
)
self._test1(np.cos,
(np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees,
),
results=(np.cos(np.arange(0, pi/2, pi/4)), )
)
def test_tan(self):
self._test1(np.tan, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless,
np.arange(0, pi/2, pi/4) * self.ureg.radian,
np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m
), (self.ureg.m, ), '', results=(None, None, np.tan(np.arange(0, pi/2, pi/4)*0.001)))
self._test1(np.tan, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees,
), results=(np.tan(np.arange(0, pi/2, pi/4)), ))
def test_arcsin(self):
self._test1(np.arcsin, (np.arange(0, .9, .1) * self.ureg.dimensionless,
np.arange(0, .9, .1) * self.ureg.m / self.ureg.m
), (self.ureg.m, ), 'radian')
def test_arccos(self):
x = np.arange(0, .9, .1) * self.ureg.m
self._test1(np.arccos, (np.arange(0, .9, .1) * self.ureg.dimensionless,
np.arange(0, .9, .1) * self.ureg.m / self.ureg.m
), (self.ureg.m, ), 'radian')
def test_arctan(self):
self._test1(np.arctan, (np.arange(0, .9, .1) * self.ureg.dimensionless,
np.arange(0, .9, .1) * self.ureg.m / self.ureg.m
), (self.ureg.m, ), 'radian')
def test_arctan2(self):
m = self.ureg.m
j = self.ureg.J
km = self.ureg.km
self._test2(np.arctan2, np.arange(0, .9, .1) * m,
(np.arange(0, .9, .1) * m, np.arange(.9, 0., -.1) * m,
np.arange(0, .9, .1) * km, np.arange(.9, 0., -.1) * km,
),
raise_with=np.arange(0, .9, .1) * j,
output_units='radian')
def test_hypot(self):
self.assertTrue(np.hypot(3. * self.ureg.m, 4. * self.ureg.m) == 5. * self.ureg.m)
self.assertTrue(np.hypot(3. * self.ureg.m, 400. * self.ureg.cm) == 5. * self.ureg.m)
self.assertRaises(ValueError, np.hypot, 1. * self.ureg.m, 2. * self.ureg.J)
def test_sinh(self):
self._test1(np.sinh, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless,
np.arange(0, pi/2, pi/4) * self.ureg.radian,
np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m
), (self.ureg.m, ), '', results=(None, None, np.sinh(np.arange(0, pi/2, pi/4)*0.001)))
self._test1(np.sinh, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees,
), results=(np.sinh(np.arange(0, pi/2, pi/4)), ))
def test_cosh(self):
self._test1(np.cosh, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless,
np.arange(0, pi/2, pi/4) * self.ureg.radian,
np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m
), (self.ureg.m, ), '', results=(None, None, np.cosh(np.arange(0, pi/2, pi/4)*0.001)))
self._test1(np.cosh, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees,
), results=(np.cosh(np.arange(0, pi/2, pi/4)), ))
def test_tanh(self):
self._test1(np.tanh, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless,
np.arange(0, pi/2, pi/4) * self.ureg.radian,
np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m
), (self.ureg.m, ), '', results=(None, None, np.tanh(np.arange(0, pi/2, pi/4)*0.001)))
self._test1(np.tanh, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees,
), results=(np.tanh(np.arange(0, pi/2, pi/4)), ))
def test_arcsinh(self):
self._test1(np.arcsinh, (np.arange(0, .9, .1) * self.ureg.dimensionless,
np.arange(0, .9, .1) * self.ureg.m / self.ureg.m
), (self.ureg.m, ), 'radian')
def test_arccosh(self):
self._test1(np.arccosh, (np.arange(1., 1.9, .1) * self.ureg.dimensionless,
np.arange(1., 1.9, .1) * self.ureg.m / self.ureg.m
), (self.ureg.m, ), 'radian')
def test_arctanh(self):
self._test1(np.arctanh, (np.arange(0, .9, .1) * self.ureg.dimensionless,
np.arange(0, .9, .1) * self.ureg.m / self.ureg.m
), (.1 * self.ureg.m, ), 'radian')
def test_deg2rad(self):
self._test1(np.deg2rad, (np.arange(0, pi/2, pi/4) * self.ureg.degrees,
), (self.ureg.m, ), 'radians')
def test_rad2deg(self):
self._test1(np.rad2deg,
(np.arange(0, pi/2, pi/4) * self.ureg.dimensionless,
np.arange(0, pi/2, pi/4) * self.ureg.radian,
np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m,
),
(self.ureg.m, ), 'degree',
results=(None,
None,
np.rad2deg(np.arange(0, pi/2, pi/4)*0.001) * self.ureg.degree,
))
class TestComparisonUfuncs(TestUFuncs):
"""Universal functions (ufunc) > Comparison functions
http://docs.scipy.org/doc/numpy/reference/ufuncs.html#comparison-functions
greater(x1, x2[, out]) Return the truth value of (x1 > x2) element-wise.
greater_equal(x1, x2[, out]) Return the truth value of (x1 >= x2) element-wise.
less(x1, x2[, out]) Return the truth value of (x1 < x2) element-wise.
less_equal(x1, x2[, out]) Return the truth value of (x1 =< x2) element-wise.
not_equal(x1, x2[, out]) Return (x1 != x2) element-wise.
equal(x1, x2[, out]) Return (x1 == x2) element-wise.
"""
def test_greater(self):
self._testn2(np.greater,
self.q1,
(self.q2, ),
(self.qm, ))
def test_greater_equal(self):
self._testn2(np.greater_equal,
self.q1,
(self.q2, ),
(self.qm, ))
def test_less(self):
self._testn2(np.less,
self.q1,
(self.q2, ),
(self.qm, ))
def test_less_equal(self):
self._testn2(np.less_equal,
self.q1,
(self.q2, ),
(self.qm, ))
def test_not_equal(self):
self._testn2(np.not_equal,
self.q1,
(self.q2, ),
(self.qm, ))
def test_equal(self):
self._testn2(np.equal,
self.q1,
(self.q2, ),
(self.qm, ))
class TestFloatingUfuncs(TestUFuncs):
"""Universal functions (ufunc) > Floating functions
http://docs.scipy.org/doc/numpy/reference/ufuncs.html#floating-functions
isreal(x) Returns a bool array, where True if input element is real.
iscomplex(x) Returns a bool array, where True if input element is complex.
isfinite(x[, out]) Test element-wise for finite-ness (not infinity or not Not a Number).
isinf(x[, out]) Test element-wise for positive or negative infinity.
isnan(x[, out]) Test element-wise for Not a Number (NaN), return result as a bool array.
signbit(x[, out]) Returns element-wise True where signbit is set (less than zero).
copysign(x1, x2[, out]) Change the sign of x1 to that of x2, element-wise.
nextafter(x1, x2[, out]) Return the next representable floating-point value after x1 in the direction of x2 element-wise.
modf(x[, out1, out2]) Return the fractional and integral parts of an array, element-wise.
ldexp(x1, x2[, out]) Compute y = x1 * 2**x2.
frexp(x[, out1, out2]) Split the number, x, into a normalized fraction (y1) and exponent (y2)
fmod(x1, x2[, out]) Return the element-wise remainder of division.
floor(x[, out]) Return the floor of the input, element-wise.
ceil(x[, out]) Return the ceiling of the input, element-wise.
trunc(x[, out]) Return the truncated value of the input, element-wise.
"""
def test_isreal(self):
self._testn(np.isreal,
(self.q1, self.qm, self.qless))
def test_iscomplex(self):
self._testn(np.iscomplex,
(self.q1, self.qm, self.qless))
def test_isfinite(self):
self._testn(np.isreal,
(self.q1, self.qm, self.qless))
def test_isinf(self):
self._testn(np.isinf,
(self.q1, self.qm, self.qless))
def test_isnan(self):
self._testn(np.isnan,
(self.q1, self.qm, self.qless))
def test_signbit(self):
self._testn(np.signbit,
(self.q1, self.qm, self.qless))
def test_copysign(self):
self._test2(np.copysign,
self.q1,
(self.q2, self.qs),
(self.qm, ))
def test_nextafter(self):
self._test2(np.nextafter,
self.q1,
(self.q2, self.qs),
(self.qm, ))
def test_modf(self):
self._test1_2o(np.modf,
(self.q2, self.qs),
)
def test_ldexp(self):
x1, x2 = np.frexp(self.q2)
self._test2(np.ldexp,
x1,
(x2, ))
def test_frexp(self):
self._test1_2o(np.frexp,
(self.q2, self.qs),
output_units=('same', None))
def test_fmod(self):
# See TestMathUfuncs.test_fmod
pass
def test_floor(self):
self._test1(np.floor,
(self.q1, self.qm, self.qless))
def test_ceil(self):
self._test1(np.ceil,
(self.q1, self.qm, self.qless))
def test_trunc(self):
self._test1(np.trunc,
(self.q1, self.qm, self.qless))

View File

@ -0,0 +1,642 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
import math
import copy
import itertools
import operator as op
from pint.unit import (ScaleConverter, OffsetConverter, UnitsContainer,
Definition, PrefixDefinition, UnitDefinition,
DimensionDefinition, _freeze, Converter, UnitRegistry,
LazyRegistry, ParserHelper)
from pint import DimensionalityError, UndefinedUnitError
from pint.compat import u, unittest, np, string_types
from pint.testsuite import QuantityTestCase, helpers, BaseTestCase
from pint.testsuite.parameterized import ParameterizedTestCase
class TestConverter(BaseTestCase):
def test_converter(self):
c = Converter()
self.assertTrue(c.is_multiplicative)
self.assertTrue(c.to_reference(8))
self.assertTrue(c.from_reference(8))
def test_multiplicative_converter(self):
c = ScaleConverter(20.)
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., 2)
self.assertEqual(c.from_reference(c.to_reference(100)), 100)
self.assertEqual(c.to_reference(c.from_reference(100)), 100)
@helpers.requires_numpy()
def test_converter_inplace(self):
for c in (ScaleConverter(20.), OffsetConverter(20., 2)):
fun1 = lambda x, y: c.from_reference(c.to_reference(x, y), y)
fun2 = lambda x, y: c.to_reference(c.from_reference(x, y), y)
for fun, (inplace, comp) in itertools.product((fun1, fun2),
((True, self.assertIs), (False, self.assertIsNot))):
a = np.ones((1, 10))
ac = np.ones((1, 10))
r = fun(a, inplace)
np.testing.assert_allclose(r, ac)
comp(a, r)
class TestDefinition(BaseTestCase):
def test_invalid(self):
self.assertRaises(ValueError, Definition.from_string, 'x = [time] * meter')
self.assertRaises(ValueError, Definition.from_string, '[x] = [time] * meter')
def test_prefix_definition(self):
for definition in ('m- = 1e-3', 'm- = 10**-3', 'm- = 0.001'):
x = Definition.from_string(definition)
self.assertIsInstance(x, PrefixDefinition)
self.assertEqual(x.name, 'm')
self.assertEqual(x.aliases, ())
self.assertEqual(x.converter.to_reference(1000), 1)
self.assertEqual(x.converter.from_reference(0.001), 1)
self.assertEqual(str(x), 'm')
x = Definition.from_string('kilo- = 1e-3 = k-')
self.assertIsInstance(x, PrefixDefinition)
self.assertEqual(x.name, 'kilo')
self.assertEqual(x.aliases, ())
self.assertEqual(x.symbol, 'k')
self.assertEqual(x.converter.to_reference(1000), 1)
self.assertEqual(x.converter.from_reference(.001), 1)
x = Definition.from_string('kilo- = 1e-3 = k- = anotherk-')
self.assertIsInstance(x, PrefixDefinition)
self.assertEqual(x.name, 'kilo')
self.assertEqual(x.aliases, ('anotherk', ))
self.assertEqual(x.symbol, 'k')
self.assertEqual(x.converter.to_reference(1000), 1)
self.assertEqual(x.converter.from_reference(.001), 1)
def test_baseunit_definition(self):
x = Definition.from_string('meter = [length]')
self.assertIsInstance(x, UnitDefinition)
self.assertTrue(x.is_base)
self.assertEqual(x.reference, UnitsContainer({'[length]': 1}))
def test_unit_definition(self):
x = Definition.from_string('coulomb = ampere * second')
self.assertIsInstance(x, UnitDefinition)
self.assertFalse(x.is_base)
self.assertIsInstance(x.converter, ScaleConverter)
self.assertEqual(x.converter.scale, 1)
self.assertEqual(x.reference, UnitsContainer(ampere=1, second=1))
x = Definition.from_string('faraday = 96485.3399 * coulomb')
self.assertIsInstance(x, UnitDefinition)
self.assertFalse(x.is_base)
self.assertIsInstance(x.converter, ScaleConverter)
self.assertEqual(x.converter.scale, 96485.3399)
self.assertEqual(x.reference, UnitsContainer(coulomb=1))
x = Definition.from_string('degF = 9 / 5 * kelvin; offset: 255.372222')
self.assertIsInstance(x, UnitDefinition)
self.assertFalse(x.is_base)
self.assertIsInstance(x.converter, OffsetConverter)
self.assertEqual(x.converter.scale, 9/5)
self.assertEqual(x.converter.offset, 255.372222)
self.assertEqual(x.reference, UnitsContainer(kelvin=1))
def test_dimension_definition(self):
x = DimensionDefinition('[time]', '', (), converter='')
self.assertTrue(x.is_base)
self.assertEqual(x.name, '[time]')
x = Definition.from_string('[speed] = [length]/[time]')
self.assertIsInstance(x, DimensionDefinition)
self.assertEqual(x.reference, UnitsContainer({'[length]': 1, '[time]': -1}))
class TestUnitsContainer(QuantityTestCase):
def _test_inplace(self, operator, value1, value2, expected_result):
value1 = copy.copy(value1)
value2 = copy.copy(value2)
id1 = id(value1)
id2 = id(value2)
value1 = operator(value1, value2)
value2_cpy = copy.copy(value2)
self.assertEqual(value1, expected_result)
self.assertEqual(id1, id(value1))
self.assertEqual(value2, value2_cpy)
self.assertEqual(id2, id(value2))
def _test_not_inplace(self, operator, value1, value2, expected_result):
id1 = id(value1)
id2 = id(value2)
value1_cpy = copy.copy(value1)
value2_cpy = copy.copy(value2)
result = operator(value1, value2)
self.assertEqual(expected_result, result)
self.assertEqual(value1, value1_cpy)
self.assertEqual(value2, value2_cpy)
self.assertNotEqual(id(result), id1)
self.assertNotEqual(id(result), id2)
def test_unitcontainer_creation(self):
x = UnitsContainer(meter=1, second=2)
y = UnitsContainer({'meter': 1.0, 'second': 2.0})
self.assertIsInstance(x['meter'], float)
self.assertEqual(x, y)
self.assertIsNot(x, y)
z = copy.copy(x)
self.assertEqual(x, z)
self.assertIsNot(x, z)
z = UnitsContainer(x)
self.assertEqual(x, z)
self.assertIsNot(x, z)
def test_unitcontainer_repr(self):
x = UnitsContainer()
self.assertEqual(str(x), 'dimensionless')
self.assertEqual(repr(x), '<UnitsContainer({})>')
x = UnitsContainer(meter=1, second=2)
self.assertEqual(str(x), 'meter * second ** 2')
self.assertEqual(repr(x), "<UnitsContainer({'meter': 1.0, 'second': 2.0})>")
x = UnitsContainer(meter=1, second=2.5)
self.assertEqual(str(x), 'meter * second ** 2.5')
self.assertEqual(repr(x), "<UnitsContainer({'meter': 1.0, 'second': 2.5})>")
def test_unitcontainer_bool(self):
self.assertTrue(UnitsContainer(meter=1, second=2))
self.assertFalse(UnitsContainer())
def test_unitcontainer_comp(self):
x = UnitsContainer(meter=1, second=2)
y = UnitsContainer(meter=1., second=2)
z = UnitsContainer(meter=1, second=3)
self.assertTrue(x == y)
self.assertFalse(x != y)
self.assertFalse(x == z)
self.assertTrue(x != z)
def test_unitcontainer_arithmetic(self):
x = UnitsContainer(meter=1)
y = UnitsContainer(second=1)
z = UnitsContainer(meter=1, second=-2)
self._test_not_inplace(op.mul, x, y, UnitsContainer(meter=1, second=1))
self._test_not_inplace(op.truediv, x, y, UnitsContainer(meter=1, second=-1))
self._test_not_inplace(op.pow, z, 2, UnitsContainer(meter=2, second=-4))
self._test_not_inplace(op.pow, z, -2, UnitsContainer(meter=-2, second=4))
self._test_inplace(op.imul, x, y, UnitsContainer(meter=1, second=1))
self._test_inplace(op.itruediv, x, y, UnitsContainer(meter=1, second=-1))
self._test_inplace(op.ipow, z, 2, UnitsContainer(meter=2, second=-4))
self._test_inplace(op.ipow, z, -2, UnitsContainer(meter=-2, second=4))
def test_string_comparison(self):
x = UnitsContainer(meter=1)
y = UnitsContainer(second=1)
z = UnitsContainer(meter=1, second=-2)
self.assertEqual(x, 'meter')
self.assertEqual('meter', x)
self.assertNotEqual(x, 'meter ** 2')
self.assertNotEqual(x, 'meter * meter')
self.assertNotEqual(x, 'second')
self.assertEqual(y, 'second')
self.assertEqual(z, 'meter/second/second')
def test_invalid(self):
self.assertRaises(TypeError, UnitsContainer, {1: 2})
self.assertRaises(TypeError, UnitsContainer, {'1': '2'})
d = UnitsContainer()
self.assertRaises(TypeError, d.__setitem__, 1, 2)
self.assertRaises(TypeError, d.__setitem__, '1', '2')
self.assertRaises(TypeError, d.__mul__, list())
self.assertRaises(TypeError, d.__imul__, list())
self.assertRaises(TypeError, d.__pow__, list())
self.assertRaises(TypeError, d.__ipow__, list())
self.assertRaises(TypeError, d.__truediv__, list())
self.assertRaises(TypeError, d.__itruediv__, list())
self.assertRaises(TypeError, d.__rtruediv__, list())
class TestRegistry(QuantityTestCase):
FORCE_NDARRAY = False
def setup(self):
self.ureg.autoconvert_offset_to_baseunit = False
def test_base(self):
ureg = UnitRegistry(None)
ureg.define('meter = [length]')
self.assertRaises(ValueError, ureg.define, 'meter = [length]')
self.assertRaises(TypeError, ureg.define, list())
x = ureg.define('degC = kelvin; offset: 273.15')
def test_define(self):
ureg = UnitRegistry(None)
self.assertIsInstance(dir(ureg), list)
self.assertGreater(len(dir(ureg)), 0)
def test_load(self):
import pkg_resources
from pint import unit
data = pkg_resources.resource_filename(unit.__name__, 'default_en.txt')
ureg1 = UnitRegistry()
ureg2 = UnitRegistry(data)
self.assertEqual(dir(ureg1), dir(ureg2))
self.assertRaises(ValueError, UnitRegistry(None).load_definitions, 'notexisting')
def test_default_format(self):
ureg = UnitRegistry()
q = ureg.meter
s1 = '{0}'.format(q)
s2 = '{0:~}'.format(q)
ureg.default_format = '~'
s3 = '{0}'.format(q)
self.assertEqual(s2, s3)
self.assertNotEqual(s1, s3)
self.assertEqual(ureg.default_format, '~')
def test_parse_number(self):
self.assertEqual(self.ureg.parse_expression('pi'), math.pi)
self.assertEqual(self.ureg.parse_expression('x', x=2), 2)
self.assertEqual(self.ureg.parse_expression('x', x=2.3), 2.3)
self.assertEqual(self.ureg.parse_expression('x * y', x=2.3, y=3), 2.3 * 3)
self.assertEqual(self.ureg.parse_expression('x', x=(1+1j)), (1+1j))
def test_parse_single(self):
self.assertEqual(self.ureg.parse_expression('meter'), self.Q_(1, UnitsContainer(meter=1.)))
self.assertEqual(self.ureg.parse_expression('second'), self.Q_(1, UnitsContainer(second=1.)))
def test_parse_alias(self):
self.assertEqual(self.ureg.parse_expression('metre'), self.Q_(1, UnitsContainer(meter=1.)))
def test_parse_plural(self):
self.assertEqual(self.ureg.parse_expression('meters'), self.Q_(1, UnitsContainer(meter=1.)))
def test_parse_prefix(self):
self.assertEqual(self.ureg.parse_expression('kilometer'), self.Q_(1, UnitsContainer(kilometer=1.)))
#self.assertEqual(self.ureg._units['kilometer'], self.Q_(1000., UnitsContainer(meter=1.)))
def test_parse_complex(self):
self.assertEqual(self.ureg.parse_expression('kilometre'), self.Q_(1, UnitsContainer(kilometer=1.)))
self.assertEqual(self.ureg.parse_expression('kilometres'), self.Q_(1, UnitsContainer(kilometer=1.)))
def test_str_errors(self):
self.assertEqual(str(UndefinedUnitError('rabbits')), "'{0!s}' is not defined in the unit registry".format('rabbits'))
self.assertEqual(str(UndefinedUnitError(('rabbits', 'horses'))), "{0!s} are not defined in the unit registry".format(('rabbits', 'horses')))
self.assertEqual(u(str(DimensionalityError('meter', 'second'))),
"Cannot convert from 'meter' to 'second'")
self.assertEqual(str(DimensionalityError('meter', 'second', 'length', 'time')),
"Cannot convert from 'meter' (length) to 'second' (time)")
def test_parse_mul_div(self):
self.assertEqual(self.ureg.parse_expression('meter*meter'), self.Q_(1, UnitsContainer(meter=2.)))
self.assertEqual(self.ureg.parse_expression('meter**2'), self.Q_(1, UnitsContainer(meter=2.)))
self.assertEqual(self.ureg.parse_expression('meter*second'), self.Q_(1, UnitsContainer(meter=1., second=1)))
self.assertEqual(self.ureg.parse_expression('meter/second'), self.Q_(1, UnitsContainer(meter=1., second=-1)))
self.assertEqual(self.ureg.parse_expression('meter/second**2'), self.Q_(1, UnitsContainer(meter=1., second=-2)))
def test_parse_pretty(self):
self.assertEqual(self.ureg.parse_expression('meter/second²'),
self.Q_(1, UnitsContainer(meter=1., second=-2)))
self.assertEqual(self.ureg.parse_expression('m³/s³'),
self.Q_(1, UnitsContainer(meter=3., second=-3)))
self.assertEqual(self.ureg.parse_expression('meter² · second'),
self.Q_(1, UnitsContainer(meter=2., second=1)))
self.assertEqual(self.ureg.parse_expression('meter⁰.⁵·second'),
self.Q_(1, UnitsContainer(meter=0.5, second=1)))
self.assertEqual(self.ureg.parse_expression('meter³⁷/second⁴.³²¹'),
self.Q_(1, UnitsContainer(meter=37, second=-4.321)))
def test_parse_factor(self):
self.assertEqual(self.ureg.parse_expression('42*meter'), self.Q_(42, UnitsContainer(meter=1.)))
self.assertEqual(self.ureg.parse_expression('meter*42'), self.Q_(42, UnitsContainer(meter=1.)))
def test_rep_and_parse(self):
q = self.Q_(1, 'g/(m**2*s)')
self.assertEqual(self.Q_(q.magnitude, str(q.units)), q)
def test_as_delta(self):
parse = self.ureg.parse_units
self.assertEqual(parse('kelvin', as_delta=True), UnitsContainer(kelvin=1))
self.assertEqual(parse('kelvin', as_delta=False), UnitsContainer(kelvin=1))
self.assertEqual(parse('kelvin**(-1)', as_delta=True), UnitsContainer(kelvin=-1))
self.assertEqual(parse('kelvin**(-1)', as_delta=False), UnitsContainer(kelvin=-1))
self.assertEqual(parse('kelvin**2', as_delta=True), UnitsContainer(kelvin=2))
self.assertEqual(parse('kelvin**2', as_delta=False), UnitsContainer(kelvin=2))
self.assertEqual(parse('kelvin*meter', as_delta=True), UnitsContainer(kelvin=1, meter= 1))
self.assertEqual(parse('kelvin*meter', as_delta=False), UnitsContainer(kelvin=1, meter=1))
def test_name(self):
self.assertRaises(UndefinedUnitError, self.ureg.get_name, 'asdf')
def test_symbol(self):
self.assertRaises(UndefinedUnitError, self.ureg.get_symbol, 'asdf')
self.assertEqual(self.ureg.get_symbol('meter'), 'm')
self.assertEqual(self.ureg.get_symbol('second'), 's')
self.assertEqual(self.ureg.get_symbol('hertz'), 'Hz')
self.assertEqual(self.ureg.get_symbol('kilometer'), 'km')
self.assertEqual(self.ureg.get_symbol('megahertz'), 'MHz')
self.assertEqual(self.ureg.get_symbol('millisecond'), 'ms')
def test_imperial_symbol(self):
self.assertEqual(self.ureg.get_symbol('inch'), 'in')
self.assertEqual(self.ureg.get_symbol('foot'), 'ft')
self.assertEqual(self.ureg.get_symbol('inches'), 'in')
self.assertEqual(self.ureg.get_symbol('feet'), 'ft')
self.assertEqual(self.ureg.get_symbol('international_foot'), 'ft')
self.assertEqual(self.ureg.get_symbol('international_inch'), 'in')
def test_pint(self):
p = self.ureg.pint
l = self.ureg.liter
ip = self.ureg.imperial_pint
self.assertLess(p, l)
self.assertLess(p, ip)
def test_wraps(self):
def func(x):
return x
ureg = self.ureg
f0 = ureg.wraps(None, [None, ])(func)
self.assertEqual(f0(3.), 3.)
f0 = ureg.wraps(None, None, )(func)
self.assertEqual(f0(3.), 3.)
f1 = ureg.wraps(None, ['meter', ])(func)
self.assertRaises(ValueError, f1, 3.)
self.assertEqual(f1(3. * ureg.centimeter), 0.03)
self.assertEqual(f1(3. * ureg.meter), 3.)
self.assertRaises(ValueError, f1, 3 * ureg.second)
f1b = ureg.wraps(None, [ureg.meter, ])(func)
self.assertRaises(ValueError, f1b, 3.)
self.assertEqual(f1b(3. * ureg.centimeter), 0.03)
self.assertEqual(f1b(3. * ureg.meter), 3.)
self.assertRaises(ValueError, f1b, 3 * ureg.second)
f1 = ureg.wraps(None, 'meter')(func)
self.assertRaises(ValueError, f1, 3.)
self.assertEqual(f1(3. * ureg.centimeter), 0.03)
self.assertEqual(f1(3. * ureg.meter), 3.)
self.assertRaises(ValueError, f1, 3 * ureg.second)
f2 = ureg.wraps('centimeter', ['meter', ])(func)
self.assertRaises(ValueError, f2, 3.)
self.assertEqual(f2(3. * ureg.centimeter), 0.03 * ureg.centimeter)
self.assertEqual(f2(3. * ureg.meter), 3 * ureg.centimeter)
f3 = ureg.wraps('centimeter', ['meter', ], strict=False)(func)
self.assertEqual(f3(3), 3 * ureg.centimeter)
self.assertEqual(f3(3. * ureg.centimeter), 0.03 * ureg.centimeter)
self.assertEqual(f3(3. * ureg.meter), 3. * ureg.centimeter)
def gfunc(x, y):
return x + y
g0 = ureg.wraps(None, [None, None])(gfunc)
self.assertEqual(g0(3, 1), 4)
g1 = ureg.wraps(None, ['meter', 'centimeter'])(gfunc)
self.assertRaises(ValueError, g1, 3 * ureg.meter, 1)
self.assertEqual(g1(3 * ureg.meter, 1 * ureg.centimeter), 4)
self.assertEqual(g1(3 * ureg.meter, 1 * ureg.meter), 3 + 100)
def hfunc(x, y):
return x, y
h0 = ureg.wraps(None, [None, None])(hfunc)
self.assertEqual(h0(3, 1), (3, 1))
h1 = ureg.wraps(['meter', 'cm'], [None, None])(hfunc)
self.assertEqual(h1(3, 1), [3 * ureg.meter, 1 * ureg.cm])
h2 = ureg.wraps(('meter', 'cm'), [None, None])(hfunc)
self.assertEqual(h2(3, 1), (3 * ureg.meter, 1 * ureg.cm))
def test_to_ref_vs_to(self):
self.ureg.autoconvert_offset_to_baseunit = True
q = 8. * self.ureg.inch
t = 8. * self.ureg.degF
dt = 8. * self.ureg.delta_degF
self.assertEqual(q.to('cm').magnitude, self.ureg._units['inch'].converter.to_reference(8.))
self.assertEqual(t.to('kelvin').magnitude, self.ureg._units['degF'].converter.to_reference(8.))
self.assertEqual(dt.to('kelvin').magnitude, self.ureg._units['delta_degF'].converter.to_reference(8.))
def test_redefinition(self):
d = UnitRegistry().define
with self.capture_log() as buffer:
d('meter = [fruits]')
d('kilo- = 1000')
d('[speed] = [vegetables]')
# aliases
d('bla = 3.2 meter = inch')
d('myk- = 1000 = kilo-')
self.assertEqual(len(buffer), 5)
def test_convert_parse_str(self):
ureg = self.ureg
self.assertEqual(ureg.convert(1, 'meter', 'inch'),
ureg.convert(1, UnitsContainer(meter=1), UnitsContainer(inch=1)))
@helpers.requires_numpy()
def test_convert_inplace(self):
ureg = self.ureg
# Conversions with single units take a different codepath than
# Conversions with more than one unit.
src_dst1 = UnitsContainer(meter=1), UnitsContainer(inch=1)
src_dst2 = UnitsContainer(meter=1, second=-1), UnitsContainer(inch=1, minute=-1)
for src, dst in (src_dst1, src_dst2):
v = ureg.convert(1, src, dst),
a = np.ones((3, 1))
ac = np.ones((3, 1))
r1 = ureg.convert(a, src, dst)
np.testing.assert_allclose(r1, v * ac)
self.assertIsNot(r1, a)
r2 = ureg.convert(a, src, dst, inplace=True)
np.testing.assert_allclose(r2, v * ac)
self.assertIs(r2, a)
def test_repeated_convert(self):
# Because of caching, repeated conversions were failing.
self.ureg.convert(1, "m", "ft")
self.ureg.convert(1, "m", "ft")
def test_singular_SI_prefix_convert(self):
# Fix for issue 156
self.ureg.convert(1, 'mm', 'm')
self.ureg.convert(1, 'ms', 's')
self.ureg.convert(1, 'm', 'mm')
self.ureg.convert(1, 's', 'ms')
def test_parse_units(self):
ureg = self.ureg
self.assertEqual(ureg.parse_units(''), UnitsContainer())
self.assertRaises(ValueError, ureg.parse_units, '2 * meter')
class TestCompatibleUnits(QuantityTestCase):
FORCE_NDARRAY= False
def _test(self, input_units):
gd = self.ureg.get_dimensionality
dim = gd(input_units)
equiv = self.ureg.get_compatible_units(input_units)
for eq in equiv:
self.assertEqual(gd(eq), dim)
self.assertEqual(equiv, self.ureg.get_compatible_units(dim))
def _test2(self, units1, units2):
equiv1 = self.ureg.get_compatible_units(units1)
equiv2 = self.ureg.get_compatible_units(units2)
self.assertEqual(equiv1, equiv2)
def test_many(self):
self._test(self.ureg.meter.units)
self._test(self.ureg.seconds.units)
self._test(self.ureg.newton.units)
self._test(self.ureg.kelvin.units)
def test_context_sp(self):
gd = self.ureg.get_dimensionality
# length, frequency, energy
valid = [gd(self.ureg.meter.units), gd(self.ureg.hertz.units), gd(self.ureg.joule.units)]
with self.ureg.context('sp'):
equiv = self.ureg.get_compatible_units(self.ureg.meter.units)
result = set()
for eq in equiv:
dim = gd(eq)
result.add(_freeze(dim))
self.assertIn(dim, valid)
self.assertEqual(len(result), len(valid))
def test_get_base_units(self):
ureg = UnitRegistry()
self.assertEqual(ureg.get_base_units(''), (1, UnitsContainer()))
self.assertEqual(ureg.get_base_units('meter'), ureg.get_base_units(ParserHelper(meter=1)))
def test_get_compatible_units(self):
ureg = UnitRegistry()
self.assertEqual(ureg.get_compatible_units(''), (1, UnitsContainer()))
self.assertEqual(ureg.get_compatible_units('meter'), ureg.get_compatible_units(ParserHelper(meter=1)))
class TestRegistryWithDefaultRegistry(TestRegistry):
@classmethod
def setUpClass(cls):
from pint import _DEFAULT_REGISTRY
cls.ureg = _DEFAULT_REGISTRY
cls.Q_ = cls.ureg.Quantity
def test_lazy(self):
x = LazyRegistry()
x.test = 'test'
self.assertIsInstance(x, UnitRegistry)
y = LazyRegistry()
q = y('meter')
self.assertIsInstance(y, UnitRegistry)
def test_redefinition(self):
d = self.ureg.define
self.assertRaises(ValueError, d, 'meter = [time]')
self.assertRaises(ValueError, d, 'kilo- = 1000')
self.assertRaises(ValueError, d, '[speed] = [length]')
# aliases
self.assertIn('inch', self.ureg._units)
self.assertRaises(ValueError, d, 'bla = 3.2 meter = inch')
self.assertRaises(ValueError, d, 'myk- = 1000 = kilo-')
class TestErrors(BaseTestCase):
def test_errors(self):
x = ('meter', )
msg = "'meter' is not defined in the unit registry"
self.assertEqual(str(UndefinedUnitError(x)), msg)
self.assertEqual(str(UndefinedUnitError(list(x))), msg)
self.assertEqual(str(UndefinedUnitError(set(x))), msg)
msg = "Cannot convert from 'a' (c) to 'b' (d)msg"
ex = DimensionalityError('a', 'b', 'c', 'd', 'msg')
self.assertEqual(str(ex), msg)
class TestConvertWithOffset(QuantityTestCase, ParameterizedTestCase):
# The dicts in convert_with_offset are used to create a UnitsContainer.
# We create UnitsContainer to avoid any auto-conversion of units.
convert_with_offset = [
(({'degC': 1}, {'degC': 1}), 10),
(({'degC': 1}, {'kelvin': 1}), 283.15),
(({'degC': 1}, {'degC': 1, 'millimeter': 1, 'meter': -1}), 'error'),
(({'degC': 1}, {'kelvin': 1, 'millimeter': 1, 'meter': -1}), 283150),
(({'kelvin': 1}, {'degC': 1}), -263.15),
(({'kelvin': 1}, {'kelvin': 1}), 10),
(({'kelvin': 1}, {'degC': 1, 'millimeter': 1, 'meter': -1}), 'error'),
(({'kelvin': 1}, {'kelvin': 1, 'millimeter': 1, 'meter': -1}), 10000),
(({'degC': 1, 'millimeter': 1, 'meter': -1}, {'degC': 1}), 'error'),
(({'degC': 1, 'millimeter': 1, 'meter': -1}, {'kelvin': 1}), 'error'),
(({'degC': 1, 'millimeter': 1, 'meter': -1}, {'degC': 1, 'millimeter': 1, 'meter': -1}), 10),
(({'degC': 1, 'millimeter': 1, 'meter': -1}, {'kelvin': 1, 'millimeter': 1, 'meter': -1}), 'error'),
(({'kelvin': 1, 'millimeter': 1, 'meter': -1}, {'degC': 1}), -273.14),
(({'kelvin': 1, 'millimeter': 1, 'meter': -1}, {'kelvin': 1}), 0.01),
(({'kelvin': 1, 'millimeter': 1, 'meter': -1}, {'degC': 1, 'millimeter': 1, 'meter': -1}), 'error'),
(({'kelvin': 1, 'millimeter': 1, 'meter': -1}, {'kelvin': 1, 'millimeter': 1, 'meter': -1}), 10),
(({'degC': 2}, {'kelvin': 2}), 'error'),
(({'degC': 1, 'degF': 1}, {'kelvin': 2}), 'error'),
(({'degC': 1, 'kelvin': 1}, {'kelvin': 2}), 'error'),
]
@ParameterizedTestCase.parameterize(("input", "expected_output"),
convert_with_offset)
def test_to_and_from_offset_units(self, input_tuple, expected):
src, dst = input_tuple
src, dst = UnitsContainer(src), UnitsContainer(dst)
value = 10.
convert = self.ureg.convert
if isinstance(expected, string_types):
self.assertRaises(DimensionalityError, convert, value, src, dst)
if src != dst:
self.assertRaises(DimensionalityError, convert, value, dst, src)
else:
self.assertQuantityAlmostEqual(convert(value, src, dst),
expected, atol=0.001)
if src != dst:
self.assertQuantityAlmostEqual(convert(expected, dst, src),
value, atol=0.001)

View File

@ -0,0 +1,185 @@
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, print_function, absolute_import
import collections
from pint.testsuite import BaseTestCase
from pint.util import (string_preprocessor, find_shortest_path, matrix_to_string,
transpose, find_connected_nodes, ParserHelper)
class TestParseHelper(BaseTestCase):
def test_basic(self):
# Parse Helper ar mutables, so we build one everytime
x = lambda: ParserHelper(1, meter=2)
xp = lambda: ParserHelper(1, meter=2)
y = lambda: ParserHelper(2, meter=2)
self.assertEqual(x(), xp())
self.assertNotEqual(x(), y())
self.assertEqual(ParserHelper.from_string(''), ParserHelper())
self.assertEqual(repr(x()), "<ParserHelper(1, {'meter': 2})>")
self.assertEqual(ParserHelper(2), 2)
self.assertEqual(x(), dict(meter=2))
self.assertEqual(x(), 'meter ** 2')
self.assertNotEqual(y(), dict(meter=2))
self.assertNotEqual(y(), 'meter ** 2')
self.assertNotEqual(xp(), object())
def test_calculate(self):
# Parse Helper ar mutables, so we build one everytime
x = lambda: ParserHelper(1., meter=2)
y = lambda: ParserHelper(2., meter=-2)
z = lambda: ParserHelper(2., meter=2)
self.assertEqual(x() * 4., ParserHelper(4., meter=2))
self.assertEqual(x() * y(), ParserHelper(2.))
self.assertEqual(x() * 'second', ParserHelper(1., meter=2, second=1))
self.assertEqual(x() / 4., ParserHelper(0.25, meter=2))
self.assertEqual(x() / 'second', ParserHelper(1., meter=2, second=-1))
self.assertEqual(x() / z(), ParserHelper(0.5))
self.assertEqual(4. / z(), ParserHelper(2., meter=-2))
self.assertEqual('seconds' / z(), ParserHelper(0.5, seconds=1, meter=-2))
self.assertEqual(dict(seconds=1) / z(), ParserHelper(0.5, seconds=1, meter=-2))
class TestStringProcessor(BaseTestCase):
def _test(self, bef, aft):
for pattern in ('{0}', '+{0}+'):
b = pattern.format(bef)
a = pattern.format(aft)
self.assertEqual(string_preprocessor(b), a)
def test_square_cube(self):
self._test('bcd^3', 'bcd**3')
self._test('bcd^ 3', 'bcd** 3')
self._test('bcd ^3', 'bcd **3')
self._test('bcd squared', 'bcd**2')
self._test('bcd squared', 'bcd**2')
self._test('bcd cubed', 'bcd**3')
self._test('sq bcd', 'bcd**2')
self._test('square bcd', 'bcd**2')
self._test('cubic bcd', 'bcd**3')
self._test('bcd efg', 'bcd*efg')
def test_per(self):
self._test('miles per hour', 'miles/hour')
def test_numbers(self):
self._test('1,234,567', '1234567')
self._test('1e-24', '1e-24')
self._test('1e+24', '1e+24')
self._test('1e24', '1e24')
self._test('1E-24', '1E-24')
self._test('1E+24', '1E+24')
self._test('1E24', '1E24')
def test_space_multiplication(self):
self._test('bcd efg', 'bcd*efg')
self._test('bcd efg', 'bcd*efg')
self._test('1 hour', '1*hour')
self._test('1. hour', '1.*hour')
self._test('1.1 hour', '1.1*hour')
self._test('1E24 hour', '1E24*hour')
self._test('1E-24 hour', '1E-24*hour')
self._test('1E+24 hour', '1E+24*hour')
self._test('1.2E24 hour', '1.2E24*hour')
self._test('1.2E-24 hour', '1.2E-24*hour')
self._test('1.2E+24 hour', '1.2E+24*hour')
def test_joined_multiplication(self):
self._test('1hour', '1*hour')
self._test('1.hour', '1.*hour')
self._test('1.1hour', '1.1*hour')
self._test('1h', '1*h')
self._test('1.h', '1.*h')
self._test('1.1h', '1.1*h')
def test_names(self):
self._test('g_0', 'g_0')
self._test('g0', 'g0')
self._test('g', 'g')
self._test('water_60F', 'water_60F')
class TestGraph(BaseTestCase):
def test_start_not_in_graph(self):
g = collections.defaultdict(list)
g[1] = set((2,))
g[2] = set((3,))
self.assertIs(find_connected_nodes(g, 9), None)
def test_shortest_path(self):
g = collections.defaultdict(list)
g[1] = set((2,))
g[2] = set((3,))
p = find_shortest_path(g, 1, 2)
self.assertEqual(p, [1, 2])
p = find_shortest_path(g, 1, 3)
self.assertEqual(p, [1, 2, 3])
p = find_shortest_path(g, 3, 1)
self.assertIs(p, None)
g = collections.defaultdict(list)
g[1] = set((2,))
g[2] = set((3, 1))
g[3] = set((2,))
p = find_shortest_path(g, 1, 2)
self.assertEqual(p, [1, 2])
p = find_shortest_path(g, 1, 3)
self.assertEqual(p, [1, 2, 3])
p = find_shortest_path(g, 3, 1)
self.assertEqual(p, [3, 2, 1])
p = find_shortest_path(g, 2, 1)
self.assertEqual(p, [2, 1])
class TestMatrix(BaseTestCase):
def test_matrix_to_string(self):
self.assertEqual(matrix_to_string([[1, 2], [3, 4]],
row_headers=None,
col_headers=None),
'1\t2\n'
'3\t4')
self.assertEqual(matrix_to_string([[1, 2], [3, 4]],
row_headers=None,
col_headers=None,
fmtfun=lambda x: '{0:.2f}'.format(x)),
'1.00\t2.00\n'
'3.00\t4.00')
self.assertEqual(matrix_to_string([[1, 2], [3, 4]],
row_headers=['c', 'd'],
col_headers=None),
'c\t1\t2\n'
'd\t3\t4')
self.assertEqual(matrix_to_string([[1, 2], [3, 4]],
row_headers=None,
col_headers=['a', 'b']),
'a\tb\n'
'1\t2\n'
'3\t4')
self.assertEqual(matrix_to_string([[1, 2], [3, 4]],
row_headers=['c', 'd'],
col_headers=['a', 'b']),
'\ta\tb\n'
'c\t1\t2\n'
'd\t3\t4')
def test_transpose(self):
self.assertEqual(transpose([[1, 2], [3, 4]]), [[1, 3], [2, 4]])

1396
CadQuery/Libs/pint/unit.py Normal file

File diff suppressed because it is too large Load Diff

425
CadQuery/Libs/pint/util.py Normal file
View File

@ -0,0 +1,425 @@
# -*- coding: utf-8 -*-
"""
pint.util
~~~~~~~~~
Miscellaneous functions for pint.
:copyright: 2013 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import division, unicode_literals, print_function, absolute_import
import re
import operator
from numbers import Number
from fractions import Fraction
import logging
from token import STRING, NAME, OP
from tokenize import untokenize
from .compat import string_types, tokenizer, lru_cache, NullHandler, maketrans
logger = logging.getLogger(__name__)
logger.addHandler(NullHandler())
def matrix_to_string(matrix, row_headers=None, col_headers=None, fmtfun=lambda x: str(int(x))):
"""Takes a 2D matrix (as nested list) and returns a string.
"""
ret = []
if col_headers:
ret.append(('\t' if row_headers else '') + '\t'.join(col_headers))
if row_headers:
ret += [rh + '\t' + '\t'.join(fmtfun(f) for f in row)
for rh, row in zip(row_headers, matrix)]
else:
ret += ['\t'.join(fmtfun(f) for f in row)
for row in matrix]
return '\n'.join(ret)
def transpose(matrix):
"""Takes a 2D matrix (as nested list) and returns the transposed version.
"""
return [list(val) for val in zip(*matrix)]
def column_echelon_form(matrix, ntype=Fraction, transpose_result=False):
"""Calculates the column echelon form using Gaussian elimination.
:param matrix: a 2D matrix as nested list.
:param ntype: the numerical type to use in the calculation.
:param transpose_result: indicates if the returned matrix should be transposed.
:return: column echelon form, transformed identity matrix, swapped rows
"""
lead = 0
M = transpose(matrix)
_transpose = transpose if transpose_result else lambda x: x
rows, cols = len(M), len(M[0])
new_M = []
for row in M:
r = []
for x in row:
if isinstance(x, float):
x = ntype.from_float(x)
else:
x = ntype(x)
r.append(x)
new_M.append(r)
M = new_M
# M = [[ntype(x) for x in row] for row in M]
I = [[ntype(1) if n == nc else ntype(0) for nc in range(rows)] for n in range(rows)]
swapped = []
for r in range(rows):
if lead >= cols:
return _transpose(M), _transpose(I), swapped
i = r
while M[i][lead] == 0:
i += 1
if i != rows:
continue
i = r
lead += 1
if cols == lead:
return _transpose(M), _transpose(I), swapped
M[i], M[r] = M[r], M[i]
I[i], I[r] = I[r], I[i]
swapped.append(i)
lv = M[r][lead]
M[r] = [mrx / lv for mrx in M[r]]
I[r] = [mrx / lv for mrx in I[r]]
for i in range(rows):
if i == r:
continue
lv = M[i][lead]
M[i] = [iv - lv*rv for rv, iv in zip(M[r], M[i])]
I[i] = [iv - lv*rv for rv, iv in zip(I[r], I[i])]
lead += 1
return _transpose(M), _transpose(I), swapped
def pi_theorem(quantities, registry=None):
"""Builds dimensionless quantities using the Buckingham π theorem
:param quantities: mapping between variable name and units
:type quantities: dict
:return: a list of dimensionless quantities expressed as dicts
"""
# Preprocess input and build the dimensionality Matrix
quant = []
dimensions = set()
if registry is None:
getdim = lambda x: x
else:
getdim = registry.get_dimensionality
for name, value in quantities.items():
if isinstance(value, string_types):
value = ParserHelper.from_string(value)
if isinstance(value, dict):
dims = getdim(value)
elif not hasattr(value, 'dimensionality'):
dims = getdim(value)
else:
dims = value.dimensionality
if not registry and any(not key.startswith('[') for key in dims):
logger.warning('A non dimension was found and a registry was not provided. '
'Assuming that it is a dimension name: {0}.'.format(dims))
quant.append((name, dims))
dimensions = dimensions.union(dims.keys())
dimensions = list(dimensions)
# Calculate dimensionless quantities
M = [[dimensionality[dimension] for name, dimensionality in quant]
for dimension in dimensions]
M, identity, pivot = column_echelon_form(M, transpose_result=False)
# Collect results
# Make all numbers integers and minimize the number of negative exponents.
# Remove zeros
results = []
for rowm, rowi in zip(M, identity):
if any(el != 0 for el in rowm):
continue
max_den = max(f.denominator for f in rowi)
neg = -1 if sum(f < 0 for f in rowi) > sum(f > 0 for f in rowi) else 1
results.append(dict((q[0], neg * f.numerator * max_den / f.denominator)
for q, f in zip(quant, rowi) if f.numerator != 0))
return results
def solve_dependencies(dependencies):
"""Solve a dependency graph.
:param dependencies: dependency dictionary. For each key, the value is
an iterable indicating its dependencies.
:return: list of sets, each containing keys of independents tasks dependent
only of the previous tasks in the list.
"""
d = dict((key, set(dependencies[key])) for key in dependencies)
r = []
while d:
# values not in keys (items without dep)
t = set(i for v in d.values() for i in v) - set(d.keys())
# and keys without value (items without dep)
t.update(k for k, v in d.items() if not v)
# can be done right away
r.append(t)
# and cleaned up
d = dict(((k, v - t) for k, v in d.items() if v))
return r
def find_shortest_path(graph, start, end, path=None):
path = (path or []) + [start]
if start == end:
return path
if not start in graph:
return None
shortest = None
for node in graph[start]:
if node not in path:
newpath = find_shortest_path(graph, node, end, path)
if newpath:
if not shortest or len(newpath) < len(shortest):
shortest = newpath
return shortest
def find_connected_nodes(graph, start, visited=None):
if not start in graph:
return None
visited = (visited or set())
visited.add(start)
for node in graph[start]:
if node not in visited:
find_connected_nodes(graph, node, visited)
return visited
class ParserHelper(dict):
"""The ParserHelper stores in place the product of variables and
their respective exponent and implements the corresponding operations.
"""
__slots__ = ('scale', )
def __init__(self, scale=1, *args, **kwargs):
self.scale = scale
dict.__init__(self, *args, **kwargs)
@classmethod
def from_word(cls, input_word):
"""Creates a ParserHelper object with a single variable with exponent one.
Equivalent to: ParserHelper({'word': 1})
"""
ret = cls()
ret.add(input_word, 1)
return ret
@classmethod
def from_string(cls, input_string):
return cls._from_string(input_string).copy()
@classmethod
@lru_cache()
def _from_string(cls, input_string):
"""Parse linear expression mathematical units and return a quantity object.
"""
if not input_string:
return cls()
input_string = string_preprocessor(input_string)
if '[' in input_string:
input_string = input_string.replace('[', '__obra__').replace(']', '__cbra__')
reps = True
else:
reps = False
gen = tokenizer(input_string)
result = []
for toknum, tokval, _, _, _ in gen:
if toknum == NAME:
if not tokval:
continue
result.extend([
(NAME, 'L_'),
(OP, '('),
(STRING, '"' + tokval + '"'),
(OP, ')')
])
else:
result.append((toknum, tokval))
ret = eval(untokenize(result),
{'__builtins__': None},
{'L_': cls.from_word})
if isinstance(ret, Number):
return ParserHelper(ret)
if not reps:
return ret
return ParserHelper(ret.scale,
dict((key.replace('__obra__', '[').replace('__cbra__', ']'), value)
for key, value in ret.items()))
def copy(self):
return ParserHelper(scale=self.scale, **self)
def __missing__(self, key):
return 0.0
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.scale == other.scale and super(ParserHelper, self).__eq__(other)
elif isinstance(other, dict):
return self.scale == 1 and super(ParserHelper, self).__eq__(other)
elif isinstance(other, string_types):
return self == ParserHelper.from_string(other)
elif isinstance(other, Number):
return self.scale == other and not len(self)
else:
return False
def __ne__(self, other):
return not self.__eq__(other)
def add(self, key, value):
newval = self.__getitem__(key) + value
if newval:
self.__setitem__(key, newval)
else:
del self[key]
def operate(self, items, op=operator.iadd, cleanup=True):
for key, value in items:
self[key] = op(self[key], value)
if cleanup:
keys = [key for key, value in self.items() if value == 0]
for key in keys:
del self[key]
def __str__(self):
tmp = '{%s}' % ', '.join(["'{0}': {1}".format(key, value) for key, value in sorted(self.items())])
return '{0} {1}'.format(self.scale, tmp)
def __repr__(self):
tmp = '{%s}' % ', '.join(["'{0}': {1}".format(key, value) for key, value in sorted(self.items())])
return '<ParserHelper({0}, {1})>'.format(self.scale, tmp)
def __mul__(self, other):
if isinstance(other, string_types):
self.add(other, 1)
elif isinstance(other, Number):
self.scale *= other
elif isinstance(other, self.__class__):
self.scale *= other.scale
self.operate(other.items())
else:
self.operate(other.items())
return self
__imul__ = __mul__
__rmul__ = __mul__
def __pow__(self, other):
self.scale **= other
for key in self.keys():
self[key] *= other
return self
__ipow__ = __pow__
def __truediv__(self, other):
if isinstance(other, string_types):
self.add(other, -1)
elif isinstance(other, Number):
self.scale /= other
elif isinstance(other, self.__class__):
self.scale /= other.scale
self.operate(other.items(), operator.sub)
else:
self.operate(other.items(), operator.sub)
return self
__itruediv__ = __truediv__
__floordiv__ = __truediv__
def __rtruediv__(self, other):
self.__pow__(-1)
if isinstance(other, string_types):
self.add(other, 1)
elif isinstance(other, Number):
self.scale *= other
elif isinstance(other, self.__class__):
self.scale *= other.scale
self.operate(other.items(), operator.add)
else:
self.operate(other.items(), operator.add)
return self
#: List of regex substitution pairs.
_subs_re = [(r"([\w\.\-\+\*\\\^])\s+", r"\1 "), # merge multiple spaces
(r"({0}) squared", r"\1**2"), # Handle square and cube
(r"({0}) cubed", r"\1**3"),
(r"cubic ({0})", r"\1**3"),
(r"square ({0})", r"\1**2"),
(r"sq ({0})", r"\1**2"),
(r"\b([0-9]+\.?[0-9]*)(?=[e|E][a-zA-Z]|[a-df-zA-DF-Z])", r"\1*"), # Handle numberLetter for multiplication
(r"([\w\.\-])\s+(?=\w)", r"\1*"), # Handle space for multiplication
]
#: Compiles the regex and replace {0} by a regex that matches an identifier.
_subs_re = [(re.compile(a.format(r"[_a-zA-Z][_a-zA-Z0-9]*")), b) for a, b in _subs_re]
_pretty_table = maketrans('⁰¹²³⁴⁵⁶⁷⁸⁹·⁻', '0123456789*-')
_pretty_exp_re = re.compile(r"⁻?[⁰¹²³⁴⁵⁶⁷⁸⁹]+(?:\.[⁰¹²³⁴⁵⁶⁷⁸⁹]*)?")
def string_preprocessor(input_string):
input_string = input_string.replace(",", "")
input_string = input_string.replace(" per ", "/")
for a, b in _subs_re:
input_string = a.sub(b, input_string)
# Replace pretty format characters
for pretty_exp in _pretty_exp_re.findall(input_string):
exp = '**' + pretty_exp.translate(_pretty_table)
input_string = input_string.replace(pretty_exp, exp)
input_string = input_string.translate(_pretty_table)
# Handle caret exponentiation
input_string = input_string.replace("^", "**")
return input_string

View File

@ -12,10 +12,10 @@ ZIP = os.path.join(os.getcwd(), 'libs.zip')
if len(sys.argv) == 2 and sys.argv[1] == 'gen':
#--- gen zip file
import jedi, pep8, pyqode, pyqode.core, pyqode.python, pyqode.qt, pygments, frosted, pies, builtins, future, pyflakes, docutils
import jedi, pep8, pyqode, pyqode.core, pyqode.python, pyqode.qt, pygments, frosted, pies, builtins, future, pyflakes, docutils, pint
from qidle.system import embed_package_into_zip
embed_package_into_zip([jedi, pep8, pyqode, pyqode.core, pyqode.python,
pyqode.qt, pygments, pyflakes, builtins, future, docutils], ZIP)
pyqode.qt, pygments, pyflakes, builtins, future, docutils, pint], ZIP)
else:
# remove all pyqode path from sys.path (to make sure the package are
# imported from the zip archive)