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 _handle_status(status
, obj_name
):
36 raise RuntimeError('unexpected error')
39 def _create_from_ptr(ptr
):
40 if ptr
is None or ptr
== native_bt
.value_null
:
43 typeid
= native_bt
.value_get_type(ptr
)
44 return _TYPE_TO_OBJ
[typeid
]._create
_from
_ptr
(ptr
)
47 def _create_from_ptr_and_get_ref(ptr
):
48 if ptr
is None or ptr
== native_bt
.value_null
:
51 typeid
= native_bt
.value_get_type(ptr
)
52 return _TYPE_TO_OBJ
[typeid
]._create
_from
_ptr
_and
_get
_ref
(ptr
)
55 def create_value(value
):
60 if isinstance(value
, _Value
):
63 if isinstance(value
, bool):
64 return BoolValue(value
)
66 if isinstance(value
, int):
67 return IntegerValue(value
)
69 if isinstance(value
, float):
70 return RealValue(value
)
72 if isinstance(value
, str):
73 return StringValue(value
)
76 return MapValue(value
)
81 return ArrayValue(value
)
85 raise TypeError("cannot create value object from '{}' object".format(value
.__class
__.__name
__))
88 class _Value(object._SharedObject
, metaclass
=abc
.ABCMeta
):
89 _get_ref
= native_bt
.value_get_ref
90 _put_ref
= native_bt
.value_put_ref
92 def __eq__(self
, other
):
94 # self is never the null value object
97 # try type-specific comparison first
98 spec_eq
= self
._spec
_eq
(other
)
100 if spec_eq
is not None:
103 if not isinstance(other
, _Value
):
104 # not comparing apples to apples
107 # fall back to native comparison function
108 return native_bt
.value_compare(self
._ptr
, other
._ptr
)
110 def __ne__(self
, other
):
111 return not (self
== other
)
114 def _spec_eq(self
, other
):
117 def _handle_status(self
, status
):
118 _handle_status(status
, self
._NAME
)
120 def _check_create_status(self
, ptr
):
122 raise bt2
.CreationError(
123 'cannot create {} value object'.format(self
._NAME
.lower()))
126 @functools.total_ordering
127 class _NumericValue(_Value
):
129 def _extract_value(other
):
130 if isinstance(other
, _NumericValue
):
133 if other
is True or other
is False:
136 if isinstance(other
, numbers
.Integral
):
139 if isinstance(other
, numbers
.Real
):
142 if isinstance(other
, numbers
.Complex
):
143 return complex(other
)
145 raise TypeError("'{}' object is not a number object".format(other
.__class
__.__name
__))
148 return int(self
._value
)
151 return float(self
._value
)
154 return repr(self
._value
)
156 def __lt__(self
, other
):
157 if not isinstance(other
, numbers
.Number
):
158 raise TypeError('unorderable types: {}() < {}()'.format(self
.__class
__.__name
__,
159 other
.__class
__.__name
__))
161 return self
._value
< float(other
)
163 def __le__(self
, other
):
164 if not isinstance(other
, numbers
.Number
):
165 raise TypeError('unorderable types: {}() <= {}()'.format(self
.__class
__.__name
__,
166 other
.__class
__.__name
__))
168 return self
._value
<= float(other
)
170 def _spec_eq(self
, other
):
173 def __eq__(self
, other
):
174 if not isinstance(other
, numbers
.Number
):
177 return self
._value
== complex(other
)
179 def __rmod__(self
, other
):
180 return self
._extract
_value
(other
) % self
._value
182 def __mod__(self
, other
):
183 return self
._value
% self
._extract
_value
(other
)
185 def __rfloordiv__(self
, other
):
186 return self
._extract
_value
(other
) // self
._value
188 def __floordiv__(self
, other
):
189 return self
._value
// self
._extract
_value
(other
)
191 def __round__(self
, ndigits
=None):
193 return round(self
._value
)
195 return round(self
._value
, ndigits
)
198 return math
.ceil(self
._value
)
201 return math
.floor(self
._value
)
204 return int(self
._value
)
207 return abs(self
._value
)
209 def __add__(self
, other
):
210 return self
._value
+ self
._extract
_value
(other
)
212 def __radd__(self
, other
):
213 return self
.__add
__(other
)
221 def __mul__(self
, other
):
222 return self
._value
* self
._extract
_value
(other
)
224 def __rmul__(self
, other
):
225 return self
.__mul
__(other
)
227 def __truediv__(self
, other
):
228 return self
._value
/ self
._extract
_value
(other
)
230 def __rtruediv__(self
, other
):
231 return self
._extract
_value
(other
) / self
._value
233 def __pow__(self
, exponent
):
234 return self
._value
** self
._extract
_value
(exponent
)
236 def __rpow__(self
, base
):
237 return self
._extract
_value
(base
) ** self
._value
239 def __iadd__(self
, other
):
240 self
.value
= self
+ other
243 def __isub__(self
, other
):
244 self
.value
= self
- other
247 def __imul__(self
, other
):
248 self
.value
= self
* other
251 def __itruediv__(self
, other
):
252 self
.value
= self
/ other
255 def __ifloordiv__(self
, other
):
256 self
.value
= self
// other
259 def __imod__(self
, other
):
260 self
.value
= self
% other
263 def __ipow__(self
, other
):
264 self
.value
= self
** other
268 class _IntegralValue(_NumericValue
, numbers
.Integral
):
269 def __lshift__(self
, other
):
270 return self
._value
<< self
._extract
_value
(other
)
272 def __rlshift__(self
, other
):
273 return self
._extract
_value
(other
) << self
._value
275 def __rshift__(self
, other
):
276 return self
._value
>> self
._extract
_value
(other
)
278 def __rrshift__(self
, other
):
279 return self
._extract
_value
(other
) >> self
._value
281 def __and__(self
, other
):
282 return self
._value
& self
._extract
_value
(other
)
284 def __rand__(self
, other
):
285 return self
._extract
_value
(other
) & self
._value
287 def __xor__(self
, other
):
288 return self
._value ^ self
._extract
_value
(other
)
290 def __rxor__(self
, other
):
291 return self
._extract
_value
(other
) ^ self
._value
293 def __or__(self
, other
):
294 return self
._value | self
._extract
_value
(other
)
296 def __ror__(self
, other
):
297 return self
._extract
_value
(other
) | self
._value
299 def __invert__(self
):
302 def __ilshift__(self
, other
):
303 self
.value
= self
<< other
306 def __irshift__(self
, other
):
307 self
.value
= self
>> other
310 def __iand__(self
, other
):
311 self
.value
= self
& other
314 def __ixor__(self
, other
):
315 self
.value
= self ^ other
318 def __ior__(self
, other
):
319 self
.value
= self | other
323 class _RealValue(_NumericValue
, numbers
.Real
):
327 class BoolValue(_Value
):
330 def __init__(self
, value
=None):
332 ptr
= native_bt
.value_bool_create()
334 ptr
= native_bt
.value_bool_create_init(self
._value
_to
_bool
(value
))
336 self
._check
_create
_status
(ptr
)
337 super().__init
__(ptr
)
339 def _spec_eq(self
, other
):
340 if isinstance(other
, numbers
.Number
):
341 return self
._value
== bool(other
)
347 return repr(self
._value
)
349 def _value_to_bool(self
, value
):
350 if isinstance(value
, BoolValue
):
353 if not isinstance(value
, bool):
354 raise TypeError("'{}' object is not a 'bool' or 'BoolValue' object".format(value
.__class
__))
360 value
= native_bt
.value_bool_get(self
._ptr
)
363 def _set_value(self
, value
):
364 native_bt
.value_bool_set(self
._ptr
, self
._value
_to
_bool
(value
))
366 value
= property(fset
=_set_value
)
369 class IntegerValue(_IntegralValue
):
372 def __init__(self
, value
=None):
374 ptr
= native_bt
.value_integer_create()
376 ptr
= native_bt
.value_integer_create_init(self
._value
_to
_int
(value
))
378 self
._check
_create
_status
(ptr
)
379 super().__init
__(ptr
)
381 def _value_to_int(self
, value
):
382 if not isinstance(value
, numbers
.Real
):
383 raise TypeError('expecting a number object')
386 utils
._check
_int
64(value
)
391 return native_bt
.value_integer_get(self
._ptr
)
393 def _set_value(self
, value
):
394 native_bt
.value_integer_set(self
._ptr
, self
._value
_to
_int
(value
))
396 value
= property(fset
=_set_value
)
399 class RealValue(_RealValue
):
400 _NAME
= 'Real number'
402 def __init__(self
, value
=None):
404 ptr
= native_bt
.value_real_create()
406 value
= self
._value
_to
_float
(value
)
407 ptr
= native_bt
.value_real_create_init(value
)
409 self
._check
_create
_status
(ptr
)
410 super().__init
__(ptr
)
412 def _value_to_float(self
, value
):
413 if not isinstance(value
, numbers
.Real
):
414 raise TypeError("expecting a real number object")
420 return native_bt
.value_real_get(self
._ptr
)
422 def _set_value(self
, value
):
423 native_bt
.value_real_set(self
._ptr
, self
._value
_to
_float
(value
))
425 value
= property(fset
=_set_value
)
428 @functools.total_ordering
429 class StringValue(collections
.abc
.Sequence
, _Value
):
432 def __init__(self
, value
=None):
434 ptr
= native_bt
.value_string_create()
436 ptr
= native_bt
.value_string_create_init(self
._value
_to
_str
(value
))
438 self
._check
_create
_status
(ptr
)
439 super().__init
__(ptr
)
441 def _value_to_str(self
, value
):
442 if isinstance(value
, self
.__class
__):
445 utils
._check
_str
(value
)
450 return native_bt
.value_string_get(self
._ptr
)
452 def _set_value(self
, value
):
453 status
= native_bt
.value_string_set(self
._ptr
, self
._value
_to
_str
(value
))
454 self
._handle
_status
(status
)
456 value
= property(fset
=_set_value
)
458 def _spec_eq(self
, other
):
460 return self
._value
== self
._value
_to
_str
(other
)
464 def __le__(self
, other
):
465 return self
._value
<= self
._value
_to
_str
(other
)
467 def __lt__(self
, other
):
468 return self
._value
< self
._value
_to
_str
(other
)
471 return bool(self
._value
)
474 return repr(self
._value
)
479 def __getitem__(self
, index
):
480 return self
._value
[index
]
483 return len(self
._value
)
485 def __iadd__(self
, value
):
486 curvalue
= self
._value
487 curvalue
+= self
._value
_to
_str
(value
)
488 self
.value
= curvalue
494 return len(self
) != 0
496 def __delitem__(self
, index
):
497 raise NotImplementedError
500 class ArrayValue(_Container
, collections
.abc
.MutableSequence
, _Value
):
503 def __init__(self
, value
=None):
504 ptr
= native_bt
.value_array_create()
505 self
._check
_create
_status
(ptr
)
506 super().__init
__(ptr
)
508 # Python will raise a TypeError if there's anything wrong with
509 # the iterable protocol.
510 if value
is not None:
514 def _spec_eq(self
, other
):
516 if len(self
) != len(other
):
520 for self_elem
, other_elem
in zip(self
, other
):
521 if self_elem
!= other_elem
:
529 size
= native_bt
.value_array_get_size(self
._ptr
)
533 def _check_index(self
, index
):
534 # TODO: support slices also
535 if not isinstance(index
, numbers
.Integral
):
536 raise TypeError("'{}' object is not an integral number object: invalid index".format(index
.__class
__.__name
__))
540 if index
< 0 or index
>= len(self
):
541 raise IndexError('array value object index is out of range')
543 def __getitem__(self
, index
):
544 self
._check
_index
(index
)
545 ptr
= native_bt
.value_array_borrow_element_by_index(self
._ptr
, index
)
547 return _create_from_ptr_and_get_ref(ptr
)
549 def __setitem__(self
, index
, value
):
550 self
._check
_index
(index
)
551 value
= create_value(value
)
554 ptr
= native_bt
.value_null
558 status
= native_bt
.value_array_set_element_by_index(
559 self
._ptr
, index
, ptr
)
560 self
._handle
_status
(status
)
562 def append(self
, value
):
563 value
= create_value(value
)
566 ptr
= native_bt
.value_null
570 status
= native_bt
.value_array_append_element(self
._ptr
, ptr
)
571 self
._handle
_status
(status
)
573 def __iadd__(self
, iterable
):
574 # Python will raise a TypeError if there's anything wrong with
575 # the iterable protocol.
576 for elem
in iterable
:
582 return '[{}]'.format(', '.join([repr(v
) for v
in self
]))
584 def insert(self
, value
):
585 raise NotImplementedError
588 class _MapValueKeyIterator(collections
.abc
.Iterator
):
589 def __init__(self
, map_obj
):
590 self
._map
_obj
= map_obj
592 keys_ptr
= native_bt
.value_map_get_keys(map_obj
._ptr
)
595 raise RuntimeError('unexpected error: cannot get map value object keys')
597 self
._keys
= _create_from_ptr(keys_ptr
)
600 if self
._at
== len(self
._map
_obj
):
603 key
= self
._keys
[self
._at
]
608 class MapValue(_Container
, collections
.abc
.MutableMapping
, _Value
):
611 def __init__(self
, value
=None):
612 ptr
= native_bt
.value_map_create()
613 self
._check
_create
_status
(ptr
)
614 super().__init
__(ptr
)
616 # Python will raise a TypeError if there's anything wrong with
617 # the iterable/mapping protocol.
618 if value
is not None:
619 for key
, elem
in value
.items():
622 def __eq__(self
, other
):
623 return _Value
.__eq
__(self
, other
)
625 def __ne__(self
, other
):
626 return _Value
.__ne
__(self
, other
)
628 def _spec_eq(self
, other
):
630 if len(self
) != len(other
):
634 for self_key
in self
:
635 if self_key
not in other
:
638 self_value
= self
[self_key
]
639 other_value
= other
[self_key
]
641 if self_value
!= other_value
:
649 size
= native_bt
.value_map_get_size(self
._ptr
)
653 def __contains__(self
, key
):
654 self
._check
_key
_type
(key
)
655 return native_bt
.value_map_has_entry(self
._ptr
, key
)
657 def _check_key_type(self
, key
):
658 utils
._check
_str
(key
)
660 def _check_key(self
, key
):
664 def __getitem__(self
, key
):
666 ptr
= native_bt
.value_map_borrow_entry_value(self
._ptr
, key
)
668 return _create_from_ptr_and_get_ref(ptr
)
671 return _MapValueKeyIterator(self
)
673 def __setitem__(self
, key
, value
):
674 self
._check
_key
_type
(key
)
675 value
= create_value(value
)
678 ptr
= native_bt
.value_null
682 status
= native_bt
.value_map_insert_entry(self
._ptr
, key
, ptr
)
683 self
._handle
_status
(status
)
686 items
= ['{}: {}'.format(repr(k
), repr(v
)) for k
, v
in self
.items()]
687 return '{{{}}}'.format(', '.join(items
))
691 native_bt
.VALUE_TYPE_BOOL
: BoolValue
,
692 native_bt
.VALUE_TYPE_INTEGER
: IntegerValue
,
693 native_bt
.VALUE_TYPE_REAL
: RealValue
,
694 native_bt
.VALUE_TYPE_STRING
: StringValue
,
695 native_bt
.VALUE_TYPE_ARRAY
: ArrayValue
,
696 native_bt
.VALUE_TYPE_MAP
: MapValue
,
This page took 0.044161 seconds and 4 git commands to generate.