Python: bt: do not expose ClockType
[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 StructureFieldDeclaration(FieldDeclaration):
1713 def __init__(self):
1714 """
1715 Create a new structure field declaration.
1716 """
1717
1718 self._ft = nbt._bt_ctf_field_type_structure_create()
1719 super().__init__()
1720
1721 def add_field(self, field_type, field_name):
1722 """
1723 Add a field of type "field_type" to the structure.
1724 """
1725
1726 ret = nbt._bt_ctf_field_type_structure_add_field(self._ft,
1727 field_type._ft,
1728 str(field_name))
1729
1730 if ret < 0:
1731 raise ValueError("Could not add field to structure.")
1732
1733 @property
1734 def fields(self):
1735 """
1736 Generator returning the structure's field as tuples of (field name, field declaration).
1737 """
1738
1739 count = nbt._bt_ctf_field_type_structure_get_field_count(self._ft)
1740
1741 if count < 0:
1742 raise TypeError("Could not get Structure field count")
1743
1744 for i in range(count):
1745 field_name = nbt._bt_python_ctf_field_type_structure_get_field_name(self._ft, i)
1746
1747 if field_name is None:
1748 msg = "Could not get Structure field name at index {}".format(i)
1749 raise TypeError(msg)
1750
1751 field_type_native = nbt._bt_python_ctf_field_type_structure_get_field_type(self._ft, i)
1752
1753 if field_type_native is None:
1754 msg = "Could not get Structure field type at index {}".format(i)
1755 raise TypeError(msg)
1756
1757 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
1758 yield (field_name, field_type)
1759
1760 def get_field_by_name(self, name):
1761 """
1762 Get a field declaration by name (FieldDeclaration).
1763 """
1764
1765 field_type_native = nbt._bt_ctf_field_type_structure_get_field_type_by_name(self._ft, name)
1766
1767 if field_type_native is None:
1768 msg = "Could not find Structure field with name {}".format(name)
1769 raise TypeError(msg)
1770
1771 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
1772
1773 class VariantFieldDeclaration(FieldDeclaration):
1774 def __init__(self, enum_tag, tag_name):
1775 """
1776 Create a new variant field declaration.
1777 """
1778
1779 isinst = isinstance(enum_tag, CTFWriter.EnumerationFieldDeclaration)
1780 if enum_tag is None or not isinst:
1781 raise TypeError("Invalid tag type; must be of type EnumerationFieldDeclaration.")
1782
1783 self._ft = nbt._bt_ctf_field_type_variant_create(enum_tag._ft,
1784 str(tag_name))
1785 super().__init__()
1786
1787 @property
1788 def tag_name(self):
1789 """
1790 Get the variant's tag name.
1791 """
1792
1793 ret = nbt._bt_ctf_field_type_variant_get_tag_name(self._ft)
1794
1795 if ret is None:
1796 raise TypeError("Could not get Variant tag name")
1797
1798 return ret
1799
1800 @property
1801 def tag_type(self):
1802 """
1803 Get the variant's tag type.
1804 """
1805
1806 ret = nbt._bt_ctf_field_type_variant_get_tag_type(self._ft)
1807
1808 if ret is None:
1809 raise TypeError("Could not get Variant tag type")
1810
1811 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
1812
1813 def add_field(self, field_type, field_name):
1814 """
1815 Add a field of type "field_type" to the variant.
1816 """
1817
1818 ret = nbt._bt_ctf_field_type_variant_add_field(self._ft,
1819 field_type._ft,
1820 str(field_name))
1821
1822 if ret < 0:
1823 raise ValueError("Could not add field to variant.")
1824
1825 @property
1826 def fields(self):
1827 """
1828 Generator returning the variant's field as tuples of (field name, field declaration).
1829 """
1830
1831 count = nbt._bt_ctf_field_type_variant_get_field_count(self._ft)
1832
1833 if count < 0:
1834 raise TypeError("Could not get Variant field count")
1835
1836 for i in range(count):
1837 field_name = nbt._bt_python_ctf_field_type_variant_get_field_name(self._ft, i)
1838
1839 if field_name is None:
1840 msg = "Could not get Variant field name at index {}".format(i)
1841 raise TypeError(msg)
1842
1843 field_type_native = nbt._bt_python_ctf_field_type_variant_get_field_type(self._ft, i)
1844
1845 if field_type_native is None:
1846 msg = "Could not get Variant field type at index {}".format(i)
1847 raise TypeError(msg)
1848
1849 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
1850 yield (field_name, field_type)
1851
1852 def get_field_by_name(self, name):
1853 """
1854 Get a field declaration by name (FieldDeclaration).
1855 """
1856
1857 field_type_native = nbt._bt_ctf_field_type_variant_get_field_type_by_name(self._ft,
1858 name)
1859
1860 if field_type_native is None:
1861 msg = "Could not find Variant field with name {}".format(name)
1862 raise TypeError(msg)
1863
1864 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
1865
1866 def get_field_from_tag(self, tag):
1867 """
1868 Get a field declaration from tag (EnumerationField).
1869 """
1870
1871 field_type_native = nbt._bt_ctf_field_type_variant_get_field_type_from_tag(self._ft, tag._f)
1872
1873 if field_type_native is None:
1874 msg = "Could not find Variant field with tag value {}".format(tag.value)
1875 raise TypeError(msg)
1876
1877 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
1878
1879 class ArrayFieldDeclaration(FieldDeclaration):
1880 def __init__(self, element_type, length):
1881 """
1882 Create a new array field declaration.
1883 """
1884
1885 self._ft = nbt._bt_ctf_field_type_array_create(element_type._ft,
1886 length)
1887 super().__init__()
1888
1889 @property
1890 def element_type(self):
1891 """
1892 Get the array's element type.
1893 """
1894
1895 ret = nbt._bt_ctf_field_type_array_get_element_type(self._ft)
1896
1897 if ret is None:
1898 raise TypeError("Could not get Array element type")
1899
1900 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
1901
1902 @property
1903 def length(self):
1904 """
1905 Get the array's length.
1906 """
1907
1908 ret = nbt._bt_ctf_field_type_array_get_length(self._ft)
1909
1910 if ret < 0:
1911 raise TypeError("Could not get Array length")
1912
1913 return ret
1914
1915 class SequenceFieldDeclaration(FieldDeclaration):
1916 def __init__(self, element_type, length_field_name):
1917 """
1918 Create a new sequence field declaration.
1919 """
1920
1921 self._ft = nbt._bt_ctf_field_type_sequence_create(element_type._ft,
1922 str(length_field_name))
1923 super().__init__()
1924
1925 @property
1926 def element_type(self):
1927 """
1928 Get the sequence's element type.
1929 """
1930
1931 ret = nbt._bt_ctf_field_type_sequence_get_element_type(self._ft)
1932
1933 if ret is None:
1934 raise TypeError("Could not get Sequence element type")
1935
1936 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(ret)
1937
1938 @property
1939 def length_field_name(self):
1940 """
1941 Get the sequence's length field name.
1942 """
1943
1944 ret = nbt._bt_ctf_field_type_sequence_get_length_field_name(self._ft)
1945
1946 if ret is None:
1947 raise TypeError("Could not get Sequence length field name")
1948
1949 return ret
1950
1951 class StringFieldDeclaration(FieldDeclaration):
1952 def __init__(self):
1953 """
1954 Create a new string field declaration.
1955 """
1956
1957 self._ft = nbt._bt_ctf_field_type_string_create()
1958 super().__init__()
1959
1960 @property
1961 def encoding(self):
1962 """
1963 Get a string declaration's encoding (a constant from the CTFStringEncoding class).
1964 """
1965
1966 return nbt._bt_ctf_field_type_string_get_encoding(self._ft)
1967
1968 @encoding.setter
1969 def encoding(self, encoding):
1970 """
1971 Set a string declaration's encoding. Must be a constant from the CTFStringEncoding class.
1972 """
1973
1974 ret = nbt._bt_ctf_field_type_string_set_encoding(self._ft, encoding)
1975 if ret < 0:
1976 raise ValueError("Could not set string encoding.")
1977
1978 @staticmethod
1979 def create_field(field_type):
1980 """
1981 Create an instance of a field.
1982 """
1983 isinst = isinstance(field_type, CTFWriter.FieldDeclaration)
1984
1985 if field_type is None or not isinst:
1986 raise TypeError("Invalid field_type. Type must be a FieldDeclaration-derived class.")
1987
1988 if isinstance(field_type, CTFWriter.IntegerFieldDeclaration):
1989 return CTFWriter.IntegerField(field_type)
1990 elif isinstance(field_type, CTFWriter.EnumerationFieldDeclaration):
1991 return CTFWriter.EnumerationField(field_type)
1992 elif isinstance(field_type, CTFWriter.FloatFieldDeclaration):
1993 return CTFWriter.FloatFieldingPoint(field_type)
1994 elif isinstance(field_type, CTFWriter.StructureFieldDeclaration):
1995 return CTFWriter.StructureField(field_type)
1996 elif isinstance(field_type, CTFWriter.VariantFieldDeclaration):
1997 return CTFWriter.VariantField(field_type)
1998 elif isinstance(field_type, CTFWriter.ArrayFieldDeclaration):
1999 return CTFWriter.ArrayField(field_type)
2000 elif isinstance(field_type, CTFWriter.SequenceFieldDeclaration):
2001 return CTFWriter.SequenceField(field_type)
2002 elif isinstance(field_type, CTFWriter.StringFieldDeclaration):
2003 return CTFWriter.StringField(field_type)
2004
2005 class Field:
2006 """
2007 Base class, do not instantiate.
2008 """
2009
2010 def __init__(self, field_type):
2011 if not isinstance(field_type, CTFWriter.FieldDeclaration):
2012 raise TypeError("Invalid field_type argument.")
2013
2014 self._f = nbt._bt_ctf_field_create(field_type._ft)
2015
2016 if self._f is None:
2017 raise ValueError("Field creation failed.")
2018
2019 def __del__(self):
2020 nbt._bt_ctf_field_put(self._f)
2021
2022 @staticmethod
2023 def _create_field_from_native_instance(native_field_instance):
2024 type_dict = {
2025 CTFTypeId.INTEGER: CTFWriter.IntegerField,
2026 CTFTypeId.FLOAT: CTFWriter.FloatFieldingPoint,
2027 CTFTypeId.ENUM: CTFWriter.EnumerationField,
2028 CTFTypeId.STRING: CTFWriter.StringField,
2029 CTFTypeId.STRUCT: CTFWriter.StructureField,
2030 CTFTypeId.VARIANT: CTFWriter.VariantField,
2031 CTFTypeId.ARRAY: CTFWriter.ArrayField,
2032 CTFTypeId.SEQUENCE: CTFWriter.SequenceField
2033 }
2034
2035 field_type = nbt._bt_python_get_field_type(native_field_instance)
2036
2037 if field_type == CTFTypeId.UNKNOWN:
2038 raise TypeError("Invalid field instance")
2039
2040 field = CTFWriter.Field.__new__(CTFWriter.Field)
2041 field._f = native_field_instance
2042 field.__class__ = type_dict[field_type]
2043
2044 return field
2045
2046 @property
2047 def declaration(self):
2048 native_field_type = nbt._bt_ctf_field_get_type(self._f)
2049
2050 if native_field_type is None:
2051 raise TypeError("Invalid field instance")
2052 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(
2053 native_field_type)
2054
2055 class IntegerField(Field):
2056 @property
2057 def value(self):
2058 """
2059 Get an integer field's value.
2060 """
2061
2062 signedness = nbt._bt_python_field_integer_get_signedness(self._f)
2063
2064 if signedness < 0:
2065 raise TypeError("Invalid integer instance.")
2066
2067 if signedness == 0:
2068 ret, value = nbt._bt_ctf_field_unsigned_integer_get_value(self._f)
2069 else:
2070 ret, value = nbt._bt_ctf_field_signed_integer_get_value(self._f)
2071
2072 if ret < 0:
2073 raise ValueError("Could not get integer field value.")
2074
2075 return value
2076
2077 @value.setter
2078 def value(self, value):
2079 """
2080 Set an integer field's value.
2081 """
2082
2083 if not isinstance(value, int):
2084 raise TypeError("IntegerField's value must be an int")
2085
2086 signedness = nbt._bt_python_field_integer_get_signedness(self._f)
2087 if signedness < 0:
2088 raise TypeError("Invalid integer instance.")
2089
2090 if signedness == 0:
2091 ret = nbt._bt_ctf_field_unsigned_integer_set_value(self._f, value)
2092 else:
2093 ret = nbt._bt_ctf_field_signed_integer_set_value(self._f, value)
2094
2095 if ret < 0:
2096 raise ValueError("Could not set integer field value.")
2097
2098 class EnumerationField(Field):
2099 @property
2100 def container(self):
2101 """
2102 Return the enumeration's underlying container field (an integer field).
2103 """
2104
2105 container = CTFWriter.IntegerField.__new__(CTFWriter.IntegerField)
2106 container._f = nbt._bt_ctf_field_enumeration_get_container(self._f)
2107
2108 if container._f is None:
2109 raise TypeError("Invalid enumeration field type.")
2110
2111 return container
2112
2113 @property
2114 def value(self):
2115 """
2116 Get the enumeration field's mapping name.
2117 """
2118
2119 value = nbt._bt_ctf_field_enumeration_get_mapping_name(self._f)
2120
2121 if value is None:
2122 raise ValueError("Could not get enumeration's mapping name.")
2123
2124 return value
2125
2126 @value.setter
2127 def value(self, value):
2128 """
2129 Set the enumeration field's value. Must be an integer as mapping names
2130 may be ambiguous.
2131 """
2132
2133 if not isinstance(value, int):
2134 raise TypeError("EnumerationField value must be an int")
2135
2136 self.container.value = value
2137
2138 class FloatFieldingPoint(Field):
2139 @property
2140 def value(self):
2141 """
2142 Get a floating point field's value.
2143 """
2144
2145 ret, value = nbt._bt_ctf_field_floating_point_get_value(self._f)
2146
2147 if ret < 0:
2148 raise ValueError("Could not get floating point field value.")
2149
2150 return value
2151
2152 @value.setter
2153 def value(self, value):
2154 """
2155 Set a floating point field's value.
2156 """
2157
2158 if not isinstance(value, int) and not isinstance(value, float):
2159 raise TypeError("Value must be either a float or an int")
2160
2161 ret = nbt._bt_ctf_field_floating_point_set_value(self._f, float(value))
2162
2163 if ret < 0:
2164 raise ValueError("Could not set floating point field value.")
2165
2166 class StructureField(Field):
2167 def field(self, field_name):
2168 """
2169 Get the structure's field corresponding to the provided field name.
2170 """
2171
2172 native_instance = nbt._bt_ctf_field_structure_get_field(self._f,
2173 str(field_name))
2174
2175 if native_instance is None:
2176 raise ValueError("Invalid field_name provided.")
2177
2178 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2179
2180 class VariantField(Field):
2181 def field(self, tag):
2182 """
2183 Return the variant's selected field. The "tag" field is the selector enum field.
2184 """
2185
2186 native_instance = nbt._bt_ctf_field_variant_get_field(self._f, tag._f)
2187
2188 if native_instance is None:
2189 raise ValueError("Invalid tag provided.")
2190
2191 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2192
2193 class ArrayField(Field):
2194 def field(self, index):
2195 """
2196 Return the array's field at position "index".
2197 """
2198
2199 native_instance = nbt._bt_ctf_field_array_get_field(self._f, index)
2200
2201 if native_instance is None:
2202 raise IndexError("Invalid index provided.")
2203
2204 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2205
2206 class SequenceField(Field):
2207 @property
2208 def length(self):
2209 """
2210 Get the sequence's length field (IntegerField).
2211 """
2212
2213 native_instance = nbt._bt_ctf_field_sequence_get_length(self._f)
2214
2215 if native_instance is None:
2216 length = -1
2217
2218 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2219
2220 @length.setter
2221 def length(self, length_field):
2222 """
2223 Set the sequence's length field (IntegerField).
2224 """
2225
2226 if not isinstance(length_field, CTFWriter.IntegerField):
2227 raise TypeError("Invalid length field.")
2228
2229 if length_field.declaration.signed:
2230 raise TypeError("Sequence field length must be unsigned")
2231
2232 ret = nbt._bt_ctf_field_sequence_set_length(self._f, length_field._f)
2233
2234 if ret < 0:
2235 raise ValueError("Could not set sequence length.")
2236
2237 def field(self, index):
2238 """
2239 Return the sequence's field at position "index".
2240 """
2241
2242 native_instance = nbt._bt_ctf_field_sequence_get_field(self._f, index)
2243
2244 if native_instance is None:
2245 raise ValueError("Could not get sequence element at index.")
2246
2247 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2248
2249 class StringField(Field):
2250 @property
2251 def value(self):
2252 """
2253 Get a string field's value.
2254 """
2255
2256 return nbt._bt_ctf_field_string_get_value(self._f)
2257
2258 @value.setter
2259 def value(self, value):
2260 """
2261 Set a string field's value.
2262 """
2263
2264 ret = nbt._bt_ctf_field_string_set_value(self._f, str(value))
2265
2266 if ret < 0:
2267 raise ValueError("Could not set string field value.")
2268
2269 class EventClass:
2270 def __init__(self, name):
2271 """
2272 Create a new event class of the given name.
2273 """
2274
2275 self._ec = nbt._bt_ctf_event_class_create(name)
2276
2277 if self._ec is None:
2278 raise ValueError("Event class creation failed.")
2279
2280 def __del__(self):
2281 nbt._bt_ctf_event_class_put(self._ec)
2282
2283 def add_field(self, field_type, field_name):
2284 """
2285 Add a field of type "field_type" to the event class.
2286 """
2287
2288 ret = nbt._bt_ctf_event_class_add_field(self._ec, field_type._ft,
2289 str(field_name))
2290
2291 if ret < 0:
2292 raise ValueError("Could not add field to event class.")
2293
2294 @property
2295 def name(self):
2296 """
2297 Get the event class' name.
2298 """
2299
2300 name = nbt._bt_ctf_event_class_get_name(self._ec)
2301
2302 if name is None:
2303 raise TypeError("Could not get EventClass name")
2304
2305 return name
2306
2307 @property
2308 def id(self):
2309 """
2310 Get the event class' id. Returns a negative value if unset.
2311 """
2312
2313 id = nbt._bt_ctf_event_class_get_id(self._ec)
2314
2315 if id < 0:
2316 raise TypeError("Could not get EventClass id")
2317
2318 return id
2319
2320 @id.setter
2321 def id(self, id):
2322 """
2323 Set the event class' id. Throws a TypeError if the event class
2324 is already registered to a stream class.
2325 """
2326
2327 ret = nbt._bt_ctf_event_class_set_id(self._ec, id)
2328
2329 if ret < 0:
2330 raise TypeError("Can't change an Event Class's id after it has been assigned to a stream class")
2331
2332 @property
2333 def stream_class(self):
2334 """
2335 Get the event class' stream class. Returns None if unset.
2336 """
2337 stream_class_native = nbt._bt_ctf_event_class_get_stream_class(self._ec)
2338
2339 if stream_class_native is None:
2340 return None
2341
2342 stream_class = CTFWriter.StreamClass.__new__(CTFWriter.StreamClass)
2343 stream_class._sc = stream_class_native
2344
2345 return stream_class
2346
2347 @property
2348 def fields(self):
2349 """
2350 Generator returning the event class' fields as tuples of (field name, field declaration).
2351 """
2352
2353 count = nbt._bt_ctf_event_class_get_field_count(self._ec)
2354
2355 if count < 0:
2356 raise TypeError("Could not get EventClass' field count")
2357
2358 for i in range(count):
2359 field_name = nbt._bt_python_ctf_event_class_get_field_name(self._ec, i)
2360
2361 if field_name is None:
2362 msg = "Could not get EventClass' field name at index {}".format(i)
2363 raise TypeError(msg)
2364
2365 field_type_native = nbt._bt_python_ctf_event_class_get_field_type(self._ec, i)
2366
2367 if field_type_native is None:
2368 msg = "Could not get EventClass' field type at index {}".format(i)
2369 raise TypeError(msg)
2370
2371 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2372 yield (field_name, field_type)
2373
2374 def get_field_by_name(self, name):
2375 """
2376 Get a field declaration by name (FieldDeclaration).
2377 """
2378
2379 field_type_native = nbt._bt_ctf_event_class_get_field_by_name(self._ec, name)
2380
2381 if field_type_native is None:
2382 msg = "Could not find EventClass field with name {}".format(name)
2383 raise TypeError(msg)
2384
2385 return CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2386
2387 class Event:
2388 def __init__(self, event_class):
2389 """
2390 Create a new event of the given event class.
2391 """
2392
2393 if not isinstance(event_class, CTFWriter.EventClass):
2394 raise TypeError("Invalid event_class argument.")
2395
2396 self._e = nbt._bt_ctf_event_create(event_class._ec)
2397
2398 if self._e is None:
2399 raise ValueError("Event creation failed.")
2400
2401 def __del__(self):
2402 nbt._bt_ctf_event_put(self._e)
2403
2404 @property
2405 def event_class(self):
2406 """
2407 Get the event's class.
2408 """
2409
2410 event_class_native = nbt._bt_ctf_event_get_class(self._e)
2411
2412 if event_class_native is None:
2413 return None
2414
2415 event_class = CTFWriter.EventClass.__new__(CTFWriter.EventClass)
2416 event_class._ec = event_class_native
2417
2418 return event_class
2419
2420 def clock(self):
2421 """
2422 Get a clock from event. Returns None if the event's class
2423 is not registered to a stream class.
2424 """
2425
2426 clock_instance = nbt._bt_ctf_event_get_clock(self._e)
2427
2428 if clock_instance is None:
2429 return None
2430
2431 clock = CTFWriter.Clock.__new__(CTFWriter.Clock)
2432 clock._c = clock_instance
2433
2434 return clock
2435
2436 def payload(self, field_name):
2437 """
2438 Get a field from event.
2439 """
2440
2441 native_instance = nbt._bt_ctf_event_get_payload(self._e,
2442 str(field_name))
2443
2444 if native_instance is None:
2445 raise ValueError("Could not get event payload.")
2446
2447 return CTFWriter.Field._create_field_from_native_instance(native_instance)
2448
2449 def set_payload(self, field_name, value_field):
2450 """
2451 Set a manually created field as an event's payload.
2452 """
2453
2454 if not isinstance(value, CTFWriter.Field):
2455 raise TypeError("Invalid value type.")
2456
2457 ret = nbt._bt_ctf_event_set_payload(self._e, str(field_name),
2458 value_field._f)
2459
2460 if ret < 0:
2461 raise ValueError("Could not set event field payload.")
2462
2463 class StreamClass:
2464 def __init__(self, name):
2465 """
2466 Create a new stream class of the given name.
2467 """
2468
2469 self._sc = nbt._bt_ctf_stream_class_create(name)
2470
2471 if self._sc is None:
2472 raise ValueError("Stream class creation failed.")
2473
2474 def __del__(self):
2475 nbt._bt_ctf_stream_class_put(self._sc)
2476
2477 @property
2478 def name(self):
2479 """
2480 Get a stream class' name.
2481 """
2482
2483 name = nbt._bt_ctf_stream_class_get_name(self._sc)
2484
2485 if name is None:
2486 raise TypeError("Could not get StreamClass name")
2487
2488 return name
2489
2490 @property
2491 def clock(self):
2492 """
2493 Get a stream class' clock.
2494 """
2495
2496 clock_instance = nbt._bt_ctf_stream_class_get_clock(self._sc)
2497
2498 if clock_instance is None:
2499 return None
2500
2501 clock = CTFWriter.Clock.__new__(CTFWriter.Clock)
2502 clock._c = clock_instance
2503
2504 return clock
2505
2506 @clock.setter
2507 def clock(self, clock):
2508 """
2509 Assign a clock to a stream class.
2510 """
2511
2512 if not isinstance(clock, CTFWriter.Clock):
2513 raise TypeError("Invalid clock type.")
2514
2515 ret = nbt._bt_ctf_stream_class_set_clock(self._sc, clock._c)
2516
2517 if ret < 0:
2518 raise ValueError("Could not set stream class clock.")
2519
2520 @property
2521 def id(self):
2522 """
2523 Get a stream class' id.
2524 """
2525
2526 ret = nbt._bt_ctf_stream_class_get_id(self._sc)
2527
2528 if ret < 0:
2529 raise TypeError("Could not get StreamClass id")
2530
2531 return ret
2532
2533 @id.setter
2534 def id(self, id):
2535 """
2536 Assign an id to a stream class.
2537 """
2538
2539 ret = nbt._bt_ctf_stream_class_set_id(self._sc, id)
2540
2541 if ret < 0:
2542 raise TypeError("Could not set stream class id.")
2543
2544 @property
2545 def event_classes(self):
2546 """
2547 Generator returning the stream class' event classes.
2548 """
2549
2550 count = nbt._bt_ctf_stream_class_get_event_class_count(self._sc)
2551
2552 if count < 0:
2553 raise TypeError("Could not get StreamClass' event class count")
2554
2555 for i in range(count):
2556 event_class_native = nbt._bt_ctf_stream_class_get_event_class(self._sc, i)
2557
2558 if event_class_native is None:
2559 msg = "Could not get StreamClass' event class at index {}".format(i)
2560 raise TypeError(msg)
2561
2562 event_class = CTFWriter.EventClass.__new__(CTFWriter.EventClass)
2563 event_class._ec = event_class_native
2564 yield event_class
2565
2566 def add_event_class(self, event_class):
2567 """
2568 Add an event class to a stream class. New events can be added even after a
2569 stream has been instantiated and events have been appended. However, a stream
2570 will not accept events of a class that has not been added to the stream
2571 class beforehand.
2572 """
2573
2574 if not isinstance(event_class, CTFWriter.EventClass):
2575 raise TypeError("Invalid event_class type.")
2576
2577 ret = nbt._bt_ctf_stream_class_add_event_class(self._sc,
2578 event_class._ec)
2579
2580 if ret < 0:
2581 raise ValueError("Could not add event class.")
2582
2583 @property
2584 def packet_context_type(self):
2585 """
2586 Get the StreamClass' packet context type (StructureFieldDeclaration)
2587 """
2588
2589 field_type_native = nbt._bt_ctf_stream_class_get_packet_context_type(self._sc)
2590
2591 if field_type_native is None:
2592 raise ValueError("Invalid StreamClass")
2593
2594 field_type = CTFWriter.FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
2595
2596 return field_type
2597
2598 @packet_context_type.setter
2599 def packet_context_type(self, field_type):
2600 """
2601 Set a StreamClass' packet context type. Must be of type
2602 StructureFieldDeclaration.
2603 """
2604
2605 if not isinstance(field_type, CTFWriter.StructureFieldDeclaration):
2606 raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
2607
2608 ret = nbt._bt_ctf_stream_class_set_packet_context_type(self._sc,
2609 field_type._ft)
2610
2611 if ret < 0:
2612 raise ValueError("Failed to set packet context type.")
2613
2614 class Stream:
2615 def __init__(self, stream_class):
2616 """
2617 Create a stream of the given class.
2618 """
2619
2620 if not isinstance(stream_class, CTFWriter.StreamClass):
2621 raise TypeError("Invalid stream_class argument must be of type StreamClass.")
2622
2623 self._s = nbt._bt_ctf_stream_create(stream_class._sc)
2624
2625 if self._s is None:
2626 raise ValueError("Stream creation failed.")
2627
2628 def __del__(self):
2629 nbt._bt_ctf_stream_put(self._s)
2630
2631 @property
2632 def discarded_events(self):
2633 """
2634 Get a stream's discarded event count.
2635 """
2636
2637 ret, count = nbt._bt_ctf_stream_get_discarded_events_count(self._s)
2638
2639 if ret < 0:
2640 raise ValueError("Could not get the stream's discarded events count")
2641
2642 return count
2643
2644 def append_discarded_events(self, event_count):
2645 """
2646 Increase the current packet's discarded event count.
2647 """
2648
2649 nbt._bt_ctf_stream_append_discarded_events(self._s, event_count)
2650
2651 def append_event(self, event):
2652 """
2653 Append "event" to the stream's current packet. The stream's associated clock
2654 will be sampled during this call. The event shall not be modified after
2655 being appended to a stream.
2656 """
2657
2658 ret = nbt._bt_ctf_stream_append_event(self._s, event._e)
2659
2660 if ret < 0:
2661 raise ValueError("Could not append event to stream.")
2662
2663 @property
2664 def packet_context(self):
2665 """
2666 Get a Stream's packet context field (a StructureField).
2667 """
2668
2669 native_field = nbt._bt_ctf_stream_get_packet_context(self._s)
2670
2671 if native_field is None:
2672 raise ValueError("Invalid Stream.")
2673
2674 return CTFWriter.Field._create_field_from_native_instance(native_field)
2675
2676 @packet_context.setter
2677 def packet_context(self, field):
2678 """
2679 Set a Stream's packet context field (must be a StructureField).
2680 """
2681
2682 if not isinstance(field, CTFWriter.StructureField):
2683 raise TypeError("Argument field must be of type StructureField")
2684
2685 ret = nbt._bt_ctf_stream_set_packet_context(self._s, field._f)
2686
2687 if ret < 0:
2688 raise ValueError("Invalid packet context field.")
2689
2690 def flush(self):
2691 """
2692 The stream's current packet's events will be flushed to disk. Events
2693 subsequently appended to the stream will be added to a new packet.
2694 """
2695
2696 ret = nbt._bt_ctf_stream_flush(self._s)
2697
2698 if ret < 0:
2699 raise ValueError("Could not flush stream.")
2700
2701 class Writer:
2702 def __init__(self, path):
2703 """
2704 Create a new writer that will produce a trace in the given path.
2705 """
2706
2707 self._w = nbt._bt_ctf_writer_create(path)
2708
2709 if self._w is None:
2710 raise ValueError("Writer creation failed.")
2711
2712 def __del__(self):
2713 nbt._bt_ctf_writer_put(self._w)
2714
2715 def create_stream(self, stream_class):
2716 """
2717 Create a new stream instance and register it to the writer.
2718 """
2719
2720 if not isinstance(stream_class, CTFWriter.StreamClass):
2721 raise TypeError("Invalid stream_class type.")
2722
2723 stream = CTFWriter.Stream.__new__(CTFWriter.Stream)
2724 stream._s = nbt._bt_ctf_writer_create_stream(self._w, stream_class._sc)
2725
2726 return stream
2727
2728 def add_environment_field(self, name, value):
2729 """
2730 Add an environment field to the trace.
2731 """
2732
2733 ret = nbt._bt_ctf_writer_add_environment_field(self._w, str(name),
2734 str(value))
2735
2736 if ret < 0:
2737 raise ValueError("Could not add environment field to trace.")
2738
2739 def add_clock(self, clock):
2740 """
2741 Add a clock to the trace. Clocks assigned to stream classes must be
2742 registered to the writer.
2743 """
2744
2745 ret = nbt._bt_ctf_writer_add_clock(self._w, clock._c)
2746
2747 if ret < 0:
2748 raise ValueError("Could not add clock to Writer.")
2749
2750 @property
2751 def metadata(self):
2752 """
2753 Get the trace's TSDL meta-data.
2754 """
2755
2756 return nbt._bt_ctf_writer_get_metadata_string(self._w)
2757
2758 def flush_metadata(self):
2759 """
2760 Flush the trace's metadata to the metadata file.
2761 """
2762
2763 nbt._bt_ctf_writer_flush_metadata(self._w)
2764
2765 @property
2766 def byte_order(self):
2767 """
2768 Get the trace's byte order. Must be a constant from the ByteOrder
2769 class.
2770 """
2771
2772 raise NotImplementedError("Getter not implemented.")
2773
2774 @byte_order.setter
2775 def byte_order(self, byte_order):
2776 """
2777 Set the trace's byte order. Must be a constant from the ByteOrder
2778 class. Defaults to the host machine's endianness
2779 """
2780
2781 ret = nbt._bt_ctf_writer_set_byte_order(self._w, byte_order)
2782
2783 if ret < 0:
2784 raise ValueError("Could not set trace's byte order.")
This page took 0.207736 seconds and 5 git commands to generate.