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