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