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