Python: document EventDeclaration
[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 """Field declaration class. Do not instantiate."""
884
885 def __init__(self):
886 raise NotImplementedError("FieldDeclaration cannot be instantiated")
887
888 def __repr__(self):
889 return "({0}) {1} {2}".format(CTFScope.scope_name(self.scope),
890 CTFTypeId.type_name(self.type),
891 self.name)
892
893 @property
894 def name(self):
895 """Return the name of a FieldDeclaration or None on error."""
896
897 return self._name
898
899 @property
900 def type(self):
901 """
902 Return the FieldDeclaration's type. One of the entries in class
903 CTFTypeId.
904 """
905
906 return nbt._bt_ctf_field_type(self._fd)
907
908 @property
909 def scope(self):
910 """
911 Return the FieldDeclaration's scope.
912 """
913
914 return self._s
915
916
917 class IntegerFieldDeclaration(FieldDeclaration):
918 """Do not instantiate."""
919
920 def __init__(self):
921 raise NotImplementedError("IntegerFieldDeclaration cannot be instantiated")
922
923 @property
924 def signedness(self):
925 """
926 Return the signedness of an integer:
927 0 if unsigned; 1 if signed; -1 on error.
928 """
929
930 return nbt._bt_ctf_get_int_signedness(self._fd)
931
932 @property
933 def base(self):
934 """Return the base of an int or a negative value on error."""
935
936 return nbt._bt_ctf_get_int_base(self._fd)
937
938 @property
939 def byte_order(self):
940 """
941 Return the byte order. One of class ByteOrder's entries.
942 """
943
944 ret = nbt._bt_ctf_get_int_byte_order(self._fd)
945
946 if ret == 1234:
947 return ByteOrder.BYTE_ORDER_LITTLE_ENDIAN
948 elif ret == 4321:
949 return ByteOrder.BYTE_ORDER_BIG_ENDIAN
950 else:
951 return ByteOrder.BYTE_ORDER_UNKNOWN
952
953 @property
954 def length(self):
955 """
956 Return the size, in bits, of an int or a negative
957 value on error.
958 """
959
960 return nbt._bt_ctf_get_int_len(self._fd)
961
962 @property
963 def encoding(self):
964 """
965 Return the encoding. One of class CTFStringEncoding's entries.
966 Return a negative value on error.
967 """
968
969 return nbt._bt_ctf_get_encoding(self._fd)
970
971
972 class EnumerationFieldDeclaration(FieldDeclaration):
973 """Do not instantiate."""
974
975 def __init__(self):
976 raise NotImplementedError("EnumerationFieldDeclaration cannot be instantiated")
977
978
979 class ArrayFieldDeclaration(FieldDeclaration):
980 """Do not instantiate."""
981
982 def __init__(self):
983 raise NotImplementedError("ArrayFieldDeclaration cannot be instantiated")
984
985 @property
986 def length(self):
987 """
988 Return the length of an array or a negative
989 value on error.
990 """
991
992 return nbt._bt_ctf_get_array_len(self._fd)
993
994 @property
995 def element_declaration(self):
996 """
997 Return element declaration.
998 """
999
1000 field_decl_ptr = nbt._bt_python_get_array_element_declaration(self._fd)
1001
1002 return _create_field_declaration(field_decl_ptr, "", self.scope)
1003
1004
1005 class SequenceFieldDeclaration(FieldDeclaration):
1006 """Do not instantiate."""
1007
1008 def __init__(self):
1009 raise NotImplementedError("SequenceFieldDeclaration cannot be instantiated")
1010
1011 @property
1012 def element_declaration(self):
1013 """
1014 Return element declaration.
1015 """
1016
1017 field_decl_ptr = nbt._bt_python_get_sequence_element_declaration(self._fd)
1018
1019 return _create_field_declaration(field_decl_ptr, "", self.scope)
1020
1021
1022 class FloatFieldDeclaration(FieldDeclaration):
1023 """Do not instantiate."""
1024
1025 def __init__(self):
1026 raise NotImplementedError("FloatFieldDeclaration cannot be instantiated")
1027
1028
1029 class StructureFieldDeclaration(FieldDeclaration):
1030 """Do not instantiate."""
1031
1032 def __init__(self):
1033 raise NotImplementedError("StructureFieldDeclaration cannot be instantiated")
1034
1035
1036 class StringFieldDeclaration(FieldDeclaration):
1037 """Do not instantiate."""
1038
1039 def __init__(self):
1040 raise NotImplementedError("StringFieldDeclaration cannot be instantiated")
1041
1042
1043 class VariantFieldDeclaration(FieldDeclaration):
1044 """Do not instantiate."""
1045
1046 def __init__(self):
1047 raise NotImplementedError("VariantFieldDeclaration cannot be instantiated")
1048
1049
1050 def field_error():
1051 """
1052 Return the last error code encountered while
1053 accessing a field and reset the error flag.
1054 Return 0 if no error, a negative value otherwise.
1055 """
1056
1057 return nbt._bt_ctf_field_get_error()
1058
1059
1060 def _create_field_declaration(declaration_ptr, name, scope):
1061 """
1062 Private field declaration factory.
1063 """
1064
1065 if declaration_ptr is None:
1066 raise ValueError("declaration_ptr must be valid")
1067 if scope not in _scopes:
1068 raise ValueError("Invalid scope provided")
1069
1070 type = nbt._bt_ctf_field_type(declaration_ptr)
1071 declaration = None
1072
1073 if type == CTFTypeId.INTEGER:
1074 declaration = IntegerFieldDeclaration.__new__(IntegerFieldDeclaration)
1075 elif type == CTFTypeId.ENUM:
1076 declaration = EnumerationFieldDeclaration.__new__(EnumerationFieldDeclaration)
1077 elif type == CTFTypeId.ARRAY:
1078 declaration = ArrayFieldDeclaration.__new__(ArrayFieldDeclaration)
1079 elif type == CTFTypeId.SEQUENCE:
1080 declaration = SequenceFieldDeclaration.__new__(SequenceFieldDeclaration)
1081 elif type == CTFTypeId.FLOAT:
1082 declaration = FloatFieldDeclaration.__new__(FloatFieldDeclaration)
1083 elif type == CTFTypeId.STRUCT:
1084 declaration = StructureFieldDeclaration.__new__(StructureFieldDeclaration)
1085 elif type == CTFTypeId.STRING:
1086 declaration = StringFieldDeclaration.__new__(StringFieldDeclaration)
1087 elif type == CTFTypeId.VARIANT:
1088 declaration = VariantFieldDeclaration.__new__(VariantFieldDeclaration)
1089 else:
1090 return declaration
1091
1092 declaration._fd = declaration_ptr
1093 declaration._s = scope
1094 declaration._name = name
1095
1096 return declaration
1097
1098
1099 class _Definition:
1100 def __init__(self, definition_ptr, scope):
1101 self._d = definition_ptr
1102 self._s = scope
1103
1104 if scope not in _scopes:
1105 ValueError("Invalid scope provided")
1106
1107 @property
1108 def name(self):
1109 """Return the name of a field or None on error."""
1110
1111 return nbt._bt_ctf_field_name(self._d)
1112
1113 @property
1114 def type(self):
1115 """Return the type of a field or -1 if unknown."""
1116
1117 return nbt._bt_ctf_field_type(nbt._bt_ctf_get_decl_from_def(self._d))
1118
1119 @property
1120 def declaration(self):
1121 """Return the associated Definition object."""
1122
1123 return _create_field_declaration(
1124 nbt._bt_ctf_get_decl_from_def(self._d), self.name, self.scope)
1125
1126 def _get_enum_str(self):
1127 """
1128 Return the string matching the current enumeration.
1129 Return None on error.
1130 """
1131
1132 return nbt._bt_ctf_get_enum_str(self._d)
1133
1134 def _get_array_element_at(self, index):
1135 """
1136 Return the array's element at position index.
1137 Return None on error
1138 """
1139
1140 array_ptr = nbt._bt_python_get_array_from_def(self._d)
1141
1142 if array_ptr is None:
1143 return None
1144
1145 definition_ptr = nbt._bt_array_index(array_ptr, index)
1146
1147 if definition_ptr is None:
1148 return None
1149
1150 return _Definition(definition_ptr, self.scope)
1151
1152 def _get_sequence_len(self):
1153 """
1154 Return the len of a sequence or a negative
1155 value on error.
1156 """
1157
1158 seq = nbt._bt_python_get_sequence_from_def(self._d)
1159
1160 return nbt._bt_sequence_len(seq)
1161
1162 def _get_sequence_element_at(self, index):
1163 """
1164 Return the sequence's element at position index,
1165 otherwise return None
1166 """
1167
1168 seq = nbt._bt_python_get_sequence_from_def(self._d)
1169
1170 if seq is not None:
1171 definition_ptr = nbt._bt_sequence_index(seq, index)
1172
1173 if definition_ptr is not None:
1174 return _Definition(definition_ptr, self.scope)
1175
1176 def _get_uint64(self):
1177 """
1178 Return the value associated with the field.
1179 If the field does not exist or is not of the type requested,
1180 the value returned is undefined. To check if an error occured,
1181 use the field_error() function after accessing a field.
1182 """
1183
1184 return nbt._bt_ctf_get_uint64(self._d)
1185
1186 def _get_int64(self):
1187 """
1188 Return the value associated with the field.
1189 If the field does not exist or is not of the type requested,
1190 the value returned is undefined. To check if an error occured,
1191 use the field_error() function after accessing a field.
1192 """
1193
1194 return nbt._bt_ctf_get_int64(self._d)
1195
1196 def _get_char_array(self):
1197 """
1198 Return the value associated with the field.
1199 If the field does not exist or is not of the type requested,
1200 the value returned is undefined. To check if an error occurred,
1201 use the field_error() function after accessing a field.
1202 """
1203
1204 return nbt._bt_ctf_get_char_array(self._d)
1205
1206 def _get_str(self):
1207 """
1208 Return the value associated with the field.
1209 If the field does not exist or is not of the type requested,
1210 the value returned is undefined. To check if an error occurred,
1211 use the field_error() function after accessing a field.
1212 """
1213
1214 return nbt._bt_ctf_get_string(self._d)
1215
1216 def _get_float(self):
1217 """
1218 Return the value associated with the field.
1219 If the field does not exist or is not of the type requested,
1220 the value returned is undefined. To check if an error occurred,
1221 use the field_error() function after accessing a field.
1222 """
1223
1224 return nbt._bt_ctf_get_float(self._d)
1225
1226 def _get_variant(self):
1227 """
1228 Return the variant's selected field.
1229 If the field does not exist or is not of the type requested,
1230 the value returned is undefined. To check if an error occurred,
1231 use the field_error() function after accessing a field.
1232 """
1233
1234 return nbt._bt_ctf_get_variant(self._d)
1235
1236 def _get_struct_field_count(self):
1237 """
1238 Return the number of fields contained in the structure.
1239 If the field does not exist or is not of the type requested,
1240 the value returned is undefined.
1241 """
1242
1243 return nbt._bt_ctf_get_struct_field_count(self._d)
1244
1245 def _get_struct_field_at(self, i):
1246 """
1247 Return the structure's field at position i.
1248 If the field does not exist or is not of the type requested,
1249 the value returned is undefined. To check if an error occurred,
1250 use the field_error() function after accessing a field.
1251 """
1252
1253 return nbt._bt_ctf_get_struct_field_index(self._d, i)
1254
1255 @property
1256 def value(self):
1257 """
1258 Return the value associated with the field according to its type.
1259 Return None on error.
1260 """
1261
1262 id = self.type
1263 value = None
1264
1265 if id == CTFTypeId.STRING:
1266 value = self._get_str()
1267 elif id == CTFTypeId.ARRAY:
1268 element_decl = self.declaration.element_declaration
1269
1270 if ((element_decl.type == CTFTypeId.INTEGER
1271 and element_decl.length == 8)
1272 and (element_decl.encoding == CTFStringEncoding.ASCII or element_decl.encoding == CTFStringEncoding.UTF8)):
1273 value = nbt._bt_python_get_array_string(self._d)
1274 else:
1275 value = []
1276
1277 for i in range(self.declaration.length):
1278 element = self._get_array_element_at(i)
1279 value.append(element.value)
1280 elif id == CTFTypeId.INTEGER:
1281 if self.declaration.signedness == 0:
1282 value = self._get_uint64()
1283 else:
1284 value = self._get_int64()
1285 elif id == CTFTypeId.ENUM:
1286 value = self._get_enum_str()
1287 elif id == CTFTypeId.SEQUENCE:
1288 element_decl = self.declaration.element_declaration
1289
1290 if ((element_decl.type == CTFTypeId.INTEGER
1291 and element_decl.length == 8)
1292 and (element_decl.encoding == CTFStringEncoding.ASCII or element_decl.encoding == CTFStringEncoding.UTF8)):
1293 value = nbt._bt_python_get_sequence_string(self._d)
1294 else:
1295 seq_len = self._get_sequence_len()
1296 value = []
1297
1298 for i in range(seq_len):
1299 evDef = self._get_sequence_element_at(i)
1300 value.append(evDef.value)
1301 elif id == CTFTypeId.FLOAT:
1302 value = self._get_float()
1303 elif id == CTFTypeId.VARIANT:
1304 variant = _Definition.__new__(_Definition)
1305 variant._d = self._get_variant()
1306 value = variant.value
1307 elif id == CTFTypeId.STRUCT:
1308 value = {}
1309
1310 for i in range(self._get_struct_field_count()):
1311 member = _Definition(self._get_struct_field_at(i), self.scope)
1312 value[member.name] = member.value
1313
1314 if field_error():
1315 raise FieldError(
1316 "Error occurred while accessing field {} of type {}".format(
1317 self.name,
1318 CTFTypeId.type_name(id)))
1319
1320 return value
1321
1322 @property
1323 def scope(self):
1324 """Return the scope of a field or None on error."""
1325
1326 return self._s
1327
1328
1329 class CTFWriter:
1330 # Used to compare to -1ULL in error checks
1331 _MAX_UINT64 = 0xFFFFFFFFFFFFFFFF
1332
1333 class EnumerationMapping:
1334 """
1335 Enumeration mapping class. start and end values are inclusive.
1336 """
1337
1338 def __init__(self, name, start, end):
1339 self.name = name
1340 self.start = start
1341 self.end = end
1342
1343 class Clock:
1344 def __init__(self, name):
1345 self._c = nbt._bt_ctf_clock_create(name)
1346
1347 if self._c is None:
1348 raise ValueError("Invalid clock name.")
1349
1350 def __del__(self):
1351 nbt._bt_ctf_clock_put(self._c)
1352
1353 @property
1354 def name(self):
1355 """
1356 Get the clock's name.
1357 """
1358
1359 name = nbt._bt_ctf_clock_get_name(self._c)
1360
1361 if name is None:
1362 raise ValueError("Invalid clock instance.")
1363
1364 return name
1365
1366 @property
1367 def description(self):
1368 """
1369 Get the clock's description. None if unset.
1370 """
1371
1372 return nbt._bt_ctf_clock_get_description(self._c)
1373
1374 @description.setter
1375 def description(self, desc):
1376 """
1377 Set the clock's description. The description appears in the clock's TSDL
1378 meta-data.
1379 """
1380
1381 ret = nbt._bt_ctf_clock_set_description(self._c, str(desc))
1382
1383 if ret < 0:
1384 raise ValueError("Invalid clock description.")
1385
1386 @property
1387 def frequency(self):
1388 """
1389 Get the clock's frequency (Hz).
1390 """
1391
1392 freq = nbt._bt_ctf_clock_get_frequency(self._c)
1393
1394 if freq == CTFWriter._MAX_UINT64:
1395 raise ValueError("Invalid clock instance")
1396
1397 return freq
1398
1399 @frequency.setter
1400 def frequency(self, freq):
1401 """
1402 Set the clock's frequency (Hz).
1403 """
1404
1405 ret = nbt._bt_ctf_clock_set_frequency(self._c, freq)
1406
1407 if ret < 0:
1408 raise ValueError("Invalid frequency value.")
1409
1410 @property
1411 def precision(self):
1412 """
1413 Get the clock's precision (in clock ticks).
1414 """
1415
1416 precision = nbt._bt_ctf_clock_get_precision(self._c)
1417
1418 if precision == CTFWriter._MAX_UINT64:
1419 raise ValueError("Invalid clock instance")
1420
1421 return precision
1422
1423 @precision.setter
1424 def precision(self, precision):
1425 """
1426 Set the clock's precision (in clock ticks).
1427 """
1428
1429 ret = nbt._bt_ctf_clock_set_precision(self._c, precision)
1430
1431 @property
1432 def offset_seconds(self):
1433 """
1434 Get the clock's offset in seconds from POSIX.1 Epoch.
1435 """
1436
1437 offset_s = nbt._bt_ctf_clock_get_offset_s(self._c)
1438
1439 if offset_s == CTFWriter._MAX_UINT64:
1440 raise ValueError("Invalid clock instance")
1441
1442 return offset_s
1443
1444 @offset_seconds.setter
1445 def offset_seconds(self, offset_s):
1446 """
1447 Set the clock's offset in seconds from POSIX.1 Epoch.
1448 """
1449
1450 ret = nbt._bt_ctf_clock_set_offset_s(self._c, offset_s)
1451
1452 if ret < 0:
1453 raise ValueError("Invalid offset value.")
1454
1455 @property
1456 def offset(self):
1457 """
1458 Get the clock's offset in ticks from POSIX.1 Epoch + offset in seconds.
1459 """
1460
1461 offset = nbt._bt_ctf_clock_get_offset(self._c)
1462
1463 if offset == CTFWriter._MAX_UINT64:
1464 raise ValueError("Invalid clock instance")
1465
1466 return offset
1467
1468 @offset.setter
1469 def offset(self, offset):
1470 """
1471 Set the clock's offset in ticks from POSIX.1 Epoch + offset in seconds.
1472 """
1473
1474 ret = nbt._bt_ctf_clock_set_offset(self._c, offset)
1475
1476 if ret < 0:
1477 raise ValueError("Invalid offset value.")
1478
1479 @property
1480 def absolute(self):
1481 """
1482 Get a clock's absolute attribute. A clock is absolute if the clock
1483 is a global reference across the trace's other clocks.
1484 """
1485
1486 is_absolute = nbt._bt_ctf_clock_get_is_absolute(self._c)
1487
1488 if is_absolute == -1:
1489 raise ValueError("Invalid clock instance")
1490
1491 return False if is_absolute == 0 else True
1492
1493 @absolute.setter
1494 def absolute(self, is_absolute):
1495 """
1496 Set a clock's absolute attribute. A clock is absolute if the clock
1497 is a global reference across the trace's other clocks.
1498 """
1499
1500 ret = nbt._bt_ctf_clock_set_is_absolute(self._c, int(is_absolute))
1501
1502 if ret < 0:
1503 raise ValueError("Could not set the clock's absolute attribute.")
1504
1505 @property
1506 def uuid(self):
1507 """
1508 Get a clock's UUID (an object of type UUID).
1509 """
1510
1511 uuid_list = []
1512
1513 for i in range(16):
1514 ret, value = nbt._bt_python_ctf_clock_get_uuid_index(self._c, i)
1515
1516 if ret < 0:
1517 raise ValueError("Invalid clock instance")
1518
1519 uuid_list.append(value)
1520
1521 return UUID(bytes=bytes(uuid_list))
1522
1523 @uuid.setter
1524 def uuid(self, uuid):
1525 """
1526 Set a clock's UUID (an object of type UUID).
1527 """
1528
1529 uuid_bytes = uuid.bytes
1530
1531 if len(uuid_bytes) != 16:
1532 raise ValueError("Invalid UUID provided. UUID length must be 16 bytes")
1533
1534 for i in range(len(uuid_bytes)):
1535 ret = nbt._bt_python_ctf_clock_set_uuid_index(self._c, i,
1536 uuid_bytes[i])
1537
1538 if ret < 0:
1539 raise ValueError("Invalid clock instance")
1540
1541 @property
1542 def time(self):
1543 """
1544 Get the current time in nanoseconds since the clock's origin (offset and
1545 offset_s attributes).
1546 """
1547
1548 time = nbt._bt_ctf_clock_get_time(self._c)
1549
1550 if time == CTFWriter._MAX_UINT64:
1551 raise ValueError("Invalid clock instance")
1552
1553 return time
1554
1555 @time.setter
1556 def time(self, time):
1557 """
1558 Set the current time in nanoseconds since the clock's origin (offset and
1559 offset_s attributes). The clock's value will be sampled as events are
1560 appended to a stream.
1561 """
1562
1563 ret = nbt._bt_ctf_clock_set_time(self._c, time)
1564
1565 if ret < 0:
1566 raise ValueError("Invalid time value.")
1567
1568 class FieldDeclaration:
1569 """
1570 FieldDeclaration should not be instantiated directly. Instantiate
1571 one of the concrete FieldDeclaration classes.
1572 """
1573
1574 class IntegerBase:
1575 # These values are based on the bt_ctf_integer_base enum
1576 # declared in event-types.h.
1577 INTEGER_BASE_UNKNOWN = -1
1578 INTEGER_BASE_BINARY = 2
1579 INTEGER_BASE_OCTAL = 8
1580 INTEGER_BASE_DECIMAL = 10
1581 INTEGER_BASE_HEXADECIMAL = 16
1582
1583 def __init__(self):
1584 if self._ft is None:
1585 raise ValueError("FieldDeclaration creation failed.")
1586
1587 def __del__(self):
1588 nbt._bt_ctf_field_type_put(self._ft)
1589
1590 @staticmethod
1591 def _create_field_declaration_from_native_instance(
1592 native_field_declaration):
1593 type_dict = {
1594 CTFTypeId.INTEGER: CTFWriter.IntegerFieldDeclaration,
1595 CTFTypeId.FLOAT: CTFWriter.FloatFieldDeclaration,
1596 CTFTypeId.ENUM: CTFWriter.EnumerationFieldDeclaration,
1597 CTFTypeId.STRING: CTFWriter.StringFieldDeclaration,
1598 CTFTypeId.STRUCT: CTFWriter.StructureFieldDeclaration,
1599 CTFTypeId.VARIANT: CTFWriter.VariantFieldDeclaration,
1600 CTFTypeId.ARRAY: CTFWriter.ArrayFieldDeclaration,
1601 CTFTypeId.SEQUENCE: CTFWriter.SequenceFieldDeclaration
1602 }
1603
1604 field_type_id = nbt._bt_ctf_field_type_get_type_id(native_field_declaration)
1605
1606 if field_type_id == CTFTypeId.UNKNOWN:
1607 raise TypeError("Invalid field instance")
1608
1609 declaration = CTFWriter.Field.__new__(CTFWriter.Field)
1610 declaration._ft = native_field_declaration
1611 declaration.__class__ = type_dict[field_type_id]
1612
1613 return declaration
1614
1615 @property
1616 def alignment(self):
1617 """
1618 Get the field declaration's alignment. Returns -1 on error.
1619 """
1620
1621 return nbt._bt_ctf_field_type_get_alignment(self._ft)
1622
1623 @alignment.setter
1624 def alignment(self, alignment):
1625 """
1626 Set the field declaration's alignment. Defaults to 1 (bit-aligned). However,
1627 some types, such as structures and string, may impose other alignment
1628 constraints.
1629 """
1630
1631 ret = nbt._bt_ctf_field_type_set_alignment(self._ft, alignment)
1632
1633 if ret < 0:
1634 raise ValueError("Invalid alignment value.")
1635
1636 @property
1637 def byte_order(self):
1638 """
1639 Get the field declaration's byte order. One of the ByteOrder's constant.
1640 """
1641
1642 return nbt._bt_ctf_field_type_get_byte_order(self._ft)
1643
1644 @byte_order.setter
1645 def byte_order(self, byte_order):
1646 """
1647 Set the field declaration's byte order. Use constants defined in the ByteOrder
1648 class.
1649 """
1650
1651 ret = nbt._bt_ctf_field_type_set_byte_order(self._ft, byte_order)
1652
1653 if ret < 0:
1654 raise ValueError("Could not set byte order value.")
1655
1656 class IntegerFieldDeclaration(FieldDeclaration):
1657 def __init__(self, size):
1658 """
1659 Create a new integer field declaration of the given size.
1660 """
1661 self._ft = nbt._bt_ctf_field_type_integer_create(size)
1662 super().__init__()
1663
1664 @property
1665 def size(self):
1666 """
1667 Get an integer's size.
1668 """
1669
1670 ret = nbt._bt_ctf_field_type_integer_get_size(self._ft)
1671
1672 if ret < 0:
1673 raise ValueError("Could not get Integer's size attribute.")
1674 else:
1675 return ret
1676
1677 @property
1678 def signed(self):
1679 """
1680 Get an integer's signedness attribute.
1681 """
1682
1683 ret = nbt._bt_ctf_field_type_integer_get_signed(self._ft)
1684
1685 if ret < 0:
1686 raise ValueError("Could not get Integer's signed attribute.")
1687 elif ret > 0:
1688 return True
1689 else:
1690 return False
1691
1692 @signed.setter
1693 def signed(self, signed):
1694 """
1695 Set an integer's signedness attribute.
1696 """
1697
1698 ret = nbt._bt_ctf_field_type_integer_set_signed(self._ft, signed)
1699
1700 if ret < 0:
1701 raise ValueError("Could not set Integer's signed attribute.")
1702
1703 @property
1704 def base(self):
1705 """
1706 Get the integer's base used to pretty-print the resulting trace.
1707 Returns a constant from the FieldDeclaration.IntegerBase class.
1708 """
1709
1710 return nbt._bt_ctf_field_type_integer_get_base(self._ft)
1711
1712 @base.setter
1713 def base(self, base):
1714 """
1715 Set the integer's base used to pretty-print the resulting trace.
1716 The base must be a constant of the FieldDeclarationIntegerBase class.
1717 """
1718
1719 ret = nbt._bt_ctf_field_type_integer_set_base(self._ft, base)
1720
1721 if ret < 0:
1722 raise ValueError("Could not set Integer's base.")
1723
1724 @property
1725 def encoding(self):
1726 """
1727 Get the integer's encoding (one of the constants of the
1728 CTFStringEncoding class).
1729 Returns a constant from the CTFStringEncoding class.
1730 """
1731
1732 return nbt._bt_ctf_field_type_integer_get_encoding(self._ft)
1733
1734 @encoding.setter
1735 def encoding(self, encoding):
1736 """
1737 An integer encoding may be set to signal that the integer must be printed
1738 as a text character. Must be a constant from the CTFStringEncoding class.
1739 """
1740
1741 ret = nbt._bt_ctf_field_type_integer_set_encoding(self._ft, encoding)
1742
1743 if ret < 0:
1744 raise ValueError("Could not set Integer's encoding.")
1745
1746 class EnumerationFieldDeclaration(FieldDeclaration):
1747 def __init__(self, integer_type):
1748 """
1749 Create a new enumeration field declaration with the given underlying container type.
1750 """
1751 isinst = isinstance(integer_type, CTFWriter.IntegerFieldDeclaration)
1752
1753 if integer_type is None or not isinst:
1754 raise TypeError("Invalid integer container.")
1755
1756 self._ft = nbt._bt_ctf_field_type_enumeration_create(integer_type._ft)
1757 super().__init__()
1758
1759 @property
1760 def container(self):
1761 """
1762 Get the enumeration's underlying container type.
1763 """
1764
1765 ret = nbt._bt_ctf_field_type_enumeration_get_container_type(self._ft)
1766
1767 if ret is None:
1768 raise TypeError("Invalid enumeration declaration")
1769
1770 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
1771
1772 def add_mapping(self, name, range_start, range_end):
1773 """
1774 Add a mapping to the enumeration. The range's values are inclusive.
1775 """
1776
1777 if range_start < 0 or range_end < 0:
1778 ret = nbt._bt_ctf_field_type_enumeration_add_mapping(self._ft,
1779 str(name),
1780 range_start,
1781 range_end)
1782 else:
1783 ret = nbt._bt_ctf_field_type_enumeration_add_mapping_unsigned(self._ft,
1784 str(name),
1785 range_start,
1786 range_end)
1787
1788 if ret < 0:
1789 raise ValueError("Could not add mapping to enumeration declaration.")
1790
1791 @property
1792 def mappings(self):
1793 """
1794 Generator returning instances of EnumerationMapping.
1795 """
1796
1797 signed = self.container.signed
1798
1799 count = nbt._bt_ctf_field_type_enumeration_get_mapping_count(self._ft)
1800
1801 for i in range(count):
1802 if signed:
1803 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, i)
1804 else:
1805 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, i)
1806
1807 if len(ret) != 3:
1808 msg = "Could not get Enumeration mapping at index {}".format(i)
1809 raise TypeError(msg)
1810
1811 name, range_start, range_end = ret
1812 yield CTFWriter.EnumerationMapping(name, range_start, range_end)
1813
1814 def get_mapping_by_name(self, name):
1815 """
1816 Get a mapping by name (EnumerationMapping).
1817 """
1818
1819 index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_name(self._ft, name)
1820
1821 if index < 0:
1822 return None
1823
1824 if self.container.signed:
1825 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, index)
1826 else:
1827 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, index)
1828
1829 if len(ret) != 3:
1830 msg = "Could not get Enumeration mapping at index {}".format(i)
1831 raise TypeError(msg)
1832
1833 name, range_start, range_end = ret
1834
1835 return CTFWriter.EnumerationMapping(name, range_start, range_end)
1836
1837 def get_mapping_by_value(self, value):
1838 """
1839 Get a mapping by value (EnumerationMapping).
1840 """
1841
1842 if value < 0:
1843 index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_value(self._ft, value)
1844 else:
1845 index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_unsigned_value(self._ft, value)
1846
1847 if index < 0:
1848 return None
1849
1850 if self.container.signed:
1851 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, index)
1852 else:
1853 ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, index)
1854
1855 if len(ret) != 3:
1856 msg = "Could not get Enumeration mapping at index {}".format(i)
1857 raise TypeError(msg)
1858
1859 name, range_start, range_end = ret
1860
1861 return CTFWriter.EnumerationMapping(name, range_start, range_end)
1862
1863 class FloatFieldDeclaration(FieldDeclaration):
1864 FLT_EXP_DIG = 8
1865 DBL_EXP_DIG = 11
1866 FLT_MANT_DIG = 24
1867 DBL_MANT_DIG = 53
1868
1869 def __init__(self):
1870 """
1871 Create a new floating point field declaration.
1872 """
1873
1874 self._ft = nbt._bt_ctf_field_type_floating_point_create()
1875 super().__init__()
1876
1877 @property
1878 def exponent_digits(self):
1879 """
1880 Get the number of exponent digits used to store the floating point field.
1881 """
1882
1883 ret = nbt._bt_ctf_field_type_floating_point_get_exponent_digits(self._ft)
1884
1885 if ret < 0:
1886 raise TypeError(
1887 "Could not get Floating point exponent digit count")
1888
1889 return ret
1890
1891 @exponent_digits.setter
1892 def exponent_digits(self, exponent_digits):
1893 """
1894 Set the number of exponent digits to use to store the floating point field.
1895 The only values currently supported are FLT_EXP_DIG and DBL_EXP_DIG which
1896 are defined as constants of this class.
1897 """
1898
1899 ret = nbt._bt_ctf_field_type_floating_point_set_exponent_digits(self._ft,
1900 exponent_digits)
1901
1902 if ret < 0:
1903 raise ValueError("Could not set exponent digit count.")
1904
1905 @property
1906 def mantissa_digits(self):
1907 """
1908 Get the number of mantissa digits used to store the floating point field.
1909 """
1910
1911 ret = nbt._bt_ctf_field_type_floating_point_get_mantissa_digits(self._ft)
1912
1913 if ret < 0:
1914 raise TypeError("Could not get Floating point mantissa digit count")
1915
1916 return ret
1917
1918 @mantissa_digits.setter
1919 def mantissa_digits(self, mantissa_digits):
1920 """
1921 Set the number of mantissa digits to use to store the floating point field.
1922 The only values currently supported are FLT_MANT_DIG and DBL_MANT_DIG which
1923 are defined as constants of this class.
1924 """
1925
1926 ret = nbt._bt_ctf_field_type_floating_point_set_mantissa_digits(self._ft,
1927 mantissa_digits)
1928
1929 if ret < 0:
1930 raise ValueError("Could not set mantissa digit count.")
1931
1932 class FloatingPointFieldDeclaration(FloatFieldDeclaration):
1933 pass
1934
1935 class StructureFieldDeclaration(FieldDeclaration):
1936 def __init__(self):
1937 """
1938 Create a new structure field declaration.
1939 """
1940
1941 self._ft = nbt._bt_ctf_field_type_structure_create()
1942 super().__init__()
1943
1944 def add_field(self, field_type, field_name):
1945 """
1946 Add a field of type "field_type" to the structure.
1947 """
1948
1949 ret = nbt._bt_ctf_field_type_structure_add_field(self._ft,
1950 field_type._ft,
1951 str(field_name))
1952
1953 if ret < 0:
1954 raise ValueError("Could not add field to structure.")
1955
1956 @property
1957 def fields(self):
1958 """
1959 Generator returning the structure's field as tuples of (field name, field declaration).
1960 """
1961
1962 count = nbt._bt_ctf_field_type_structure_get_field_count(self._ft)
1963
1964 if count < 0:
1965 raise TypeError("Could not get Structure field count")
1966
1967 for i in range(count):
1968 field_name = nbt._bt_python_ctf_field_type_structure_get_field_name(self._ft, i)
1969
1970 if field_name is None:
1971 msg = "Could not get Structure field name at index {}".format(i)
1972 raise TypeError(msg)
1973
1974 field_type_native = nbt._bt_python_ctf_field_type_structure_get_field_type(self._ft, i)
1975
1976 if field_type_native is None:
1977 msg = "Could not get Structure field type at index {}".format(i)
1978 raise TypeError(msg)
1979
1980 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
1981 yield (field_name, field_type)
1982
1983 def get_field_by_name(self, name):
1984 """
1985 Get a field declaration by name (FieldDeclaration).
1986 """
1987
1988 field_type_native = nbt._bt_ctf_field_type_structure_get_field_type_by_name(self._ft, name)
1989
1990 if field_type_native is None:
1991 msg = "Could not find Structure field with name {}".format(name)
1992 raise TypeError(msg)
1993
1994 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
1995
1996 class VariantFieldDeclaration(FieldDeclaration):
1997 def __init__(self, enum_tag, tag_name):
1998 """
1999 Create a new variant field declaration.
2000 """
2001
2002 isinst = isinstance(enum_tag, CTFWriter.EnumerationFieldDeclaration)
2003 if enum_tag is None or not isinst:
2004 raise TypeError("Invalid tag type; must be of type EnumerationFieldDeclaration.")
2005
2006 self._ft = nbt._bt_ctf_field_type_variant_create(enum_tag._ft,
2007 str(tag_name))
2008 super().__init__()
2009
2010 @property
2011 def tag_name(self):
2012 """
2013 Get the variant's tag name.
2014 """
2015
2016 ret = nbt._bt_ctf_field_type_variant_get_tag_name(self._ft)
2017
2018 if ret is None:
2019 raise TypeError("Could not get Variant tag name")
2020
2021 return ret
2022
2023 @property
2024 def tag_type(self):
2025 """
2026 Get the variant's tag type.
2027 """
2028
2029 ret = nbt._bt_ctf_field_type_variant_get_tag_type(self._ft)
2030
2031 if ret is None:
2032 raise TypeError("Could not get Variant tag type")
2033
2034 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
2035
2036 def add_field(self, field_type, field_name):
2037 """
2038 Add a field of type "field_type" to the variant.
2039 """
2040
2041 ret = nbt._bt_ctf_field_type_variant_add_field(self._ft,
2042 field_type._ft,
2043 str(field_name))
2044
2045 if ret < 0:
2046 raise ValueError("Could not add field to variant.")
2047
2048 @property
2049 def fields(self):
2050 """
2051 Generator returning the variant's field as tuples of (field name, field declaration).
2052 """
2053
2054 count = nbt._bt_ctf_field_type_variant_get_field_count(self._ft)
2055
2056 if count < 0:
2057 raise TypeError("Could not get Variant field count")
2058
2059 for i in range(count):
2060 field_name = nbt._bt_python_ctf_field_type_variant_get_field_name(self._ft, i)
2061
2062 if field_name is None:
2063 msg = "Could not get Variant field name at index {}".format(i)
2064 raise TypeError(msg)
2065
2066 field_type_native = nbt._bt_python_ctf_field_type_variant_get_field_type(self._ft, i)
2067
2068 if field_type_native is None:
2069 msg = "Could not get Variant field type at index {}".format(i)
2070 raise TypeError(msg)
2071
2072 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2073 yield (field_name, field_type)
2074
2075 def get_field_by_name(self, name):
2076 """
2077 Get a field declaration by name (FieldDeclaration).
2078 """
2079
2080 field_type_native = nbt._bt_ctf_field_type_variant_get_field_type_by_name(self._ft,
2081 name)
2082
2083 if field_type_native is None:
2084 msg = "Could not find Variant field with name {}".format(name)
2085 raise TypeError(msg)
2086
2087 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2088
2089 def get_field_from_tag(self, tag):
2090 """
2091 Get a field declaration from tag (EnumerationField).
2092 """
2093
2094 field_type_native = nbt._bt_ctf_field_type_variant_get_field_type_from_tag(self._ft, tag._f)
2095
2096 if field_type_native is None:
2097 msg = "Could not find Variant field with tag value {}".format(tag.value)
2098 raise TypeError(msg)
2099
2100 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2101
2102 class ArrayFieldDeclaration(FieldDeclaration):
2103 def __init__(self, element_type, length):
2104 """
2105 Create a new array field declaration.
2106 """
2107
2108 self._ft = nbt._bt_ctf_field_type_array_create(element_type._ft,
2109 length)
2110 super().__init__()
2111
2112 @property
2113 def element_type(self):
2114 """
2115 Get the array's element type.
2116 """
2117
2118 ret = nbt._bt_ctf_field_type_array_get_element_type(self._ft)
2119
2120 if ret is None:
2121 raise TypeError("Could not get Array element type")
2122
2123 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
2124
2125 @property
2126 def length(self):
2127 """
2128 Get the array's length.
2129 """
2130
2131 ret = nbt._bt_ctf_field_type_array_get_length(self._ft)
2132
2133 if ret < 0:
2134 raise TypeError("Could not get Array length")
2135
2136 return ret
2137
2138 class SequenceFieldDeclaration(FieldDeclaration):
2139 def __init__(self, element_type, length_field_name):
2140 """
2141 Create a new sequence field declaration.
2142 """
2143
2144 self._ft = nbt._bt_ctf_field_type_sequence_create(element_type._ft,
2145 str(length_field_name))
2146 super().__init__()
2147
2148 @property
2149 def element_type(self):
2150 """
2151 Get the sequence's element type.
2152 """
2153
2154 ret = nbt._bt_ctf_field_type_sequence_get_element_type(self._ft)
2155
2156 if ret is None:
2157 raise TypeError("Could not get Sequence element type")
2158
2159 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
2160
2161 @property
2162 def length_field_name(self):
2163 """
2164 Get the sequence's length field name.
2165 """
2166
2167 ret = nbt._bt_ctf_field_type_sequence_get_length_field_name(self._ft)
2168
2169 if ret is None:
2170 raise TypeError("Could not get Sequence length field name")
2171
2172 return ret
2173
2174 class StringFieldDeclaration(FieldDeclaration):
2175 def __init__(self):
2176 """
2177 Create a new string field declaration.
2178 """
2179
2180 self._ft = nbt._bt_ctf_field_type_string_create()
2181 super().__init__()
2182
2183 @property
2184 def encoding(self):
2185 """
2186 Get a string declaration's encoding (a constant from the CTFStringEncoding class).
2187 """
2188
2189 return nbt._bt_ctf_field_type_string_get_encoding(self._ft)
2190
2191 @encoding.setter
2192 def encoding(self, encoding):
2193 """
2194 Set a string declaration's encoding. Must be a constant from the CTFStringEncoding class.
2195 """
2196
2197 ret = nbt._bt_ctf_field_type_string_set_encoding(self._ft, encoding)
2198 if ret < 0:
2199 raise ValueError("Could not set string encoding.")
2200
2201 @staticmethod
2202 def create_field(field_type):
2203 """
2204 Create an instance of a field.
2205 """
2206 isinst = isinstance(field_type, CTFWriter.FieldDeclaration)
2207
2208 if field_type is None or not isinst:
2209 raise TypeError("Invalid field_type. Type must be a FieldDeclaration-derived class.")
2210
2211 if isinstance(field_type, CTFWriter.IntegerFieldDeclaration):
2212 return CTFWriter.IntegerField(field_type)
2213 elif isinstance(field_type, CTFWriter.EnumerationFieldDeclaration):
2214 return CTFWriter.EnumerationField(field_type)
2215 elif isinstance(field_type, CTFWriter.FloatFieldDeclaration):
2216 return CTFWriter.FloatingPointField(field_type)
2217 elif isinstance(field_type, CTFWriter.StructureFieldDeclaration):
2218 return CTFWriter.StructureField(field_type)
2219 elif isinstance(field_type, CTFWriter.VariantFieldDeclaration):
2220 return CTFWriter.VariantField(field_type)
2221 elif isinstance(field_type, CTFWriter.ArrayFieldDeclaration):
2222 return CTFWriter.ArrayField(field_type)
2223 elif isinstance(field_type, CTFWriter.SequenceFieldDeclaration):
2224 return CTFWriter.SequenceField(field_type)
2225 elif isinstance(field_type, CTFWriter.StringFieldDeclaration):
2226 return CTFWriter.StringField(field_type)
2227
2228 class Field:
2229 """
2230 Base class, do not instantiate.
2231 """
2232
2233 def __init__(self, field_type):
2234 if not isinstance(field_type, CTFWriter.FieldDeclaration):
2235 raise TypeError("Invalid field_type argument.")
2236
2237 self._f = nbt._bt_ctf_field_create(field_type._ft)
2238
2239 if self._f is None:
2240 raise ValueError("Field creation failed.")
2241
2242 def __del__(self):
2243 nbt._bt_ctf_field_put(self._f)
2244
2245 @staticmethod
2246 def _create_field_from_native_instance(native_field_instance):
2247 type_dict = {
2248 CTFTypeId.INTEGER: CTFWriter.IntegerField,
2249 CTFTypeId.FLOAT: CTFWriter.FloatingPointField,
2250 CTFTypeId.ENUM: CTFWriter.EnumerationField,
2251 CTFTypeId.STRING: CTFWriter.StringField,
2252 CTFTypeId.STRUCT: CTFWriter.StructureField,
2253 CTFTypeId.VARIANT: CTFWriter.VariantField,
2254 CTFTypeId.ARRAY: CTFWriter.ArrayField,
2255 CTFTypeId.SEQUENCE: CTFWriter.SequenceField
2256 }
2257
2258 field_type = nbt._bt_python_get_field_type(native_field_instance)
2259
2260 if field_type == CTFTypeId.UNKNOWN:
2261 raise TypeError("Invalid field instance")
2262
2263 field = CTFWriter.Field.__new__(CTFWriter.Field)
2264 field._f = native_field_instance
2265 field.__class__ = type_dict[field_type]
2266
2267 return field
2268
2269 @property
2270 def declaration(self):
2271 native_field_type = nbt._bt_ctf_field_get_type(self._f)
2272
2273 if native_field_type is None:
2274 raise TypeError("Invalid field instance")
2275 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(
2276 native_field_type)
2277
2278 class IntegerField(Field):
2279 @property
2280 def value(self):
2281 """
2282 Get an integer field's value.
2283 """
2284
2285 signedness = nbt._bt_python_field_integer_get_signedness(self._f)
2286
2287 if signedness < 0:
2288 raise TypeError("Invalid integer instance.")
2289
2290 if signedness == 0:
2291 ret, value = nbt._bt_ctf_field_unsigned_integer_get_value(self._f)
2292 else:
2293 ret, value = nbt._bt_ctf_field_signed_integer_get_value(self._f)
2294
2295 if ret < 0:
2296 raise ValueError("Could not get integer field value.")
2297
2298 return value
2299
2300 @value.setter
2301 def value(self, value):
2302 """
2303 Set an integer field's value.
2304 """
2305
2306 if not isinstance(value, int):
2307 raise TypeError("IntegerField's value must be an int")
2308
2309 signedness = nbt._bt_python_field_integer_get_signedness(self._f)
2310 if signedness < 0:
2311 raise TypeError("Invalid integer instance.")
2312
2313 if signedness == 0:
2314 ret = nbt._bt_ctf_field_unsigned_integer_set_value(self._f, value)
2315 else:
2316 ret = nbt._bt_ctf_field_signed_integer_set_value(self._f, value)
2317
2318 if ret < 0:
2319 raise ValueError("Could not set integer field value.")
2320
2321 class EnumerationField(Field):
2322 @property
2323 def container(self):
2324 """
2325 Return the enumeration's underlying container field (an integer field).
2326 """
2327
2328 container = CTFWriter.IntegerField.__new__(CTFWriter.IntegerField)
2329 container._f = nbt._bt_ctf_field_enumeration_get_container(self._f)
2330
2331 if container._f is None:
2332 raise TypeError("Invalid enumeration field type.")
2333
2334 return container
2335
2336 @property
2337 def value(self):
2338 """
2339 Get the enumeration field's mapping name.
2340 """
2341
2342 value = nbt._bt_ctf_field_enumeration_get_mapping_name(self._f)
2343
2344 if value is None:
2345 raise ValueError("Could not get enumeration's mapping name.")
2346
2347 return value
2348
2349 @value.setter
2350 def value(self, value):
2351 """
2352 Set the enumeration field's value. Must be an integer as mapping names
2353 may be ambiguous.
2354 """
2355
2356 if not isinstance(value, int):
2357 raise TypeError("EnumerationField value must be an int")
2358
2359 self.container.value = value
2360
2361 class FloatingPointField(Field):
2362 @property
2363 def value(self):
2364 """
2365 Get a floating point field's value.
2366 """
2367
2368 ret, value = nbt._bt_ctf_field_floating_point_get_value(self._f)
2369
2370 if ret < 0:
2371 raise ValueError("Could not get floating point field value.")
2372
2373 return value
2374
2375 @value.setter
2376 def value(self, value):
2377 """
2378 Set a floating point field's value.
2379 """
2380
2381 if not isinstance(value, int) and not isinstance(value, float):
2382 raise TypeError("Value must be either a float or an int")
2383
2384 ret = nbt._bt_ctf_field_floating_point_set_value(self._f, float(value))
2385
2386 if ret < 0:
2387 raise ValueError("Could not set floating point field value.")
2388
2389 # oops!! This class is provided to ensure backward-compatibility since
2390 # a stable release publicly exposed this abomination.
2391 class FloatFieldingPoint(FloatingPointField):
2392 pass
2393
2394 class StructureField(Field):
2395 def field(self, field_name):
2396 """
2397 Get the structure's field corresponding to the provided field name.
2398 """
2399
2400 native_instance = nbt._bt_ctf_field_structure_get_field(self._f,
2401 str(field_name))
2402
2403 if native_instance is None:
2404 raise ValueError("Invalid field_name provided.")
2405
2406 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2407
2408 class VariantField(Field):
2409 def field(self, tag):
2410 """
2411 Return the variant's selected field. The "tag" field is the selector enum field.
2412 """
2413
2414 native_instance = nbt._bt_ctf_field_variant_get_field(self._f, tag._f)
2415
2416 if native_instance is None:
2417 raise ValueError("Invalid tag provided.")
2418
2419 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2420
2421 class ArrayField(Field):
2422 def field(self, index):
2423 """
2424 Return the array's field at position "index".
2425 """
2426
2427 native_instance = nbt._bt_ctf_field_array_get_field(self._f, index)
2428
2429 if native_instance is None:
2430 raise IndexError("Invalid index provided.")
2431
2432 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2433
2434 class SequenceField(Field):
2435 @property
2436 def length(self):
2437 """
2438 Get the sequence's length field (IntegerField).
2439 """
2440
2441 native_instance = nbt._bt_ctf_field_sequence_get_length(self._f)
2442
2443 if native_instance is None:
2444 length = -1
2445
2446 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2447
2448 @length.setter
2449 def length(self, length_field):
2450 """
2451 Set the sequence's length field (IntegerField).
2452 """
2453
2454 if not isinstance(length_field, CTFWriter.IntegerField):
2455 raise TypeError("Invalid length field.")
2456
2457 if length_field.declaration.signed:
2458 raise TypeError("Sequence field length must be unsigned")
2459
2460 ret = nbt._bt_ctf_field_sequence_set_length(self._f, length_field._f)
2461
2462 if ret < 0:
2463 raise ValueError("Could not set sequence length.")
2464
2465 def field(self, index):
2466 """
2467 Return the sequence's field at position "index".
2468 """
2469
2470 native_instance = nbt._bt_ctf_field_sequence_get_field(self._f, index)
2471
2472 if native_instance is None:
2473 raise ValueError("Could not get sequence element at index.")
2474
2475 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2476
2477 class StringField(Field):
2478 @property
2479 def value(self):
2480 """
2481 Get a string field's value.
2482 """
2483
2484 return nbt._bt_ctf_field_string_get_value(self._f)
2485
2486 @value.setter
2487 def value(self, value):
2488 """
2489 Set a string field's value.
2490 """
2491
2492 ret = nbt._bt_ctf_field_string_set_value(self._f, str(value))
2493
2494 if ret < 0:
2495 raise ValueError("Could not set string field value.")
2496
2497 class EventClass:
2498 def __init__(self, name):
2499 """
2500 Create a new event class of the given name.
2501 """
2502
2503 self._ec = nbt._bt_ctf_event_class_create(name)
2504
2505 if self._ec is None:
2506 raise ValueError("Event class creation failed.")
2507
2508 def __del__(self):
2509 nbt._bt_ctf_event_class_put(self._ec)
2510
2511 def add_field(self, field_type, field_name):
2512 """
2513 Add a field of type "field_type" to the event class.
2514 """
2515
2516 ret = nbt._bt_ctf_event_class_add_field(self._ec, field_type._ft,
2517 str(field_name))
2518
2519 if ret < 0:
2520 raise ValueError("Could not add field to event class.")
2521
2522 @property
2523 def name(self):
2524 """
2525 Get the event class' name.
2526 """
2527
2528 name = nbt._bt_ctf_event_class_get_name(self._ec)
2529
2530 if name is None:
2531 raise TypeError("Could not get EventClass name")
2532
2533 return name
2534
2535 @property
2536 def id(self):
2537 """
2538 Get the event class' id. Returns a negative value if unset.
2539 """
2540
2541 id = nbt._bt_ctf_event_class_get_id(self._ec)
2542
2543 if id < 0:
2544 raise TypeError("Could not get EventClass id")
2545
2546 return id
2547
2548 @id.setter
2549 def id(self, id):
2550 """
2551 Set the event class' id. Throws a TypeError if the event class
2552 is already registered to a stream class.
2553 """
2554
2555 ret = nbt._bt_ctf_event_class_set_id(self._ec, id)
2556
2557 if ret < 0:
2558 raise TypeError("Can't change an Event Class's id after it has been assigned to a stream class")
2559
2560 @property
2561 def stream_class(self):
2562 """
2563 Get the event class' stream class. Returns None if unset.
2564 """
2565 stream_class_native = nbt._bt_ctf_event_class_get_stream_class(self._ec)
2566
2567 if stream_class_native is None:
2568 return None
2569
2570 stream_class = CTFWriter.StreamClass.__new__(CTFWriter.StreamClass)
2571 stream_class._sc = stream_class_native
2572
2573 return stream_class
2574
2575 @property
2576 def fields(self):
2577 """
2578 Generator returning the event class' fields as tuples of (field name, field declaration).
2579 """
2580
2581 count = nbt._bt_ctf_event_class_get_field_count(self._ec)
2582
2583 if count < 0:
2584 raise TypeError("Could not get EventClass' field count")
2585
2586 for i in range(count):
2587 field_name = nbt._bt_python_ctf_event_class_get_field_name(self._ec, i)
2588
2589 if field_name is None:
2590 msg = "Could not get EventClass' field name at index {}".format(i)
2591 raise TypeError(msg)
2592
2593 field_type_native = nbt._bt_python_ctf_event_class_get_field_type(self._ec, i)
2594
2595 if field_type_native is None:
2596 msg = "Could not get EventClass' field type at index {}".format(i)
2597 raise TypeError(msg)
2598
2599 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2600 yield (field_name, field_type)
2601
2602 def get_field_by_name(self, name):
2603 """
2604 Get a field declaration by name (FieldDeclaration).
2605 """
2606
2607 field_type_native = nbt._bt_ctf_event_class_get_field_by_name(self._ec, name)
2608
2609 if field_type_native is None:
2610 msg = "Could not find EventClass field with name {}".format(name)
2611 raise TypeError(msg)
2612
2613 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2614
2615 class Event:
2616 def __init__(self, event_class):
2617 """
2618 Create a new event of the given event class.
2619 """
2620
2621 if not isinstance(event_class, CTFWriter.EventClass):
2622 raise TypeError("Invalid event_class argument.")
2623
2624 self._e = nbt._bt_ctf_event_create(event_class._ec)
2625
2626 if self._e is None:
2627 raise ValueError("Event creation failed.")
2628
2629 def __del__(self):
2630 nbt._bt_ctf_event_put(self._e)
2631
2632 @property
2633 def event_class(self):
2634 """
2635 Get the event's class.
2636 """
2637
2638 event_class_native = nbt._bt_ctf_event_get_class(self._e)
2639
2640 if event_class_native is None:
2641 return None
2642
2643 event_class = CTFWriter.EventClass.__new__(CTFWriter.EventClass)
2644 event_class._ec = event_class_native
2645
2646 return event_class
2647
2648 def clock(self):
2649 """
2650 Get a clock from event. Returns None if the event's class
2651 is not registered to a stream class.
2652 """
2653
2654 clock_instance = nbt._bt_ctf_event_get_clock(self._e)
2655
2656 if clock_instance is None:
2657 return None
2658
2659 clock = CTFWriter.Clock.__new__(CTFWriter.Clock)
2660 clock._c = clock_instance
2661
2662 return clock
2663
2664 def payload(self, field_name):
2665 """
2666 Get a field from event.
2667 """
2668
2669 native_instance = nbt._bt_ctf_event_get_payload(self._e,
2670 str(field_name))
2671
2672 if native_instance is None:
2673 raise ValueError("Could not get event payload.")
2674
2675 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2676
2677 def set_payload(self, field_name, value_field):
2678 """
2679 Set a manually created field as an event's payload.
2680 """
2681
2682 if not isinstance(value, CTFWriter.Field):
2683 raise TypeError("Invalid value type.")
2684
2685 ret = nbt._bt_ctf_event_set_payload(self._e, str(field_name),
2686 value_field._f)
2687
2688 if ret < 0:
2689 raise ValueError("Could not set event field payload.")
2690
2691 class StreamClass:
2692 def __init__(self, name):
2693 """
2694 Create a new stream class of the given name.
2695 """
2696
2697 self._sc = nbt._bt_ctf_stream_class_create(name)
2698
2699 if self._sc is None:
2700 raise ValueError("Stream class creation failed.")
2701
2702 def __del__(self):
2703 nbt._bt_ctf_stream_class_put(self._sc)
2704
2705 @property
2706 def name(self):
2707 """
2708 Get a stream class' name.
2709 """
2710
2711 name = nbt._bt_ctf_stream_class_get_name(self._sc)
2712
2713 if name is None:
2714 raise TypeError("Could not get StreamClass name")
2715
2716 return name
2717
2718 @property
2719 def clock(self):
2720 """
2721 Get a stream class' clock.
2722 """
2723
2724 clock_instance = nbt._bt_ctf_stream_class_get_clock(self._sc)
2725
2726 if clock_instance is None:
2727 return None
2728
2729 clock = CTFWriter.Clock.__new__(CTFWriter.Clock)
2730 clock._c = clock_instance
2731
2732 return clock
2733
2734 @clock.setter
2735 def clock(self, clock):
2736 """
2737 Assign a clock to a stream class.
2738 """
2739
2740 if not isinstance(clock, CTFWriter.Clock):
2741 raise TypeError("Invalid clock type.")
2742
2743 ret = nbt._bt_ctf_stream_class_set_clock(self._sc, clock._c)
2744
2745 if ret < 0:
2746 raise ValueError("Could not set stream class clock.")
2747
2748 @property
2749 def id(self):
2750 """
2751 Get a stream class' id.
2752 """
2753
2754 ret = nbt._bt_ctf_stream_class_get_id(self._sc)
2755
2756 if ret < 0:
2757 raise TypeError("Could not get StreamClass id")
2758
2759 return ret
2760
2761 @id.setter
2762 def id(self, id):
2763 """
2764 Assign an id to a stream class.
2765 """
2766
2767 ret = nbt._bt_ctf_stream_class_set_id(self._sc, id)
2768
2769 if ret < 0:
2770 raise TypeError("Could not set stream class id.")
2771
2772 @property
2773 def event_classes(self):
2774 """
2775 Generator returning the stream class' event classes.
2776 """
2777
2778 count = nbt._bt_ctf_stream_class_get_event_class_count(self._sc)
2779
2780 if count < 0:
2781 raise TypeError("Could not get StreamClass' event class count")
2782
2783 for i in range(count):
2784 event_class_native = nbt._bt_ctf_stream_class_get_event_class(self._sc, i)
2785
2786 if event_class_native is None:
2787 msg = "Could not get StreamClass' event class at index {}".format(i)
2788 raise TypeError(msg)
2789
2790 event_class = CTFWriter.EventClass.__new__(CTFWriter.EventClass)
2791 event_class._ec = event_class_native
2792 yield event_class
2793
2794 def add_event_class(self, event_class):
2795 """
2796 Add an event class to a stream class. New events can be added even after a
2797 stream has been instantiated and events have been appended. However, a stream
2798 will not accept events of a class that has not been added to the stream
2799 class beforehand.
2800 """
2801
2802 if not isinstance(event_class, CTFWriter.EventClass):
2803 raise TypeError("Invalid event_class type.")
2804
2805 ret = nbt._bt_ctf_stream_class_add_event_class(self._sc,
2806 event_class._ec)
2807
2808 if ret < 0:
2809 raise ValueError("Could not add event class.")
2810
2811 @property
2812 def packet_context_type(self):
2813 """
2814 Get the StreamClass' packet context type (StructureFieldDeclaration)
2815 """
2816
2817 field_type_native = nbt._bt_ctf_stream_class_get_packet_context_type(self._sc)
2818
2819 if field_type_native is None:
2820 raise ValueError("Invalid StreamClass")
2821
2822 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2823
2824 return field_type
2825
2826 @packet_context_type.setter
2827 def packet_context_type(self, field_type):
2828 """
2829 Set a StreamClass' packet context type. Must be of type
2830 StructureFieldDeclaration.
2831 """
2832
2833 if not isinstance(field_type, CTFWriter.StructureFieldDeclaration):
2834 raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
2835
2836 ret = nbt._bt_ctf_stream_class_set_packet_context_type(self._sc,
2837 field_type._ft)
2838
2839 if ret < 0:
2840 raise ValueError("Failed to set packet context type.")
2841
2842 class Stream:
2843 def __init__(self):
2844 raise NotImplementedError("Stream cannot be instantiated; use Writer.create_stream()")
2845
2846 def __del__(self):
2847 nbt._bt_ctf_stream_put(self._s)
2848
2849 @property
2850 def discarded_events(self):
2851 """
2852 Get a stream's discarded event count.
2853 """
2854
2855 ret, count = nbt._bt_ctf_stream_get_discarded_events_count(self._s)
2856
2857 if ret < 0:
2858 raise ValueError("Could not get the stream's discarded events count")
2859
2860 return count
2861
2862 def append_discarded_events(self, event_count):
2863 """
2864 Increase the current packet's discarded event count.
2865 """
2866
2867 nbt._bt_ctf_stream_append_discarded_events(self._s, event_count)
2868
2869 def append_event(self, event):
2870 """
2871 Append "event" to the stream's current packet. The stream's associated clock
2872 will be sampled during this call. The event shall not be modified after
2873 being appended to a stream.
2874 """
2875
2876 ret = nbt._bt_ctf_stream_append_event(self._s, event._e)
2877
2878 if ret < 0:
2879 raise ValueError("Could not append event to stream.")
2880
2881 @property
2882 def packet_context(self):
2883 """
2884 Get a Stream's packet context field (a StructureField).
2885 """
2886
2887 native_field = nbt._bt_ctf_stream_get_packet_context(self._s)
2888
2889 if native_field is None:
2890 raise ValueError("Invalid Stream.")
2891
2892 return CTFWriter.Field._create_field_from_native_instance(native_field)
2893
2894 @packet_context.setter
2895 def packet_context(self, field):
2896 """
2897 Set a Stream's packet context field (must be a StructureField).
2898 """
2899
2900 if not isinstance(field, CTFWriter.StructureField):
2901 raise TypeError("Argument field must be of type StructureField")
2902
2903 ret = nbt._bt_ctf_stream_set_packet_context(self._s, field._f)
2904
2905 if ret < 0:
2906 raise ValueError("Invalid packet context field.")
2907
2908 def flush(self):
2909 """
2910 The stream's current packet's events will be flushed to disk. Events
2911 subsequently appended to the stream will be added to a new packet.
2912 """
2913
2914 ret = nbt._bt_ctf_stream_flush(self._s)
2915
2916 if ret < 0:
2917 raise ValueError("Could not flush stream.")
2918
2919 class Writer:
2920 def __init__(self, path):
2921 """
2922 Create a new writer that will produce a trace in the given path.
2923 """
2924
2925 self._w = nbt._bt_ctf_writer_create(path)
2926
2927 if self._w is None:
2928 raise ValueError("Writer creation failed.")
2929
2930 def __del__(self):
2931 nbt._bt_ctf_writer_put(self._w)
2932
2933 def create_stream(self, stream_class):
2934 """
2935 Create a new stream instance and register it to the writer.
2936 """
2937
2938 if not isinstance(stream_class, CTFWriter.StreamClass):
2939 raise TypeError("Invalid stream_class type.")
2940
2941 stream = CTFWriter.Stream.__new__(CTFWriter.Stream)
2942 stream._s = nbt._bt_ctf_writer_create_stream(self._w, stream_class._sc)
2943
2944 return stream
2945
2946 def add_environment_field(self, name, value):
2947 """
2948 Add an environment field to the trace.
2949 """
2950
2951 ret = nbt._bt_ctf_writer_add_environment_field(self._w, str(name),
2952 str(value))
2953
2954 if ret < 0:
2955 raise ValueError("Could not add environment field to trace.")
2956
2957 def add_clock(self, clock):
2958 """
2959 Add a clock to the trace. Clocks assigned to stream classes must be
2960 registered to the writer.
2961 """
2962
2963 ret = nbt._bt_ctf_writer_add_clock(self._w, clock._c)
2964
2965 if ret < 0:
2966 raise ValueError("Could not add clock to Writer.")
2967
2968 @property
2969 def metadata(self):
2970 """
2971 Get the trace's TSDL meta-data.
2972 """
2973
2974 return nbt._bt_ctf_writer_get_metadata_string(self._w)
2975
2976 def flush_metadata(self):
2977 """
2978 Flush the trace's metadata to the metadata file.
2979 """
2980
2981 nbt._bt_ctf_writer_flush_metadata(self._w)
2982
2983 @property
2984 def byte_order(self):
2985 """
2986 Get the trace's byte order. Must be a constant from the ByteOrder
2987 class.
2988 """
2989
2990 raise NotImplementedError("Getter not implemented.")
2991
2992 @byte_order.setter
2993 def byte_order(self, byte_order):
2994 """
2995 Set the trace's byte order. Must be a constant from the ByteOrder
2996 class. Defaults to the host machine's endianness
2997 """
2998
2999 ret = nbt._bt_ctf_writer_set_byte_order(self._w, byte_order)
3000
3001 if ret < 0:
3002 raise ValueError("Could not set trace's byte order.")
This page took 0.09836 seconds and 5 git commands to generate.