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