Python bindings: add has_intersection property to TraceCollection
[babeltrace.git] / bindings / python / reader.py
1 # reader.py
2 #
3 # Babeltrace reader interface Python module
4 #
5 # Copyright 2012-2015 EfficiOS Inc.
6 #
7 # Author: Danny Serres <danny.serres@efficios.com>
8 # Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 #
10 # Permission is hereby granted, free of charge, to any person obtaining a copy
11 # of this software and associated documentation files (the "Software"), to deal
12 # in the Software without restriction, including without limitation the rights
13 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 # copies of the Software, and to permit persons to whom the Software is
15 # furnished to do so, subject to the following conditions:
16 #
17 # The above copyright notice and this permission notice shall be included in
18 # all copies or substantial portions of the Software.
19 #
20 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 # SOFTWARE.
27
28 import babeltrace.nativebt as nbt
29 import babeltrace.common as common
30 import collections
31 import os
32 from datetime import datetime
33
34
35 class TraceCollection:
36 """
37 A :class:`TraceCollection` is a collection of opened traces.
38
39 Once a trace collection is created, you can add traces to the
40 collection by using the :meth:`add_trace` or
41 :meth:`add_traces_recursive`, and then iterate on the merged
42 events using :attr:`events`.
43
44 You may use :meth:`remove_trace` to close and remove a specific
45 trace from a trace collection.
46 """
47
48 def __init__(self, intersect_mode=False):
49 """
50 Creates an empty trace collection.
51 """
52
53 self._tc = nbt._bt_context_create()
54 self._intersect_mode = intersect_mode
55
56 def __del__(self):
57 nbt._bt_context_put(self._tc)
58
59 def add_trace(self, path, format_str):
60 """
61 Adds a trace to the trace collection.
62
63 *path* is the exact path of the trace on the filesystem.
64
65 *format_str* is a string indicating the type of trace to
66 add. ``ctf`` is currently the only supported trace format.
67
68 Returns the corresponding :class:`TraceHandle` instance for
69 this opened trace on success, or ``None`` on error.
70
71 This function **does not** recurse directories to find a
72 trace. See :meth:`add_traces_recursive` for a recursive
73 version of this function.
74 """
75
76 ret = nbt._bt_context_add_trace(self._tc, path, format_str,
77 None, None, None)
78
79 if ret < 0:
80 return None
81
82 th = TraceHandle.__new__(TraceHandle)
83 th._id = ret
84 th._trace_collection = self
85
86 return th
87
88 def add_traces_recursive(self, path, format_str):
89 """
90 Adds traces to this trace collection by recursively searching
91 in the *path* directory.
92
93 *format_str* is a string indicating the type of trace to add.
94 ``ctf`` is currently the only supported trace format.
95
96 Returns a :class:`dict` object mapping full paths to trace
97 handles for each trace found, or ``None`` on error.
98
99 See also :meth:`add_trace`.
100 """
101
102 trace_handles = {}
103 noTrace = True
104 error = False
105
106 for fullpath, dirs, files in os.walk(path):
107 if "metadata" in files:
108 trace_handle = self.add_trace(fullpath, format_str)
109
110 if trace_handle is None:
111 error = True
112 continue
113
114 trace_handles[fullpath] = trace_handle
115 noTrace = False
116
117 if noTrace and error:
118 return None
119
120 return trace_handles
121
122 def remove_trace(self, trace_handle):
123 """
124 Removes a trace from the trace collection using its trace
125 handle *trace_handle*.
126
127 :class:`TraceHandle` objects are returned by :meth:`add_trace`
128 and :meth:`add_traces_recursive`.
129 """
130
131 try:
132 nbt._bt_context_remove_trace(self._tc, trace_handle._id)
133 except AttributeError:
134 raise TypeError("in remove_trace, argument 2 must be a TraceHandle instance")
135
136 @property
137 def intersect_mode(self):
138 return self._intersect_mode
139
140 @property
141 def has_intersection(self):
142 return nbt._bt_python_has_intersection(self._tc)
143
144 @property
145 def events(self):
146 """
147 Generates the ordered :class:`Event` objects of all the opened
148 traces contained in this trace collection.
149
150 Due to limitations of the native Babeltrace API, only one event
151 may be "alive" at a given time, i.e. a user **should never**
152 store a copy of the events returned by this function for
153 ulterior use. Users shall make sure to copy the information
154 they need *from* an event before accessing the next one.
155 """
156
157 begin_pos_ptr = nbt._bt_python_create_iter_pos()
158 end_pos_ptr = nbt._bt_python_create_iter_pos()
159
160 if not self.intersect_mode:
161 begin_pos_ptr.type = nbt.SEEK_BEGIN
162 end_pos_ptr.type = nbt.SEEK_LAST
163
164 for event in self._events(begin_pos_ptr, end_pos_ptr):
165 yield event
166
167 nbt._bt_iter_free_pos(begin_pos_ptr)
168 nbt._bt_iter_free_pos(end_pos_ptr)
169
170 def events_timestamps(self, timestamp_begin, timestamp_end):
171 """
172 Generates the ordered :class:`Event` objects of all the opened
173 traces contained in this trace collection from *timestamp_begin*
174 to *timestamp_end*.
175
176 *timestamp_begin* and *timestamp_end* are given in nanoseconds
177 since Epoch.
178
179 See :attr:`events` for notes and limitations.
180 """
181
182 begin_pos_ptr = nbt._bt_python_create_iter_pos()
183 end_pos_ptr = nbt._bt_python_create_iter_pos()
184 begin_pos_ptr.type = end_pos_ptr.type = nbt.SEEK_TIME
185 begin_pos_ptr.u.seek_time = timestamp_begin
186 end_pos_ptr.u.seek_time = timestamp_end
187
188 for event in self._events(begin_pos_ptr, end_pos_ptr):
189 yield event
190
191 nbt._bt_iter_free_pos(begin_pos_ptr)
192 nbt._bt_iter_free_pos(end_pos_ptr)
193
194 @property
195 def timestamp_begin(self):
196 """
197 Begin timestamp of this trace collection (nanoseconds since
198 Epoch).
199 """
200
201 pos_ptr = nbt._bt_iter_pos()
202 pos_ptr.type = nbt.SEEK_BEGIN
203
204 return self._timestamp_at_pos(pos_ptr)
205
206 @property
207 def timestamp_end(self):
208 """
209 End timestamp of this trace collection (nanoseconds since
210 Epoch).
211 """
212
213 pos_ptr = nbt._bt_iter_pos()
214 pos_ptr.type = nbt.SEEK_LAST
215
216 return self._timestamp_at_pos(pos_ptr)
217
218 def _timestamp_at_pos(self, pos_ptr):
219 ctf_it_ptr = nbt._bt_ctf_iter_create(self._tc, pos_ptr, pos_ptr)
220
221 if ctf_it_ptr is None:
222 raise NotImplementedError("Creation of multiple iterators is unsupported.")
223
224 ev_ptr = nbt._bt_ctf_iter_read_event(ctf_it_ptr)
225 nbt._bt_ctf_iter_destroy(ctf_it_ptr)
226
227 ev = Event.__new__(Event)
228 ev._e = ev_ptr
229
230 return ev.timestamp
231
232 def _events(self, begin_pos_ptr, end_pos_ptr):
233 if self.intersect_mode:
234 if not self.has_intersection:
235 # There are no events to provide.
236 return
237
238 ctf_it_ptr = nbt._bt_python_ctf_iter_create_intersect(
239 self._tc, begin_pos_ptr, end_pos_ptr
240 )
241 else:
242 ctf_it_ptr = nbt._bt_ctf_iter_create(
243 self._tc, begin_pos_ptr, end_pos_ptr
244 )
245
246 if ctf_it_ptr is None:
247 raise NotImplementedError("Creation of multiple iterators is unsupported.")
248
249 while True:
250 ev_ptr = nbt._bt_ctf_iter_read_event(ctf_it_ptr)
251
252 if ev_ptr is None:
253 break
254
255 ev = Event.__new__(Event)
256 ev._e = ev_ptr
257
258 try:
259 yield ev
260 except GeneratorExit:
261 break
262
263 ret = nbt._bt_iter_next(nbt._bt_ctf_get_iter(ctf_it_ptr))
264
265 if ret != 0:
266 break
267
268 nbt._bt_ctf_iter_destroy(ctf_it_ptr)
269
270
271 # Based on enum bt_clock_type in clock-type.h
272 class _ClockType:
273 CLOCK_CYCLES = 0
274 CLOCK_REAL = 1
275
276
277 class TraceHandle:
278 """
279 A :class:`TraceHandle` is a handle allowing the user to manipulate
280 a specific trace directly. It is a unique identifier representing a
281 trace, and is not meant to be instantiated by the user.
282 """
283
284 def __init__(self):
285 raise NotImplementedError("TraceHandle cannot be instantiated")
286
287 def __repr__(self):
288 return "Babeltrace TraceHandle: trace_id('{0}')".format(self._id)
289
290 @property
291 def id(self):
292 """
293 Numeric ID of this trace handle.
294 """
295
296 return self._id
297
298 @property
299 def path(self):
300 """
301 Path of the underlying trace.
302 """
303
304 return nbt._bt_trace_handle_get_path(self._trace_collection._tc,
305 self._id)
306
307 @property
308 def timestamp_begin(self):
309 """
310 Buffers creation timestamp (nanoseconds since Epoch) of the
311 underlying trace.
312 """
313
314 ret, value = nbt._bt_trace_handle_get_timestamp_begin(
315 self._trace_collection._tc, self._id, _ClockType.CLOCK_REAL)
316 if ret != 0:
317 raise ValueError("Invalid TraceHandle")
318 return value
319
320 @property
321 def timestamp_end(self):
322 """
323 Buffers destruction timestamp (nanoseconds since Epoch) of the
324 underlying trace.
325 """
326
327 ret, value = nbt._bt_trace_handle_get_timestamp_end(
328 self._trace_collection._tc, self._id, _ClockType.CLOCK_REAL)
329 if ret != 0:
330 raise ValueError("Invalid TraceHandle")
331 return value
332
333 @property
334 def events(self):
335 """
336 Generates all the :class:`EventDeclaration` objects of the
337 underlying trace.
338 """
339
340 ret = nbt._bt_python_event_decl_listcaller(self.id,
341 self._trace_collection._tc)
342
343 if not isinstance(ret, list):
344 return
345
346 ptr_list, count = ret
347
348 for i in range(count):
349 tmp = EventDeclaration.__new__(EventDeclaration)
350 tmp._ed = nbt._bt_python_decl_one_from_list(ptr_list, i)
351 yield tmp
352
353
354
355
356 # Priority of the scopes when searching for event fields
357 _scopes = [
358 common.CTFScope.EVENT_FIELDS,
359 common.CTFScope.EVENT_CONTEXT,
360 common.CTFScope.STREAM_EVENT_CONTEXT,
361 common.CTFScope.STREAM_EVENT_HEADER,
362 common.CTFScope.STREAM_PACKET_CONTEXT,
363 common.CTFScope.TRACE_PACKET_HEADER
364 ]
365
366
367 class Event(collections.Mapping):
368 """
369 An :class:`Event` object represents a trace event. :class:`Event`
370 objects are returned by :attr:`TraceCollection.events` and are
371 not meant to be instantiated by the user.
372
373 :class:`Event` has a :class:`dict`-like interface for accessing
374 an event's field value by field name:
375
376 .. code-block:: python
377
378 event['my_field']
379
380 If a field name exists in multiple scopes, the value of the first
381 field found is returned. The scopes are searched in the following
382 order:
383
384 1. Event fields (:attr:`babeltrace.common.CTFScope.EVENT_FIELDS`)
385 2. Event context (:attr:`babeltrace.common.CTFScope.EVENT_CONTEXT`)
386 3. Stream event context (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_CONTEXT`)
387 4. Event header (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_HEADER`)
388 5. Packet context (:attr:`babeltrace.common.CTFScope.STREAM_PACKET_CONTEXT`)
389 6. Packet header (:attr:`babeltrace.common.CTFScope.TRACE_PACKET_HEADER`)
390
391 It is still possible to obtain a field's value from a specific
392 scope using :meth:`field_with_scope`.
393
394 Field values are returned as native Python types, that is:
395
396 +-----------------------+----------------------------------+
397 | Field type | Python type |
398 +=======================+==================================+
399 | Integer | :class:`int` |
400 +-----------------------+----------------------------------+
401 | Floating point number | :class:`float` |
402 +-----------------------+----------------------------------+
403 | Enumeration | :class:`str` (enumeration label) |
404 +-----------------------+----------------------------------+
405 | String | :class:`str` |
406 +-----------------------+----------------------------------+
407 | Array | :class:`list` of native Python |
408 | | objects |
409 +-----------------------+----------------------------------+
410 | Sequence | :class:`list` of native Python |
411 | | objects |
412 +-----------------------+----------------------------------+
413 | Structure | :class:`dict` mapping field |
414 | | names to native Python objects |
415 +-----------------------+----------------------------------+
416
417 For example, printing the third element of a sequence named ``seq``
418 in a structure named ``my_struct`` of the ``event``'s field named
419 ``my_field`` is done this way:
420
421 .. code-block:: python
422
423 print(event['my_field']['my_struct']['seq'][2])
424 """
425
426 def __init__(self):
427 raise NotImplementedError("Event cannot be instantiated")
428
429 @property
430 def name(self):
431 """
432 Event name or ``None`` on error.
433 """
434
435 return nbt._bt_ctf_event_name(self._e)
436
437 @property
438 def cycles(self):
439 """
440 Event timestamp in cycles or -1 on error.
441 """
442
443 return nbt._bt_ctf_get_cycles(self._e)
444
445 @property
446 def timestamp(self):
447 """
448 Event timestamp (nanoseconds since Epoch).
449 """
450
451 ret, value = nbt._bt_ctf_get_timestamp(self._e)
452 if ret < 0:
453 raise RuntimeError("Failed to get event timestamp")
454 return value
455
456 @property
457 def datetime(self):
458 """
459 Event timestamp as a standard :class:`datetime.datetime`
460 object.
461
462 Note that the :class:`datetime.datetime` class' precision
463 is limited to microseconds, whereas :attr:`timestamp` provides
464 the event's timestamp with a nanosecond resolution.
465 """
466
467 return datetime.fromtimestamp(self.timestamp / 1E9)
468
469 def field_with_scope(self, field_name, scope):
470 """
471 Returns the value of a field named *field_name* within the
472 scope *scope*, or ``None`` if the field cannot be found.
473
474 *scope* must be one of :class:`babeltrace.common.CTFScope`
475 constants.
476 """
477
478 if scope not in _scopes:
479 raise ValueError("Invalid scope provided")
480
481 field = self._field_with_scope(field_name, scope)
482
483 if field is not None:
484 return field.value
485
486 def field_list_with_scope(self, scope):
487 """
488 Returns a list of field names in the scope *scope*.
489 """
490
491 if scope not in _scopes:
492 raise ValueError("Invalid scope provided")
493
494 field_names = []
495
496 for field in self._field_list_with_scope(scope):
497 field_names.append(field.name)
498
499 return field_names
500
501 @property
502 def handle(self):
503 """
504 :class:`TraceHandle` object containing this event, or ``None``
505 on error.
506 """
507
508 ret = nbt._bt_ctf_event_get_handle_id(self._e)
509
510 if ret < 0:
511 return None
512
513 th = TraceHandle.__new__(TraceHandle)
514 th._id = ret
515 th._trace_collection = self.get_trace_collection()
516
517 return th
518
519 @property
520 def trace_collection(self):
521 """
522 :class:`TraceCollection` object containing this event, or
523 ``None`` on error.
524 """
525
526 trace_collection = TraceCollection()
527 trace_collection._tc = nbt._bt_ctf_event_get_context(self._e)
528
529 if trace_collection._tc is not None:
530 return trace_collection
531
532 def __getitem__(self, field_name):
533 field = self._field(field_name)
534
535 if field is not None:
536 return field.value
537
538 raise KeyError(field_name)
539
540 def __iter__(self):
541 for key in self.keys():
542 yield key
543
544 def __len__(self):
545 count = 0
546
547 for scope in _scopes:
548 scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
549 ret = nbt._bt_python_field_listcaller(self._e, scope_ptr)
550
551 if isinstance(ret, list):
552 count += ret[1]
553
554 return count
555
556 def __contains__(self, field_name):
557 return self._field(field_name) is not None
558
559 def keys(self):
560 """
561 Returns the list of field names.
562
563 Note: field names are unique within the returned list, although
564 a field name could exist in multiple scopes. Use
565 :meth:`field_list_with_scope` to obtain the list of field names
566 of a given scope.
567 """
568
569 field_names = set()
570
571 for scope in _scopes:
572 for name in self.field_list_with_scope(scope):
573 field_names.add(name)
574
575 return list(field_names)
576
577 def get(self, field_name, default=None):
578 """
579 Returns the value of the field named *field_name*, or *default*
580 when not found.
581
582 See :class:`Event` note about how fields are retrieved by
583 name when multiple fields share the same name in different
584 scopes.
585 """
586
587 field = self._field(field_name)
588
589 if field is None:
590 return default
591
592 return field.value
593
594 def items(self):
595 """
596 Generates pairs of (field name, field value).
597
598 This method iterates :meth:`keys` to find field names, which
599 means some fields could be unavailable if other fields share
600 their names in scopes with higher priorities.
601 """
602
603 for field in self.keys():
604 yield (field, self[field])
605
606 def _field_with_scope(self, field_name, scope):
607 scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
608
609 if scope_ptr is None:
610 return None
611
612 definition_ptr = nbt._bt_ctf_get_field(self._e, scope_ptr, field_name)
613
614 if definition_ptr is None:
615 return None
616
617 field = _Definition(definition_ptr, scope)
618
619 return field
620
621 def _field(self, field_name):
622 field = None
623
624 for scope in _scopes:
625 field = self._field_with_scope(field_name, scope)
626
627 if field is not None:
628 break
629
630 return field
631
632 def _field_list_with_scope(self, scope):
633 fields = []
634 scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
635
636 # Returns a list [list_ptr, count]. If list_ptr is NULL, SWIG will only
637 # provide the "count" return value
638 count = 0
639 list_ptr = None
640 ret = nbt._bt_python_field_listcaller(self._e, scope_ptr)
641
642 if isinstance(ret, list):
643 list_ptr, count = ret
644
645 for i in range(count):
646 definition_ptr = nbt._bt_python_field_one_from_list(list_ptr, i)
647
648 if definition_ptr is not None:
649 definition = _Definition(definition_ptr, scope)
650 fields.append(definition)
651
652 return fields
653
654
655 class FieldError(Exception):
656 """
657 Field error, raised when the value of a field cannot be accessed.
658 """
659
660 def __init__(self, value):
661 self.value = value
662
663 def __str__(self):
664 return repr(self.value)
665
666
667 class EventDeclaration:
668 """
669 An event declaration contains the properties of a class of events,
670 that is, the common properties and fields layout of all the actual
671 recorded events associated with this declaration.
672
673 This class is not meant to be instantiated by the user. It is
674 returned by :attr:`TraceHandle.events`.
675 """
676
677 MAX_UINT64 = 0xFFFFFFFFFFFFFFFF
678
679 def __init__(self):
680 raise NotImplementedError("EventDeclaration cannot be instantiated")
681
682 @property
683 def name(self):
684 """
685 Event name, or ``None`` on error.
686 """
687
688 return nbt._bt_ctf_get_decl_event_name(self._ed)
689
690 @property
691 def id(self):
692 """
693 Event numeric ID, or -1 on error.
694 """
695
696 id = nbt._bt_ctf_get_decl_event_id(self._ed)
697
698 if id == self.MAX_UINT64:
699 id = -1
700
701 return id
702
703 @property
704 def fields(self):
705 """
706 Generates all the field declarations of this event, going
707 through each scope in the following order:
708
709 1. Event fields (:attr:`babeltrace.common.CTFScope.EVENT_FIELDS`)
710 2. Event context (:attr:`babeltrace.common.CTFScope.EVENT_CONTEXT`)
711 3. Stream event context (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_CONTEXT`)
712 4. Event header (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_HEADER`)
713 5. Packet context (:attr:`babeltrace.common.CTFScope.STREAM_PACKET_CONTEXT`)
714 6. Packet header (:attr:`babeltrace.common.CTFScope.TRACE_PACKET_HEADER`)
715
716 All the generated field declarations inherit
717 :class:`FieldDeclaration`, and are among:
718
719 * :class:`IntegerFieldDeclaration`
720 * :class:`FloatFieldDeclaration`
721 * :class:`EnumerationFieldDeclaration`
722 * :class:`StringFieldDeclaration`
723 * :class:`ArrayFieldDeclaration`
724 * :class:`SequenceFieldDeclaration`
725 * :class:`StructureFieldDeclaration`
726 * :class:`VariantFieldDeclaration`
727 """
728
729 for scope in _scopes:
730 for declaration in self.fields_scope(scope):
731 yield declaration
732
733 def fields_scope(self, scope):
734 """
735 Generates all the field declarations of the event's scope
736 *scope*.
737
738 *scope* must be one of :class:`babeltrace.common.CTFScope` constants.
739
740 All the generated field declarations inherit
741 :class:`FieldDeclaration`, and are among:
742
743 * :class:`IntegerFieldDeclaration`
744 * :class:`FloatFieldDeclaration`
745 * :class:`EnumerationFieldDeclaration`
746 * :class:`StringFieldDeclaration`
747 * :class:`ArrayFieldDeclaration`
748 * :class:`SequenceFieldDeclaration`
749 * :class:`StructureFieldDeclaration`
750 * :class:`VariantFieldDeclaration`
751 """
752 ret = nbt._by_python_field_decl_listcaller(self._ed, scope)
753
754 if not isinstance(ret, list):
755 return
756
757 list_ptr, count = ret
758
759 for i in range(count):
760 field_decl_ptr = nbt._bt_python_field_decl_one_from_list(list_ptr, i)
761
762 if field_decl_ptr is not None:
763 decl_ptr = nbt._bt_ctf_get_decl_from_field_decl(field_decl_ptr)
764 name = nbt._bt_ctf_get_decl_field_name(field_decl_ptr)
765 field_declaration = _create_field_declaration(decl_ptr, name,
766 scope)
767 yield field_declaration
768
769
770 class FieldDeclaration:
771 """
772 Base class for concrete field declarations.
773
774 This class is not meant to be instantiated by the user.
775 """
776
777 def __init__(self):
778 raise NotImplementedError("FieldDeclaration cannot be instantiated")
779
780 def __repr__(self):
781 return "({0}) {1} {2}".format(common.CTFScope.scope_name(self.scope),
782 common.CTFTypeId.type_name(self.type),
783 self.name)
784
785 @property
786 def name(self):
787 """
788 Field name, or ``None`` on error.
789 """
790
791 return self._name
792
793 @property
794 def type(self):
795 """
796 Field type (one of :class:`babeltrace.common.CTFTypeId`
797 constants).
798 """
799
800 return nbt._bt_ctf_field_type(self._fd)
801
802 @property
803 def scope(self):
804 """
805 Field scope (one of:class:`babeltrace.common.CTFScope`
806 constants).
807 """
808
809 return self._s
810
811
812 class IntegerFieldDeclaration(FieldDeclaration):
813 """
814 Integer field declaration.
815 """
816
817 def __init__(self):
818 raise NotImplementedError("IntegerFieldDeclaration cannot be instantiated")
819
820 @property
821 def signedness(self):
822 """
823 0 if this integer is unsigned, 1 if signed, or -1 on error.
824 """
825
826 return nbt._bt_ctf_get_int_signedness(self._fd)
827
828 @property
829 def base(self):
830 """
831 Integer base (:class:`int`), or a negative value on error.
832 """
833
834 return nbt._bt_ctf_get_int_base(self._fd)
835
836 @property
837 def byte_order(self):
838 """
839 Integer byte order (one of
840 :class:`babeltrace.common.ByteOrder` constants).
841 """
842
843 ret = nbt._bt_ctf_get_int_byte_order(self._fd)
844
845 if ret == 1234:
846 return common.ByteOrder.BYTE_ORDER_LITTLE_ENDIAN
847 elif ret == 4321:
848 return common.ByteOrder.BYTE_ORDER_BIG_ENDIAN
849 else:
850 return common.ByteOrder.BYTE_ORDER_UNKNOWN
851
852 @property
853 def size(self):
854 """
855 Integer size in bits, or a negative value on error.
856 """
857 return nbt._bt_ctf_get_int_len(self._fd)
858
859 @property
860 def length(self):
861 return self.size
862
863 @property
864 def encoding(self):
865 """
866 Integer encoding (one of
867 :class:`babeltrace.common.CTFStringEncoding` constants).
868 """
869
870 return nbt._bt_ctf_get_encoding(self._fd)
871
872
873 class EnumerationFieldDeclaration(FieldDeclaration):
874 """
875 Enumeration field declaration.
876
877 .. note::
878
879 As of this version, this class is missing some properties.
880 """
881
882 def __init__(self):
883 raise NotImplementedError("EnumerationFieldDeclaration cannot be instantiated")
884
885
886 class ArrayFieldDeclaration(FieldDeclaration):
887 """
888 Static array field declaration.
889 """
890
891 def __init__(self):
892 raise NotImplementedError("ArrayFieldDeclaration cannot be instantiated")
893
894 @property
895 def length(self):
896 """
897 Fixed length of this static array (number of contained
898 elements), or a negative value on error.
899 """
900
901 return nbt._bt_ctf_get_array_len(self._fd)
902
903 @property
904 def element_declaration(self):
905 """
906 Field declaration of the underlying element.
907 """
908
909 field_decl_ptr = nbt._bt_python_get_array_element_declaration(self._fd)
910
911 return _create_field_declaration(field_decl_ptr, "", self.scope)
912
913
914 class SequenceFieldDeclaration(FieldDeclaration):
915 """
916 Sequence (dynamic array) field declaration.
917
918 .. note::
919
920 As of this version, this class is missing some properties.
921 """
922
923 def __init__(self):
924 raise NotImplementedError("SequenceFieldDeclaration cannot be instantiated")
925
926 @property
927 def element_declaration(self):
928 """
929 Field declaration of the underlying element.
930 """
931
932 field_decl_ptr = nbt._bt_python_get_sequence_element_declaration(self._fd)
933
934 return _create_field_declaration(field_decl_ptr, "", self.scope)
935
936
937 class FloatFieldDeclaration(FieldDeclaration):
938 """
939 Floating point number field declaration.
940
941 .. note::
942
943 As of this version, this class is missing some properties.
944 """
945
946 def __init__(self):
947 raise NotImplementedError("FloatFieldDeclaration cannot be instantiated")
948
949
950 class StructureFieldDeclaration(FieldDeclaration):
951 """
952 Structure (ordered map of field names to field declarations) field
953 declaration.
954
955 .. note::
956
957 As of this version, this class is missing some properties.
958 """
959
960 def __init__(self):
961 raise NotImplementedError("StructureFieldDeclaration cannot be instantiated")
962
963
964 class StringFieldDeclaration(FieldDeclaration):
965 """
966 String (NULL-terminated array of bytes) field declaration.
967
968 .. note::
969
970 As of this version, this class is missing some properties.
971 """
972
973 def __init__(self):
974 raise NotImplementedError("StringFieldDeclaration cannot be instantiated")
975
976
977 class VariantFieldDeclaration(FieldDeclaration):
978 """
979 Variant (dynamic selection between different types) field declaration.
980
981 .. note::
982
983 As of this version, this class is missing some properties.
984 """
985
986 def __init__(self):
987 raise NotImplementedError("VariantFieldDeclaration cannot be instantiated")
988
989
990 def field_error():
991 """
992 Return the last error code encountered while
993 accessing a field and reset the error flag.
994 Return 0 if no error, a negative value otherwise.
995 """
996
997 return nbt._bt_ctf_field_get_error()
998
999
1000 def _create_field_declaration(declaration_ptr, name, scope):
1001 """
1002 Private field declaration factory.
1003 """
1004
1005 if declaration_ptr is None:
1006 raise ValueError("declaration_ptr must be valid")
1007 if scope not in _scopes:
1008 raise ValueError("Invalid scope provided")
1009
1010 type = nbt._bt_ctf_field_type(declaration_ptr)
1011 declaration = None
1012
1013 if type == common.CTFTypeId.INTEGER:
1014 declaration = IntegerFieldDeclaration.__new__(IntegerFieldDeclaration)
1015 elif type == common.CTFTypeId.ENUM:
1016 declaration = EnumerationFieldDeclaration.__new__(EnumerationFieldDeclaration)
1017 elif type == common.CTFTypeId.ARRAY:
1018 declaration = ArrayFieldDeclaration.__new__(ArrayFieldDeclaration)
1019 elif type == common.CTFTypeId.SEQUENCE:
1020 declaration = SequenceFieldDeclaration.__new__(SequenceFieldDeclaration)
1021 elif type == common.CTFTypeId.FLOAT:
1022 declaration = FloatFieldDeclaration.__new__(FloatFieldDeclaration)
1023 elif type == common.CTFTypeId.STRUCT:
1024 declaration = StructureFieldDeclaration.__new__(StructureFieldDeclaration)
1025 elif type == common.CTFTypeId.STRING:
1026 declaration = StringFieldDeclaration.__new__(StringFieldDeclaration)
1027 elif type == common.CTFTypeId.VARIANT:
1028 declaration = VariantFieldDeclaration.__new__(VariantFieldDeclaration)
1029 else:
1030 return declaration
1031
1032 declaration._fd = declaration_ptr
1033 declaration._s = scope
1034 declaration._name = name
1035
1036 return declaration
1037
1038
1039 class _Definition:
1040 def __init__(self, definition_ptr, scope):
1041 self._d = definition_ptr
1042 self._s = scope
1043
1044 if scope not in _scopes:
1045 ValueError("Invalid scope provided")
1046
1047 @property
1048 def name(self):
1049 """Return the name of a field or None on error."""
1050
1051 return nbt._bt_ctf_field_name(self._d)
1052
1053 @property
1054 def type(self):
1055 """Return the type of a field or -1 if unknown."""
1056
1057 return nbt._bt_ctf_field_type(nbt._bt_ctf_get_decl_from_def(self._d))
1058
1059 @property
1060 def declaration(self):
1061 """Return the associated Definition object."""
1062
1063 return _create_field_declaration(
1064 nbt._bt_ctf_get_decl_from_def(self._d), self.name, self.scope)
1065
1066 def _get_enum_str(self):
1067 """
1068 Return the string matching the current enumeration.
1069 Return None on error.
1070 """
1071
1072 return nbt._bt_ctf_get_enum_str(self._d)
1073
1074 def _get_array_element_at(self, index):
1075 """
1076 Return the array's element at position index.
1077 Return None on error
1078 """
1079
1080 array_ptr = nbt._bt_python_get_array_from_def(self._d)
1081
1082 if array_ptr is None:
1083 return None
1084
1085 definition_ptr = nbt._bt_array_index(array_ptr, index)
1086
1087 if definition_ptr is None:
1088 return None
1089
1090 return _Definition(definition_ptr, self.scope)
1091
1092 def _get_sequence_len(self):
1093 """
1094 Return the len of a sequence or a negative
1095 value on error.
1096 """
1097
1098 seq = nbt._bt_python_get_sequence_from_def(self._d)
1099
1100 return nbt._bt_sequence_len(seq)
1101
1102 def _get_sequence_element_at(self, index):
1103 """
1104 Return the sequence's element at position index,
1105 otherwise return None
1106 """
1107
1108 seq = nbt._bt_python_get_sequence_from_def(self._d)
1109
1110 if seq is not None:
1111 definition_ptr = nbt._bt_sequence_index(seq, index)
1112
1113 if definition_ptr is not None:
1114 return _Definition(definition_ptr, self.scope)
1115
1116 def _get_uint64(self):
1117 """
1118 Return the value associated with the field.
1119 If the field does not exist or is not of the type requested,
1120 the value returned is undefined. To check if an error occured,
1121 use the field_error() function after accessing a field.
1122 """
1123
1124 return nbt._bt_ctf_get_uint64(self._d)
1125
1126 def _get_int64(self):
1127 """
1128 Return the value associated with the field.
1129 If the field does not exist or is not of the type requested,
1130 the value returned is undefined. To check if an error occured,
1131 use the field_error() function after accessing a field.
1132 """
1133
1134 return nbt._bt_ctf_get_int64(self._d)
1135
1136 def _get_char_array(self):
1137 """
1138 Return the value associated with the field.
1139 If the field does not exist or is not of the type requested,
1140 the value returned is undefined. To check if an error occurred,
1141 use the field_error() function after accessing a field.
1142 """
1143
1144 return nbt._bt_ctf_get_char_array(self._d)
1145
1146 def _get_str(self):
1147 """
1148 Return the value associated with the field.
1149 If the field does not exist or is not of the type requested,
1150 the value returned is undefined. To check if an error occurred,
1151 use the field_error() function after accessing a field.
1152 """
1153
1154 return nbt._bt_ctf_get_string(self._d)
1155
1156 def _get_float(self):
1157 """
1158 Return the value associated with the field.
1159 If the field does not exist or is not of the type requested,
1160 the value returned is undefined. To check if an error occurred,
1161 use the field_error() function after accessing a field.
1162 """
1163
1164 return nbt._bt_ctf_get_float(self._d)
1165
1166 def _get_variant(self):
1167 """
1168 Return the variant's selected field.
1169 If the field does not exist or is not of the type requested,
1170 the value returned is undefined. To check if an error occurred,
1171 use the field_error() function after accessing a field.
1172 """
1173
1174 return nbt._bt_ctf_get_variant(self._d)
1175
1176 def _get_struct_field_count(self):
1177 """
1178 Return the number of fields contained in the structure.
1179 If the field does not exist or is not of the type requested,
1180 the value returned is undefined.
1181 """
1182
1183 return nbt._bt_ctf_get_struct_field_count(self._d)
1184
1185 def _get_struct_field_at(self, i):
1186 """
1187 Return the structure's field at position i.
1188 If the field does not exist or is not of the type requested,
1189 the value returned is undefined. To check if an error occurred,
1190 use the field_error() function after accessing a field.
1191 """
1192
1193 return nbt._bt_ctf_get_struct_field_index(self._d, i)
1194
1195 @property
1196 def value(self):
1197 """
1198 Return the value associated with the field according to its type.
1199 Return None on error.
1200 """
1201
1202 id = self.type
1203 value = None
1204
1205 if id == common.CTFTypeId.STRING:
1206 value = self._get_str()
1207 elif id == common.CTFTypeId.ARRAY:
1208 element_decl = self.declaration.element_declaration
1209
1210 if ((element_decl.type == common.CTFTypeId.INTEGER
1211 and element_decl.length == 8)
1212 and (element_decl.encoding == common.CTFStringEncoding.ASCII or element_decl.encoding == common.CTFStringEncoding.UTF8)):
1213 value = nbt._bt_python_get_array_string(self._d)
1214 else:
1215 value = []
1216
1217 for i in range(self.declaration.length):
1218 element = self._get_array_element_at(i)
1219 value.append(element.value)
1220 elif id == common.CTFTypeId.INTEGER:
1221 if self.declaration.signedness == 0:
1222 value = self._get_uint64()
1223 else:
1224 value = self._get_int64()
1225 elif id == common.CTFTypeId.ENUM:
1226 value = self._get_enum_str()
1227 elif id == common.CTFTypeId.SEQUENCE:
1228 element_decl = self.declaration.element_declaration
1229
1230 if ((element_decl.type == common.CTFTypeId.INTEGER
1231 and element_decl.length == 8)
1232 and (element_decl.encoding == common.CTFStringEncoding.ASCII or element_decl.encoding == common.CTFStringEncoding.UTF8)):
1233 value = nbt._bt_python_get_sequence_string(self._d)
1234 else:
1235 seq_len = self._get_sequence_len()
1236 value = []
1237
1238 for i in range(seq_len):
1239 evDef = self._get_sequence_element_at(i)
1240 value.append(evDef.value)
1241 elif id == common.CTFTypeId.FLOAT:
1242 value = self._get_float()
1243 elif id == common.CTFTypeId.VARIANT:
1244 variant = _Definition.__new__(_Definition)
1245 variant._d = self._get_variant()
1246 value = variant.value
1247 elif id == common.CTFTypeId.STRUCT:
1248 value = {}
1249
1250 for i in range(self._get_struct_field_count()):
1251 member = _Definition(self._get_struct_field_at(i), self.scope)
1252 value[member.name] = member.value
1253
1254 if field_error():
1255 raise FieldError(
1256 "Error occurred while accessing field {} of type {}".format(
1257 self.name,
1258 common.CTFTypeId.type_name(id)))
1259
1260 return value
1261
1262 @property
1263 def scope(self):
1264 """Return the scope of a field or None on error."""
1265
1266 return self._s
This page took 0.061046 seconds and 4 git commands to generate.