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