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