6af3d7a01a93691bc437250dbf62b6325603e2d0
1 # The MIT License (MIT)
3 # Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 from bt2
import native_bt
, object, utils
24 import collections
.abc
32 def _handle_status(status
, obj_name
):
36 if status
== native_bt
.VALUE_STATUS_FROZEN
:
37 raise bt2
.FrozenError('{} value object is frozen'.format(obj_name
))
38 elif status
== native_bt
.VALUE_STATUS_INVAL
:
39 # In practice, this should never happen, because arguments
40 # should always be validated in this Python module before
41 # calling the native functions.
42 raise ValueError('unexpected invalid argument')
44 # In practice, this should never happen, because arguments
45 # should always be validated in this Python module before
46 # calling the native functions.
47 raise RuntimeError('unexpected error')
50 def _create_from_ptr(ptr
):
51 if ptr
is None or ptr
== native_bt
.value_null
:
54 typeid
= native_bt
.value_get_type(ptr
)
55 return _TYPE_TO_OBJ
[typeid
]._create
_from
_ptr
(ptr
)
58 def create_value(value
):
63 if isinstance(value
, _Value
):
66 if isinstance(value
, bool):
67 return BoolValue(value
)
69 if isinstance(value
, int):
70 return IntegerValue(value
)
72 if isinstance(value
, float):
73 return FloatValue(value
)
75 if isinstance(value
, str):
76 return StringValue(value
)
79 return MapValue(value
)
84 return ArrayValue(value
)
88 raise TypeError("cannot create value object from '{}' object".format(value
.__class
__.__name
__))
91 class _Value(object._Object
, object._Freezable
, metaclass
=abc
.ABCMeta
):
92 def __init__(self
, ptr
):
95 def __eq__(self
, other
):
97 # self is never the null value object
100 # try type-specific comparison first
101 spec_eq
= self
._spec
_eq
(other
)
103 if spec_eq
is not None:
106 if not isinstance(other
, _Value
):
107 # not comparing apples to apples
110 # fall back to native comparison function
111 return native_bt
.value_compare(self
._ptr
, other
._ptr
)
113 def __ne__(self
, other
):
114 return not (self
== other
)
117 def _spec_eq(self
, other
):
120 def _handle_status(self
, status
):
121 _handle_status(status
, self
._NAME
)
123 def _check_create_status(self
, ptr
):
125 raise bt2
.CreationError('cannot create {} value object'.format(self
._NAME
.lower()))
127 def _is_frozen(self
):
128 return native_bt
.value_is_frozen(self
._ptr
)
131 status
= native_bt
.value_freeze(self
._ptr
)
132 self
._handle
_status
(status
)
137 return self
.__class
__(self
.value
)
139 def __deepcopy__(self
, memo
):
140 copy
= self
.__copy
__()
141 memo
[id(self
)] = copy
145 @functools.total_ordering
146 class _NumericValue(_Value
, _BasicCopy
):
148 def _extract_value(other
):
149 if isinstance(other
, _NumericValue
):
152 if other
is True or other
is False:
155 if isinstance(other
, numbers
.Integral
):
158 if isinstance(other
, numbers
.Real
):
161 if isinstance(other
, numbers
.Complex
):
162 return complex(other
)
164 raise TypeError("'{}' object is not a number object".format(other
.__class
__.__name
__))
167 return int(self
.value
)
170 return float(self
.value
)
173 return str(self
.value
)
175 def __lt__(self
, other
):
176 if not isinstance(other
, numbers
.Number
):
177 raise TypeError('unorderable types: {}() < {}()'.format(self
.__class
__.__name
__,
178 other
.__class
__.__name
__))
180 return self
.value
< float(other
)
182 def __le__(self
, other
):
183 if not isinstance(other
, numbers
.Number
):
184 raise TypeError('unorderable types: {}() <= {}()'.format(self
.__class
__.__name
__,
185 other
.__class
__.__name
__))
187 return self
.value
<= float(other
)
189 def _spec_eq(self
, other
):
192 def __eq__(self
, other
):
193 if not isinstance(other
, numbers
.Number
):
196 return self
.value
== complex(other
)
198 def __rmod__(self
, other
):
199 return self
._extract
_value
(other
) % self
.value
201 def __mod__(self
, other
):
202 return self
.value
% self
._extract
_value
(other
)
204 def __rfloordiv__(self
, other
):
205 return self
._extract
_value
(other
) // self
.value
207 def __floordiv__(self
, other
):
208 return self
.value
// self
._extract
_value
(other
)
210 def __round__(self
, ndigits
=None):
212 return round(self
.value
)
214 return round(self
.value
, ndigits
)
217 return math
.ceil(self
.value
)
220 return math
.floor(self
.value
)
223 return int(self
.value
)
226 return abs(self
.value
)
228 def __add__(self
, other
):
229 return self
.value
+ self
._extract
_value
(other
)
231 def __radd__(self
, other
):
232 return self
.__add
__(other
)
240 def __mul__(self
, other
):
241 return self
.value
* self
._extract
_value
(other
)
243 def __rmul__(self
, other
):
244 return self
.__mul
__(other
)
246 def __truediv__(self
, other
):
247 return self
.value
/ self
._extract
_value
(other
)
249 def __rtruediv__(self
, other
):
250 return self
._extract
_value
(other
) / self
.value
252 def __pow__(self
, exponent
):
253 return self
.value
** self
._extract
_value
(exponent
)
255 def __rpow__(self
, base
):
256 return self
._extract
_value
(base
) ** self
.value
258 def __iadd__(self
, other
):
259 self
.value
= self
+ other
262 def __isub__(self
, other
):
263 self
.value
= self
- other
266 def __imul__(self
, other
):
267 self
.value
= self
* other
270 def __itruediv__(self
, other
):
271 self
.value
= self
/ other
274 def __ifloordiv__(self
, other
):
275 self
.value
= self
// other
278 def __imod__(self
, other
):
279 self
.value
= self
% other
282 def __ipow__(self
, other
):
283 self
.value
= self
** other
287 class _IntegralValue(_NumericValue
, numbers
.Integral
):
288 def __lshift__(self
, other
):
289 return self
.value
<< self
._extract
_value
(other
)
291 def __rlshift__(self
, other
):
292 return self
._extract
_value
(other
) << self
.value
294 def __rshift__(self
, other
):
295 return self
.value
>> self
._extract
_value
(other
)
297 def __rrshift__(self
, other
):
298 return self
._extract
_value
(other
) >> self
.value
300 def __and__(self
, other
):
301 return self
.value
& self
._extract
_value
(other
)
303 def __rand__(self
, other
):
304 return self
._extract
_value
(other
) & self
.value
306 def __xor__(self
, other
):
307 return self
.value ^ self
._extract
_value
(other
)
309 def __rxor__(self
, other
):
310 return self
._extract
_value
(other
) ^ self
.value
312 def __or__(self
, other
):
313 return self
.value | self
._extract
_value
(other
)
315 def __ror__(self
, other
):
316 return self
._extract
_value
(other
) | self
.value
318 def __invert__(self
):
321 def __ilshift__(self
, other
):
322 self
.value
= self
<< other
325 def __irshift__(self
, other
):
326 self
.value
= self
>> other
329 def __iand__(self
, other
):
330 self
.value
= self
& other
333 def __ixor__(self
, other
):
334 self
.value
= self ^ other
337 def __ior__(self
, other
):
338 self
.value
= self | other
342 class _RealValue(_NumericValue
, numbers
.Real
):
346 class BoolValue(_Value
, _BasicCopy
):
349 def __init__(self
, value
=None):
351 ptr
= native_bt
.value_bool_create()
353 ptr
= native_bt
.value_bool_create_init(self
._value
_to
_bool
(value
))
355 self
._check
_create
_status
(ptr
)
356 super().__init
__(ptr
)
358 def _spec_eq(self
, other
):
359 if isinstance(other
, numbers
.Number
):
360 return self
.value
== bool(other
)
366 return str(self
.value
)
368 def _value_to_bool(self
, value
):
369 if isinstance(value
, BoolValue
):
372 if not isinstance(value
, bool):
373 raise TypeError("'{}' object is not a 'bool' or 'BoolValue' object".format(value
.__class
__))
379 status
, value
= native_bt
.value_bool_get(self
._ptr
)
380 self
._handle
_status
(status
)
384 def value(self
, value
):
385 status
= native_bt
.value_bool_set(self
._ptr
, self
._value
_to
_bool
(value
))
386 self
._handle
_status
(status
)
389 class IntegerValue(_IntegralValue
):
392 def __init__(self
, value
=None):
394 ptr
= native_bt
.value_integer_create()
396 ptr
= native_bt
.value_integer_create_init(self
._value
_to
_int
(value
))
398 self
._check
_create
_status
(ptr
)
399 super().__init
__(ptr
)
401 def _value_to_int(self
, value
):
402 if not isinstance(value
, numbers
.Real
):
403 raise TypeError('expecting a number object')
406 utils
._check
_int
64(value
)
411 status
, value
= native_bt
.value_integer_get(self
._ptr
)
412 self
._handle
_status
(status
)
416 def value(self
, value
):
417 status
= native_bt
.value_integer_set(self
._ptr
, self
._value
_to
_int
(value
))
418 self
._handle
_status
(status
)
421 class FloatValue(_RealValue
):
422 _NAME
= 'Floating point number'
424 def __init__(self
, value
=None):
426 ptr
= native_bt
.value_float_create()
428 value
= self
._value
_to
_float
(value
)
429 ptr
= native_bt
.value_float_create_init(value
)
431 self
._check
_create
_status
(ptr
)
432 super().__init
__(ptr
)
434 def _value_to_float(self
, value
):
435 if not isinstance(value
, numbers
.Real
):
436 raise TypeError("expecting a real number object")
442 status
, value
= native_bt
.value_float_get(self
._ptr
)
443 self
._handle
_status
(status
)
447 def value(self
, value
):
448 value
= self
._value
_to
_float
(value
)
449 status
= native_bt
.value_float_set(self
._ptr
, value
)
450 self
._handle
_status
(status
)
453 @functools.total_ordering
454 class StringValue(_BasicCopy
, collections
.abc
.Sequence
, _Value
):
457 def __init__(self
, value
=None):
459 ptr
= native_bt
.value_string_create()
461 ptr
= native_bt
.value_string_create_init(self
._value
_to
_str
(value
))
463 self
._check
_create
_status
(ptr
)
464 super().__init
__(ptr
)
466 def _value_to_str(self
, value
):
467 if isinstance(value
, self
.__class
__):
470 utils
._check
_str
(value
)
475 status
, value
= native_bt
.value_string_get(self
._ptr
)
476 self
._handle
_status
(status
)
480 def value(self
, value
):
481 status
= native_bt
.value_string_set(self
._ptr
, self
._value
_to
_str
(value
))
482 self
._handle
_status
(status
)
484 def _spec_eq(self
, other
):
486 return self
.value
== self
._value
_to
_str
(other
)
490 def __le__(self
, other
):
491 return self
.value
<= self
._value
_to
_str
(other
)
493 def __lt__(self
, other
):
494 return self
.value
< self
._value
_to
_str
(other
)
497 return bool(self
.value
)
502 def __getitem__(self
, index
):
503 return self
.value
[index
]
506 return len(self
.value
)
508 def __iadd__(self
, value
):
509 curvalue
= self
.value
510 curvalue
+= self
._value
_to
_str
(value
)
511 self
.value
= curvalue
517 return len(self
) != 0
520 return self
.__class
__(self
)
522 def __deepcopy__(self
, memo
):
523 ptr
= native_bt
.value_copy(self
._ptr
)
526 fmt
= 'unexpected error: cannot deep-copy {} value object'
527 raise RuntimeError(fmt
.format(self
._NAME
))
529 copy
= self
.__class
__._create
_from
_ptr
(ptr
)
530 memo
[id(self
)] = copy
533 def __delitem__(self
, index
):
534 raise NotImplementedError
537 class ArrayValue(_Container
, collections
.abc
.MutableSequence
, _Value
):
540 def __init__(self
, value
=None):
541 ptr
= native_bt
.value_array_create()
542 self
._check
_create
_status
(ptr
)
543 super().__init
__(ptr
)
545 # Python will raise a TypeError if there's anything wrong with
546 # the iterable protocol.
547 if value
is not None:
551 def _spec_eq(self
, other
):
553 if len(self
) != len(other
):
557 for self_elem
, other_elem
in zip(self
, other
):
558 if self_elem
!= other_elem
:
566 size
= native_bt
.value_array_size(self
._ptr
)
567 self
._handle
_status
(size
)
570 def _check_index(self
, index
):
571 # TODO: support slices also
572 if not isinstance(index
, numbers
.Integral
):
573 raise TypeError("'{}' object is not an integral number object: invalid index".format(index
.__class
__.__name
__))
577 if index
< 0 or index
>= len(self
):
578 raise IndexError('array value object index is out of range')
580 def __getitem__(self
, index
):
581 self
._check
_index
(index
)
582 ptr
= native_bt
.value_array_get(self
._ptr
, index
)
585 raise RuntimeError('unexpected error: cannot get array value object element')
587 return _create_from_ptr(ptr
)
589 def __setitem__(self
, index
, value
):
590 self
._check
_index
(index
)
591 value
= create_value(value
)
594 ptr
= native_bt
.value_null
598 status
= native_bt
.value_array_set(self
._ptr
, index
, ptr
)
599 self
._handle
_status
(status
)
601 def append(self
, value
):
602 value
= create_value(value
)
605 ptr
= native_bt
.value_null
609 status
= native_bt
.value_array_append(self
._ptr
, ptr
)
610 self
._handle
_status
(status
)
612 def __iadd__(self
, iterable
):
613 # Python will raise a TypeError if there's anything wrong with
614 # the iterable protocol.
615 for elem
in iterable
:
624 if isinstance(elem
, StringValue
):
625 strings
.append(repr(elem
.value
))
627 strings
.append(str(elem
))
629 return '[{}]'.format(', '.join(strings
))
631 def insert(self
, value
):
632 raise NotImplementedError
635 class _MapValueKeyIterator(collections
.abc
.Iterator
):
636 def __init__(self
, map_obj
):
637 self
._map
_obj
= map_obj
639 keys_ptr
= native_bt
.value_map_get_keys_private(map_obj
._ptr
)
642 raise RuntimeError('unexpected error: cannot get map value object keys')
644 self
._keys
= _create_from_ptr(keys_ptr
)
647 if self
._at
== len(self
._map
_obj
):
650 key
= self
._keys
[self
._at
]
655 class MapValue(_Container
, collections
.abc
.MutableMapping
, _Value
):
658 def __init__(self
, value
=None):
659 ptr
= native_bt
.value_map_create()
660 self
._check
_create
_status
(ptr
)
661 super().__init
__(ptr
)
663 # Python will raise a TypeError if there's anything wrong with
664 # the iterable/mapping protocol.
665 if value
is not None:
666 for key
, elem
in value
.items():
669 def __eq__(self
, other
):
670 return _Value
.__eq
__(self
, other
)
672 def __ne__(self
, other
):
673 return _Value
.__ne
__(self
, other
)
675 def _spec_eq(self
, other
):
677 if len(self
) != len(other
):
681 for self_key
in self
:
682 if self_key
not in other
:
685 self_value
= self
[self_key
]
686 other_value
= other
[self_key
]
688 if self_value
!= other_value
:
696 size
= native_bt
.value_map_size(self
._ptr
)
697 self
._handle
_status
(size
)
700 def __contains__(self
, key
):
701 self
._check
_key
_type
(key
)
702 return native_bt
.value_map_has_key(self
._ptr
, key
)
704 def _check_key_type(self
, key
):
705 utils
._check
_str
(key
)
707 def _check_key(self
, key
):
711 def __getitem__(self
, key
):
713 ptr
= native_bt
.value_map_get(self
._ptr
, key
)
716 raise RuntimeError('unexpected error: cannot get map value object element')
718 return _create_from_ptr(ptr
)
721 return _MapValueKeyIterator(self
)
723 def __setitem__(self
, key
, value
):
724 self
._check
_key
_type
(key
)
725 value
= create_value(value
)
728 ptr
= native_bt
.value_null
732 status
= native_bt
.value_map_insert(self
._ptr
, key
, ptr
)
733 self
._handle
_status
(status
)
738 for key
, elem
in self
.items():
739 if isinstance(elem
, StringValue
):
740 value
= repr(elem
.value
)
744 strings
.append('{}: {}'.format(repr(key
), value
))
746 return '{{{}}}'.format(', '.join(strings
))
750 native_bt
.VALUE_TYPE_BOOL
: BoolValue
,
751 native_bt
.VALUE_TYPE_INTEGER
: IntegerValue
,
752 native_bt
.VALUE_TYPE_FLOAT
: FloatValue
,
753 native_bt
.VALUE_TYPE_STRING
: StringValue
,
754 native_bt
.VALUE_TYPE_ARRAY
: ArrayValue
,
755 native_bt
.VALUE_TYPE_MAP
: MapValue
,
This page took 0.045086 seconds and 4 git commands to generate.