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