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