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