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