Python: split API in reader/writer modules
[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
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
239class _ClockType:
240 CLOCK_CYCLES = 0
241 CLOCK_REAL = 1
242
243
244class 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
330class 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
615class 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
627class 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
730class 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
772class 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 length(self):
814 """
815 Integer size in bits, or a negative value on error.
816 """
817
818 return nbt._bt_ctf_get_int_len(self._fd)
819
820 @property
821 def encoding(self):
822 """
823 Integer encoding (one of
824 :class:`babeltrace.common.CTFStringEncoding` constants).
825 """
826
827 return nbt._bt_ctf_get_encoding(self._fd)
828
829
830class EnumerationFieldDeclaration(FieldDeclaration):
831 """
832 Enumeration field declaration.
833
834 .. note::
835
836 As of this version, this class is missing some properties.
837 """
838
839 def __init__(self):
840 raise NotImplementedError("EnumerationFieldDeclaration cannot be instantiated")
841
842
843class ArrayFieldDeclaration(FieldDeclaration):
844 """
845 Static array field declaration.
846 """
847
848 def __init__(self):
849 raise NotImplementedError("ArrayFieldDeclaration cannot be instantiated")
850
851 @property
852 def length(self):
853 """
854 Fixed length of this static array (number of contained
855 elements), or a negative value on error.
856 """
857
858 return nbt._bt_ctf_get_array_len(self._fd)
859
860 @property
861 def element_declaration(self):
862 """
863 Field declaration of the underlying element.
864 """
865
866 field_decl_ptr = nbt._bt_python_get_array_element_declaration(self._fd)
867
868 return _create_field_declaration(field_decl_ptr, "", self.scope)
869
870
871class SequenceFieldDeclaration(FieldDeclaration):
872 """
873 Sequence (dynamic array) field declaration.
874
875 .. note::
876
877 As of this version, this class is missing some properties.
878 """
879
880 def __init__(self):
881 raise NotImplementedError("SequenceFieldDeclaration cannot be instantiated")
882
883 @property
884 def element_declaration(self):
885 """
886 Field declaration of the underlying element.
887 """
888
889 field_decl_ptr = nbt._bt_python_get_sequence_element_declaration(self._fd)
890
891 return _create_field_declaration(field_decl_ptr, "", self.scope)
892
893
894class FloatFieldDeclaration(FieldDeclaration):
895 """
896 Floating point number field declaration.
897
898 .. note::
899
900 As of this version, this class is missing some properties.
901 """
902
903 def __init__(self):
904 raise NotImplementedError("FloatFieldDeclaration cannot be instantiated")
905
906
907class StructureFieldDeclaration(FieldDeclaration):
908 """
909 Structure (ordered map of field names to field declarations) field
910 declaration.
911
912 .. note::
913
914 As of this version, this class is missing some properties.
915 """
916
917 def __init__(self):
918 raise NotImplementedError("StructureFieldDeclaration cannot be instantiated")
919
920
921class StringFieldDeclaration(FieldDeclaration):
922 """
923 String (NULL-terminated array of bytes) field declaration.
924
925 .. note::
926
927 As of this version, this class is missing some properties.
928 """
929
930 def __init__(self):
931 raise NotImplementedError("StringFieldDeclaration cannot be instantiated")
932
933
934class VariantFieldDeclaration(FieldDeclaration):
935 """
936 Variant (dynamic selection between different types) field declaration.
937
938 .. note::
939
940 As of this version, this class is missing some properties.
941 """
942
943 def __init__(self):
944 raise NotImplementedError("VariantFieldDeclaration cannot be instantiated")
945
946
947def field_error():
948 """
949 Return the last error code encountered while
950 accessing a field and reset the error flag.
951 Return 0 if no error, a negative value otherwise.
952 """
953
954 return nbt._bt_ctf_field_get_error()
955
956
957def _create_field_declaration(declaration_ptr, name, scope):
958 """
959 Private field declaration factory.
960 """
961
962 if declaration_ptr is None:
963 raise ValueError("declaration_ptr must be valid")
964 if scope not in _scopes:
965 raise ValueError("Invalid scope provided")
966
967 type = nbt._bt_ctf_field_type(declaration_ptr)
968 declaration = None
969
970 if type == common.CTFTypeId.INTEGER:
971 declaration = IntegerFieldDeclaration.__new__(IntegerFieldDeclaration)
972 elif type == common.CTFTypeId.ENUM:
973 declaration = EnumerationFieldDeclaration.__new__(EnumerationFieldDeclaration)
974 elif type == common.CTFTypeId.ARRAY:
975 declaration = ArrayFieldDeclaration.__new__(ArrayFieldDeclaration)
976 elif type == common.CTFTypeId.SEQUENCE:
977 declaration = SequenceFieldDeclaration.__new__(SequenceFieldDeclaration)
978 elif type == common.CTFTypeId.FLOAT:
979 declaration = FloatFieldDeclaration.__new__(FloatFieldDeclaration)
980 elif type == common.CTFTypeId.STRUCT:
981 declaration = StructureFieldDeclaration.__new__(StructureFieldDeclaration)
982 elif type == common.CTFTypeId.STRING:
983 declaration = StringFieldDeclaration.__new__(StringFieldDeclaration)
984 elif type == common.CTFTypeId.VARIANT:
985 declaration = VariantFieldDeclaration.__new__(VariantFieldDeclaration)
986 else:
987 return declaration
988
989 declaration._fd = declaration_ptr
990 declaration._s = scope
991 declaration._name = name
992
993 return declaration
994
995
996class _Definition:
997 def __init__(self, definition_ptr, scope):
998 self._d = definition_ptr
999 self._s = scope
1000
1001 if scope not in _scopes:
1002 ValueError("Invalid scope provided")
1003
1004 @property
1005 def name(self):
1006 """Return the name of a field or None on error."""
1007
1008 return nbt._bt_ctf_field_name(self._d)
1009
1010 @property
1011 def type(self):
1012 """Return the type of a field or -1 if unknown."""
1013
1014 return nbt._bt_ctf_field_type(nbt._bt_ctf_get_decl_from_def(self._d))
1015
1016 @property
1017 def declaration(self):
1018 """Return the associated Definition object."""
1019
1020 return _create_field_declaration(
1021 nbt._bt_ctf_get_decl_from_def(self._d), self.name, self.scope)
1022
1023 def _get_enum_str(self):
1024 """
1025 Return the string matching the current enumeration.
1026 Return None on error.
1027 """
1028
1029 return nbt._bt_ctf_get_enum_str(self._d)
1030
1031 def _get_array_element_at(self, index):
1032 """
1033 Return the array's element at position index.
1034 Return None on error
1035 """
1036
1037 array_ptr = nbt._bt_python_get_array_from_def(self._d)
1038
1039 if array_ptr is None:
1040 return None
1041
1042 definition_ptr = nbt._bt_array_index(array_ptr, index)
1043
1044 if definition_ptr is None:
1045 return None
1046
1047 return _Definition(definition_ptr, self.scope)
1048
1049 def _get_sequence_len(self):
1050 """
1051 Return the len of a sequence or a negative
1052 value on error.
1053 """
1054
1055 seq = nbt._bt_python_get_sequence_from_def(self._d)
1056
1057 return nbt._bt_sequence_len(seq)
1058
1059 def _get_sequence_element_at(self, index):
1060 """
1061 Return the sequence's element at position index,
1062 otherwise return None
1063 """
1064
1065 seq = nbt._bt_python_get_sequence_from_def(self._d)
1066
1067 if seq is not None:
1068 definition_ptr = nbt._bt_sequence_index(seq, index)
1069
1070 if definition_ptr is not None:
1071 return _Definition(definition_ptr, self.scope)
1072
1073 def _get_uint64(self):
1074 """
1075 Return the value associated with the field.
1076 If the field does not exist or is not of the type requested,
1077 the value returned is undefined. To check if an error occured,
1078 use the field_error() function after accessing a field.
1079 """
1080
1081 return nbt._bt_ctf_get_uint64(self._d)
1082
1083 def _get_int64(self):
1084 """
1085 Return the value associated with the field.
1086 If the field does not exist or is not of the type requested,
1087 the value returned is undefined. To check if an error occured,
1088 use the field_error() function after accessing a field.
1089 """
1090
1091 return nbt._bt_ctf_get_int64(self._d)
1092
1093 def _get_char_array(self):
1094 """
1095 Return the value associated with the field.
1096 If the field does not exist or is not of the type requested,
1097 the value returned is undefined. To check if an error occurred,
1098 use the field_error() function after accessing a field.
1099 """
1100
1101 return nbt._bt_ctf_get_char_array(self._d)
1102
1103 def _get_str(self):
1104 """
1105 Return the value associated with the field.
1106 If the field does not exist or is not of the type requested,
1107 the value returned is undefined. To check if an error occurred,
1108 use the field_error() function after accessing a field.
1109 """
1110
1111 return nbt._bt_ctf_get_string(self._d)
1112
1113 def _get_float(self):
1114 """
1115 Return the value associated with the field.
1116 If the field does not exist or is not of the type requested,
1117 the value returned is undefined. To check if an error occurred,
1118 use the field_error() function after accessing a field.
1119 """
1120
1121 return nbt._bt_ctf_get_float(self._d)
1122
1123 def _get_variant(self):
1124 """
1125 Return the variant's selected field.
1126 If the field does not exist or is not of the type requested,
1127 the value returned is undefined. To check if an error occurred,
1128 use the field_error() function after accessing a field.
1129 """
1130
1131 return nbt._bt_ctf_get_variant(self._d)
1132
1133 def _get_struct_field_count(self):
1134 """
1135 Return the number of fields contained in the structure.
1136 If the field does not exist or is not of the type requested,
1137 the value returned is undefined.
1138 """
1139
1140 return nbt._bt_ctf_get_struct_field_count(self._d)
1141
1142 def _get_struct_field_at(self, i):
1143 """
1144 Return the structure's field at position i.
1145 If the field does not exist or is not of the type requested,
1146 the value returned is undefined. To check if an error occurred,
1147 use the field_error() function after accessing a field.
1148 """
1149
1150 return nbt._bt_ctf_get_struct_field_index(self._d, i)
1151
1152 @property
1153 def value(self):
1154 """
1155 Return the value associated with the field according to its type.
1156 Return None on error.
1157 """
1158
1159 id = self.type
1160 value = None
1161
1162 if id == common.CTFTypeId.STRING:
1163 value = self._get_str()
1164 elif id == common.CTFTypeId.ARRAY:
1165 element_decl = self.declaration.element_declaration
1166
1167 if ((element_decl.type == common.CTFTypeId.INTEGER
1168 and element_decl.length == 8)
1169 and (element_decl.encoding == common.CTFStringEncoding.ASCII or element_decl.encoding == common.CTFStringEncoding.UTF8)):
1170 value = nbt._bt_python_get_array_string(self._d)
1171 else:
1172 value = []
1173
1174 for i in range(self.declaration.length):
1175 element = self._get_array_element_at(i)
1176 value.append(element.value)
1177 elif id == common.CTFTypeId.INTEGER:
1178 if self.declaration.signedness == 0:
1179 value = self._get_uint64()
1180 else:
1181 value = self._get_int64()
1182 elif id == common.CTFTypeId.ENUM:
1183 value = self._get_enum_str()
1184 elif id == common.CTFTypeId.SEQUENCE:
1185 element_decl = self.declaration.element_declaration
1186
1187 if ((element_decl.type == common.CTFTypeId.INTEGER
1188 and element_decl.length == 8)
1189 and (element_decl.encoding == common.CTFStringEncoding.ASCII or element_decl.encoding == common.CTFStringEncoding.UTF8)):
1190 value = nbt._bt_python_get_sequence_string(self._d)
1191 else:
1192 seq_len = self._get_sequence_len()
1193 value = []
1194
1195 for i in range(seq_len):
1196 evDef = self._get_sequence_element_at(i)
1197 value.append(evDef.value)
1198 elif id == common.CTFTypeId.FLOAT:
1199 value = self._get_float()
1200 elif id == common.CTFTypeId.VARIANT:
1201 variant = _Definition.__new__(_Definition)
1202 variant._d = self._get_variant()
1203 value = variant.value
1204 elif id == common.CTFTypeId.STRUCT:
1205 value = {}
1206
1207 for i in range(self._get_struct_field_count()):
1208 member = _Definition(self._get_struct_field_at(i), self.scope)
1209 value[member.name] = member.value
1210
1211 if field_error():
1212 raise FieldError(
1213 "Error occurred while accessing field {} of type {}".format(
1214 self.name,
1215 common.CTFTypeId.type_name(id)))
1216
1217 return value
1218
1219 @property
1220 def scope(self):
1221 """Return the scope of a field or None on error."""
1222
1223 return self._s
This page took 0.065772 seconds and 4 git commands to generate.