19e307cda1c16aa2e303f20c92b3fd9a963c7ccd
[babeltrace.git] / bindings / python / bt.py
1 # nativebt.i.in
2 #
3 # Babeltrace native 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 collections
30 import os
31 from datetime import datetime
32 from uuid import UUID
33
34
35 class TraceCollection:
36 """
37 A :class:`TraceCollection` is a collection of opened traces.
38
39 In general, once a trace collection is created, you add one to many
40 independent traces to it using :meth:`add_trace` or
41 :meth:`add_traces_recursive`, and then iterate the ordered events
42 of all traces merged together using :attr:`events`.
43
44 You may use :meth:`remove_trace` to close and remove a specific
45 trace from a trace collection, although all the traces of a given
46 trace collection will be automatically removed when it is garbage
47 collected.
48 """
49
50 def __init__(self):
51 """
52 Creates an empty trace collection.
53 """
54
55 self._tc = nbt._bt_context_create()
56
57 def __del__(self):
58 nbt._bt_context_put(self._tc)
59
60 def add_trace(self, path, format_str):
61 """
62 Adds a trace to the trace collection.
63
64 The trace is located at the file system path *path*. This
65 function **does not** recurse directories to find the trace:
66 *path* must point to the exact trace location (see
67 :meth:`add_traces_recursive` for a recursive version of this
68 function).
69
70 *format_str* is a string indicating the Babeltrace type of the
71 trace to add. ``ctf`` is the only currently supported trace
72 format.
73
74 Once added, the trace is opened.
75
76 Returns the corresponding :class:`TraceHandle` instance for
77 this opened trace on success, or ``None`` on error.
78 """
79
80 ret = nbt._bt_context_add_trace(self._tc, path, format_str,
81 None, None, None)
82
83 if ret < 0:
84 return None
85
86 th = TraceHandle.__new__(TraceHandle)
87 th._id = ret
88 th._trace_collection = self
89
90 return th
91
92 def add_traces_recursive(self, path, format_str):
93 """
94 Adds traces to this trace collection by recursively searching
95 in the *path* directory.
96
97 *format_str* is a string indicating the Babeltrace type of the
98 traces to find and add. ``ctf`` is the only currently supported
99 trace format.
100
101 See also :meth:`add_trace`.
102
103 Returns a :class:`dict` object mapping full paths to trace
104 handles for each trace found, or ``None`` on error.
105 """
106
107 trace_handles = {}
108 noTrace = True
109 error = False
110
111 for fullpath, dirs, files in os.walk(path):
112 if "metadata" in files:
113 trace_handle = self.add_trace(fullpath, format_str)
114
115 if trace_handle is None:
116 error = True
117 continue
118
119 trace_handles[fullpath] = trace_handle
120 noTrace = False
121
122 if noTrace and error:
123 return None
124
125 return trace_handles
126
127 def remove_trace(self, trace_handle):
128 """
129 Removes a trace from the trace collection using its trace
130 handle *trace_handle*.
131
132 :class:`TraceHandle` objects are returned by :meth:`add_trace`
133 and :meth:`add_traces_recursive`.
134
135 The trace is closed before being removed.
136 """
137
138 try:
139 nbt._bt_context_remove_trace(self._tc, trace_handle._id)
140 except AttributeError:
141 raise TypeError("in remove_trace, argument 2 must be a TraceHandle instance")
142
143 @property
144 def events(self):
145 """
146 Generates the ordered :class:`Event` objects of all the opened
147 traces contained in this trace collection. Iterate this function
148 to iterate actual events.
149
150 Due to limitations of the native Babeltrace API, only one event
151 may be "alive" at a given time, i.e. a user **should never**
152 store a copy of the events returned by this function for
153 ulterior use. Users shall make sure to copy the information
154 they need *from* an event before accessing the next one.
155
156 Furthermore, :class:`Event` objects become invalid when the
157 generator goes out of scope as the underlying iterator will be
158 reclaimed. Using an event after the the generator has gone out
159 of scope may result in a crash or data corruption.
160 """
161
162 begin_pos_ptr = nbt._bt_iter_pos()
163 end_pos_ptr = nbt._bt_iter_pos()
164 begin_pos_ptr.type = nbt.SEEK_BEGIN
165 end_pos_ptr.type = nbt.SEEK_LAST
166
167 for event in self._events(begin_pos_ptr, end_pos_ptr):
168 yield event
169
170 def events_timestamps(self, timestamp_begin, timestamp_end):
171 """
172 Generates the ordered :class:`Event` objects of all the opened
173 traces contained in this trace collection from *timestamp_begin*
174 to *timestamp_end*.
175
176 See :attr:`events` for notes and limitations.
177 """
178
179 begin_pos_ptr = nbt._bt_iter_pos()
180 end_pos_ptr = nbt._bt_iter_pos()
181 begin_pos_ptr.type = end_pos_ptr.type = nbt.SEEK_TIME
182 begin_pos_ptr.u.seek_time = timestamp_begin
183 end_pos_ptr.u.seek_time = timestamp_end
184
185 for event in self._events(begin_pos_ptr, end_pos_ptr):
186 yield event
187
188 @property
189 def timestamp_begin(self):
190 """
191 Trace collection's begin timestamp.
192 """
193
194 pos_ptr = nbt._bt_iter_pos()
195 pos_ptr.type = nbt.SEEK_BEGIN
196
197 return self._timestamp_at_pos(pos_ptr)
198
199 @property
200 def timestamp_end(self):
201 """
202 Trace collection's end timestamp.
203 """
204
205 pos_ptr = nbt._bt_iter_pos()
206 pos_ptr.type = nbt.SEEK_LAST
207
208 return self._timestamp_at_pos(pos_ptr)
209
210 def _timestamp_at_pos(self, pos_ptr):
211 ctf_it_ptr = nbt._bt_ctf_iter_create(self._tc, pos_ptr, pos_ptr)
212
213 if ctf_it_ptr is None:
214 raise NotImplementedError("Creation of multiple iterators is unsupported.")
215
216 ev_ptr = nbt._bt_ctf_iter_read_event(ctf_it_ptr)
217 nbt._bt_ctf_iter_destroy(ctf_it_ptr)
218
219 def _events(self, begin_pos_ptr, end_pos_ptr):
220 ctf_it_ptr = nbt._bt_ctf_iter_create(self._tc, begin_pos_ptr, end_pos_ptr)
221
222 if ctf_it_ptr is None:
223 raise NotImplementedError("Creation of multiple iterators is unsupported.")
224
225 while True:
226 ev_ptr = nbt._bt_ctf_iter_read_event(ctf_it_ptr)
227
228 if ev_ptr is None:
229 break
230
231 ev = Event.__new__(Event)
232 ev._e = ev_ptr
233
234 try:
235 yield ev
236 except GeneratorExit:
237 break
238
239 ret = nbt._bt_iter_next(nbt._bt_ctf_get_iter(ctf_it_ptr))
240
241 if ret != 0:
242 break
243
244 nbt._bt_ctf_iter_destroy(ctf_it_ptr)
245
246
247 # Based on enum bt_clock_type in clock-type.h
248 class _ClockType:
249 CLOCK_CYCLES = 0
250 CLOCK_REAL = 1
251
252
253 class TraceHandle:
254 """
255 A :class:`TraceHandle` is a handle allowing the user to manipulate
256 a specific trace directly. It is a unique identifier representing a
257 trace, and is not meant to be instantiated by the user.
258 """
259
260 def __init__(self):
261 raise NotImplementedError("TraceHandle cannot be instantiated")
262
263 def __repr__(self):
264 return "Babeltrace TraceHandle: trace_id('{0}')".format(self._id)
265
266 @property
267 def id(self):
268 """
269 Trace handle's numeric ID.
270 """
271
272 return self._id
273
274 @property
275 def path(self):
276 """
277 Path of the underlying trace.
278 """
279
280 return nbt._bt_trace_handle_get_path(self._trace_collection._tc,
281 self._id)
282
283 @property
284 def timestamp_begin(self):
285 """
286 Buffers creation timestamp (nanoseconds since Epoch) of the
287 underlying trace.
288 """
289
290 return nbt._bt_trace_handle_get_timestamp_begin(self._trace_collection._tc,
291 self._id,
292 _ClockType.CLOCK_REAL)
293
294 @property
295 def timestamp_end(self):
296 """
297 Buffers destruction timestamp (nanoseconds since Epoch) of the
298 underlying trace.
299 """
300
301 return nbt._bt_trace_handle_get_timestamp_end(self._trace_collection._tc,
302 self._id,
303 _ClockType.CLOCK_REAL)
304
305 @property
306 def events(self):
307 """
308 Generates all the :class:`EventDeclaration` objects of the
309 underlying trace.
310
311 Note that this doesn't generate actual trace *events*, but
312 rather their declarations, i.e. their layouts and metadata.
313 """
314
315 ret = nbt._bt_python_event_decl_listcaller(self.id,
316 self._trace_collection._tc)
317
318 if not isinstance(ret, list):
319 return
320
321 ptr_list, count = ret
322
323 for i in range(count):
324 tmp = EventDeclaration.__new__(EventDeclaration)
325 tmp._ed = nbt._bt_python_decl_one_from_list(ptr_list, i)
326 yield tmp
327
328
329 class CTFStringEncoding:
330 """
331 CTF string encodings.
332 """
333
334 #: None
335 NONE = 0
336
337 #: UTF-8
338 UTF8 = 1
339
340 #: ASCII
341 ASCII = 2
342
343 #: Unknown
344 UNKNOWN = 3
345
346
347 # Based on the enum in ctf-writer/writer.h
348 class ByteOrder:
349 """
350 Byte orders.
351 """
352
353 #: Native byte order
354 BYTE_ORDER_NATIVE = 0
355
356 #: Little-endian
357 BYTE_ORDER_LITTLE_ENDIAN = 1
358
359 #: Big-endian
360 BYTE_ORDER_BIG_ENDIAN = 2
361
362 #: Network byte order (big-endian)
363 BYTE_ORDER_NETWORK = 3
364
365 #: Unknown byte order
366 BYTE_ORDER_UNKNOWN = 4 # Python-specific entry
367
368
369 # enum equivalent, accessible constants
370 # These are taken directly from ctf/events.h
371 # All changes to enums must also be made here
372 class CTFTypeId:
373 """
374 CTF numeric type identifiers.
375 """
376
377 #: Unknown type
378 UNKNOWN = 0
379
380 #: Integer
381 INTEGER = 1
382
383 #: Floating point number
384 FLOAT = 2
385
386 #: Enumeration
387 ENUM = 3
388
389 #: String
390 STRING = 4
391
392 #: Structure
393 STRUCT = 5
394
395 #: Untagged variant
396 UNTAGGED_VARIANT = 6
397
398 #: Variant
399 VARIANT = 7
400
401 #: Array
402 ARRAY = 8
403
404 #: Sequence
405 SEQUENCE = 9
406
407 NR_CTF_TYPES = 10
408
409 def type_name(id):
410 """
411 Returns the name of the CTF numeric type identifier *id*.
412 """
413
414 name = "UNKNOWN_TYPE"
415 constants = [
416 attr for attr in dir(CTFTypeId) if not callable(
417 getattr(
418 CTFTypeId,
419 attr)) and not attr.startswith("__")]
420
421 for attr in constants:
422 if getattr(CTFTypeId, attr) == id:
423 name = attr
424 break
425
426 return name
427
428
429 class CTFScope:
430 """
431 CTF scopes.
432 """
433
434 #: Packet header
435 TRACE_PACKET_HEADER = 0
436
437 #: Packet context
438 STREAM_PACKET_CONTEXT = 1
439
440 #: Event header
441 STREAM_EVENT_HEADER = 2
442
443 #: Stream event context
444 STREAM_EVENT_CONTEXT = 3
445
446 #: Event context
447 EVENT_CONTEXT = 4
448
449 #: Event fields
450 EVENT_FIELDS = 5
451
452 def scope_name(scope):
453 """
454 Returns the name of the CTF scope *scope*.
455 """
456
457 name = "UNKNOWN_SCOPE"
458 constants = [
459 attr for attr in dir(CTFScope) if not callable(
460 getattr(
461 CTFScope,
462 attr)) and not attr.startswith("__")]
463
464 for attr in constants:
465 if getattr(CTFScope, attr) == scope:
466 name = attr
467 break
468
469 return name
470
471
472 # Priority of the scopes when searching for event fields
473 _scopes = [
474 CTFScope.EVENT_FIELDS,
475 CTFScope.EVENT_CONTEXT,
476 CTFScope.STREAM_EVENT_CONTEXT,
477 CTFScope.STREAM_EVENT_HEADER,
478 CTFScope.STREAM_PACKET_CONTEXT,
479 CTFScope.TRACE_PACKET_HEADER
480 ]
481
482
483 class Event(collections.Mapping):
484 """
485 An :class:`Event` object represents a trace event. :class:`Event`
486 objects are returned by :attr:`TraceCollection.events` and are
487 not meant to be instantiated by the user.
488
489 :class:`Event` has a :class:`dict`-like interface for accessing
490 an event's field value by field name:
491
492 .. code-block:: python
493
494 event['my_field']
495
496 If a field name exists in multiple scopes, the value of the first
497 field found is returned. The scopes are searched in the following
498 order:
499
500 1. Event fields (:attr:`CTFScope.EVENT_FIELDS`)
501 2. Event context (:attr:`CTFScope.EVENT_CONTEXT`)
502 3. Stream event context (:attr:`CTFScope.STREAM_EVENT_CONTEXT`)
503 4. Event header (:attr:`CTFScope.STREAM_EVENT_HEADER`)
504 5. Packet context (:attr:`CTFScope.STREAM_PACKET_CONTEXT`)
505 6. Packet header (:attr:`CTFScope.TRACE_PACKET_HEADER`)
506
507 It is still possible to obtain a field's value from a specific
508 scope using :meth:`field_with_scope`.
509
510 Field values are returned as native Python types, that is:
511
512 +-----------------------+----------------------------------+
513 | Field type | Python type |
514 +=======================+==================================+
515 | Integer | :class:`int` |
516 +-----------------------+----------------------------------+
517 | Floating point number | :class:`float` |
518 +-----------------------+----------------------------------+
519 | Enumeration | :class:`str` (enumeration label) |
520 +-----------------------+----------------------------------+
521 | String | :class:`str` |
522 +-----------------------+----------------------------------+
523 | Array | :class:`list` of native Python |
524 | | objects |
525 +-----------------------+----------------------------------+
526 | Sequence | :class:`list` of native Python |
527 | | objects |
528 +-----------------------+----------------------------------+
529 | Structure | :class:`dict` mapping field |
530 | | names to native Python objects |
531 +-----------------------+----------------------------------+
532
533 For example, printing the third element of a sequence named ``seq``
534 in a structure named ``my_struct`` of the ``event``'s field named
535 ``my_field`` is done this way:
536
537 .. code-block:: python
538
539 print(event['my_field']['my_struct']['seq'][2])
540 """
541
542 def __init__(self):
543 raise NotImplementedError("Event cannot be instantiated")
544
545 @property
546 def name(self):
547 """
548 Event's name or ``None`` on error.
549 """
550
551 return nbt._bt_ctf_event_name(self._e)
552
553 @property
554 def cycles(self):
555 """
556 Event's timestamp in cycles or -1 on error.
557 """
558
559 return nbt._bt_ctf_get_cycles(self._e)
560
561 @property
562 def timestamp(self):
563 """
564 Event's timestamp (nanoseconds since Epoch) or -1 on error.
565 """
566
567 return nbt._bt_ctf_get_timestamp(self._e)
568
569 @property
570 def datetime(self):
571 """
572 Event's timestamp as a standard :class:`datetime.datetime`
573 object.
574
575 Note that the :class:`datetime.datetime` class' precision
576 is limited to microseconds, whereas :attr:`timestamp` provides
577 the event's timestamp with a nanosecond resolution.
578 """
579
580 return datetime.fromtimestamp(self.timestamp / 1E9)
581
582 def field_with_scope(self, field_name, scope):
583 """
584 Returns the value of a field named *field_name* within the
585 scope *scope*, or ``None`` if the field cannot be found.
586
587 *scope* must be one of :class:`CTFScope` constants.
588 """
589
590 if scope not in _scopes:
591 raise ValueError("Invalid scope provided")
592
593 field = self._field_with_scope(field_name, scope)
594
595 if field is not None:
596 return field.value
597
598 def field_list_with_scope(self, scope):
599 """
600 Returns a list of field names in the scope *scope*.
601 """
602
603 if scope not in _scopes:
604 raise ValueError("Invalid scope provided")
605
606 field_names = []
607
608 for field in self._field_list_with_scope(scope):
609 field_names.append(field.name)
610
611 return field_names
612
613 @property
614 def handle(self):
615 """
616 :class:`TraceHandle` object containing this event, or ``None``
617 on error.
618 """
619
620 ret = nbt._bt_ctf_event_get_handle_id(self._e)
621
622 if ret < 0:
623 return None
624
625 th = TraceHandle.__new__(TraceHandle)
626 th._id = ret
627 th._trace_collection = self.get_trace_collection()
628
629 return th
630
631 @property
632 def trace_collection(self):
633 """
634 :class:`TraceCollection` object containing this event, or
635 ``None`` on error.
636 """
637
638 trace_collection = TraceCollection()
639 trace_collection._tc = nbt._bt_ctf_event_get_context(self._e)
640
641 if trace_collection._tc is not None:
642 return trace_collection
643
644 def __getitem__(self, field_name):
645 field = self._field(field_name)
646
647 if field is not None:
648 return field.value
649
650 raise KeyError(field_name)
651
652 def __iter__(self):
653 for key in self.keys():
654 yield key
655
656 def __len__(self):
657 count = 0
658
659 for scope in _scopes:
660 scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
661 ret = nbt._bt_python_field_listcaller(self._e, scope_ptr)
662
663 if isinstance(ret, list):
664 count += ret[1]
665
666 return count
667
668 def __contains__(self, field_name):
669 return self._field(field_name) is not None
670
671 def keys(self):
672 """
673 Returns the list of field names.
674
675 Note: field names are unique within the returned list, although
676 a field name could exist in multiple scopes. Use
677 :meth:`field_list_with_scope` to obtain the list of field names
678 of a given scope.
679 """
680
681 field_names = set()
682
683 for scope in _scopes:
684 for name in self.field_list_with_scope(scope):
685 field_names.add(name)
686
687 return list(field_names)
688
689 def get(self, field_name, default=None):
690 """
691 Returns the value of the field named *field_name*, or *default*
692 when not found.
693
694 See :class:`Event` note about how fields are retrieved by
695 name when multiple fields share the same name in different
696 scopes.
697 """
698
699 field = self._field(field_name)
700
701 if field is None:
702 return default
703
704 return field.value
705
706 def items(self):
707 """
708 Generates pairs of (field name, field value).
709
710 This method iterates :meth:`keys` to find field names, which
711 means some fields could be unavailable if other fields share
712 their names in scopes with higher priorities.
713 """
714
715 for field in self.keys():
716 yield (field, self[field])
717
718 def _field_with_scope(self, field_name, scope):
719 scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
720
721 if scope_ptr is None:
722 return None
723
724 definition_ptr = nbt._bt_ctf_get_field(self._e, scope_ptr, field_name)
725
726 if definition_ptr is None:
727 return None
728
729 field = _Definition(definition_ptr, scope)
730
731 return field
732
733 def _field(self, field_name):
734 field = None
735
736 for scope in _scopes:
737 field = self._field_with_scope(field_name, scope)
738
739 if field is not None:
740 break
741
742 return field
743
744 def _field_list_with_scope(self, scope):
745 fields = []
746 scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
747
748 # Returns a list [list_ptr, count]. If list_ptr is NULL, SWIG will only
749 # provide the "count" return value
750 count = 0
751 list_ptr = None
752 ret = nbt._bt_python_field_listcaller(self._e, scope_ptr)
753
754 if isinstance(ret, list):
755 list_ptr, count = ret
756
757 for i in range(count):
758 definition_ptr = nbt._bt_python_field_one_from_list(list_ptr, i)
759
760 if definition_ptr is not None:
761 definition = _Definition(definition_ptr, scope)
762 fields.append(definition)
763
764 return fields
765
766
767 class FieldError(Exception):
768 """
769 Field error, raised when a field's value cannot be accessed.
770 """
771
772 def __init__(self, value):
773 self.value = value
774
775 def __str__(self):
776 return repr(self.value)
777
778
779 class EventDeclaration:
780 """
781 An event declaration contains the properties of a class of events,
782 that is, the common properties and fields layout of all the actual
783 recorded events associated with this declaration.
784
785 This class is not meant to be instantiated by the user. It is
786 returned by :attr:`TraceHandle.events`.
787 """
788
789 MAX_UINT64 = 0xFFFFFFFFFFFFFFFF
790
791 def __init__(self):
792 raise NotImplementedError("EventDeclaration cannot be instantiated")
793
794 @property
795 def name(self):
796 """
797 Event's name, or ``None`` on error.
798 """
799
800 return nbt._bt_ctf_get_decl_event_name(self._ed)
801
802 @property
803 def id(self):
804 """
805 Event's numeric ID, or -1 on error.
806 """
807
808 id = nbt._bt_ctf_get_decl_event_id(self._ed)
809
810 if id == self.MAX_UINT64:
811 id = -1
812
813 return id
814
815 @property
816 def fields(self):
817 """
818 Generates all the event's field declarations, going through
819 each scope in the following order:
820
821 1. Event fields (:attr:`CTFScope.EVENT_FIELDS`)
822 2. Event context (:attr:`CTFScope.EVENT_CONTEXT`)
823 3. Stream event context (:attr:`CTFScope.STREAM_EVENT_CONTEXT`)
824 4. Event header (:attr:`CTFScope.STREAM_EVENT_HEADER`)
825 5. Packet context (:attr:`CTFScope.STREAM_PACKET_CONTEXT`)
826 6. Packet header (:attr:`CTFScope.TRACE_PACKET_HEADER`)
827
828 All the generated field declarations inherit
829 :class:`FieldDeclaration`, and are among:
830
831 * :class:`IntegerFieldDeclaration`
832 * :class:`FloatFieldDeclaration`
833 * :class:`EnumerationFieldDeclaration`
834 * :class:`StringFieldDeclaration`
835 * :class:`ArrayFieldDeclaration`
836 * :class:`SequenceFieldDeclaration`
837 * :class:`StructureFieldDeclaration`
838 * :class:`VariantFieldDeclaration`
839 """
840
841 for scope in _scopes:
842 for declaration in self.fields_scope(scope):
843 yield declaration
844
845 def fields_scope(self, scope):
846 """
847 Generates all the field declarations of the event's scope
848 *scope*.
849
850 *scope* must be one of :class:`CTFScope` constants.
851
852 All the generated field declarations inherit
853 :class:`FieldDeclaration`, and are among:
854
855 * :class:`IntegerFieldDeclaration`
856 * :class:`FloatFieldDeclaration`
857 * :class:`EnumerationFieldDeclaration`
858 * :class:`StringFieldDeclaration`
859 * :class:`ArrayFieldDeclaration`
860 * :class:`SequenceFieldDeclaration`
861 * :class:`StructureFieldDeclaration`
862 * :class:`VariantFieldDeclaration`
863 """
864 ret = nbt._by_python_field_decl_listcaller(self._ed, scope)
865
866 if not isinstance(ret, list):
867 return
868
869 list_ptr, count = ret
870
871 for i in range(count):
872 field_decl_ptr = nbt._bt_python_field_decl_one_from_list(list_ptr, i)
873
874 if field_decl_ptr is not None:
875 decl_ptr = nbt._bt_ctf_get_decl_from_field_decl(field_decl_ptr)
876 name = nbt._bt_ctf_get_decl_field_name(field_decl_ptr)
877 field_declaration = _create_field_declaration(decl_ptr, name,
878 scope)
879 yield field_declaration
880
881
882 class FieldDeclaration:
883 """
884 Base class for concrete field declarations.
885
886 This class is not meant to be instantiated by the user.
887 """
888
889 def __init__(self):
890 raise NotImplementedError("FieldDeclaration cannot be instantiated")
891
892 def __repr__(self):
893 return "({0}) {1} {2}".format(CTFScope.scope_name(self.scope),
894 CTFTypeId.type_name(self.type),
895 self.name)
896
897 @property
898 def name(self):
899 """
900 Field's name, or ``None`` on error.
901 """
902
903 return self._name
904
905 @property
906 def type(self):
907 """
908 Field's type (one of :class:`CTFTypeId` constants).
909 """
910
911 return nbt._bt_ctf_field_type(self._fd)
912
913 @property
914 def scope(self):
915 """
916 Field's scope (one of :class:`CTFScope` constants).
917 """
918
919 return self._s
920
921
922 class IntegerFieldDeclaration(FieldDeclaration):
923 """Do not instantiate."""
924
925 def __init__(self):
926 raise NotImplementedError("IntegerFieldDeclaration cannot be instantiated")
927
928 @property
929 def signedness(self):
930 """
931 Return the signedness of an integer:
932 0 if unsigned; 1 if signed; -1 on error.
933 """
934
935 return nbt._bt_ctf_get_int_signedness(self._fd)
936
937 @property
938 def base(self):
939 """Return the base of an int or a negative value on error."""
940
941 return nbt._bt_ctf_get_int_base(self._fd)
942
943 @property
944 def byte_order(self):
945 """
946 Return the byte order. One of class ByteOrder's entries.
947 """
948
949 ret = nbt._bt_ctf_get_int_byte_order(self._fd)
950
951 if ret == 1234:
952 return ByteOrder.BYTE_ORDER_LITTLE_ENDIAN
953 elif ret == 4321:
954 return ByteOrder.BYTE_ORDER_BIG_ENDIAN
955 else:
956 return ByteOrder.BYTE_ORDER_UNKNOWN
957
958 @property
959 def length(self):
960 """
961 Return the size, in bits, of an int or a negative
962 value on error.
963 """
964
965 return nbt._bt_ctf_get_int_len(self._fd)
966
967 @property
968 def encoding(self):
969 """
970 Return the encoding. One of class CTFStringEncoding's entries.
971 Return a negative value on error.
972 """
973
974 return nbt._bt_ctf_get_encoding(self._fd)
975
976
977 class EnumerationFieldDeclaration(FieldDeclaration):
978 """
979 Enumeration field declaration.
980
981 .. note::
982
983 As of this version, this class is missing some properties.
984 """
985
986 def __init__(self):
987 raise NotImplementedError("EnumerationFieldDeclaration cannot be instantiated")
988
989
990 class ArrayFieldDeclaration(FieldDeclaration):
991 """
992 Static array field declaration.
993 """
994
995 def __init__(self):
996 raise NotImplementedError("ArrayFieldDeclaration cannot be instantiated")
997
998 @property
999 def length(self):
1000 """
1001 Static array's fixed length (number of contained elements), or
1002 a negative value on error.
1003 """
1004
1005 return nbt._bt_ctf_get_array_len(self._fd)
1006
1007 @property
1008 def element_declaration(self):
1009 """
1010 Underlying element's field declaration.
1011 """
1012
1013 field_decl_ptr = nbt._bt_python_get_array_element_declaration(self._fd)
1014
1015 return _create_field_declaration(field_decl_ptr, "", self.scope)
1016
1017
1018 class SequenceFieldDeclaration(FieldDeclaration):
1019 """
1020 Sequence (dynamic array) field declaration.
1021
1022 .. note::
1023
1024 As of this version, this class is missing some properties.
1025 """
1026
1027 def __init__(self):
1028 raise NotImplementedError("SequenceFieldDeclaration cannot be instantiated")
1029
1030 @property
1031 def element_declaration(self):
1032 """
1033 Underlying element's field declaration.
1034 """
1035
1036 field_decl_ptr = nbt._bt_python_get_sequence_element_declaration(self._fd)
1037
1038 return _create_field_declaration(field_decl_ptr, "", self.scope)
1039
1040
1041 class FloatFieldDeclaration(FieldDeclaration):
1042 """
1043 Floating point number field declaration.
1044
1045 .. note::
1046
1047 As of this version, this class is missing some properties.
1048 """
1049
1050 def __init__(self):
1051 raise NotImplementedError("FloatFieldDeclaration cannot be instantiated")
1052
1053
1054 class StructureFieldDeclaration(FieldDeclaration):
1055 """Do not instantiate."""
1056
1057 def __init__(self):
1058 raise NotImplementedError("StructureFieldDeclaration cannot be instantiated")
1059
1060
1061 class StringFieldDeclaration(FieldDeclaration):
1062 """Do not instantiate."""
1063
1064 def __init__(self):
1065 raise NotImplementedError("StringFieldDeclaration cannot be instantiated")
1066
1067
1068 class VariantFieldDeclaration(FieldDeclaration):
1069 """Do not instantiate."""
1070
1071 def __init__(self):
1072 raise NotImplementedError("VariantFieldDeclaration cannot be instantiated")
1073
1074
1075 def field_error():
1076 """
1077 Return the last error code encountered while
1078 accessing a field and reset the error flag.
1079 Return 0 if no error, a negative value otherwise.
1080 """
1081
1082 return nbt._bt_ctf_field_get_error()
1083
1084
1085 def _create_field_declaration(declaration_ptr, name, scope):
1086 """
1087 Private field declaration factory.
1088 """
1089
1090 if declaration_ptr is None:
1091 raise ValueError("declaration_ptr must be valid")
1092 if scope not in _scopes:
1093 raise ValueError("Invalid scope provided")
1094
1095 type = nbt._bt_ctf_field_type(declaration_ptr)
1096 declaration = None
1097
1098 if type == CTFTypeId.INTEGER:
1099 declaration = IntegerFieldDeclaration.__new__(IntegerFieldDeclaration)
1100 elif type == CTFTypeId.ENUM:
1101 declaration = EnumerationFieldDeclaration.__new__(EnumerationFieldDeclaration)
1102 elif type == CTFTypeId.ARRAY:
1103 declaration = ArrayFieldDeclaration.__new__(ArrayFieldDeclaration)
1104 elif type == CTFTypeId.SEQUENCE:
1105 declaration = SequenceFieldDeclaration.__new__(SequenceFieldDeclaration)
1106 elif type == CTFTypeId.FLOAT:
1107 declaration = FloatFieldDeclaration.__new__(FloatFieldDeclaration)
1108 elif type == CTFTypeId.STRUCT:
1109 declaration = StructureFieldDeclaration.__new__(StructureFieldDeclaration)
1110 elif type == CTFTypeId.STRING:
1111 declaration = StringFieldDeclaration.__new__(StringFieldDeclaration)
1112 elif type == CTFTypeId.VARIANT:
1113 declaration = VariantFieldDeclaration.__new__(VariantFieldDeclaration)
1114 else:
1115 return declaration
1116
1117 declaration._fd = declaration_ptr
1118 declaration._s = scope
1119 declaration._name = name
1120
1121 return declaration
1122
1123
1124 class _Definition:
1125 def __init__(self, definition_ptr, scope):
1126 self._d = definition_ptr
1127 self._s = scope
1128
1129 if scope not in _scopes:
1130 ValueError("Invalid scope provided")
1131
1132 @property
1133 def name(self):
1134 """Return the name of a field or None on error."""
1135
1136 return nbt._bt_ctf_field_name(self._d)
1137
1138 @property
1139 def type(self):
1140 """Return the type of a field or -1 if unknown."""
1141
1142 return nbt._bt_ctf_field_type(nbt._bt_ctf_get_decl_from_def(self._d))
1143
1144 @property
1145 def declaration(self):
1146 """Return the associated Definition object."""
1147
1148 return _create_field_declaration(
1149 nbt._bt_ctf_get_decl_from_def(self._d), self.name, self.scope)
1150
1151 def _get_enum_str(self):
1152 """
1153 Return the string matching the current enumeration.
1154 Return None on error.
1155 """
1156
1157 return nbt._bt_ctf_get_enum_str(self._d)
1158
1159 def _get_array_element_at(self, index):
1160 """
1161 Return the array's element at position index.
1162 Return None on error
1163 """
1164
1165 array_ptr = nbt._bt_python_get_array_from_def(self._d)
1166
1167 if array_ptr is None:
1168 return None
1169
1170 definition_ptr = nbt._bt_array_index(array_ptr, index)
1171
1172 if definition_ptr is None:
1173 return None
1174
1175 return _Definition(definition_ptr, self.scope)
1176
1177 def _get_sequence_len(self):
1178 """
1179 Return the len of a sequence or a negative
1180 value on error.
1181 """
1182
1183 seq = nbt._bt_python_get_sequence_from_def(self._d)
1184
1185 return nbt._bt_sequence_len(seq)
1186
1187 def _get_sequence_element_at(self, index):
1188 """
1189 Return the sequence's element at position index,
1190 otherwise return None
1191 """
1192
1193 seq = nbt._bt_python_get_sequence_from_def(self._d)
1194
1195 if seq is not None:
1196 definition_ptr = nbt._bt_sequence_index(seq, index)
1197
1198 if definition_ptr is not None:
1199 return _Definition(definition_ptr, self.scope)
1200
1201 def _get_uint64(self):
1202 """
1203 Return the value associated with the field.
1204 If the field does not exist or is not of the type requested,
1205 the value returned is undefined. To check if an error occured,
1206 use the field_error() function after accessing a field.
1207 """
1208
1209 return nbt._bt_ctf_get_uint64(self._d)
1210
1211 def _get_int64(self):
1212 """
1213 Return the value associated with the field.
1214 If the field does not exist or is not of the type requested,
1215 the value returned is undefined. To check if an error occured,
1216 use the field_error() function after accessing a field.
1217 """
1218
1219 return nbt._bt_ctf_get_int64(self._d)
1220
1221 def _get_char_array(self):
1222 """
1223 Return the value associated with the field.
1224 If the field does not exist or is not of the type requested,
1225 the value returned is undefined. To check if an error occurred,
1226 use the field_error() function after accessing a field.
1227 """
1228
1229 return nbt._bt_ctf_get_char_array(self._d)
1230
1231 def _get_str(self):
1232 """
1233 Return the value associated with the field.
1234 If the field does not exist or is not of the type requested,
1235 the value returned is undefined. To check if an error occurred,
1236 use the field_error() function after accessing a field.
1237 """
1238
1239 return nbt._bt_ctf_get_string(self._d)
1240
1241 def _get_float(self):
1242 """
1243 Return the value associated with the field.
1244 If the field does not exist or is not of the type requested,
1245 the value returned is undefined. To check if an error occurred,
1246 use the field_error() function after accessing a field.
1247 """
1248
1249 return nbt._bt_ctf_get_float(self._d)
1250
1251 def _get_variant(self):
1252 """
1253 Return the variant's selected field.
1254 If the field does not exist or is not of the type requested,
1255 the value returned is undefined. To check if an error occurred,
1256 use the field_error() function after accessing a field.
1257 """
1258
1259 return nbt._bt_ctf_get_variant(self._d)
1260
1261 def _get_struct_field_count(self):
1262 """
1263 Return the number of fields contained in the structure.
1264 If the field does not exist or is not of the type requested,
1265 the value returned is undefined.
1266 """
1267
1268 return nbt._bt_ctf_get_struct_field_count(self._d)
1269
1270 def _get_struct_field_at(self, i):
1271 """
1272 Return the structure's field at position i.
1273 If the field does not exist or is not of the type requested,
1274 the value returned is undefined. To check if an error occurred,
1275 use the field_error() function after accessing a field.
1276 """
1277
1278 return nbt._bt_ctf_get_struct_field_index(self._d, i)
1279
1280 @property
1281 def value(self):
1282 """
1283 Return the value associated with the field according to its type.
1284 Return None on error.
1285 """
1286
1287 id = self.type
1288 value = None
1289
1290 if id == CTFTypeId.STRING:
1291 value = self._get_str()
1292 elif id == CTFTypeId.ARRAY:
1293 element_decl = self.declaration.element_declaration
1294
1295 if ((element_decl.type == CTFTypeId.INTEGER
1296 and element_decl.length == 8)
1297 and (element_decl.encoding == CTFStringEncoding.ASCII or element_decl.encoding == CTFStringEncoding.UTF8)):
1298 value = nbt._bt_python_get_array_string(self._d)
1299 else:
1300 value = []
1301
1302 for i in range(self.declaration.length):
1303 element = self._get_array_element_at(i)
1304 value.append(element.value)
1305 elif id == CTFTypeId.INTEGER:
1306 if self.declaration.signedness == 0:
1307 value = self._get_uint64()
1308 else:
1309 value = self._get_int64()
1310 elif id == CTFTypeId.ENUM:
1311 value = self._get_enum_str()
1312 elif id == CTFTypeId.SEQUENCE:
1313 element_decl = self.declaration.element_declaration
1314
1315 if ((element_decl.type == CTFTypeId.INTEGER
1316 and element_decl.length == 8)
1317 and (element_decl.encoding == CTFStringEncoding.ASCII or element_decl.encoding == CTFStringEncoding.UTF8)):
1318 value = nbt._bt_python_get_sequence_string(self._d)
1319 else:
1320 seq_len = self._get_sequence_len()
1321 value = []
1322
1323 for i in range(seq_len):
1324 evDef = self._get_sequence_element_at(i)
1325 value.append(evDef.value)
1326 elif id == CTFTypeId.FLOAT:
1327 value = self._get_float()
1328 elif id == CTFTypeId.VARIANT:
1329 variant = _Definition.__new__(_Definition)
1330 variant._d = self._get_variant()
1331 value = variant.value
1332 elif id == CTFTypeId.STRUCT:
1333 value = {}
1334
1335 for i in range(self._get_struct_field_count()):
1336 member = _Definition(self._get_struct_field_at(i), self.scope)
1337 value[member.name] = member.value
1338
1339 if field_error():
1340 raise FieldError(
1341 "Error occurred while accessing field {} of type {}".format(
1342 self.name,
1343 CTFTypeId.type_name(id)))
1344
1345 return value
1346
1347 @property
1348 def scope(self):
1349 """Return the scope of a field or None on error."""
1350
1351 return self._s
1352
1353
1354 class CTFWriter:
1355 # Used to compare to -1ULL in error checks
1356 _MAX_UINT64 = 0xFFFFFFFFFFFFFFFF
1357
1358 class EnumerationMapping:
1359 """
1360 Enumeration mapping class. start and end values are inclusive.
1361 """
1362
1363 def __init__(self, name, start, end):
1364 self.name = name
1365 self.start = start
1366 self.end = end
1367
1368 class Clock:
1369 def __init__(self, name):
1370 self._c = nbt._bt_ctf_clock_create(name)
1371
1372 if self._c is None:
1373 raise ValueError("Invalid clock name.")
1374
1375 def __del__(self):
1376 nbt._bt_ctf_clock_put(self._c)
1377
1378 @property
1379 def name(self):
1380 """
1381 Get the clock's name.
1382 """
1383
1384 name = nbt._bt_ctf_clock_get_name(self._c)
1385
1386 if name is None:
1387 raise ValueError("Invalid clock instance.")
1388
1389 return name
1390
1391 @property
1392 def description(self):
1393 """
1394 Get the clock's description. None if unset.
1395 """
1396
1397 return nbt._bt_ctf_clock_get_description(self._c)
1398
1399 @description.setter
1400 def description(self, desc):
1401 """
1402 Set the clock's description. The description appears in the clock's TSDL
1403 meta-data.
1404 """
1405
1406 ret = nbt._bt_ctf_clock_set_description(self._c, str(desc))
1407
1408 if ret < 0:
1409 raise ValueError("Invalid clock description.")
1410
1411 @property
1412 def frequency(self):
1413 """
1414 Get the clock's frequency (Hz).
1415 """
1416
1417 freq = nbt._bt_ctf_clock_get_frequency(self._c)
1418
1419 if freq == CTFWriter._MAX_UINT64:
1420 raise ValueError("Invalid clock instance")
1421
1422 return freq
1423
1424 @frequency.setter
1425 def frequency(self, freq):
1426 """
1427 Set the clock's frequency (Hz).
1428 """
1429
1430 ret = nbt._bt_ctf_clock_set_frequency(self._c, freq)
1431
1432 if ret < 0:
1433 raise ValueError("Invalid frequency value.")
1434
1435 @property
1436 def precision(self):
1437 """
1438 Get the clock's precision (in clock ticks).
1439 """
1440
1441 precision = nbt._bt_ctf_clock_get_precision(self._c)
1442
1443 if precision == CTFWriter._MAX_UINT64:
1444 raise ValueError("Invalid clock instance")
1445
1446 return precision
1447
1448 @precision.setter
1449 def precision(self, precision):
1450 """
1451 Set the clock's precision (in clock ticks).
1452 """
1453
1454 ret = nbt._bt_ctf_clock_set_precision(self._c, precision)
1455
1456 @property
1457 def offset_seconds(self):
1458 """
1459 Get the clock's offset in seconds from POSIX.1 Epoch.
1460 """
1461
1462 offset_s = nbt._bt_ctf_clock_get_offset_s(self._c)
1463
1464 if offset_s == CTFWriter._MAX_UINT64:
1465 raise ValueError("Invalid clock instance")
1466
1467 return offset_s
1468
1469 @offset_seconds.setter
1470 def offset_seconds(self, offset_s):
1471 """
1472 Set the clock's offset in seconds from POSIX.1 Epoch.
1473 """
1474
1475 ret = nbt._bt_ctf_clock_set_offset_s(self._c, offset_s)
1476
1477 if ret < 0:
1478 raise ValueError("Invalid offset value.")
1479
1480 @property
1481 def offset(self):
1482 """
1483 Get the clock's offset in ticks from POSIX.1 Epoch + offset in seconds.
1484 """
1485
1486 offset = nbt._bt_ctf_clock_get_offset(self._c)
1487
1488 if offset == CTFWriter._MAX_UINT64:
1489 raise ValueError("Invalid clock instance")
1490
1491 return offset
1492
1493 @offset.setter
1494 def offset(self, offset):
1495 """
1496 Set the clock's offset in ticks from POSIX.1 Epoch + offset in seconds.
1497 """
1498
1499 ret = nbt._bt_ctf_clock_set_offset(self._c, offset)
1500
1501 if ret < 0:
1502 raise ValueError("Invalid offset value.")
1503
1504 @property
1505 def absolute(self):
1506 """
1507 Get a clock's absolute attribute. A clock is absolute if the clock
1508 is a global reference across the trace's other clocks.
1509 """
1510
1511 is_absolute = nbt._bt_ctf_clock_get_is_absolute(self._c)
1512
1513 if is_absolute == -1:
1514 raise ValueError("Invalid clock instance")
1515
1516 return False if is_absolute == 0 else True
1517
1518 @absolute.setter
1519 def absolute(self, is_absolute):
1520 """
1521 Set a clock's absolute attribute. A clock is absolute if the clock
1522 is a global reference across the trace's other clocks.
1523 """
1524
1525 ret = nbt._bt_ctf_clock_set_is_absolute(self._c, int(is_absolute))
1526
1527 if ret < 0:
1528 raise ValueError("Could not set the clock's absolute attribute.")
1529
1530 @property
1531 def uuid(self):
1532 """
1533 Get a clock's UUID (an object of type UUID).
1534 """
1535
1536 uuid_list = []
1537
1538 for i in range(16):
1539 ret, value = nbt._bt_python_ctf_clock_get_uuid_index(self._c, i)
1540
1541 if ret < 0:
1542 raise ValueError("Invalid clock instance")
1543
1544 uuid_list.append(value)
1545
1546 return UUID(bytes=bytes(uuid_list))
1547
1548 @uuid.setter
1549 def uuid(self, uuid):
1550 """
1551 Set a clock's UUID (an object of type UUID).
1552 """
1553
1554 uuid_bytes = uuid.bytes
1555
1556 if len(uuid_bytes) != 16:
1557 raise ValueError("Invalid UUID provided. UUID length must be 16 bytes")
1558
1559 for i in range(len(uuid_bytes)):
1560 ret = nbt._bt_python_ctf_clock_set_uuid_index(self._c, i,
1561 uuid_bytes[i])
1562
1563 if ret < 0:
1564 raise ValueError("Invalid clock instance")
1565
1566 @property
1567 def time(self):
1568 """
1569 Get the current time in nanoseconds since the clock's origin (offset and
1570 offset_s attributes).
1571 """
1572
1573 time = nbt._bt_ctf_clock_get_time(self._c)
1574
1575 if time == CTFWriter._MAX_UINT64:
1576 raise ValueError("Invalid clock instance")
1577
1578 return time
1579
1580 @time.setter
1581 def time(self, time):
1582 """
1583 Set the current time in nanoseconds since the clock's origin (offset and
1584 offset_s attributes). The clock's value will be sampled as events are
1585 appended to a stream.
1586 """
1587
1588 ret = nbt._bt_ctf_clock_set_time(self._c, time)
1589
1590 if ret < 0:
1591 raise ValueError("Invalid time value.")
1592
1593 class FieldDeclaration:
1594 """
1595 FieldDeclaration should not be instantiated directly. Instantiate
1596 one of the concrete FieldDeclaration classes.
1597 """
1598
1599 class IntegerBase:
1600 # These values are based on the bt_ctf_integer_base enum
1601 # declared in event-types.h.
1602 INTEGER_BASE_UNKNOWN = -1
1603 INTEGER_BASE_BINARY = 2
1604 INTEGER_BASE_OCTAL = 8
1605 INTEGER_BASE_DECIMAL = 10
1606 INTEGER_BASE_HEXADECIMAL = 16
1607
1608 def __init__(self):
1609 if self._ft is None:
1610 raise ValueError("FieldDeclaration creation failed.")
1611
1612 def __del__(self):
1613 nbt._bt_ctf_field_type_put(self._ft)
1614
1615 @staticmethod
1616 def _create_field_declaration_from_native_instance(
1617 native_field_declaration):
1618 type_dict = {
1619 CTFTypeId.INTEGER: CTFWriter.IntegerFieldDeclaration,
1620 CTFTypeId.FLOAT: CTFWriter.FloatFieldDeclaration,
1621 CTFTypeId.ENUM: CTFWriter.EnumerationFieldDeclaration,
1622 CTFTypeId.STRING: CTFWriter.StringFieldDeclaration,
1623 CTFTypeId.STRUCT: CTFWriter.StructureFieldDeclaration,
1624 CTFTypeId.VARIANT: CTFWriter.VariantFieldDeclaration,
1625 CTFTypeId.ARRAY: CTFWriter.ArrayFieldDeclaration,
1626 CTFTypeId.SEQUENCE: CTFWriter.SequenceFieldDeclaration
1627 }
1628
1629 field_type_id = nbt._bt_ctf_field_type_get_type_id(native_field_declaration)
1630
1631 if field_type_id == CTFTypeId.UNKNOWN:
1632 raise TypeError("Invalid field instance")
1633
1634 declaration = CTFWriter.Field.__new__(CTFWriter.Field)
1635 declaration._ft = native_field_declaration
1636 declaration.__class__ = type_dict[field_type_id]
1637
1638 return declaration
1639
1640 @property
1641 def alignment(self):
1642 """
1643 Get the field declaration's alignment. Returns -1 on error.
1644 """
1645
1646 return nbt._bt_ctf_field_type_get_alignment(self._ft)
1647
1648 @alignment.setter
1649 def alignment(self, alignment):
1650 """
1651 Set the field declaration's alignment. Defaults to 1 (bit-aligned). However,
1652 some types, such as structures and string, may impose other alignment
1653 constraints.
1654 """
1655
1656 ret = nbt._bt_ctf_field_type_set_alignment(self._ft, alignment)
1657
1658 if ret < 0:
1659 raise ValueError("Invalid alignment value.")
1660
1661 @property
1662 def byte_order(self):
1663 """
1664 Get the field declaration's byte order. One of the ByteOrder's constant.
1665 """
1666
1667 return nbt._bt_ctf_field_type_get_byte_order(self._ft)
1668
1669 @byte_order.setter
1670 def byte_order(self, byte_order):
1671 """
1672 Set the field declaration's byte order. Use constants defined in the ByteOrder
1673 class.
1674 """
1675
1676 ret = nbt._bt_ctf_field_type_set_byte_order(self._ft, byte_order)
1677
1678 if ret < 0:
1679 raise ValueError("Could not set byte order value.")
1680
1681 class IntegerFieldDeclaration(FieldDeclaration):
1682 def __init__(self, size):
1683 """
1684 Create a new integer field declaration of the given size.
1685 """
1686 self._ft = nbt._bt_ctf_field_type_integer_create(size)
1687 super().__init__()
1688
1689 @property
1690 def size(self):
1691 """
1692 Get an integer's size.
1693 """
1694
1695 ret = nbt._bt_ctf_field_type_integer_get_size(self._ft)
1696
1697 if ret < 0:
1698 raise ValueError("Could not get Integer's size attribute.")
1699 else:
1700 return ret
1701
1702 @property
1703 def signed(self):
1704 """
1705 Get an integer's signedness attribute.
1706 """
1707
1708 ret = nbt._bt_ctf_field_type_integer_get_signed(self._ft)
1709
1710 if ret < 0:
1711 raise ValueError("Could not get Integer's signed attribute.")
1712 elif ret > 0:
1713 return True
1714 else:
1715 return False
1716
1717 @signed.setter
1718 def signed(self, signed):
1719 """
1720 Set an integer's signedness attribute.
1721 """
1722
1723 ret = nbt._bt_ctf_field_type_integer_set_signed(self._ft, signed)
1724
1725 if ret < 0:
1726 raise ValueError("Could not set Integer's signed attribute.")
1727
1728 @property
1729 def base(self):
1730 """
1731 Get the integer's base used to pretty-print the resulting trace.
1732 Returns a constant from the FieldDeclaration.IntegerBase class.
1733 """
1734
1735 return nbt._bt_ctf_field_type_integer_get_base(self._ft)
1736
1737 @base.setter
1738 def base(self, base):
1739 """
1740 Set the integer's base used to pretty-print the resulting trace.
1741 The base must be a constant of the FieldDeclarationIntegerBase class.
1742 """
1743
1744 ret = nbt._bt_ctf_field_type_integer_set_base(self._ft, base)
1745
1746 if ret < 0:
1747 raise ValueError("Could not set Integer's base.")
1748
1749 @property
1750 def encoding(self):
1751 """
1752 Get the integer's encoding (one of the constants of the
1753 CTFStringEncoding class).
1754 Returns a constant from the CTFStringEncoding class.
1755 """
1756
1757 return nbt._bt_ctf_field_type_integer_get_encoding(self._ft)
1758
1759 @encoding.setter
1760 def encoding(self, encoding):
1761 """
1762 An integer encoding may be set to signal that the integer must be printed
1763 as a text character. Must be a constant from the CTFStringEncoding class.
1764 """
1765
1766 ret = nbt._bt_ctf_field_type_integer_set_encoding(self._ft, encoding)
1767
1768 if ret < 0:
1769 raise ValueError("Could not set Integer's encoding.")
1770
1771 class EnumerationFieldDeclaration(FieldDeclaration):
1772 def __init__(self, integer_type):
1773 """
1774 Create a new enumeration field declaration with the given underlying container type.
1775 """
1776 isinst = isinstance(integer_type, CTFWriter.IntegerFieldDeclaration)
1777
1778 if integer_type is None or not isinst:
1779 raise TypeError("Invalid integer container.")
1780
1781 self._ft = nbt._bt_ctf_field_type_enumeration_create(integer_type._ft)
1782 super().__init__()
1783
1784 @property
1785 def container(self):
1786 """
1787 Get the enumeration's underlying container type.
1788 """
1789
1790 ret = nbt._bt_ctf_field_type_enumeration_get_container_type(self._ft)
1791
1792 if ret is None:
1793 raise TypeError("Invalid enumeration declaration")
1794
1795 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
1796
1797 def add_mapping(self, name, range_start, range_end):
1798 """
1799 Add a mapping to the enumeration. The range's values are inclusive.
1800 """
1801
1802 if range_start < 0 or range_end < 0:
1803 ret = nbt._bt_ctf_field_type_enumeration_add_mapping(self._ft,
1804 str(name),
1805 range_start,
1806 range_end)
1807 else:
1808 ret = nbt._bt_ctf_field_type_enumeration_add_mapping_unsigned(self._ft,
1809 str(name),
1810 range_start,
1811 range_end)
1812
1813 if ret < 0:
1814 raise ValueError("Could not add mapping to enumeration declaration.")
1815
1816 @property
1817 def mappings(self):
1818 """
1819 Generator returning instances of EnumerationMapping.
1820 """
1821
1822 signed = self.container.signed
1823
1824 count = nbt._bt_ctf_field_type_enumeration_get_mapping_count(self._ft)
1825
1826 for i in range(count):
1827 if signed:
1828 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, i)
1829 else:
1830 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, i)
1831
1832 if len(ret) != 3:
1833 msg = "Could not get Enumeration mapping at index {}".format(i)
1834 raise TypeError(msg)
1835
1836 name, range_start, range_end = ret
1837 yield CTFWriter.EnumerationMapping(name, range_start, range_end)
1838
1839 def get_mapping_by_name(self, name):
1840 """
1841 Get a mapping by name (EnumerationMapping).
1842 """
1843
1844 index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_name(self._ft, name)
1845
1846 if index < 0:
1847 return None
1848
1849 if self.container.signed:
1850 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, index)
1851 else:
1852 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, index)
1853
1854 if len(ret) != 3:
1855 msg = "Could not get Enumeration mapping at index {}".format(i)
1856 raise TypeError(msg)
1857
1858 name, range_start, range_end = ret
1859
1860 return CTFWriter.EnumerationMapping(name, range_start, range_end)
1861
1862 def get_mapping_by_value(self, value):
1863 """
1864 Get a mapping by value (EnumerationMapping).
1865 """
1866
1867 if value < 0:
1868 index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_value(self._ft, value)
1869 else:
1870 index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_unsigned_value(self._ft, value)
1871
1872 if index < 0:
1873 return None
1874
1875 if self.container.signed:
1876 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, index)
1877 else:
1878 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, index)
1879
1880 if len(ret) != 3:
1881 msg = "Could not get Enumeration mapping at index {}".format(i)
1882 raise TypeError(msg)
1883
1884 name, range_start, range_end = ret
1885
1886 return CTFWriter.EnumerationMapping(name, range_start, range_end)
1887
1888 class FloatFieldDeclaration(FieldDeclaration):
1889 FLT_EXP_DIG = 8
1890 DBL_EXP_DIG = 11
1891 FLT_MANT_DIG = 24
1892 DBL_MANT_DIG = 53
1893
1894 def __init__(self):
1895 """
1896 Create a new floating point field declaration.
1897 """
1898
1899 self._ft = nbt._bt_ctf_field_type_floating_point_create()
1900 super().__init__()
1901
1902 @property
1903 def exponent_digits(self):
1904 """
1905 Get the number of exponent digits used to store the floating point field.
1906 """
1907
1908 ret = nbt._bt_ctf_field_type_floating_point_get_exponent_digits(self._ft)
1909
1910 if ret < 0:
1911 raise TypeError(
1912 "Could not get Floating point exponent digit count")
1913
1914 return ret
1915
1916 @exponent_digits.setter
1917 def exponent_digits(self, exponent_digits):
1918 """
1919 Set the number of exponent digits to use to store the floating point field.
1920 The only values currently supported are FLT_EXP_DIG and DBL_EXP_DIG which
1921 are defined as constants of this class.
1922 """
1923
1924 ret = nbt._bt_ctf_field_type_floating_point_set_exponent_digits(self._ft,
1925 exponent_digits)
1926
1927 if ret < 0:
1928 raise ValueError("Could not set exponent digit count.")
1929
1930 @property
1931 def mantissa_digits(self):
1932 """
1933 Get the number of mantissa digits used to store the floating point field.
1934 """
1935
1936 ret = nbt._bt_ctf_field_type_floating_point_get_mantissa_digits(self._ft)
1937
1938 if ret < 0:
1939 raise TypeError("Could not get Floating point mantissa digit count")
1940
1941 return ret
1942
1943 @mantissa_digits.setter
1944 def mantissa_digits(self, mantissa_digits):
1945 """
1946 Set the number of mantissa digits to use to store the floating point field.
1947 The only values currently supported are FLT_MANT_DIG and DBL_MANT_DIG which
1948 are defined as constants of this class.
1949 """
1950
1951 ret = nbt._bt_ctf_field_type_floating_point_set_mantissa_digits(self._ft,
1952 mantissa_digits)
1953
1954 if ret < 0:
1955 raise ValueError("Could not set mantissa digit count.")
1956
1957 class FloatingPointFieldDeclaration(FloatFieldDeclaration):
1958 pass
1959
1960 class StructureFieldDeclaration(FieldDeclaration):
1961 def __init__(self):
1962 """
1963 Create a new structure field declaration.
1964 """
1965
1966 self._ft = nbt._bt_ctf_field_type_structure_create()
1967 super().__init__()
1968
1969 def add_field(self, field_type, field_name):
1970 """
1971 Add a field of type "field_type" to the structure.
1972 """
1973
1974 ret = nbt._bt_ctf_field_type_structure_add_field(self._ft,
1975 field_type._ft,
1976 str(field_name))
1977
1978 if ret < 0:
1979 raise ValueError("Could not add field to structure.")
1980
1981 @property
1982 def fields(self):
1983 """
1984 Generator returning the structure's field as tuples of (field name, field declaration).
1985 """
1986
1987 count = nbt._bt_ctf_field_type_structure_get_field_count(self._ft)
1988
1989 if count < 0:
1990 raise TypeError("Could not get Structure field count")
1991
1992 for i in range(count):
1993 field_name = nbt._bt_python_ctf_field_type_structure_get_field_name(self._ft, i)
1994
1995 if field_name is None:
1996 msg = "Could not get Structure field name at index {}".format(i)
1997 raise TypeError(msg)
1998
1999 field_type_native = nbt._bt_python_ctf_field_type_structure_get_field_type(self._ft, i)
2000
2001 if field_type_native is None:
2002 msg = "Could not get Structure field type at index {}".format(i)
2003 raise TypeError(msg)
2004
2005 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2006 yield (field_name, field_type)
2007
2008 def get_field_by_name(self, name):
2009 """
2010 Get a field declaration by name (FieldDeclaration).
2011 """
2012
2013 field_type_native = nbt._bt_ctf_field_type_structure_get_field_type_by_name(self._ft, name)
2014
2015 if field_type_native is None:
2016 msg = "Could not find Structure field with name {}".format(name)
2017 raise TypeError(msg)
2018
2019 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2020
2021 class VariantFieldDeclaration(FieldDeclaration):
2022 def __init__(self, enum_tag, tag_name):
2023 """
2024 Create a new variant field declaration.
2025 """
2026
2027 isinst = isinstance(enum_tag, CTFWriter.EnumerationFieldDeclaration)
2028 if enum_tag is None or not isinst:
2029 raise TypeError("Invalid tag type; must be of type EnumerationFieldDeclaration.")
2030
2031 self._ft = nbt._bt_ctf_field_type_variant_create(enum_tag._ft,
2032 str(tag_name))
2033 super().__init__()
2034
2035 @property
2036 def tag_name(self):
2037 """
2038 Get the variant's tag name.
2039 """
2040
2041 ret = nbt._bt_ctf_field_type_variant_get_tag_name(self._ft)
2042
2043 if ret is None:
2044 raise TypeError("Could not get Variant tag name")
2045
2046 return ret
2047
2048 @property
2049 def tag_type(self):
2050 """
2051 Get the variant's tag type.
2052 """
2053
2054 ret = nbt._bt_ctf_field_type_variant_get_tag_type(self._ft)
2055
2056 if ret is None:
2057 raise TypeError("Could not get Variant tag type")
2058
2059 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
2060
2061 def add_field(self, field_type, field_name):
2062 """
2063 Add a field of type "field_type" to the variant.
2064 """
2065
2066 ret = nbt._bt_ctf_field_type_variant_add_field(self._ft,
2067 field_type._ft,
2068 str(field_name))
2069
2070 if ret < 0:
2071 raise ValueError("Could not add field to variant.")
2072
2073 @property
2074 def fields(self):
2075 """
2076 Generator returning the variant's field as tuples of (field name, field declaration).
2077 """
2078
2079 count = nbt._bt_ctf_field_type_variant_get_field_count(self._ft)
2080
2081 if count < 0:
2082 raise TypeError("Could not get Variant field count")
2083
2084 for i in range(count):
2085 field_name = nbt._bt_python_ctf_field_type_variant_get_field_name(self._ft, i)
2086
2087 if field_name is None:
2088 msg = "Could not get Variant field name at index {}".format(i)
2089 raise TypeError(msg)
2090
2091 field_type_native = nbt._bt_python_ctf_field_type_variant_get_field_type(self._ft, i)
2092
2093 if field_type_native is None:
2094 msg = "Could not get Variant field type at index {}".format(i)
2095 raise TypeError(msg)
2096
2097 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2098 yield (field_name, field_type)
2099
2100 def get_field_by_name(self, name):
2101 """
2102 Get a field declaration by name (FieldDeclaration).
2103 """
2104
2105 field_type_native = nbt._bt_ctf_field_type_variant_get_field_type_by_name(self._ft,
2106 name)
2107
2108 if field_type_native is None:
2109 msg = "Could not find Variant field with name {}".format(name)
2110 raise TypeError(msg)
2111
2112 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2113
2114 def get_field_from_tag(self, tag):
2115 """
2116 Get a field declaration from tag (EnumerationField).
2117 """
2118
2119 field_type_native = nbt._bt_ctf_field_type_variant_get_field_type_from_tag(self._ft, tag._f)
2120
2121 if field_type_native is None:
2122 msg = "Could not find Variant field with tag value {}".format(tag.value)
2123 raise TypeError(msg)
2124
2125 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2126
2127 class ArrayFieldDeclaration(FieldDeclaration):
2128 def __init__(self, element_type, length):
2129 """
2130 Create a new array field declaration.
2131 """
2132
2133 self._ft = nbt._bt_ctf_field_type_array_create(element_type._ft,
2134 length)
2135 super().__init__()
2136
2137 @property
2138 def element_type(self):
2139 """
2140 Get the array's element type.
2141 """
2142
2143 ret = nbt._bt_ctf_field_type_array_get_element_type(self._ft)
2144
2145 if ret is None:
2146 raise TypeError("Could not get Array element type")
2147
2148 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
2149
2150 @property
2151 def length(self):
2152 """
2153 Get the array's length.
2154 """
2155
2156 ret = nbt._bt_ctf_field_type_array_get_length(self._ft)
2157
2158 if ret < 0:
2159 raise TypeError("Could not get Array length")
2160
2161 return ret
2162
2163 class SequenceFieldDeclaration(FieldDeclaration):
2164 def __init__(self, element_type, length_field_name):
2165 """
2166 Create a new sequence field declaration.
2167 """
2168
2169 self._ft = nbt._bt_ctf_field_type_sequence_create(element_type._ft,
2170 str(length_field_name))
2171 super().__init__()
2172
2173 @property
2174 def element_type(self):
2175 """
2176 Get the sequence's element type.
2177 """
2178
2179 ret = nbt._bt_ctf_field_type_sequence_get_element_type(self._ft)
2180
2181 if ret is None:
2182 raise TypeError("Could not get Sequence element type")
2183
2184 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
2185
2186 @property
2187 def length_field_name(self):
2188 """
2189 Get the sequence's length field name.
2190 """
2191
2192 ret = nbt._bt_ctf_field_type_sequence_get_length_field_name(self._ft)
2193
2194 if ret is None:
2195 raise TypeError("Could not get Sequence length field name")
2196
2197 return ret
2198
2199 class StringFieldDeclaration(FieldDeclaration):
2200 def __init__(self):
2201 """
2202 Create a new string field declaration.
2203 """
2204
2205 self._ft = nbt._bt_ctf_field_type_string_create()
2206 super().__init__()
2207
2208 @property
2209 def encoding(self):
2210 """
2211 Get a string declaration's encoding (a constant from the CTFStringEncoding class).
2212 """
2213
2214 return nbt._bt_ctf_field_type_string_get_encoding(self._ft)
2215
2216 @encoding.setter
2217 def encoding(self, encoding):
2218 """
2219 Set a string declaration's encoding. Must be a constant from the CTFStringEncoding class.
2220 """
2221
2222 ret = nbt._bt_ctf_field_type_string_set_encoding(self._ft, encoding)
2223 if ret < 0:
2224 raise ValueError("Could not set string encoding.")
2225
2226 @staticmethod
2227 def create_field(field_type):
2228 """
2229 Create an instance of a field.
2230 """
2231 isinst = isinstance(field_type, CTFWriter.FieldDeclaration)
2232
2233 if field_type is None or not isinst:
2234 raise TypeError("Invalid field_type. Type must be a FieldDeclaration-derived class.")
2235
2236 if isinstance(field_type, CTFWriter.IntegerFieldDeclaration):
2237 return CTFWriter.IntegerField(field_type)
2238 elif isinstance(field_type, CTFWriter.EnumerationFieldDeclaration):
2239 return CTFWriter.EnumerationField(field_type)
2240 elif isinstance(field_type, CTFWriter.FloatFieldDeclaration):
2241 return CTFWriter.FloatingPointField(field_type)
2242 elif isinstance(field_type, CTFWriter.StructureFieldDeclaration):
2243 return CTFWriter.StructureField(field_type)
2244 elif isinstance(field_type, CTFWriter.VariantFieldDeclaration):
2245 return CTFWriter.VariantField(field_type)
2246 elif isinstance(field_type, CTFWriter.ArrayFieldDeclaration):
2247 return CTFWriter.ArrayField(field_type)
2248 elif isinstance(field_type, CTFWriter.SequenceFieldDeclaration):
2249 return CTFWriter.SequenceField(field_type)
2250 elif isinstance(field_type, CTFWriter.StringFieldDeclaration):
2251 return CTFWriter.StringField(field_type)
2252
2253 class Field:
2254 """
2255 Base class, do not instantiate.
2256 """
2257
2258 def __init__(self, field_type):
2259 if not isinstance(field_type, CTFWriter.FieldDeclaration):
2260 raise TypeError("Invalid field_type argument.")
2261
2262 self._f = nbt._bt_ctf_field_create(field_type._ft)
2263
2264 if self._f is None:
2265 raise ValueError("Field creation failed.")
2266
2267 def __del__(self):
2268 nbt._bt_ctf_field_put(self._f)
2269
2270 @staticmethod
2271 def _create_field_from_native_instance(native_field_instance):
2272 type_dict = {
2273 CTFTypeId.INTEGER: CTFWriter.IntegerField,
2274 CTFTypeId.FLOAT: CTFWriter.FloatingPointField,
2275 CTFTypeId.ENUM: CTFWriter.EnumerationField,
2276 CTFTypeId.STRING: CTFWriter.StringField,
2277 CTFTypeId.STRUCT: CTFWriter.StructureField,
2278 CTFTypeId.VARIANT: CTFWriter.VariantField,
2279 CTFTypeId.ARRAY: CTFWriter.ArrayField,
2280 CTFTypeId.SEQUENCE: CTFWriter.SequenceField
2281 }
2282
2283 field_type = nbt._bt_python_get_field_type(native_field_instance)
2284
2285 if field_type == CTFTypeId.UNKNOWN:
2286 raise TypeError("Invalid field instance")
2287
2288 field = CTFWriter.Field.__new__(CTFWriter.Field)
2289 field._f = native_field_instance
2290 field.__class__ = type_dict[field_type]
2291
2292 return field
2293
2294 @property
2295 def declaration(self):
2296 native_field_type = nbt._bt_ctf_field_get_type(self._f)
2297
2298 if native_field_type is None:
2299 raise TypeError("Invalid field instance")
2300 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(
2301 native_field_type)
2302
2303 class IntegerField(Field):
2304 @property
2305 def value(self):
2306 """
2307 Get an integer field's value.
2308 """
2309
2310 signedness = nbt._bt_python_field_integer_get_signedness(self._f)
2311
2312 if signedness < 0:
2313 raise TypeError("Invalid integer instance.")
2314
2315 if signedness == 0:
2316 ret, value = nbt._bt_ctf_field_unsigned_integer_get_value(self._f)
2317 else:
2318 ret, value = nbt._bt_ctf_field_signed_integer_get_value(self._f)
2319
2320 if ret < 0:
2321 raise ValueError("Could not get integer field value.")
2322
2323 return value
2324
2325 @value.setter
2326 def value(self, value):
2327 """
2328 Set an integer field's value.
2329 """
2330
2331 if not isinstance(value, int):
2332 raise TypeError("IntegerField's value must be an int")
2333
2334 signedness = nbt._bt_python_field_integer_get_signedness(self._f)
2335 if signedness < 0:
2336 raise TypeError("Invalid integer instance.")
2337
2338 if signedness == 0:
2339 ret = nbt._bt_ctf_field_unsigned_integer_set_value(self._f, value)
2340 else:
2341 ret = nbt._bt_ctf_field_signed_integer_set_value(self._f, value)
2342
2343 if ret < 0:
2344 raise ValueError("Could not set integer field value.")
2345
2346 class EnumerationField(Field):
2347 @property
2348 def container(self):
2349 """
2350 Return the enumeration's underlying container field (an integer field).
2351 """
2352
2353 container = CTFWriter.IntegerField.__new__(CTFWriter.IntegerField)
2354 container._f = nbt._bt_ctf_field_enumeration_get_container(self._f)
2355
2356 if container._f is None:
2357 raise TypeError("Invalid enumeration field type.")
2358
2359 return container
2360
2361 @property
2362 def value(self):
2363 """
2364 Get the enumeration field's mapping name.
2365 """
2366
2367 value = nbt._bt_ctf_field_enumeration_get_mapping_name(self._f)
2368
2369 if value is None:
2370 raise ValueError("Could not get enumeration's mapping name.")
2371
2372 return value
2373
2374 @value.setter
2375 def value(self, value):
2376 """
2377 Set the enumeration field's value. Must be an integer as mapping names
2378 may be ambiguous.
2379 """
2380
2381 if not isinstance(value, int):
2382 raise TypeError("EnumerationField value must be an int")
2383
2384 self.container.value = value
2385
2386 class FloatingPointField(Field):
2387 @property
2388 def value(self):
2389 """
2390 Get a floating point field's value.
2391 """
2392
2393 ret, value = nbt._bt_ctf_field_floating_point_get_value(self._f)
2394
2395 if ret < 0:
2396 raise ValueError("Could not get floating point field value.")
2397
2398 return value
2399
2400 @value.setter
2401 def value(self, value):
2402 """
2403 Set a floating point field's value.
2404 """
2405
2406 if not isinstance(value, int) and not isinstance(value, float):
2407 raise TypeError("Value must be either a float or an int")
2408
2409 ret = nbt._bt_ctf_field_floating_point_set_value(self._f, float(value))
2410
2411 if ret < 0:
2412 raise ValueError("Could not set floating point field value.")
2413
2414 # oops!! This class is provided to ensure backward-compatibility since
2415 # a stable release publicly exposed this abomination.
2416 class FloatFieldingPoint(FloatingPointField):
2417 pass
2418
2419 class StructureField(Field):
2420 def field(self, field_name):
2421 """
2422 Get the structure's field corresponding to the provided field name.
2423 """
2424
2425 native_instance = nbt._bt_ctf_field_structure_get_field(self._f,
2426 str(field_name))
2427
2428 if native_instance is None:
2429 raise ValueError("Invalid field_name provided.")
2430
2431 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2432
2433 class VariantField(Field):
2434 def field(self, tag):
2435 """
2436 Return the variant's selected field. The "tag" field is the selector enum field.
2437 """
2438
2439 native_instance = nbt._bt_ctf_field_variant_get_field(self._f, tag._f)
2440
2441 if native_instance is None:
2442 raise ValueError("Invalid tag provided.")
2443
2444 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2445
2446 class ArrayField(Field):
2447 def field(self, index):
2448 """
2449 Return the array's field at position "index".
2450 """
2451
2452 native_instance = nbt._bt_ctf_field_array_get_field(self._f, index)
2453
2454 if native_instance is None:
2455 raise IndexError("Invalid index provided.")
2456
2457 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2458
2459 class SequenceField(Field):
2460 @property
2461 def length(self):
2462 """
2463 Get the sequence's length field (IntegerField).
2464 """
2465
2466 native_instance = nbt._bt_ctf_field_sequence_get_length(self._f)
2467
2468 if native_instance is None:
2469 length = -1
2470
2471 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2472
2473 @length.setter
2474 def length(self, length_field):
2475 """
2476 Set the sequence's length field (IntegerField).
2477 """
2478
2479 if not isinstance(length_field, CTFWriter.IntegerField):
2480 raise TypeError("Invalid length field.")
2481
2482 if length_field.declaration.signed:
2483 raise TypeError("Sequence field length must be unsigned")
2484
2485 ret = nbt._bt_ctf_field_sequence_set_length(self._f, length_field._f)
2486
2487 if ret < 0:
2488 raise ValueError("Could not set sequence length.")
2489
2490 def field(self, index):
2491 """
2492 Return the sequence's field at position "index".
2493 """
2494
2495 native_instance = nbt._bt_ctf_field_sequence_get_field(self._f, index)
2496
2497 if native_instance is None:
2498 raise ValueError("Could not get sequence element at index.")
2499
2500 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2501
2502 class StringField(Field):
2503 @property
2504 def value(self):
2505 """
2506 Get a string field's value.
2507 """
2508
2509 return nbt._bt_ctf_field_string_get_value(self._f)
2510
2511 @value.setter
2512 def value(self, value):
2513 """
2514 Set a string field's value.
2515 """
2516
2517 ret = nbt._bt_ctf_field_string_set_value(self._f, str(value))
2518
2519 if ret < 0:
2520 raise ValueError("Could not set string field value.")
2521
2522 class EventClass:
2523 def __init__(self, name):
2524 """
2525 Create a new event class of the given name.
2526 """
2527
2528 self._ec = nbt._bt_ctf_event_class_create(name)
2529
2530 if self._ec is None:
2531 raise ValueError("Event class creation failed.")
2532
2533 def __del__(self):
2534 nbt._bt_ctf_event_class_put(self._ec)
2535
2536 def add_field(self, field_type, field_name):
2537 """
2538 Add a field of type "field_type" to the event class.
2539 """
2540
2541 ret = nbt._bt_ctf_event_class_add_field(self._ec, field_type._ft,
2542 str(field_name))
2543
2544 if ret < 0:
2545 raise ValueError("Could not add field to event class.")
2546
2547 @property
2548 def name(self):
2549 """
2550 Get the event class' name.
2551 """
2552
2553 name = nbt._bt_ctf_event_class_get_name(self._ec)
2554
2555 if name is None:
2556 raise TypeError("Could not get EventClass name")
2557
2558 return name
2559
2560 @property
2561 def id(self):
2562 """
2563 Get the event class' id. Returns a negative value if unset.
2564 """
2565
2566 id = nbt._bt_ctf_event_class_get_id(self._ec)
2567
2568 if id < 0:
2569 raise TypeError("Could not get EventClass id")
2570
2571 return id
2572
2573 @id.setter
2574 def id(self, id):
2575 """
2576 Set the event class' id. Throws a TypeError if the event class
2577 is already registered to a stream class.
2578 """
2579
2580 ret = nbt._bt_ctf_event_class_set_id(self._ec, id)
2581
2582 if ret < 0:
2583 raise TypeError("Can't change an Event Class's id after it has been assigned to a stream class")
2584
2585 @property
2586 def stream_class(self):
2587 """
2588 Get the event class' stream class. Returns None if unset.
2589 """
2590 stream_class_native = nbt._bt_ctf_event_class_get_stream_class(self._ec)
2591
2592 if stream_class_native is None:
2593 return None
2594
2595 stream_class = CTFWriter.StreamClass.__new__(CTFWriter.StreamClass)
2596 stream_class._sc = stream_class_native
2597
2598 return stream_class
2599
2600 @property
2601 def fields(self):
2602 """
2603 Generator returning the event class' fields as tuples of (field name, field declaration).
2604 """
2605
2606 count = nbt._bt_ctf_event_class_get_field_count(self._ec)
2607
2608 if count < 0:
2609 raise TypeError("Could not get EventClass' field count")
2610
2611 for i in range(count):
2612 field_name = nbt._bt_python_ctf_event_class_get_field_name(self._ec, i)
2613
2614 if field_name is None:
2615 msg = "Could not get EventClass' field name at index {}".format(i)
2616 raise TypeError(msg)
2617
2618 field_type_native = nbt._bt_python_ctf_event_class_get_field_type(self._ec, i)
2619
2620 if field_type_native is None:
2621 msg = "Could not get EventClass' field type at index {}".format(i)
2622 raise TypeError(msg)
2623
2624 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2625 yield (field_name, field_type)
2626
2627 def get_field_by_name(self, name):
2628 """
2629 Get a field declaration by name (FieldDeclaration).
2630 """
2631
2632 field_type_native = nbt._bt_ctf_event_class_get_field_by_name(self._ec, name)
2633
2634 if field_type_native is None:
2635 msg = "Could not find EventClass field with name {}".format(name)
2636 raise TypeError(msg)
2637
2638 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2639
2640 class Event:
2641 def __init__(self, event_class):
2642 """
2643 Create a new event of the given event class.
2644 """
2645
2646 if not isinstance(event_class, CTFWriter.EventClass):
2647 raise TypeError("Invalid event_class argument.")
2648
2649 self._e = nbt._bt_ctf_event_create(event_class._ec)
2650
2651 if self._e is None:
2652 raise ValueError("Event creation failed.")
2653
2654 def __del__(self):
2655 nbt._bt_ctf_event_put(self._e)
2656
2657 @property
2658 def event_class(self):
2659 """
2660 Get the event's class.
2661 """
2662
2663 event_class_native = nbt._bt_ctf_event_get_class(self._e)
2664
2665 if event_class_native is None:
2666 return None
2667
2668 event_class = CTFWriter.EventClass.__new__(CTFWriter.EventClass)
2669 event_class._ec = event_class_native
2670
2671 return event_class
2672
2673 def clock(self):
2674 """
2675 Get a clock from event. Returns None if the event's class
2676 is not registered to a stream class.
2677 """
2678
2679 clock_instance = nbt._bt_ctf_event_get_clock(self._e)
2680
2681 if clock_instance is None:
2682 return None
2683
2684 clock = CTFWriter.Clock.__new__(CTFWriter.Clock)
2685 clock._c = clock_instance
2686
2687 return clock
2688
2689 def payload(self, field_name):
2690 """
2691 Get a field from event.
2692 """
2693
2694 native_instance = nbt._bt_ctf_event_get_payload(self._e,
2695 str(field_name))
2696
2697 if native_instance is None:
2698 raise ValueError("Could not get event payload.")
2699
2700 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2701
2702 def set_payload(self, field_name, value_field):
2703 """
2704 Set a manually created field as an event's payload.
2705 """
2706
2707 if not isinstance(value, CTFWriter.Field):
2708 raise TypeError("Invalid value type.")
2709
2710 ret = nbt._bt_ctf_event_set_payload(self._e, str(field_name),
2711 value_field._f)
2712
2713 if ret < 0:
2714 raise ValueError("Could not set event field payload.")
2715
2716 class StreamClass:
2717 def __init__(self, name):
2718 """
2719 Create a new stream class of the given name.
2720 """
2721
2722 self._sc = nbt._bt_ctf_stream_class_create(name)
2723
2724 if self._sc is None:
2725 raise ValueError("Stream class creation failed.")
2726
2727 def __del__(self):
2728 nbt._bt_ctf_stream_class_put(self._sc)
2729
2730 @property
2731 def name(self):
2732 """
2733 Get a stream class' name.
2734 """
2735
2736 name = nbt._bt_ctf_stream_class_get_name(self._sc)
2737
2738 if name is None:
2739 raise TypeError("Could not get StreamClass name")
2740
2741 return name
2742
2743 @property
2744 def clock(self):
2745 """
2746 Get a stream class' clock.
2747 """
2748
2749 clock_instance = nbt._bt_ctf_stream_class_get_clock(self._sc)
2750
2751 if clock_instance is None:
2752 return None
2753
2754 clock = CTFWriter.Clock.__new__(CTFWriter.Clock)
2755 clock._c = clock_instance
2756
2757 return clock
2758
2759 @clock.setter
2760 def clock(self, clock):
2761 """
2762 Assign a clock to a stream class.
2763 """
2764
2765 if not isinstance(clock, CTFWriter.Clock):
2766 raise TypeError("Invalid clock type.")
2767
2768 ret = nbt._bt_ctf_stream_class_set_clock(self._sc, clock._c)
2769
2770 if ret < 0:
2771 raise ValueError("Could not set stream class clock.")
2772
2773 @property
2774 def id(self):
2775 """
2776 Get a stream class' id.
2777 """
2778
2779 ret = nbt._bt_ctf_stream_class_get_id(self._sc)
2780
2781 if ret < 0:
2782 raise TypeError("Could not get StreamClass id")
2783
2784 return ret
2785
2786 @id.setter
2787 def id(self, id):
2788 """
2789 Assign an id to a stream class.
2790 """
2791
2792 ret = nbt._bt_ctf_stream_class_set_id(self._sc, id)
2793
2794 if ret < 0:
2795 raise TypeError("Could not set stream class id.")
2796
2797 @property
2798 def event_classes(self):
2799 """
2800 Generator returning the stream class' event classes.
2801 """
2802
2803 count = nbt._bt_ctf_stream_class_get_event_class_count(self._sc)
2804
2805 if count < 0:
2806 raise TypeError("Could not get StreamClass' event class count")
2807
2808 for i in range(count):
2809 event_class_native = nbt._bt_ctf_stream_class_get_event_class(self._sc, i)
2810
2811 if event_class_native is None:
2812 msg = "Could not get StreamClass' event class at index {}".format(i)
2813 raise TypeError(msg)
2814
2815 event_class = CTFWriter.EventClass.__new__(CTFWriter.EventClass)
2816 event_class._ec = event_class_native
2817 yield event_class
2818
2819 def add_event_class(self, event_class):
2820 """
2821 Add an event class to a stream class. New events can be added even after a
2822 stream has been instantiated and events have been appended. However, a stream
2823 will not accept events of a class that has not been added to the stream
2824 class beforehand.
2825 """
2826
2827 if not isinstance(event_class, CTFWriter.EventClass):
2828 raise TypeError("Invalid event_class type.")
2829
2830 ret = nbt._bt_ctf_stream_class_add_event_class(self._sc,
2831 event_class._ec)
2832
2833 if ret < 0:
2834 raise ValueError("Could not add event class.")
2835
2836 @property
2837 def packet_context_type(self):
2838 """
2839 Get the StreamClass' packet context type (StructureFieldDeclaration)
2840 """
2841
2842 field_type_native = nbt._bt_ctf_stream_class_get_packet_context_type(self._sc)
2843
2844 if field_type_native is None:
2845 raise ValueError("Invalid StreamClass")
2846
2847 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2848
2849 return field_type
2850
2851 @packet_context_type.setter
2852 def packet_context_type(self, field_type):
2853 """
2854 Set a StreamClass' packet context type. Must be of type
2855 StructureFieldDeclaration.
2856 """
2857
2858 if not isinstance(field_type, CTFWriter.StructureFieldDeclaration):
2859 raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
2860
2861 ret = nbt._bt_ctf_stream_class_set_packet_context_type(self._sc,
2862 field_type._ft)
2863
2864 if ret < 0:
2865 raise ValueError("Failed to set packet context type.")
2866
2867 class Stream:
2868 def __init__(self):
2869 raise NotImplementedError("Stream cannot be instantiated; use Writer.create_stream()")
2870
2871 def __del__(self):
2872 nbt._bt_ctf_stream_put(self._s)
2873
2874 @property
2875 def discarded_events(self):
2876 """
2877 Get a stream's discarded event count.
2878 """
2879
2880 ret, count = nbt._bt_ctf_stream_get_discarded_events_count(self._s)
2881
2882 if ret < 0:
2883 raise ValueError("Could not get the stream's discarded events count")
2884
2885 return count
2886
2887 def append_discarded_events(self, event_count):
2888 """
2889 Increase the current packet's discarded event count.
2890 """
2891
2892 nbt._bt_ctf_stream_append_discarded_events(self._s, event_count)
2893
2894 def append_event(self, event):
2895 """
2896 Append "event" to the stream's current packet. The stream's associated clock
2897 will be sampled during this call. The event shall not be modified after
2898 being appended to a stream.
2899 """
2900
2901 ret = nbt._bt_ctf_stream_append_event(self._s, event._e)
2902
2903 if ret < 0:
2904 raise ValueError("Could not append event to stream.")
2905
2906 @property
2907 def packet_context(self):
2908 """
2909 Get a Stream's packet context field (a StructureField).
2910 """
2911
2912 native_field = nbt._bt_ctf_stream_get_packet_context(self._s)
2913
2914 if native_field is None:
2915 raise ValueError("Invalid Stream.")
2916
2917 return CTFWriter.Field._create_field_from_native_instance(native_field)
2918
2919 @packet_context.setter
2920 def packet_context(self, field):
2921 """
2922 Set a Stream's packet context field (must be a StructureField).
2923 """
2924
2925 if not isinstance(field, CTFWriter.StructureField):
2926 raise TypeError("Argument field must be of type StructureField")
2927
2928 ret = nbt._bt_ctf_stream_set_packet_context(self._s, field._f)
2929
2930 if ret < 0:
2931 raise ValueError("Invalid packet context field.")
2932
2933 def flush(self):
2934 """
2935 The stream's current packet's events will be flushed to disk. Events
2936 subsequently appended to the stream will be added to a new packet.
2937 """
2938
2939 ret = nbt._bt_ctf_stream_flush(self._s)
2940
2941 if ret < 0:
2942 raise ValueError("Could not flush stream.")
2943
2944 class Writer:
2945 def __init__(self, path):
2946 """
2947 Create a new writer that will produce a trace in the given path.
2948 """
2949
2950 self._w = nbt._bt_ctf_writer_create(path)
2951
2952 if self._w is None:
2953 raise ValueError("Writer creation failed.")
2954
2955 def __del__(self):
2956 nbt._bt_ctf_writer_put(self._w)
2957
2958 def create_stream(self, stream_class):
2959 """
2960 Create a new stream instance and register it to the writer.
2961 """
2962
2963 if not isinstance(stream_class, CTFWriter.StreamClass):
2964 raise TypeError("Invalid stream_class type.")
2965
2966 stream = CTFWriter.Stream.__new__(CTFWriter.Stream)
2967 stream._s = nbt._bt_ctf_writer_create_stream(self._w, stream_class._sc)
2968
2969 return stream
2970
2971 def add_environment_field(self, name, value):
2972 """
2973 Add an environment field to the trace.
2974 """
2975
2976 ret = nbt._bt_ctf_writer_add_environment_field(self._w, str(name),
2977 str(value))
2978
2979 if ret < 0:
2980 raise ValueError("Could not add environment field to trace.")
2981
2982 def add_clock(self, clock):
2983 """
2984 Add a clock to the trace. Clocks assigned to stream classes must be
2985 registered to the writer.
2986 """
2987
2988 ret = nbt._bt_ctf_writer_add_clock(self._w, clock._c)
2989
2990 if ret < 0:
2991 raise ValueError("Could not add clock to Writer.")
2992
2993 @property
2994 def metadata(self):
2995 """
2996 Get the trace's TSDL meta-data.
2997 """
2998
2999 return nbt._bt_ctf_writer_get_metadata_string(self._w)
3000
3001 def flush_metadata(self):
3002 """
3003 Flush the trace's metadata to the metadata file.
3004 """
3005
3006 nbt._bt_ctf_writer_flush_metadata(self._w)
3007
3008 @property
3009 def byte_order(self):
3010 """
3011 Get the trace's byte order. Must be a constant from the ByteOrder
3012 class.
3013 """
3014
3015 raise NotImplementedError("Getter not implemented.")
3016
3017 @byte_order.setter
3018 def byte_order(self, byte_order):
3019 """
3020 Set the trace's byte order. Must be a constant from the ByteOrder
3021 class. Defaults to the host machine's endianness
3022 """
3023
3024 ret = nbt._bt_ctf_writer_set_byte_order(self._w, byte_order)
3025
3026 if ret < 0:
3027 raise ValueError("Could not set trace's byte order.")
This page took 0.104363 seconds and 3 git commands to generate.