Embedded the Pint library for units with the other libraries.
This commit is contained in:
parent
3e00cf6ffe
commit
8f36ee4fac
125
CadQuery/Libs/pint/__init__.py
Normal file
125
CadQuery/Libs/pint/__init__.py
Normal 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()
|
123
CadQuery/Libs/pint/compat/__init__.py
Normal file
123
CadQuery/Libs/pint/compat/__init__.py
Normal 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
|
||||
|
153
CadQuery/Libs/pint/compat/chainmap.py
Normal file
153
CadQuery/Libs/pint/compat/chainmap.py
Normal 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()
|
177
CadQuery/Libs/pint/compat/lrucache.py
Normal file
177
CadQuery/Libs/pint/compat/lrucache.py
Normal 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
|
32
CadQuery/Libs/pint/compat/nullhandler.py
Normal file
32
CadQuery/Libs/pint/compat/nullhandler.py
Normal 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
|
136
CadQuery/Libs/pint/compat/transformdict.py
Normal file
136
CadQuery/Libs/pint/compat/transformdict.py
Normal 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))
|
51
CadQuery/Libs/pint/constants_en.txt
Normal file
51
CadQuery/Libs/pint/constants_en.txt
Normal 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
|
246
CadQuery/Libs/pint/context.py
Normal file
246
CadQuery/Libs/pint/context.py
Normal 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)
|
350
CadQuery/Libs/pint/default_en.txt
Normal file
350
CadQuery/Libs/pint/default_en.txt
Normal 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
|
197
CadQuery/Libs/pint/formatting.py
Normal file
197
CadQuery/Libs/pint/formatting.py
Normal 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
|
101
CadQuery/Libs/pint/measurement.py
Normal file
101
CadQuery/Libs/pint/measurement.py
Normal 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 = '±'
|
||||
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)
|
||||
|
||||
|
||||
|
1249
CadQuery/Libs/pint/quantity.py
Normal file
1249
CadQuery/Libs/pint/quantity.py
Normal file
File diff suppressed because it is too large
Load Diff
138
CadQuery/Libs/pint/testsuite/__init__.py
Normal file
138
CadQuery/Libs/pint/testsuite/__init__.py
Normal 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())
|
||||
|
33
CadQuery/Libs/pint/testsuite/helpers.py
Normal file
33
CadQuery/Libs/pint/testsuite/helpers.py
Normal 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.')
|
152
CadQuery/Libs/pint/testsuite/parameterized.py
Normal file
152
CadQuery/Libs/pint/testsuite/parameterized.py
Normal 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
|
632
CadQuery/Libs/pint/testsuite/test_contexts.py
Normal file
632
CadQuery/Libs/pint/testsuite/test_contexts.py
Normal 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)
|
43
CadQuery/Libs/pint/testsuite/test_formatter.py
Normal file
43
CadQuery/Libs/pint/testsuite/test_formatter.py
Normal 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')
|
473
CadQuery/Libs/pint/testsuite/test_issues.py
Normal file
473
CadQuery/Libs/pint/testsuite/test_issues.py
Normal 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)
|
160
CadQuery/Libs/pint/testsuite/test_measurement.py
Normal file
160
CadQuery/Libs/pint/testsuite/test_measurement.py
Normal 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 ± 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 ± 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 ± 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 ± 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 ± 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)
|
441
CadQuery/Libs/pint/testsuite/test_numpy.py
Normal file
441
CadQuery/Libs/pint/testsuite/test_numpy.py
Normal 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)
|
44
CadQuery/Libs/pint/testsuite/test_pitheorem.py
Normal file
44
CadQuery/Libs/pint/testsuite/test_pitheorem.py
Normal 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}])
|
995
CadQuery/Libs/pint/testsuite/test_quantity.py
Normal file
995
CadQuery/Libs/pint/testsuite/test_quantity.py
Normal 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)
|
676
CadQuery/Libs/pint/testsuite/test_umath.py
Normal file
676
CadQuery/Libs/pint/testsuite/test_umath.py
Normal 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))
|
642
CadQuery/Libs/pint/testsuite/test_unit.py
Normal file
642
CadQuery/Libs/pint/testsuite/test_unit.py
Normal 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)
|
185
CadQuery/Libs/pint/testsuite/test_util.py
Normal file
185
CadQuery/Libs/pint/testsuite/test_util.py
Normal 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
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
425
CadQuery/Libs/pint/util.py
Normal 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
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user