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