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