1 # The MIT License (MIT)
3 # Copyright (c) 2017 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 _create_from_ptr_template(ptr
, object_map
):
36 # bt_value_null is translated to None. However, we are given a reference
37 # to it that we are not going to manage anymore, since we don't create a
38 # Python wrapper for it. Therefore put that reference immediately.
39 if ptr
== native_bt
.value_null
:
43 typeid
= native_bt
.value_get_type(ptr
)
44 return object_map
[typeid
]._create
_from
_ptr
(ptr
)
47 def _create_from_ptr(ptr
):
48 return _create_from_ptr_template(ptr
, _TYPE_TO_OBJ
)
51 def _create_from_const_ptr(ptr
):
52 return _create_from_ptr_template(ptr
, _TYPE_TO_CONST_OBJ
)
55 def _create_from_ptr_and_get_ref_template(ptr
, object_map
):
56 if ptr
is None or ptr
== native_bt
.value_null
:
59 typeid
= native_bt
.value_get_type(ptr
)
60 return object_map
[typeid
]._create
_from
_ptr
_and
_get
_ref
(ptr
)
63 def _create_from_ptr_and_get_ref(ptr
):
64 return _create_from_ptr_and_get_ref_template(ptr
, _TYPE_TO_OBJ
)
67 def _create_from_const_ptr_and_get_ref(ptr
):
68 return _create_from_ptr_and_get_ref_template(ptr
, _TYPE_TO_CONST_OBJ
)
71 def create_value(value
):
76 if isinstance(value
, _Value
):
79 if isinstance(value
, bool):
80 return BoolValue(value
)
82 if isinstance(value
, numbers
.Integral
):
83 return SignedIntegerValue(value
)
85 if isinstance(value
, numbers
.Real
):
86 return RealValue(value
)
88 if isinstance(value
, str):
89 return StringValue(value
)
91 if isinstance(value
, collections
.abc
.Sequence
):
92 return ArrayValue(value
)
94 if isinstance(value
, collections
.abc
.Mapping
):
95 return MapValue(value
)
98 "cannot create value object from '{}' object".format(value
.__class
__.__name
__)
102 class _ValueConst(object._SharedObject
, metaclass
=abc
.ABCMeta
):
103 _get_ref
= staticmethod(native_bt
.value_get_ref
)
104 _put_ref
= staticmethod(native_bt
.value_put_ref
)
105 _create_value_from_ptr
= staticmethod(_create_from_const_ptr
)
106 _create_value_from_ptr_and_get_ref
= staticmethod(
107 _create_from_const_ptr_and_get_ref
110 def __ne__(self
, other
):
111 return not (self
== other
)
113 def _check_create_status(self
, ptr
):
115 raise bt2
._MemoryError(
116 'cannot create {} value object'.format(self
._NAME
.lower())
120 class _Value(_ValueConst
):
121 _create_value_from_ptr
= staticmethod(_create_from_ptr
)
122 _create_value_from_ptr_and_get_ref
= staticmethod(_create_from_ptr_and_get_ref
)
125 @functools.total_ordering
126 class _NumericValueConst(_ValueConst
):
128 def _extract_value(other
):
129 if isinstance(other
, _BoolValueConst
) or isinstance(other
, bool):
132 if isinstance(other
, numbers
.Integral
):
135 if isinstance(other
, numbers
.Real
):
138 if isinstance(other
, numbers
.Complex
):
139 return complex(other
)
142 "'{}' object is not a number object".format(other
.__class
__.__name
__)
146 return int(self
._value
)
149 return float(self
._value
)
152 return repr(self
._value
)
154 def __lt__(self
, other
):
155 return self
._value
< self
._extract
_value
(other
)
157 def __eq__(self
, other
):
159 return self
._value
== self
._extract
_value
(other
)
163 def __rmod__(self
, other
):
164 return self
._extract
_value
(other
) % self
._value
166 def __mod__(self
, other
):
167 return self
._value
% self
._extract
_value
(other
)
169 def __rfloordiv__(self
, other
):
170 return self
._extract
_value
(other
) // self
._value
172 def __floordiv__(self
, other
):
173 return self
._value
// self
._extract
_value
(other
)
175 def __round__(self
, ndigits
=None):
177 return round(self
._value
)
179 return round(self
._value
, ndigits
)
182 return math
.ceil(self
._value
)
185 return math
.floor(self
._value
)
188 return int(self
._value
)
191 return abs(self
._value
)
193 def __add__(self
, other
):
194 return self
._value
+ self
._extract
_value
(other
)
196 def __radd__(self
, other
):
197 return self
.__add
__(other
)
205 def __mul__(self
, other
):
206 return self
._value
* self
._extract
_value
(other
)
208 def __rmul__(self
, other
):
209 return self
.__mul
__(other
)
211 def __truediv__(self
, other
):
212 return self
._value
/ self
._extract
_value
(other
)
214 def __rtruediv__(self
, other
):
215 return self
._extract
_value
(other
) / self
._value
217 def __pow__(self
, exponent
):
218 return self
._value
** self
._extract
_value
(exponent
)
220 def __rpow__(self
, base
):
221 return self
._extract
_value
(base
) ** self
._value
224 class _NumericValue(_NumericValueConst
, _Value
):
228 class _IntegralValueConst(_NumericValueConst
, numbers
.Integral
):
229 def __lshift__(self
, other
):
230 return self
._value
<< self
._extract
_value
(other
)
232 def __rlshift__(self
, other
):
233 return self
._extract
_value
(other
) << self
._value
235 def __rshift__(self
, other
):
236 return self
._value
>> self
._extract
_value
(other
)
238 def __rrshift__(self
, other
):
239 return self
._extract
_value
(other
) >> self
._value
241 def __and__(self
, other
):
242 return self
._value
& self
._extract
_value
(other
)
244 def __rand__(self
, other
):
245 return self
._extract
_value
(other
) & self
._value
247 def __xor__(self
, other
):
248 return self
._value ^ self
._extract
_value
(other
)
250 def __rxor__(self
, other
):
251 return self
._extract
_value
(other
) ^ self
._value
253 def __or__(self
, other
):
254 return self
._value | self
._extract
_value
(other
)
256 def __ror__(self
, other
):
257 return self
._extract
_value
(other
) | self
._value
259 def __invert__(self
):
263 class _IntegralValue(_IntegralValueConst
, _NumericValue
):
267 class _BoolValueConst(_IntegralValueConst
):
268 _NAME
= 'Const boolean'
274 return repr(self
._value
)
278 value
= native_bt
.value_bool_get(self
._ptr
)
282 class BoolValue(_BoolValueConst
, _IntegralValue
):
285 def __init__(self
, value
=None):
287 ptr
= native_bt
.value_bool_create()
289 ptr
= native_bt
.value_bool_create_init(self
._value
_to
_bool
(value
))
291 self
._check
_create
_status
(ptr
)
292 super().__init
__(ptr
)
295 def _value_to_bool(cls
, value
):
296 if isinstance(value
, _BoolValueConst
):
299 if not isinstance(value
, bool):
301 "'{}' object is not a 'bool', 'BoolValue', or '_BoolValueConst' object".format(
308 def _set_value(self
, value
):
309 native_bt
.value_bool_set(self
._ptr
, self
._value
_to
_bool
(value
))
311 value
= property(fset
=_set_value
)
314 class _IntegerValueConst(_IntegralValueConst
):
317 return self
._get
_value
(self
._ptr
)
320 class _IntegerValue(_IntegerValueConst
, _IntegralValue
):
321 def __init__(self
, value
=None):
323 ptr
= self
._create
_default
_value
()
325 ptr
= self
._create
_value
(self
._value
_to
_int
(value
))
327 self
._check
_create
_status
(ptr
)
328 super().__init
__(ptr
)
331 def _value_to_int(cls
, value
):
332 if not isinstance(value
, numbers
.Integral
):
333 raise TypeError('expecting an integral number object')
336 cls
._check
_int
_range
(value
)
339 def _prop_set_value(self
, value
):
340 self
._set
_value
(self
._ptr
, self
._value
_to
_int
(value
))
342 value
= property(fset
=_prop_set_value
)
345 class _UnsignedIntegerValueConst(_IntegerValueConst
):
346 _NAME
= 'Const unsigned integer'
347 _get_value
= staticmethod(native_bt
.value_integer_unsigned_get
)
350 class UnsignedIntegerValue(_UnsignedIntegerValueConst
, _IntegerValue
):
351 _NAME
= 'Unsigned integer'
352 _check_int_range
= staticmethod(utils
._check
_uint
64)
353 _create_default_value
= staticmethod(native_bt
.value_integer_unsigned_create
)
354 _create_value
= staticmethod(native_bt
.value_integer_unsigned_create_init
)
355 _set_value
= staticmethod(native_bt
.value_integer_unsigned_set
)
358 class _SignedIntegerValueConst(_IntegerValueConst
):
359 _NAME
= 'Const signed integer'
360 _get_value
= staticmethod(native_bt
.value_integer_signed_get
)
363 class SignedIntegerValue(_SignedIntegerValueConst
, _IntegerValue
):
364 _NAME
= 'Signed integer'
365 _check_int_range
= staticmethod(utils
._check
_int
64)
366 _create_default_value
= staticmethod(native_bt
.value_integer_signed_create
)
367 _create_value
= staticmethod(native_bt
.value_integer_signed_create_init
)
368 _set_value
= staticmethod(native_bt
.value_integer_signed_set
)
371 class _RealValueConst(_NumericValueConst
, numbers
.Real
):
372 _NAME
= 'Const real number'
376 return native_bt
.value_real_get(self
._ptr
)
379 class RealValue(_RealValueConst
, _NumericValue
):
380 _NAME
= 'Real number'
382 def __init__(self
, value
=None):
384 ptr
= native_bt
.value_real_create()
386 value
= self
._value
_to
_float
(value
)
387 ptr
= native_bt
.value_real_create_init(value
)
389 self
._check
_create
_status
(ptr
)
390 super().__init
__(ptr
)
393 def _value_to_float(cls
, value
):
394 if not isinstance(value
, numbers
.Real
):
395 raise TypeError("expecting a real number object")
399 def _set_value(self
, value
):
400 native_bt
.value_real_set(self
._ptr
, self
._value
_to
_float
(value
))
402 value
= property(fset
=_set_value
)
405 @functools.total_ordering
406 class _StringValueConst(collections
.abc
.Sequence
, _Value
):
407 _NAME
= 'Const string'
410 def _value_to_str(cls
, value
):
411 if isinstance(value
, _StringValueConst
):
414 utils
._check
_str
(value
)
419 return native_bt
.value_string_get(self
._ptr
)
421 def __eq__(self
, other
):
423 return self
._value
== self
._value
_to
_str
(other
)
427 def __lt__(self
, other
):
428 return self
._value
< self
._value
_to
_str
(other
)
431 return bool(self
._value
)
434 return repr(self
._value
)
439 def __getitem__(self
, index
):
440 return self
._value
[index
]
443 return len(self
._value
)
445 def __contains__(self
, item
):
446 return self
._value
_to
_str
(item
) in self
._value
449 class StringValue(_StringValueConst
, _Value
):
452 def __init__(self
, value
=None):
454 ptr
= native_bt
.value_string_create()
456 ptr
= native_bt
.value_string_create_init(self
._value
_to
_str
(value
))
458 self
._check
_create
_status
(ptr
)
459 super().__init
__(ptr
)
461 def _set_value(self
, value
):
462 status
= native_bt
.value_string_set(self
._ptr
, self
._value
_to
_str
(value
))
463 utils
._handle
_func
_status
(status
)
465 value
= property(fset
=_set_value
)
467 def __iadd__(self
, value
):
468 curvalue
= self
._value
469 curvalue
+= self
._value
_to
_str
(value
)
470 self
.value
= curvalue
474 class _ContainerConst
:
476 return len(self
) != 0
479 class _Container(_ContainerConst
):
480 def __delitem__(self
, index
):
481 raise NotImplementedError
484 class _ArrayValueConst(_ContainerConst
, collections
.abc
.Sequence
, _ValueConst
):
485 _NAME
= 'Const array'
486 _borrow_element_by_index
= staticmethod(
487 native_bt
.value_array_borrow_element_by_index_const
491 def __eq__(self
, other
):
492 if not isinstance(other
, collections
.abc
.Sequence
):
495 if len(self
) != len(other
):
499 for self_elem
, other_elem
in zip(self
, other
):
500 if self_elem
!= other_elem
:
506 size
= native_bt
.value_array_get_length(self
._ptr
)
510 def _check_index(self
, index
):
511 # TODO: support slices also
512 if not isinstance(index
, numbers
.Integral
):
514 "'{}' object is not an integral number object: invalid index".format(
515 index
.__class
__.__name
__
521 if index
< 0 or index
>= len(self
):
522 raise IndexError('array value object index is out of range')
524 def __getitem__(self
, index
):
525 self
._check
_index
(index
)
526 ptr
= self
._borrow
_element
_by
_index
(self
._ptr
, index
)
528 return self
._create
_value
_from
_ptr
_and
_get
_ref
(ptr
)
531 return '[{}]'.format(', '.join([repr(v
) for v
in self
]))
534 class ArrayValue(_ArrayValueConst
, _Container
, collections
.abc
.MutableSequence
, _Value
):
536 _borrow_element_by_index
= staticmethod(
537 native_bt
.value_array_borrow_element_by_index
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 __setitem__(self
, index
, value
):
552 self
._check
_index
(index
)
553 value
= create_value(value
)
556 ptr
= native_bt
.value_null
560 status
= native_bt
.value_array_set_element_by_index(self
._ptr
, index
, ptr
)
561 utils
._handle
_func
_status
(status
)
563 def append(self
, value
):
564 value
= create_value(value
)
567 ptr
= native_bt
.value_null
571 status
= native_bt
.value_array_append_element(self
._ptr
, ptr
)
572 utils
._handle
_func
_status
(status
)
574 def __iadd__(self
, iterable
):
575 # Python will raise a TypeError if there's anything wrong with
576 # the iterable protocol.
577 for elem
in iterable
:
582 def insert(self
, value
):
583 raise NotImplementedError
586 class _MapValueKeyIterator(collections
.abc
.Iterator
):
587 def __init__(self
, map_obj
):
588 self
._map
_obj
= map_obj
590 keys_ptr
= native_bt
.value_map_get_keys(map_obj
._ptr
)
593 raise RuntimeError('unexpected error: cannot get map value object keys')
595 self
._keys
= _create_from_ptr(keys_ptr
)
598 if self
._at
== len(self
._map
_obj
):
601 key
= self
._keys
[self
._at
]
606 class _MapValueConst(_ContainerConst
, collections
.abc
.Mapping
, _ValueConst
):
608 _borrow_entry_value_ptr
= staticmethod(native_bt
.value_map_borrow_entry_value_const
)
610 def __ne__(self
, other
):
611 return _Value
.__ne
__(self
, other
)
613 def __eq__(self
, other
):
614 if not isinstance(other
, collections
.abc
.Mapping
):
617 if len(self
) != len(other
):
621 for self_key
in self
:
622 if self_key
not in other
:
625 if self
[self_key
] != other
[self_key
]:
631 size
= native_bt
.value_map_get_size(self
._ptr
)
635 def __contains__(self
, key
):
636 self
._check
_key
_type
(key
)
637 return native_bt
.value_map_has_entry(self
._ptr
, key
)
639 def _check_key_type(self
, key
):
640 utils
._check
_str
(key
)
642 def _check_key(self
, key
):
646 def __getitem__(self
, key
):
648 ptr
= self
._borrow
_entry
_value
_ptr
(self
._ptr
, key
)
650 return self
._create
_value
_from
_ptr
_and
_get
_ref
(ptr
)
653 return _MapValueKeyIterator(self
)
656 items
= ['{}: {}'.format(repr(k
), repr(v
)) for k
, v
in self
.items()]
657 return '{{{}}}'.format(', '.join(items
))
660 class MapValue(_MapValueConst
, _Container
, collections
.abc
.MutableMapping
, _Value
):
662 _borrow_entry_value_ptr
= staticmethod(native_bt
.value_map_borrow_entry_value
)
664 def __init__(self
, value
=None):
665 ptr
= native_bt
.value_map_create()
666 self
._check
_create
_status
(ptr
)
667 super().__init
__(ptr
)
669 # Python will raise a TypeError if there's anything wrong with
670 # the iterable/mapping protocol.
671 if value
is not None:
672 for key
, elem
in value
.items():
675 def __setitem__(self
, key
, value
):
676 self
._check
_key
_type
(key
)
677 value
= create_value(value
)
680 ptr
= native_bt
.value_null
684 status
= native_bt
.value_map_insert_entry(self
._ptr
, key
, ptr
)
685 utils
._handle
_func
_status
(status
)
689 native_bt
.VALUE_TYPE_BOOL
: BoolValue
,
690 native_bt
.VALUE_TYPE_UNSIGNED_INTEGER
: UnsignedIntegerValue
,
691 native_bt
.VALUE_TYPE_SIGNED_INTEGER
: SignedIntegerValue
,
692 native_bt
.VALUE_TYPE_REAL
: RealValue
,
693 native_bt
.VALUE_TYPE_STRING
: StringValue
,
694 native_bt
.VALUE_TYPE_ARRAY
: ArrayValue
,
695 native_bt
.VALUE_TYPE_MAP
: MapValue
,
698 _TYPE_TO_CONST_OBJ
= {
699 native_bt
.VALUE_TYPE_BOOL
: _BoolValueConst
,
700 native_bt
.VALUE_TYPE_UNSIGNED_INTEGER
: _UnsignedIntegerValueConst
,
701 native_bt
.VALUE_TYPE_SIGNED_INTEGER
: _SignedIntegerValueConst
,
702 native_bt
.VALUE_TYPE_REAL
: _RealValueConst
,
703 native_bt
.VALUE_TYPE_STRING
: _StringValueConst
,
704 native_bt
.VALUE_TYPE_ARRAY
: _ArrayValueConst
,
705 native_bt
.VALUE_TYPE_MAP
: _MapValueConst
,