-
Notifications
You must be signed in to change notification settings - Fork 474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Split Quantity into scalar and sequence classes #764
Closed
Closed
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
3ad6e39
create quantityscalar and sequence classes
andrewgsavage 0d0097d
add __array_function__
andrewgsavage cfc5d0d
Merge branch 'master' into split_quantity
andrewgsavage 431d5b4
replace _Q with BaseQuantity
andrewgsavage f62e946
change np ufuncs to check x2 is a BaseQuantity
andrewgsavage bbb44d6
revert changes in test_quantity
andrewgsavage d76171f
revert some more
andrewgsavage 30d542a
some more reverts
andrewgsavage 5b9e473
revert more
andrewgsavage c21bfbd
revert getattr
andrewgsavage def8348
__used -> _used
andrewgsavage 65905e0
fix path without _used
andrewgsavage 7fb3800
fix setitem
andrewgsavage e07e237
fix put
andrewgsavage f6373fb
some array manip tests
andrewgsavage 0aea9bc
remove broadcast
andrewgsavage 077d12b
atleast nd
andrewgsavage da9dcb8
squuze
andrewgsavage 2727d21
uprev numpy, disable less useful versions
andrewgsavage fef52dd
downrev numpy to one that may exist
andrewgsavage ba8cfe1
downrev numpy to one that may exist
andrewgsavage 2f507f0
test dev numpy
andrewgsavage 7c90ba7
test dev numpy
andrewgsavage f0b904e
pre release wheels
andrewgsavage 4123d14
few more funcs
andrewgsavage ca0ecfd
try to get tests green
andrewgsavage 3923c44
better way of skippping tests for other np versions
andrewgsavage 1f4cd7f
set up np version for dev versions
andrewgsavage 247700e
few more funcs
andrewgsavage 284fe70
remove unexpected failure
andrewgsavage 337e151
add more subclassed unexpected failure functions
andrewgsavage 2f741a3
organise np tests
andrewgsavage d16f820
add Joining arrays tests/funcs
andrewgsavage 0a84003
get unwrap workin
andrewgsavage 346e0b4
rationalise conversion helper funcs
andrewgsavage 67918ec
single implementation function
andrewgsavage afc7051
implement remaining subclass funcs
andrewgsavage e32e6e9
try testing np 1.16
andrewgsavage 4dcbe78
.
andrewgsavage 6c62a05
offset units
andrewgsavage a7f5841
Merge branch 'master' into split_quantity
andrewgsavage b57f012
add warning
andrewgsavage d3195d1
add warning
andrewgsavage d9ef27d
add warning
andrewgsavage ea6bebe
add warning
andrewgsavage aa66a07
add warning
andrewgsavage 5a528ad
Merge pull request #5 from andrewgsavage/ags/split_quantity2
andrewgsavage File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,7 +78,7 @@ def wrapped(self, *args, **kwargs): | |
|
||
|
||
@fix_str_conversions | ||
class _Quantity(PrettyIPython, SharedRegistryObject): | ||
class BaseQuantity(PrettyIPython, SharedRegistryObject): | ||
"""Implements a class to describe a physical quantity: | ||
the product of a numerical value and a unit of measurement. | ||
|
||
|
@@ -95,7 +95,9 @@ def __reduce__(self): | |
from . import _build_quantity | ||
return _build_quantity, (self.magnitude, self._units) | ||
|
||
def __new__(cls, value, units=None): | ||
|
||
@classmethod | ||
def _new(cls, value, units=None): | ||
if units is None: | ||
if isinstance(value, string_types): | ||
if value == '': | ||
|
@@ -132,18 +134,8 @@ def __new__(cls, value, units=None): | |
|
||
inst.__used = False | ||
inst.__handling = None | ||
# Only instances where the magnitude is iterable should have __iter__() | ||
if hasattr(inst._magnitude,"__iter__"): | ||
inst.__iter__ = cls._iter | ||
return inst | ||
|
||
def _iter(self): | ||
""" | ||
Will be become __iter__() for instances with iterable magnitudes | ||
""" | ||
# # Allow exception to propagate in case of non-iterable magnitude | ||
it_mag = iter(self.magnitude) | ||
return iter((self.__class__(mag, self._units) for mag in it_mag)) | ||
@property | ||
def debug_used(self): | ||
return self.__used | ||
|
@@ -825,7 +817,6 @@ def _imul_div(self, other, magnitude_op, units_op=None): | |
|
||
self._magnitude = magnitude_op(self._magnitude, other._magnitude) | ||
self._units = units_op(self._units, other._units) | ||
|
||
return self | ||
|
||
@check_implemented | ||
|
@@ -1395,42 +1386,6 @@ def __getattr__(self, item): | |
raise AttributeError("Neither Quantity object nor its magnitude ({}) " | ||
"has attribute '{}'".format(self._magnitude, item)) | ||
|
||
def __getitem__(self, key): | ||
try: | ||
value = self._magnitude[key] | ||
return self.__class__(value, self._units) | ||
except TypeError: | ||
raise TypeError("Neither Quantity object nor its magnitude ({})" | ||
"supports indexing".format(self._magnitude)) | ||
|
||
def __setitem__(self, key, value): | ||
try: | ||
if math.isnan(value): | ||
self._magnitude[key] = value | ||
return | ||
except (TypeError, DimensionalityError): | ||
pass | ||
|
||
try: | ||
if isinstance(value, self.__class__): | ||
factor = self.__class__(value.magnitude, value._units / self._units).to_root_units() | ||
else: | ||
factor = self.__class__(value, self._units ** (-1)).to_root_units() | ||
|
||
if isinstance(factor, self.__class__): | ||
if not factor.dimensionless: | ||
raise DimensionalityError(value, self.units, | ||
extra_msg='. Assign a quantity with the same dimensionality or ' | ||
'access the magnitude directly as ' | ||
'`obj.magnitude[%s] = %s`' % (key, value)) | ||
self._magnitude[key] = factor.magnitude | ||
else: | ||
self._magnitude[key] = factor | ||
|
||
except TypeError: | ||
raise TypeError("Neither Quantity object nor its magnitude ({})" | ||
"supports indexing".format(self._magnitude)) | ||
|
||
def tolist(self): | ||
units = self._units | ||
return [self.__class__(value, units).tolist() if isinstance(value, list) else self.__class__(value, units) | ||
|
@@ -1671,14 +1626,84 @@ def _ok_for_muldiv(self, no_offset_units=None): | |
def to_timedelta(self): | ||
return datetime.timedelta(microseconds=self.to('microseconds').magnitude) | ||
|
||
class QuantitySequenceMixin(object): | ||
def __getitem__(self, key): | ||
try: | ||
value = self._magnitude[key] | ||
return self.__class__(value, self._units) | ||
except TypeError: | ||
raise TypeError("Neither Quantity object nor its magnitude ({})" | ||
"supports indexing".format(self._magnitude)) | ||
|
||
def __setitem__(self, key, value): | ||
try: | ||
if math.isnan(value): | ||
self._magnitude[key] = value | ||
return | ||
except (TypeError, DimensionalityError): | ||
pass | ||
|
||
try: | ||
if isinstance(value, self.__class__): | ||
factor = self.__class__(value.magnitude, value._units / self._units).to_root_units() | ||
else: | ||
factor = self.__class__(value, self._units ** (-1)).to_root_units() | ||
|
||
def build_quantity_class(registry, force_ndarray=False): | ||
if isinstance(factor, self.__class__): | ||
if not factor.dimensionless: | ||
raise DimensionalityError(value, self.units, | ||
extra_msg='. Assign a quantity with the same dimensionality or ' | ||
'access the magnitude directly as ' | ||
'`obj.magnitude[%s] = %s`' % (key, value)) | ||
self._magnitude[key] = factor.magnitude | ||
else: | ||
self._magnitude[key] = factor | ||
|
||
except TypeError: | ||
raise TypeError("Neither Quantity object nor its magnitude ({})" | ||
"supports indexing".format(self._magnitude)) | ||
def __iter__(self): | ||
""" | ||
Will be become __iter__() for instances with iterable magnitudes | ||
""" | ||
# # Allow exception to propagate in case of non-iterable magnitude | ||
it_mag = iter(self.magnitude) | ||
return iter((self.__class__(mag, self._units) for mag in it_mag)) | ||
|
||
class Quantity(_Quantity): | ||
pass | ||
|
||
def build_quantity_class(registry, force_ndarray=False): | ||
|
||
class Quantity(BaseQuantity): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or this is class to be used when calling |
||
def __new__(cls, value, units=None): | ||
if units is None: | ||
if isinstance(value, string_types): | ||
if value == '': | ||
raise ValueError('Expression to parse as Quantity cannot ' | ||
'be an empty string.') | ||
inst = cls._REGISTRY.parse_expression(value) | ||
return cls.__new__(cls, inst) | ||
elif isinstance(value, cls): | ||
inst = copy.copy(value) | ||
else: | ||
inst = object.__new__(cls) | ||
inst._magnitude = _to_magnitude(value, inst.force_ndarray) | ||
inst._units = UnitsContainer() | ||
return inst | ||
if hasattr(value, "__iter__"): | ||
return QuantitySequence._new(value,units) | ||
else: | ||
return QuantityScalar._new(value,units) | ||
|
||
Quantity._REGISTRY = registry | ||
Quantity.force_ndarray = force_ndarray | ||
|
||
|
||
class QuantityScalar(Quantity): | ||
def __new__(cls, value, units=None): | ||
inst = Quantity.__new__(Quantity, value, units) | ||
return inst | ||
|
||
class QuantitySequence(Quantity,QuantitySequenceMixin): | ||
def __new__(cls, value, units=None): | ||
inst = Quantity.__new__(Quantity, value, units) | ||
return inst | ||
return Quantity |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this classe "public" (i.e. no underscore)? Is this the class users should check against when using
isinstance
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hadn't thought of this when going through it!
It should be used when the user does know the UnitRegistry. In the current version users should be checking with _Quantity (as done in pint-pandas)
Using isinstance with a Quantity from one UnitRegistry and another UnitRegistry yields false:
'''
ureg=pint.UnitRegistry()
ureg2 = pint.UnitRegistry()
isinstance(my_array,ureg2.Quantity)
False
'''
Should this be public?