Fix: typo using bt2.ClockClassOffset constructor
[babeltrace.git] / bindings / python / babeltrace / babeltrace / writer.py
CommitLineData
be5a4e67
PP
1# writer.py
2#
3# Babeltrace writer interface Python module
4#
c72a561f 5# Copyright 2012-2017 EfficiOS Inc.
be5a4e67
PP
6#
7# Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
8#
9# Permission is hereby granted, free of charge, to any person obtaining a copy
10# of this software and associated documentation files (the "Software"), to deal
11# in the Software without restriction, including without limitation the rights
12# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13# copies of the Software, and to permit persons to whom the Software is
14# furnished to do so, subject to the following conditions:
15#
16# The above copyright notice and this permission notice shall be included in
17# all copies or substantial portions of the Software.
18#
19# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25# SOFTWARE.
26
be5a4e67 27import babeltrace.common as common
c72a561f 28import bt2
be5a4e67 29
0b03f63e 30
be5a4e67
PP
31class EnumerationMapping:
32 """
1759e132 33 Mapping from an enumeration label to a range of integers.
be5a4e67
PP
34 """
35
36 def __init__(self, name, start, end):
1759e132
PP
37 """
38 Creates an enumeration mapping, where label *name* is mapped to
39 the [*start*, *end*] range of integers (*end* is included).
40
41 Set *start* and *end* to the same value to create an enumeration
42 mapping to a single value.
43 """
44
c72a561f
JG
45 self._enum_mapping = bt2._EnumerationFieldTypeMapping(self, start, end)
46
47 @property
48 def name(self):
49 return self._enum_mapping.name
50
51 @property
52 def start(self):
53 return self._enum_mapping.lower
54
55 @property
56 def end(self):
57 return self._enum_mapping.upper
be5a4e67
PP
58
59
60class Clock:
4d7ac86a
PP
61 """
62 A CTF clock allows the description of the system's clock topology, as
63 well as the definition of each clock's parameters.
64
65 :class:`Clock` objects must be registered to a :class:`Writer`
66 object (see :meth:`Writer.add_clock`), as well as be registered to
67 a :class:`StreamClass` object (see :attr:`StreamClass.clock`).
68 """
69
be5a4e67 70 def __init__(self, name):
4d7ac86a
PP
71 """
72 Creates a default CTF clock named *name*.
73
74 :exc:`ValueError` is raised on error.
75 """
76
c72a561f
JG
77 try:
78 self._clock = bt2.CtfWriterClock(name)
79 except:
be5a4e67 80 raise ValueError("Invalid clock name.")
c72a561f 81 assert self._clock
be5a4e67
PP
82
83 @property
84 def name(self):
85 """
4d7ac86a
PP
86 Clock name.
87
88 Set this attribute to change the clock's name.
89
90 :exc:`ValueError` is raised on error.
be5a4e67
PP
91 """
92
c72a561f
JG
93 try:
94 return self._clock.name
95 except:
be5a4e67
PP
96 raise ValueError("Invalid clock instance.")
97
be5a4e67
PP
98 @property
99 def description(self):
100 """
4d7ac86a
PP
101 Clock description (string).
102
103 Set this attribute to change the clock's description.
104
105 :exc:`ValueError` is raised on error.
be5a4e67
PP
106 """
107
c72a561f
JG
108 try:
109 return self._clock.description
110 except:
111 raise ValueError("Invalid clock instance.")
be5a4e67
PP
112
113 @description.setter
114 def description(self, desc):
c72a561f
JG
115 try:
116 self._clock.description = desc
117 except:
be5a4e67
PP
118 raise ValueError("Invalid clock description.")
119
120 @property
121 def frequency(self):
122 """
4d7ac86a
PP
123 Clock frequency in Hz (integer).
124
125 Set this attribute to change the clock's frequency.
126
127 :exc:`ValueError` is raised on error.
be5a4e67
PP
128 """
129
c72a561f
JG
130 try:
131 return self._clock.frequency
132 except:
133 raise ValueError("Invalid clock instance.")
be5a4e67
PP
134
135 @frequency.setter
136 def frequency(self, freq):
c72a561f
JG
137 try:
138 self._clock.frequency = freq
139 except:
be5a4e67
PP
140 raise ValueError("Invalid frequency value.")
141
142 @property
143 def precision(self):
144 """
4d7ac86a
PP
145 Clock precision in clock ticks (integer).
146
147 Set this attribute to change the clock's precision.
148
149 :exc:`ValueError` is raised on error.
be5a4e67
PP
150 """
151
c72a561f
JG
152 try:
153 return self._clock.precision
154 except:
155 raise ValueError("Invalid clock instance.")
be5a4e67
PP
156
157 @precision.setter
158 def precision(self, precision):
c72a561f
JG
159 try:
160 self._clock.precision = precision
161 except:
81cb73c3
JG
162 raise ValueError("Invalid precision value.")
163
be5a4e67
PP
164 @property
165 def offset_seconds(self):
166 """
4d7ac86a
PP
167 Clock offset in seconds since POSIX.1 Epoch (integer).
168
169 Set this attribute to change the clock's offset in seconds.
170
171 :exc:`ValueError` is raised on error.
be5a4e67
PP
172 """
173
c72a561f
JG
174 try:
175 return self._clock.offset.seconds
176 except:
177 raise ValueError("Invalid clock instance.")
be5a4e67
PP
178
179 @offset_seconds.setter
180 def offset_seconds(self, offset_s):
c72a561f 181 try:
da2edb5b
FD
182 self._clock.offset = bt2.ClockClassOffset(offset_s,
183 self._clock.offset.cycles)
c72a561f 184 except:
be5a4e67
PP
185 raise ValueError("Invalid offset value.")
186
187 @property
188 def offset(self):
189 """
4d7ac86a
PP
190 Clock offset in ticks since (POSIX.1 Epoch +
191 :attr:`offset_seconds`).
192
193 Set this attribute to change the clock's offset.
194
195 :exc:`ValueError` is raised on error.
be5a4e67
PP
196 """
197
c72a561f
JG
198 try:
199 return self._clock.offset.cycles
200 except:
201 raise ValueError("Invalid clock instance.")
be5a4e67
PP
202
203 @offset.setter
204 def offset(self, offset):
c72a561f 205 try:
da2edb5b
FD
206 self._clock.offset = bt2.ClockClassOffset(self._clock.offset.seconds,
207 offset)
c72a561f 208 except:
be5a4e67
PP
209 raise ValueError("Invalid offset value.")
210
211 @property
212 def absolute(self):
213 """
4d7ac86a
PP
214 ``True`` if this clock is absolute, i.e. if the clock is a
215 global reference across the other clocks of the trace.
216
217 Set this attribute to change the clock's absolute state
218 (boolean).
219
220 :exc:`ValueError` is raised on error.
be5a4e67
PP
221 """
222
c72a561f
JG
223 try:
224 return self._clock.is_absolute
225 except:
226 raise ValueError("Invalid clock instance.")
be5a4e67
PP
227
228 @absolute.setter
229 def absolute(self, is_absolute):
c72a561f
JG
230 try:
231 self._clock.is_absolute = is_absolute
232 except:
4d7ac86a 233 raise ValueError("Could not set the clock absolute attribute.")
be5a4e67
PP
234
235 @property
236 def uuid(self):
237 """
4d7ac86a
PP
238 Clock UUID (an :class:`uuid.UUID` object).
239
240 Set this attribute to change the clock's UUID.
241
242 :exc:`ValueError` is raised on error.
be5a4e67
PP
243 """
244
c72a561f
JG
245 try:
246 return self._clock.uuid
247 except:
248 raise ValueError("Invalid clock instance.")
be5a4e67
PP
249
250 @uuid.setter
251 def uuid(self, uuid):
be5a4e67
PP
252 uuid_bytes = uuid.bytes
253
254 if len(uuid_bytes) != 16:
c72a561f
JG
255 raise ValueError(
256 "Invalid UUID provided. UUID length must be 16 bytes")
be5a4e67 257
c72a561f
JG
258 try:
259 self._clock.uuid = uuid
260 except:
261 raise ValueError("Invalid clock instance.")
be5a4e67
PP
262
263 @property
264 def time(self):
265 """
4d7ac86a
PP
266 Clock current time; nanoseconds (integer) since clock origin
267 (POSIX.1 Epoch + :attr:`offset_seconds` + :attr:`offset`).
268
269 Set this attribute to change the clock's current time.
270
271 :exc:`ValueError` is raised on error.
be5a4e67
PP
272 """
273
c72a561f 274 raise NotImplementedError("Getter not implemented.")
be5a4e67
PP
275
276 @time.setter
277 def time(self, time):
c72a561f
JG
278 try:
279 self._clock.time = time
280 except:
be5a4e67
PP
281 raise ValueError("Invalid time value.")
282
283
fe9f5df1
PP
284class IntegerBase:
285 """
286 Display base of an integer.
287 """
288
289 #: Unknown
b3df7a8f 290 UNKNOWN = -1
fe9f5df1
PP
291
292 #: Binary
b3df7a8f 293 BIN = 2
fe9f5df1
PP
294
295 #: Octal
b3df7a8f 296 OCT = 8
fe9f5df1
PP
297
298 #: Decimal
b3df7a8f 299 DEC = 10
fe9f5df1
PP
300
301 #: Hexadecimal
b3df7a8f
PP
302 HEX = 16
303
304 # keep this for backward compatibility
305 INTEGER_BASE_UNKNOWN = -1
306 INTEGER_BASE_BINARY = 2
307 INTEGER_BASE_OCTAL = 8
308 INTEGER_BASE_DECIMAL = 10
fe9f5df1
PP
309 INTEGER_BASE_HEXADECIMAL = 16
310
311
c72a561f
JG
312_BT2_BYTE_ORDER_TO_BYTE_ORDER = {
313 bt2.ByteOrder.NATIVE: common.ByteOrder.BYTE_ORDER_NATIVE,
314 bt2.ByteOrder.LITTLE_ENDIAN: common.ByteOrder.BYTE_ORDER_LITTLE_ENDIAN,
315 bt2.ByteOrder.BIG_ENDIAN: common.ByteOrder.BYTE_ORDER_BIG_ENDIAN,
316 bt2.ByteOrder.NETWORK: common.ByteOrder.BYTE_ORDER_NETWORK,
317}
318
319_BYTE_ORDER_TO_BT2_BYTE_ORDER = {
320 common.ByteOrder.BYTE_ORDER_NATIVE: bt2.ByteOrder.NATIVE,
321 common.ByteOrder.BYTE_ORDER_LITTLE_ENDIAN: bt2.ByteOrder.LITTLE_ENDIAN,
322 common.ByteOrder.BYTE_ORDER_BIG_ENDIAN: bt2.ByteOrder.BIG_ENDIAN,
323 common.ByteOrder.BYTE_ORDER_NETWORK: bt2.ByteOrder.NETWORK,
324}
325
326_BT2_ENCODING_TO_ENCODING = {
327 bt2.Encoding.NONE: common.CTFStringEncoding.NONE,
328 bt2.Encoding.ASCII: common.CTFStringEncoding.ASCII,
329 bt2.Encoding.UTF8: common.CTFStringEncoding.UTF8,
330}
331
332_ENCODING_TO_BT2_ENCODING = {
333 common.CTFStringEncoding.NONE: bt2.Encoding.NONE,
334 common.CTFStringEncoding.ASCII: bt2.Encoding.ASCII,
335 common.CTFStringEncoding.UTF8: bt2.Encoding.UTF8,
336}
337
0b03f63e 338
be5a4e67
PP
339class FieldDeclaration:
340 """
a20c2934
PP
341 Base class of all field declarations. This class is not meant to
342 be instantiated by the user; use one of the concrete field
343 declaration subclasses instead.
be5a4e67
PP
344 """
345
fe9f5df1
PP
346 class IntegerBase(IntegerBase):
347 pass
be5a4e67
PP
348
349 def __init__(self):
ce96d6eb 350 if self._field_type is None:
be5a4e67
PP
351 raise ValueError("FieldDeclaration creation failed.")
352
be5a4e67 353 @staticmethod
c72a561f 354 def _create_field_declaration(field_type):
be5a4e67 355
c72a561f
JG
356 if type(field_type) not in _BT2_FIELD_TYPE_TO_BT_DECLARATION:
357 raise TypeError("Invalid field declaration instance.")
be5a4e67
PP
358
359 declaration = Field.__new__(Field)
ce96d6eb 360 declaration._field_type = field_type
c72a561f
JG
361 declaration.__class__ = _BT2_FIELD_TYPE_TO_BT_DECLARATION[
362 type(field_type)]
be5a4e67
PP
363 return declaration
364
365 @property
366 def alignment(self):
367 """
a20c2934
PP
368 Field alignment in bits (integer).
369
370 Set this attribute to change this field's alignment.
371
372 :exc:`ValueError` is raised on error.
be5a4e67
PP
373 """
374
c72a561f 375 try:
ce96d6eb 376 return self._field_type.alignment
c72a561f
JG
377 except:
378 raise ValueError(
379 "Could not get alignment field declaration attribute.")
be5a4e67
PP
380
381 @alignment.setter
382 def alignment(self, alignment):
c72a561f 383 try:
ce96d6eb 384 self._field_type.alignment = alignment
c72a561f 385 except:
be5a4e67
PP
386 raise ValueError("Invalid alignment value.")
387
388 @property
389 def byte_order(self):
390 """
a20c2934
PP
391 Field byte order (one of :class:`babeltrace.common.ByteOrder`
392 constants).
393
394 Set this attribute to change this field's byte order.
395
396 :exc:`ValueError` is raised on error.
be5a4e67
PP
397 """
398
c72a561f 399 try:
ce96d6eb 400 return _BT2_BYTE_ORDER_TO_BYTE_ORDER[self._field_type.byte_order]
c72a561f
JG
401 except:
402 raise ValueError(
403 "Could not get byte order field declaration attribute.")
be5a4e67
PP
404
405 @byte_order.setter
406 def byte_order(self, byte_order):
c72a561f 407 try:
ce96d6eb 408 self._field_type.byte_order = _BYTE_ORDER_TO_BT2_BYTE_ORDER[byte_order]
c72a561f 409 except:
be5a4e67
PP
410 raise ValueError("Could not set byte order value.")
411
412
c72a561f
JG
413class _EncodingProp:
414 @property
415 def encoding(self):
416 """
417 Integer encoding (one of
418 :class:`babeltrace.common.CTFStringEncoding` constants).
419
420 Set this attribute to change this field's encoding.
421
422 :exc:`ValueError` is raised on error.
423 """
424
425 try:
ce96d6eb 426 return _BT2_ENCODING_TO_ENCODING[self._field_type.encoding]
c72a561f
JG
427 except:
428 raise ValueError("Could not get field encoding.")
429
430 @encoding.setter
431 def encoding(self, encoding):
432 try:
ce96d6eb 433 self._field_type.encoding = _ENCODING_TO_BT2_ENCODING[encoding]
c72a561f
JG
434 except:
435 raise ValueError("Could not set field encoding.")
436
437
438class IntegerFieldDeclaration(FieldDeclaration, _EncodingProp):
7d06a31a
PP
439 """
440 Integer field declaration.
441 """
442
be5a4e67
PP
443 def __init__(self, size):
444 """
7d06a31a
PP
445 Creates an integer field declaration of size *size* bits.
446
447 :exc:`ValueError` is raised on error.
be5a4e67 448 """
7d06a31a 449
ce96d6eb 450 self._field_type = bt2.IntegerFieldType(size)
be5a4e67
PP
451 super().__init__()
452
453 @property
454 def size(self):
455 """
7d06a31a
PP
456 Integer size in bits (integer).
457
458 Set this attribute to change this integer's size.
459
460 :exc:`ValueError` is raised on error.
be5a4e67
PP
461 """
462
c72a561f 463 try:
ce96d6eb 464 return self._field_type.size
c72a561f 465 except:
7d06a31a 466 raise ValueError("Could not get Integer size attribute.")
be5a4e67
PP
467
468 @property
469 def signed(self):
470 """
7d06a31a
PP
471 ``True`` if this integer is signed.
472
473 Set this attribute to change this integer's signedness
474 (boolean).
475
476 :exc:`ValueError` is raised on error.
be5a4e67
PP
477 """
478
c72a561f 479 try:
ce96d6eb 480 return self._field_type.is_signed
c72a561f 481 except:
7d06a31a 482 raise ValueError("Could not get Integer signed attribute.")
be5a4e67
PP
483
484 @signed.setter
485 def signed(self, signed):
c72a561f 486 try:
ce96d6eb 487 self._field_type.is_signed = signed
c72a561f 488 except:
7d06a31a 489 raise ValueError("Could not set Integer signed attribute.")
be5a4e67
PP
490
491 @property
492 def base(self):
493 """
7d06a31a
PP
494 Integer display base (one of :class:`IntegerBase` constants).
495
496 Set this attribute to change this integer's display base.
497
498 :exc:`ValueError` is raised on error.
be5a4e67
PP
499 """
500
c72a561f 501 try:
ce96d6eb 502 return self._field_type.base
c72a561f
JG
503 except:
504 raise ValueError("Could not get Integer base attribute.")
be5a4e67
PP
505
506 @base.setter
507 def base(self, base):
c72a561f 508 try:
ce96d6eb 509 self._field_type.base = base
c72a561f 510 except:
7d06a31a 511 raise ValueError("Could not set Integer base.")
be5a4e67 512
be5a4e67
PP
513
514class EnumerationFieldDeclaration(FieldDeclaration):
6d4014ed
PP
515 """
516 Enumeration field declaration. A CTF enumeration maps labels to
517 ranges of integers.
518 """
519
be5a4e67
PP
520 def __init__(self, integer_type):
521 """
6d4014ed
PP
522 Creates an enumeration field declaration, with *integer_type*
523 being the underlying :class:`IntegerFieldDeclaration` for storing
524 the integer.
525
526 :exc:`ValueError` is raised on error.
be5a4e67 527 """
6d4014ed 528
be5a4e67
PP
529 isinst = isinstance(integer_type, IntegerFieldDeclaration)
530
531 if integer_type is None or not isinst:
532 raise TypeError("Invalid integer container.")
533
ce96d6eb 534 self._field_type = bt2.EnumerationFieldType(integer_type._field_type)
be5a4e67
PP
535 super().__init__()
536
537 @property
538 def container(self):
539 """
6d4014ed
PP
540 Underlying container (:class:`IntegerFieldDeclaration`).
541
542 :exc:`TypeError` is raised on error.
be5a4e67
PP
543 """
544
c72a561f
JG
545 try:
546 return FieldDeclaration._create_field_declaration(
ce96d6eb 547 self._field_type.integer_field_type)
c72a561f 548 except:
be5a4e67
PP
549 raise TypeError("Invalid enumeration declaration")
550
be5a4e67
PP
551 def add_mapping(self, name, range_start, range_end):
552 """
6d4014ed
PP
553 Adds a mapping to the enumeration field declaration, from the
554 label named *name* to range [*range_start*, *range_end*], where
555 *range_start* and *range_end* are integers included in the
556 range.
557
558 :exc:`ValueError` is raised on error.
be5a4e67
PP
559 """
560
c72a561f 561 try:
ce96d6eb 562 self._field_type.append_mapping(name, range_start, range_end)
c72a561f
JG
563 except:
564 raise ValueError(
565 "Could not add mapping to enumeration declaration.")
be5a4e67
PP
566
567 @property
568 def mappings(self):
569 """
6d4014ed
PP
570 Generates the mappings of this enumeration field declaration
571 (:class:`EnumerationMapping` objects).
572
573 :exc:`TypeError` is raised on error.
be5a4e67
PP
574 """
575
ce96d6eb 576 for mapping in self._field_type:
c72a561f
JG
577 yield EnumerationMapping(mapping.name, mapping.lower,
578 mapping.upper)
be5a4e67
PP
579
580 def get_mapping_by_name(self, name):
581 """
6d4014ed
PP
582 Returns the :class:`EnumerationMapping` object for the label
583 named *name*.
584
585 :exc:`TypeError` is raised on error.
be5a4e67
PP
586 """
587
c72a561f 588 try:
ce96d6eb 589 mappings = list(self._field_type.mappings_by_name(name))
c72a561f
JG
590 except:
591 raise TypeError(
592 'Could not get enumeration mappings by name \'{}\''.format(
593 name))
be5a4e67 594
c72a561f 595 if not mappings:
be5a4e67
PP
596 return None
597
c72a561f
JG
598 mapping = mappings[0]
599 return EnumerationMapping(mapping.name, mapping.lower, mapping.upper)
be5a4e67
PP
600
601 def get_mapping_by_value(self, value):
602 """
6d4014ed
PP
603 Returns the :class:`EnumerationMapping` object for the value
604 *value* (integer).
605
606 :exc:`TypeError` is raised on error.
be5a4e67
PP
607 """
608
c72a561f 609 try:
ce96d6eb 610 mappings = list(self._field_type.mappings_by_value(value))
c72a561f
JG
611 except:
612 raise TypeError(
613 'Could not get enumeration mappings by value \'{}\''.format(
614 value))
be5a4e67 615
c72a561f 616 if not mappings:
be5a4e67
PP
617 return None
618
c72a561f
JG
619 mapping = mappings[0]
620 return EnumerationMapping(mapping.name, mapping.lower, mapping.upper)
be5a4e67
PP
621
622
a777c99f
PP
623class FloatingPointFieldDeclaration(FieldDeclaration):
624 """
625 Floating point number field declaration.
626
627 A CTF floating point number is a made of three sections: the sign
628 bit, the exponent bits, and the mantissa bits. The most significant
629 bit of the resulting binary word is the sign bit, and is included
630 in the number of mantissa bits.
631
632 For example, the
633 `IEEE 754 <http://en.wikipedia.org/wiki/IEEE_floating_point>`_
634 single precision floating point number is represented on a 32-bit
635 word using an 8-bit exponent (``e``) and a 24-bit mantissa (``m``),
636 the latter count including the sign bit (``s``)::
637
638 s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
639
640 The IEEE 754 double precision floating point number uses an
641 11-bit exponent and a 53-bit mantissa.
642 """
643
644 #: IEEE 754 single precision floating point number exponent size
be5a4e67 645 FLT_EXP_DIG = 8
a777c99f
PP
646
647 #: IEEE 754 double precision floating point number exponent size
be5a4e67 648 DBL_EXP_DIG = 11
a777c99f
PP
649
650 #: IEEE 754 single precision floating point number mantissa size
be5a4e67 651 FLT_MANT_DIG = 24
a777c99f
PP
652
653 #: IEEE 754 double precision floating point number mantissa size
be5a4e67
PP
654 DBL_MANT_DIG = 53
655
656 def __init__(self):
657 """
a777c99f
PP
658 Creates a floating point number field declaration.
659
660 :exc:`ValueError` is raised on error.
be5a4e67
PP
661 """
662
ce96d6eb 663 self._field_type = bt2.FloatingPointNumberFieldType()
be5a4e67
PP
664 super().__init__()
665
666 @property
667 def exponent_digits(self):
668 """
a777c99f
PP
669 Floating point number exponent section size in bits (integer).
670
671 Set this attribute to change the floating point number's
672 exponent section's size. You may use :attr:`FLT_EXP_DIG` or
673 :attr:`DBL_EXP_DIG` for IEEE 754 floating point numbers.
674
675 :exc:`ValueError` is raised on error.
be5a4e67
PP
676 """
677
c72a561f 678 try:
ce96d6eb 679 return self._field_type.exponent_size
c72a561f 680 except:
be5a4e67
PP
681 raise TypeError(
682 "Could not get Floating point exponent digit count")
683
be5a4e67
PP
684 @exponent_digits.setter
685 def exponent_digits(self, exponent_digits):
c72a561f 686 try:
ce96d6eb 687 self._field_type.exponent_size = exponent_digits
c72a561f 688 except:
be5a4e67
PP
689 raise ValueError("Could not set exponent digit count.")
690
691 @property
692 def mantissa_digits(self):
693 """
a777c99f
PP
694 Floating point number mantissa section size in bits (integer).
695
696 Set this attribute to change the floating point number's
697 mantissa section's size. You may use :attr:`FLT_MANT_DIG` or
698 :attr:`DBL_MANT_DIG` for IEEE 754 floating point numbers.
699
700 :exc:`ValueError` is raised on error.
be5a4e67
PP
701 """
702
c72a561f 703 try:
ce96d6eb 704 return self._field_type.mantissa_size
c72a561f
JG
705 except:
706 raise TypeError(
707 "Could not get Floating point mantissa digit count")
be5a4e67 708
be5a4e67
PP
709 @mantissa_digits.setter
710 def mantissa_digits(self, mantissa_digits):
c72a561f 711 try:
ce96d6eb 712 self._field_type.mantissa_size = mantissa_digits
c72a561f 713 except:
be5a4e67
PP
714 raise ValueError("Could not set mantissa digit count.")
715
716
a777c99f 717class FloatFieldDeclaration(FloatingPointFieldDeclaration):
be5a4e67
PP
718 pass
719
720
721class StructureFieldDeclaration(FieldDeclaration):
18449dbf
PP
722 """
723 Structure field declaration, i.e. an ordered mapping from field
724 names to field declarations.
725 """
726
be5a4e67
PP
727 def __init__(self):
728 """
18449dbf
PP
729 Creates an empty structure field declaration.
730
731 :exc:`ValueError` is raised on error.
be5a4e67
PP
732 """
733
ce96d6eb 734 self._field_type = bt2.StructureFieldType()
be5a4e67
PP
735 super().__init__()
736
737 def add_field(self, field_type, field_name):
738 """
18449dbf
PP
739 Appends one :class:`FieldDeclaration` *field_type* named
740 *field_name* to the structure's ordered map.
741
742 :exc:`ValueError` is raised on error.
be5a4e67
PP
743 """
744
c72a561f 745 try:
ce96d6eb 746 self._field_type.append_field(field_name, field_type._field_type)
c72a561f 747 except:
be5a4e67
PP
748 raise ValueError("Could not add field to structure.")
749
750 @property
751 def fields(self):
752 """
18449dbf
PP
753 Generates the (field name, :class:`FieldDeclaration`) pairs
754 of this structure.
755
756 :exc:`TypeError` is raised on error.
be5a4e67
PP
757 """
758
ce96d6eb 759 for name, field_type in self._field_type.items():
c72a561f
JG
760 yield (name,
761 FieldDeclaration._create_field_declaration(
762 field_type))
be5a4e67
PP
763
764 def get_field_by_name(self, name):
765 """
18449dbf
PP
766 Returns the :class:`FieldDeclaration` mapped to the field name
767 *name* in this structure.
768
769 :exc:`TypeError` is raised on error.
be5a4e67
PP
770 """
771
ce96d6eb 772 if name not in self._field_type:
be5a4e67
PP
773 msg = "Could not find Structure field with name {}".format(name)
774 raise TypeError(msg)
775
ce96d6eb 776 field_type = self._field_type[name]
c72a561f
JG
777 return FieldDeclaration._create_field_declaration(
778 field_type)
be5a4e67
PP
779
780
781class VariantFieldDeclaration(FieldDeclaration):
62d7eb34
PP
782 """
783 Variant field declaration.
784
785 A CTF variant is a dynamic selection between different fields.
786 The value of a *tag* (a CTF enumeration) determines what is the
787 current selected field. All the possible fields must be added to
788 its field declaration before using an actual variant field.
789 """
790
be5a4e67
PP
791 def __init__(self, enum_tag, tag_name):
792 """
62d7eb34
PP
793 Creates an empty variant field declaration with tag field
794 declaration *enum_tag* (instance of
795 :class:`EnumerationFieldDeclaration`) named *tag_name*
796 (string).
797
798 :exc:`ValueError` is raised on error.
be5a4e67
PP
799 """
800
801 isinst = isinstance(enum_tag, EnumerationFieldDeclaration)
802 if enum_tag is None or not isinst:
803 raise TypeError("Invalid tag type; must be of type EnumerationFieldDeclaration.")
804
ce96d6eb 805 self._field_type = bt2.VariantFieldType(tag_name=tag_name,
0b03f63e 806 tag_field_type=enum_tag._field_type)
be5a4e67
PP
807 super().__init__()
808
809 @property
810 def tag_name(self):
811 """
62d7eb34
PP
812 Variant field declaration tag name.
813
814 :exc:`TypeError` is raised on error.
be5a4e67
PP
815 """
816
c72a561f 817 try:
ce96d6eb 818 self._field_type.tag_name
c72a561f 819 except:
be5a4e67
PP
820 raise TypeError("Could not get Variant tag name")
821
be5a4e67
PP
822 @property
823 def tag_type(self):
824 """
62d7eb34
PP
825 Variant field declaration tag field declaration
826 (:class:`EnumerationFieldDeclaration` object).
827
828 :exc:`TypeError` is raised on error.
be5a4e67
PP
829 """
830
c72a561f
JG
831 try:
832 return FieldDeclaration._create_field_declaration(
ce96d6eb 833 self._field_type.tag_field_type)
c72a561f 834 except:
be5a4e67
PP
835 raise TypeError("Could not get Variant tag type")
836
be5a4e67
PP
837 def add_field(self, field_type, field_name):
838 """
62d7eb34
PP
839 Registers the :class:`FieldDeclaration` object *field_type*
840 as the variant's selected type when the variant's tag's current
841 label is *field_name*.
842
843 :exc:`ValueError` is raised on error.
be5a4e67
PP
844 """
845
c72a561f 846 try:
ce96d6eb 847 self._field_type.append_field(name=field_name, field_type=field_type._field_type)
c72a561f 848 except:
be5a4e67
PP
849 raise ValueError("Could not add field to variant.")
850
851 @property
852 def fields(self):
853 """
62d7eb34
PP
854 Generates the (field name, :class:`FieldDeclaration`) pairs
855 of this variant field declaration.
856
857 :exc:`TypeError` is raised on error.
be5a4e67
PP
858 """
859
ce96d6eb 860 for name, member in self._field_type.items():
c72a561f 861 yield (name, FieldDeclaration._create_field_declaration(member))
be5a4e67
PP
862
863 def get_field_by_name(self, name):
864 """
62d7eb34
PP
865 Returns the :class:`FieldDeclaration` selected when the
866 variant's tag's current label is *name*.
867
868 :exc:`TypeError` is raised on error.
be5a4e67
PP
869 """
870
ce96d6eb 871 if name not in self._field_type:
c72a561f
JG
872 raise TypeError(
873 'Could not find Variant field with name {}'.format(name))
be5a4e67 874
ce96d6eb 875 field_type = self._field_type[name]
c72a561f 876 return FieldDeclaration._create_field_declaration(field_type)
be5a4e67
PP
877
878 def get_field_from_tag(self, tag):
879 """
62d7eb34
PP
880 Returns the :class:`FieldDeclaration` selected by the current
881 label of the :class:`EnumerationField` *tag*.
882
883 :exc:`TypeError` is raised on error.
be5a4e67
PP
884 """
885
c72a561f
JG
886 try:
887 return create_field(self).field(tag).declaration
888 except:
889 raise TypeError('Could not get Variant field declaration.')
be5a4e67
PP
890
891
892class ArrayFieldDeclaration(FieldDeclaration):
ee77cc15
PP
893 """
894 Static array field declaration.
895 """
896
be5a4e67
PP
897 def __init__(self, element_type, length):
898 """
ee77cc15
PP
899 Creates a static array field declaration of *length*
900 elements of type *element_type* (:class:`FieldDeclaration`).
901
902 :exc:`ValueError` is raised on error.
be5a4e67
PP
903 """
904
c72a561f 905 try:
ce96d6eb 906 self._field_type = bt2.ArrayFieldType(element_type._field_type, length)
c72a561f
JG
907 except:
908 raise ValueError('Failed to create ArrayFieldDeclaration.')
be5a4e67
PP
909 super().__init__()
910
911 @property
912 def element_type(self):
913 """
ee77cc15
PP
914 Type of the elements of this this static array (subclass of
915 :class:`FieldDeclaration`).
916
917 :exc:`TypeError` is raised on error.
be5a4e67
PP
918 """
919
c72a561f
JG
920 try:
921 return FieldDeclaration._create_field_declaration(
ce96d6eb 922 self._field_type.element_field_type)
c72a561f 923 except:
be5a4e67
PP
924 raise TypeError("Could not get Array element type")
925
be5a4e67
PP
926 @property
927 def length(self):
928 """
ee77cc15
PP
929 Length of this static array (integer).
930
931 :exc:`TypeError` is raised on error.
be5a4e67
PP
932 """
933
c72a561f 934 try:
ce96d6eb 935 return self._field_type.length
c72a561f 936 except:
be5a4e67
PP
937 raise TypeError("Could not get Array length")
938
be5a4e67
PP
939
940class SequenceFieldDeclaration(FieldDeclaration):
28ada968
PP
941 """
942 Sequence (dynamic array) field declaration.
943 """
944
be5a4e67
PP
945 def __init__(self, element_type, length_field_name):
946 """
28ada968
PP
947 Creates a sequence field declaration of
948 elements of type *element_type* (:class:`FieldDeclaration`).
949 The length of a sequence field based on this sequence field
950 declaration is obtained by retrieving the dynamic integer
951 value of the field named *length_field_name*.
952
953 :exc:`ValueError` is raised on error.
be5a4e67
PP
954 """
955
c72a561f 956 try:
ce96d6eb 957 self._field_type = bt2.SequenceFieldType(element_type, length_field_name)
c72a561f
JG
958 except:
959 raise ValueError('Failed to create SequenceFieldDeclaration.')
be5a4e67
PP
960 super().__init__()
961
962 @property
963 def element_type(self):
964 """
28ada968
PP
965 Type of the elements of this sequence (subclass of
966 :class:`FieldDeclaration`).
967
968 :exc:`TypeError` is raised on error.
be5a4e67
PP
969 """
970
c72a561f
JG
971 try:
972 return FieldDeclaration._create_field_declaration(
ce96d6eb 973 self._field_type.element_field_type)
c72a561f 974 except:
be5a4e67
PP
975 raise TypeError("Could not get Sequence element type")
976
be5a4e67
PP
977 @property
978 def length_field_name(self):
979 """
28ada968
PP
980 Name of the integer field defining the dynamic length of
981 sequence fields based on this sequence field declaration.
982
983 :exc:`TypeError` is raised on error.
be5a4e67
PP
984 """
985
c72a561f 986 try:
ce96d6eb 987 return self._field_type.length_name
c72a561f
JG
988 except:
989 raise TypeError("Could not get Sequence element type")
be5a4e67
PP
990
991
c72a561f 992class StringFieldDeclaration(FieldDeclaration, _EncodingProp):
0a1148a9
PP
993 """
994 String (NULL-terminated array of bytes) field declaration.
995 """
996
be5a4e67
PP
997 def __init__(self):
998 """
0a1148a9
PP
999 Creates a string field declaration.
1000
1001 :exc:`ValueError` is raised on error.
be5a4e67
PP
1002 """
1003
ce96d6eb 1004 self._field_type = bt2.StringFieldType()
be5a4e67
PP
1005 super().__init__()
1006
be5a4e67
PP
1007
1008@staticmethod
1009def create_field(field_type):
1010 """
1011 Create an instance of a field.
1012 """
1013 isinst = isinstance(field_type, FieldDeclaration)
1014
1015 if field_type is None or not isinst:
1016 raise TypeError("Invalid field_type. Type must be a FieldDeclaration-derived class.")
1017
1018 if isinstance(field_type, IntegerFieldDeclaration):
1019 return IntegerField(field_type)
1020 elif isinstance(field_type, EnumerationFieldDeclaration):
1021 return EnumerationField(field_type)
1022 elif isinstance(field_type, FloatFieldDeclaration):
1023 return FloatingPointField(field_type)
1024 elif isinstance(field_type, StructureFieldDeclaration):
1025 return StructureField(field_type)
1026 elif isinstance(field_type, VariantFieldDeclaration):
1027 return VariantField(field_type)
1028 elif isinstance(field_type, ArrayFieldDeclaration):
1029 return ArrayField(field_type)
1030 elif isinstance(field_type, SequenceFieldDeclaration):
1031 return SequenceField(field_type)
1032 elif isinstance(field_type, StringFieldDeclaration):
1033 return StringField(field_type)
1034
1035
1036class Field:
1037 """
d4ba140f
PP
1038 Base class of all fields. This class is not meant to be
1039 instantiated by the user, and neither are its subclasses. Use
1040 :meth:`Event.payload` to access specific, concrete fields of
1041 an event.
be5a4e67
PP
1042 """
1043
1044 def __init__(self, field_type):
1045 if not isinstance(field_type, FieldDeclaration):
1046 raise TypeError("Invalid field_type argument.")
1047
c72a561f 1048 try:
ce96d6eb 1049 self._f = field_type._field_type()
c72a561f 1050 except:
be5a4e67
PP
1051 raise ValueError("Field creation failed.")
1052
be5a4e67 1053 @staticmethod
c72a561f 1054 def _create_field(bt2_field):
be5a4e67 1055 type_dict = {
c72a561f
JG
1056 bt2._IntegerField: IntegerField,
1057 bt2._FloatingPointNumberField: FloatingPointField,
1058 bt2._EnumerationField: EnumerationField,
1059 bt2._StringField: StringField,
1060 bt2._StructureField: StructureField,
1061 bt2._VariantField: VariantField,
1062 bt2._ArrayField: ArrayField,
1063 bt2._SequenceField: SequenceField
be5a4e67
PP
1064 }
1065
c72a561f
JG
1066 if type(bt2_field) not in type_dict:
1067 raise TypeError("Invalid field instance.")
be5a4e67
PP
1068
1069 field = Field.__new__(Field)
c72a561f
JG
1070 field._f = bt2_field
1071 field.__class__ = type_dict[type(bt2_field)]
be5a4e67
PP
1072
1073 return field
1074
1075 @property
1076 def declaration(self):
d4ba140f
PP
1077 """
1078 Field declaration (subclass of :class:`FieldDeclaration`).
1079
1080 :exc:`TypeError` is raised on error.
1081 """
1082
c72a561f 1083 return FieldDeclaration._create_field_declaration(self._f.field_type)
be5a4e67
PP
1084
1085
1086class IntegerField(Field):
26912ff5
PP
1087 """
1088 Integer field, based on an :class:`IntegerFieldDeclaration` object.
1089 """
1090
be5a4e67
PP
1091 @property
1092 def value(self):
1093 """
26912ff5
PP
1094 Integer value (:class:`int`).
1095
1096 Set this attribute to change the integer field's value.
1097
1098 :exc:`ValueError` or :exc:`TypeError` are raised on error.
be5a4e67
PP
1099 """
1100
c72a561f
JG
1101 try:
1102 return int(self._f)
1103 except:
1104 ValueError('Could not get integer field value.')
be5a4e67
PP
1105
1106 @value.setter
1107 def value(self, value):
c72a561f 1108 try:
ce96d6eb 1109 self._f.value = value
c72a561f 1110 except:
be5a4e67
PP
1111 raise ValueError("Could not set integer field value.")
1112
1113
1114class EnumerationField(Field):
fbfe2f0e
PP
1115 """
1116 Enumeration field, based on an
1117 :class:`EnumerationFieldDeclaration` object.
1118 """
1119
be5a4e67
PP
1120 @property
1121 def container(self):
1122 """
fbfe2f0e
PP
1123 Underlying container (:class:`IntegerField`).
1124
1125 :exc:`TypeError` is raised on error.
be5a4e67
PP
1126 """
1127
c72a561f
JG
1128 try:
1129 return Field._create_field(self._f.integer_field)
1130 except:
be5a4e67
PP
1131 raise TypeError("Invalid enumeration field type.")
1132
be5a4e67
PP
1133 @property
1134 def value(self):
1135 """
fbfe2f0e
PP
1136 Current label of this enumeration field (:class:`str`).
1137
1138 Set this attribute to an integer (:class:`int`) to change the
1139 enumeration field's value.
1140
1141 :exc:`ValueError` is raised on error.
be5a4e67
PP
1142 """
1143
c72a561f
JG
1144 try:
1145 bt2_enum_ft = self._f.field_type
1146 mappings = list(bt2_enum_ft.mappings_by_value(self._f.value))
1147 return mappings[0].name
1148 except:
fbfe2f0e 1149 raise ValueError("Could not get enumeration mapping name.")
be5a4e67 1150
be5a4e67
PP
1151 @value.setter
1152 def value(self, value):
be5a4e67
PP
1153 if not isinstance(value, int):
1154 raise TypeError("EnumerationField value must be an int")
1155
c72a561f 1156 self._f.value = value
be5a4e67
PP
1157
1158
1159class FloatingPointField(Field):
cf3687b5
PP
1160 """
1161 Floating point number field, based on a
1162 :class:`FloatingPointFieldDeclaration` object.
1163 """
1164
be5a4e67
PP
1165 @property
1166 def value(self):
1167 """
cf3687b5
PP
1168 Floating point number value (:class:`float`).
1169
1170 Set this attribute to change the floating point number field's
1171 value.
1172
1173 :exc:`ValueError` or :exc:`TypeError` are raised on error.
be5a4e67
PP
1174 """
1175
c72a561f
JG
1176 try:
1177 float(self._f)
1178 except:
be5a4e67
PP
1179 raise ValueError("Could not get floating point field value.")
1180
be5a4e67
PP
1181 @value.setter
1182 def value(self, value):
c72a561f
JG
1183 try:
1184 self._f.value = value
1185 except:
be5a4e67
PP
1186 raise ValueError("Could not set floating point field value.")
1187
1188
c72a561f
JG
1189# This class is provided to ensure backward-compatibility since a stable
1190# release publicly exposed this... abomination.
be5a4e67
PP
1191class FloatFieldingPoint(FloatingPointField):
1192 pass
1193
1194
1195class StructureField(Field):
773edf13
PP
1196 """
1197 Structure field, based on a
1198 :class:`StructureFieldDeclaration` object.
1199 """
1200
be5a4e67
PP
1201 def field(self, field_name):
1202 """
773edf13
PP
1203 Returns the structure :class:`Field` named *field_name*.
1204
1205 :exc:`ValueError` is raised on error.
be5a4e67
PP
1206 """
1207
c72a561f 1208 try:
6f9a2deb 1209 return Field._create_field(self._f[field_name])
c72a561f 1210 except:
be5a4e67
PP
1211 raise ValueError("Invalid field_name provided.")
1212
be5a4e67
PP
1213
1214class VariantField(Field):
5f6ba8b2
PP
1215 """
1216 Variant field, based on a
1217 :class:`VariantFieldDeclaration` object.
1218 """
1219
be5a4e67
PP
1220 def field(self, tag):
1221 """
5f6ba8b2
PP
1222 Returns the :class:`Field` selected by the current label of
1223 *tag* (:class:`EnumerationField`).
1224
1225 :exc:`ValueError` is raised on error.
be5a4e67
PP
1226 """
1227
c72a561f
JG
1228 try:
1229 return Field._create_field(self._f.field(tag._f))
1230 except:
be5a4e67
PP
1231 raise ValueError("Invalid tag provided.")
1232
be5a4e67
PP
1233
1234class ArrayField(Field):
a1bdc25c
PP
1235 """
1236 Static array field, based on an
1237 :class:`ArrayFieldDeclaration` object.
1238 """
1239
be5a4e67
PP
1240 def field(self, index):
1241 """
a1bdc25c
PP
1242 Returns the :class:`Field` at index *index* in this static
1243 array.
1244
1245 :exc:`IndexError` is raised on error.
be5a4e67
PP
1246 """
1247
c72a561f
JG
1248 try:
1249 return Field._create_field(self._f[index])
1250 except:
be5a4e67
PP
1251 raise IndexError("Invalid index provided.")
1252
be5a4e67
PP
1253
1254class SequenceField(Field):
4ac159aa
PP
1255 """
1256 Sequence (dynamic array) field, based on a
1257 :class:`SequenceFieldDeclaration` object.
1258 """
1259
be5a4e67
PP
1260 @property
1261 def length(self):
1262 """
4ac159aa
PP
1263 Sequence length (:class:`IntegerField`).
1264
1265 Set this attribute to change the sequence length's integer
1266 field (integer must be unsigned).
1267
1268 :exc:`ValueError` or :exc:`TypeError` are raised on error.
be5a4e67
PP
1269 """
1270
c72a561f
JG
1271 try:
1272 length_field = self._f.length_field
1273 if length_field is None:
1274 return
1275 return Field._create_field(length_field)
1276 except:
1277 raise ValueError('Invalid sequence field.')
be5a4e67
PP
1278
1279 @length.setter
1280 def length(self, length_field):
be5a4e67
PP
1281 if not isinstance(length_field, IntegerField):
1282 raise TypeError("Invalid length field.")
1283
1284 if length_field.declaration.signed:
1285 raise TypeError("Sequence field length must be unsigned")
1286
c72a561f
JG
1287 try:
1288 self._f.length_field = length_field._f
1289 except:
be5a4e67
PP
1290 raise ValueError("Could not set sequence length.")
1291
1292 def field(self, index):
1293 """
4ac159aa
PP
1294 Returns the :class:`Field` at index *index* in this sequence.
1295
1296 :exc:`ValueError` is raised on error.
be5a4e67
PP
1297 """
1298
c72a561f
JG
1299 try:
1300 return Field._create_field(self._f[index])
1301 except:
1302 raise IndexError("Invalid index provided.")
be5a4e67
PP
1303
1304
1305class StringField(Field):
4027ea9d
PP
1306 """
1307 String (NULL-terminated array of bytes) field.
1308 """
1309
be5a4e67
PP
1310 @property
1311 def value(self):
1312 """
4027ea9d
PP
1313 String value (:class:`str`).
1314
1315 Set this attribute to change the string's value.
1316
1317 :exc:`ValueError` or :exc:`TypeError` are raised on error.
be5a4e67
PP
1318 """
1319
c72a561f
JG
1320 try:
1321 str(self._f)
1322 except:
1323 raise ValueError('Could not get string field value.')
be5a4e67
PP
1324
1325 @value.setter
1326 def value(self, value):
c72a561f
JG
1327 try:
1328 self._f.value = value
1329 except:
be5a4e67
PP
1330 raise ValueError("Could not set string field value.")
1331
1332
1333class EventClass:
ad9c62de
PP
1334 """
1335 An event class contains the properties of specific
1336 events (:class:`Event`). Any concrete event must be linked with an
1337 :class:`EventClass`.
1338
1339 Some attributes are automatically set when creating an event class.
1340 For example, if no numeric ID is explicitly set using the
1341 :attr:`id` attribute, a default, unique ID within the stream class
1342 containing this event class will be created when needed.
1343 """
1344
be5a4e67
PP
1345 def __init__(self, name):
1346 """
ad9c62de
PP
1347 Creates an event class named *name*.
1348
1349 :exc:`ValueError` is raised on error.
be5a4e67
PP
1350 """
1351
c72a561f 1352 self._ec = bt2.EventClass(name)
be5a4e67
PP
1353
1354 if self._ec is None:
1355 raise ValueError("Event class creation failed.")
1356
be5a4e67
PP
1357 def add_field(self, field_type, field_name):
1358 """
ad9c62de
PP
1359 Adds a field declaration *field_type* named *field_name* to
1360 this event class.
1361
1362 *field_type* must be one of:
1363
1364 * :class:`IntegerFieldDeclaration`
1365 * :class:`FloatingPointFieldDeclaration`
1366 * :class:`EnumerationFieldDeclaration`
1367 * :class:`StringFieldDeclaration`
1368 * :class:`ArrayFieldDeclaration`
1369 * :class:`SequenceFieldDeclaration`
1370 * :class:`StructureFieldDeclaration`
1371 * :class:`VariantFieldDeclaration`
1372
1373 :exc:`ValueError` is raised on error.
be5a4e67
PP
1374 """
1375
c72a561f
JG
1376 try:
1377 self._ec.payload_field_type.append_field(field_name,
ce96d6eb 1378 field_type._field_type)
c72a561f 1379 except:
be5a4e67
PP
1380 raise ValueError("Could not add field to event class.")
1381
1382 @property
1383 def name(self):
1384 """
ad9c62de 1385 Event class' name.
be5a4e67
PP
1386 """
1387
c72a561f
JG
1388 try:
1389 return self._ec.name
1390 except:
be5a4e67
PP
1391 raise TypeError("Could not get EventClass name")
1392
be5a4e67
PP
1393 @property
1394 def id(self):
1395 """
ad9c62de
PP
1396 Event class' numeric ID.
1397
1398 Set this attribute to assign a numeric ID to this event class.
1399 This ID must be unique amongst all the event class IDs of a
1400 given stream class.
1401
1402 :exc:`TypeError` is raised on error.
be5a4e67
PP
1403 """
1404
c72a561f
JG
1405 try:
1406 return self._ec.id
1407 except:
be5a4e67
PP
1408 raise TypeError("Could not get EventClass id")
1409
be5a4e67
PP
1410 @id.setter
1411 def id(self, id):
c72a561f
JG
1412 try:
1413 self._ec.id = id
1414 except:
1415 raise TypeError("Can't change an EventClass id after it has been assigned to a stream class.")
be5a4e67
PP
1416
1417 @property
1418 def stream_class(self):
1419 """
ad9c62de
PP
1420 :class:`StreamClass` object containing this event class,
1421 or ``None`` if not set.
be5a4e67 1422 """
ad9c62de 1423
c72a561f
JG
1424 bt2_stream_class = self._ec.stream_class
1425 if bt2_stream_class is None:
1426 return
be5a4e67
PP
1427
1428 stream_class = StreamClass.__new__(StreamClass)
ce96d6eb 1429 stream_class._stream_class = bt2_stream_class
be5a4e67
PP
1430
1431 return stream_class
1432
1433 @property
1434 def fields(self):
1435 """
ad9c62de
PP
1436 Generates the (field name, :class:`FieldDeclaration`) pairs of
1437 this event class.
1438
1439 :exc:`TypeError` is raised on error.
be5a4e67
PP
1440 """
1441
c72a561f
JG
1442 return FieldDeclaration._create_field_declaration(
1443 self._ec.payload_field_type).fields
be5a4e67
PP
1444
1445 def get_field_by_name(self, name):
1446 """
ad9c62de
PP
1447 Returns the :class:`FieldDeclaration` object named *name* in
1448 this event class.
1449
1450 :exc:`TypeError` is raised on error.
be5a4e67
PP
1451 """
1452
c72a561f
JG
1453 return FieldDeclaration._create_field_declaration(
1454 self._ec.payload_field_type)[name]
be5a4e67
PP
1455
1456
1457class Event:
59b50df8
PP
1458 """
1459 Events are specific instances of event classes
1460 (:class:`EventClass`), which means they may contain actual,
1461 concrete field values.
1462 """
1463
be5a4e67
PP
1464 def __init__(self, event_class):
1465 """
59b50df8
PP
1466 Creates an event linked with the :class:`EventClass`
1467 *event_class*.
1468
1469 :exc:`ValueError` is raised on error.
be5a4e67
PP
1470 """
1471
1472 if not isinstance(event_class, EventClass):
1473 raise TypeError("Invalid event_class argument.")
1474
c72a561f
JG
1475 try:
1476 self._e = event_class._ec()
1477 except:
be5a4e67
PP
1478 raise ValueError("Event creation failed.")
1479
be5a4e67
PP
1480 @property
1481 def event_class(self):
1482 """
59b50df8 1483 :class:`EventClass` object to which this event is linked.
be5a4e67
PP
1484 """
1485
be5a4e67 1486 event_class = EventClass.__new__(EventClass)
c72a561f 1487 event_class._ec = self._e.event_class
be5a4e67
PP
1488 return event_class
1489
1490 def clock(self):
1491 """
59b50df8
PP
1492 :class:`Clock` object used by this object, or ``None`` if
1493 the event class is not registered to a stream class.
be5a4e67
PP
1494 """
1495
c72a561f
JG
1496 try:
1497 bt2_clock = self._e.event_class.stream_class.clock
1498 except:
1499 return
be5a4e67
PP
1500
1501 clock = Clock.__new__(Clock)
c72a561f 1502 clock._c = bt2_clock
be5a4e67
PP
1503 return clock
1504
1505 def payload(self, field_name):
1506 """
59b50df8
PP
1507 Returns the :class:`Field` object named *field_name* in this
1508 event.
1509
1510 The returned field object is created using the event class'
1511 field declaration named *field_name*.
1512
1513 The return type is one of:
1514
1515 * :class:`IntegerField`
1516 * :class:`FloatingPointField`
1517 * :class:`EnumerationField`
1518 * :class:`StringField`
1519 * :class:`ArrayField`
1520 * :class:`SequenceField`
1521 * :class:`StructureField`
1522 * :class:`VariantField`
1523
1524 :exc:`TypeError` is raised on error.
be5a4e67
PP
1525 """
1526
c72a561f
JG
1527 try:
1528 return Field._create_field(self._e.payload_field[field_name])
1529 except:
1530 raise TypeError('Could not get field from event.')
be5a4e67
PP
1531
1532 def set_payload(self, field_name, value_field):
1533 """
59b50df8
PP
1534 Set the event's field named *field_name* to the manually
1535 created :class:`Field` object *value_field*.
1536
1537 *value_field*'s type must be one of:
1538
1539 * :class:`IntegerField`
1540 * :class:`FloatingPointField`
1541 * :class:`EnumerationField`
1542 * :class:`StringField`
1543 * :class:`ArrayField`
1544 * :class:`SequenceField`
1545 * :class:`StructureField`
1546 * :class:`VariantField`
1547
1548 :exc:`ValueError` is raised on error.
be5a4e67
PP
1549 """
1550
c72a561f 1551 if not isinstance(value_field, Field):
be5a4e67
PP
1552 raise TypeError("Invalid value type.")
1553
c72a561f
JG
1554 try:
1555 self._e.payload_field[field_name] = value_field._f
1556 except:
be5a4e67
PP
1557 raise ValueError("Could not set event field payload.")
1558
6b30e7f3
SM
1559 @property
1560 def stream_context(self):
1561 """
1562 Stream event context field (instance of
1563 :class:`StructureField`).
1564
1565 Set this attribute to assign a stream event context field
1566 to this stream.
1567
1568 :exc:`ValueError` is raised on error.
1569 """
1570
c72a561f
JG
1571 try:
1572 return Field._create_field(self._e.context_field)
1573 except:
6b30e7f3
SM
1574 raise ValueError("Invalid Stream.")
1575
6b30e7f3
SM
1576 @stream_context.setter
1577 def stream_context(self, field):
1578 if not isinstance(field, StructureField):
1579 raise TypeError("Argument field must be of type StructureField")
1580
c72a561f
JG
1581 try:
1582 self._e.context_field = field._f
1583 except:
6b30e7f3 1584 raise ValueError("Invalid stream context field.")
be5a4e67 1585
0b03f63e 1586
be5a4e67 1587class StreamClass:
5fd17f73
PP
1588 """
1589 A stream class contains the properties of specific
1590 streams (:class:`Stream`). Any concrete stream must be linked with
1591 a :class:`StreamClass`, usually by calling
1592 :meth:`Writer.create_stream`.
1593
1594 Some attributes are automatically set when creating a stream class.
1595 For example, if no clock is explicitly set using the
1596 :attr:`clock` attribute, a default clock will be created
1597 when needed.
1598 """
1599
be5a4e67
PP
1600 def __init__(self, name):
1601 """
5fd17f73
PP
1602 Creates a stream class named *name*.
1603
1604 :exc:`ValueError` is raised on error.
be5a4e67
PP
1605 """
1606
c72a561f 1607 try:
463fa246
JG
1608 # Set default event header and packet context.
1609 event_header_type = bt2.StructureFieldType()
cb3373fe
PP
1610 uint32_ft = bt2.IntegerFieldType(32)
1611 uint64_ft = bt2.IntegerFieldType(64)
463fa246
JG
1612 event_header_type.append_field('id', uint32_ft)
1613 event_header_type.append_field('timestamp', uint64_ft)
1614
1615 packet_context_type = bt2.StructureFieldType()
1616 packet_context_type.append_field('timestamp_begin', uint64_ft)
1617 packet_context_type.append_field('timestamp_end', uint64_ft)
1618 packet_context_type.append_field('content_size', uint64_ft)
1619 packet_context_type.append_field('packet_size', uint64_ft)
1620 packet_context_type.append_field('events_discarded', uint64_ft)
1621 sc = bt2.StreamClass(name,
1622 event_header_field_type=event_header_type,
1623 packet_context_field_type=packet_context_type)
1624 self._stream_class = sc
c72a561f 1625 except:
be5a4e67
PP
1626 raise ValueError("Stream class creation failed.")
1627
be5a4e67
PP
1628 @property
1629 def name(self):
1630 """
5fd17f73
PP
1631 Stream class' name.
1632
1633 :exc:`TypeError` is raised on error.
be5a4e67
PP
1634 """
1635
c72a561f 1636 try:
ce96d6eb 1637 return self._stream_class.name
c72a561f 1638 except:
be5a4e67
PP
1639 raise TypeError("Could not get StreamClass name")
1640
be5a4e67
PP
1641 @property
1642 def clock(self):
1643 """
5fd17f73
PP
1644 Stream class' clock (:class:`Clock` object).
1645
1646 Set this attribute to change the clock of this stream class.
1647
1648 :exc:`ValueError` is raised on error.
be5a4e67
PP
1649 """
1650
ce96d6eb 1651 if self._stream_class.clock is None:
c72a561f 1652 return
be5a4e67
PP
1653
1654 clock = Clock.__new__(Clock)
ce96d6eb 1655 clock._c = self._stream_class.clock
be5a4e67
PP
1656 return clock
1657
1658 @clock.setter
1659 def clock(self, clock):
be5a4e67
PP
1660 if not isinstance(clock, Clock):
1661 raise TypeError("Invalid clock type.")
1662
c72a561f 1663 try:
ce96d6eb 1664 self._stream_class.clock = clock._clock
c72a561f 1665 except:
be5a4e67
PP
1666 raise ValueError("Could not set stream class clock.")
1667
1668 @property
1669 def id(self):
1670 """
5fd17f73
PP
1671 Stream class' numeric ID.
1672
1673 Set this attribute to change the ID of this stream class.
1674
1675 :exc:`ValueError` is raised on error.
be5a4e67
PP
1676 """
1677
c72a561f 1678 try:
ce96d6eb 1679 return self._stream_class.id
c72a561f 1680 except:
be5a4e67
PP
1681 raise TypeError("Could not get StreamClass id")
1682
be5a4e67
PP
1683 @id.setter
1684 def id(self, id):
c72a561f 1685 try:
ce96d6eb 1686 self._stream_class.id = id
c72a561f 1687 except:
be5a4e67
PP
1688 raise TypeError("Could not set stream class id.")
1689
1690 @property
1691 def event_classes(self):
1692 """
5fd17f73
PP
1693 Generates the event classes (:class:`EventClass` objects) of
1694 this stream class.
1695
1696 :exc:`TypeError` is raised on error.
be5a4e67
PP
1697 """
1698
ce96d6eb 1699 for bt2_ec in self._stream_class.values():
be5a4e67 1700 event_class = EventClass.__new__(EventClass)
c72a561f 1701 event_class._ec = bt2_ec
be5a4e67
PP
1702 yield event_class
1703
1704 def add_event_class(self, event_class):
1705 """
5fd17f73
PP
1706 Registers the :class:`EventClass` *event_class* to this stream
1707 class.
1708
1709 Once the event class is registered, it will be generated as one
1710 of the event classes generated by :attr:`event_classes`.
1711
1712 :exc:`ValueError` is raised on error.
be5a4e67
PP
1713 """
1714
1715 if not isinstance(event_class, EventClass):
1716 raise TypeError("Invalid event_class type.")
1717
c72a561f 1718 try:
ce96d6eb 1719 self._stream_class.add_event_class(event_class._ec)
c72a561f 1720 except:
be5a4e67
PP
1721 raise ValueError("Could not add event class.")
1722
1723 @property
1724 def packet_context_type(self):
1725 """
5fd17f73
PP
1726 Stream packet context declaration.
1727
1728 Set this attribute to change the stream packet context
1729 declaration (must be an instance of
1730 :class:`StructureFieldDeclaration`).
1731
1732 :exc:`ValueError` is raised on error.
1733
be5a4e67
PP
1734 """
1735
c72a561f 1736 try:
ce96d6eb 1737 bt2_field_type = self._stream_class.packet_context_field_type
c72a561f
JG
1738 if bt2_field_type is None:
1739 raise ValueError("Invalid StreamClass")
be5a4e67 1740
c72a561f
JG
1741 field_type = FieldDeclaration._create_field_declaration(
1742 bt2_field_type)
1743 return field_type
1744 except:
be5a4e67
PP
1745 raise ValueError("Invalid StreamClass")
1746
be5a4e67
PP
1747 @packet_context_type.setter
1748 def packet_context_type(self, field_type):
04df8ef3
JG
1749 if field_type is not None and not isinstance(field_type,
1750 StructureFieldDeclaration):
be5a4e67
PP
1751 raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
1752
04df8ef3 1753 bt2_field_type = None if field_type is None else field_type._field_type
c72a561f 1754 try:
04df8ef3 1755 self._stream_class.packet_context_field_type = bt2_field_type
c72a561f 1756 except:
be5a4e67
PP
1757 raise ValueError("Failed to set packet context type.")
1758
6b30e7f3
SM
1759 @property
1760 def event_context_type(self):
1761 """
1762 Stream event context declaration.
1763
1764 Set this attribute to change the stream event context
1765 declaration (must be an instance of
1766 :class:`StructureFieldDeclaration`).
1767
1768 :exc:`ValueError` is raised on error.
1769
1770 """
1771
c72a561f 1772 try:
ce96d6eb 1773 bt2_field_type = self._stream_class.event_context_field_type
c72a561f
JG
1774 if bt2_field_type is None:
1775 raise ValueError("Invalid StreamClass")
6b30e7f3 1776
c72a561f
JG
1777 field_type = FieldDeclaration._create_field_declaration(
1778 bt2_field_type)
1779 return field_type
1780 except:
6b30e7f3
SM
1781 raise ValueError("Invalid StreamClass")
1782
6b30e7f3
SM
1783 @event_context_type.setter
1784 def event_context_type(self, field_type):
04df8ef3
JG
1785 if field_type is not None and not isinstance(field_type,
1786 StructureFieldDeclaration):
6b30e7f3
SM
1787 raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
1788
04df8ef3 1789 bt2_field_type = None if field_type is None else field_type._field_type
c72a561f 1790 try:
04df8ef3 1791 self._stream_class.event_context_field_type = bt2_field_type
c72a561f 1792 except:
6b30e7f3
SM
1793 raise ValueError("Failed to set event context type.")
1794
be5a4e67
PP
1795
1796class Stream:
898a14a5
PP
1797 """
1798 Streams are specific instances of stream classes, which means they
1799 may contain actual, concrete events.
1800
1801 :class:`Stream` objects are returned by
1802 :meth:`Writer.create_stream`; they are not meant to be
1803 instantiated by the user.
1804
1805 Concrete :class:`Event` objects are appended to
1806 :class:`Stream` objects using :meth:`append_event`.
1807
1808 When :meth:`flush` is called, a CTF packet is created, containing
1809 all the appended events since the last flush. Although the stream
1810 is flushed on object destruction, it is **strongly recommended**
1811 that the user call :meth:`flush` manually before exiting the
1812 script, as :meth:`__del__` is not always reliable.
1813 """
1814
be5a4e67
PP
1815 def __init__(self):
1816 raise NotImplementedError("Stream cannot be instantiated; use Writer.create_stream()")
1817
be5a4e67
PP
1818 @property
1819 def discarded_events(self):
1820 """
898a14a5
PP
1821 Number of discarded (lost) events in this stream so far.
1822
1823 :exc:`ValueError` is raised on error.
be5a4e67
PP
1824 """
1825
c72a561f
JG
1826 try:
1827 return self._s.discarded_events_count
1828 except:
898a14a5 1829 raise ValueError("Could not get the stream discarded events count")
be5a4e67 1830
be5a4e67
PP
1831 def append_discarded_events(self, event_count):
1832 """
898a14a5 1833 Appends *event_count* discarded events to this stream.
be5a4e67
PP
1834 """
1835
c72a561f 1836 self._s.append_discarded_events(event_count)
be5a4e67
PP
1837
1838 def append_event(self, event):
1839 """
898a14a5
PP
1840 Appends event *event* (:class:`Event` object) to this stream.
1841
1842 The stream's associated clock will be sampled during this call.
1843 *event* **shall not** be modified after being appended to this
1844 stream.
1845
1846 :exc:`ValueError` is raised on error.
be5a4e67
PP
1847 """
1848
ce96d6eb
JG
1849 try:
1850 self._s.append_event(event._e)
1851 except:
be5a4e67
PP
1852 raise ValueError("Could not append event to stream.")
1853
1854 @property
1855 def packet_context(self):
1856 """
898a14a5
PP
1857 Stream packet context field (instance of
1858 :class:`StructureField`).
1859
1860 Set this attribute to assign a stream packet context field
1861 to this stream.
1862
1863 :exc:`ValueError` is raised on error.
be5a4e67
PP
1864 """
1865
c72a561f
JG
1866 bt2_field = self._s.packet_context_field
1867 if bt2_field is None:
be5a4e67
PP
1868 raise ValueError("Invalid Stream.")
1869
c72a561f 1870 return Field._create_field(bt2_field)
be5a4e67
PP
1871
1872 @packet_context.setter
1873 def packet_context(self, field):
be5a4e67
PP
1874 if not isinstance(field, StructureField):
1875 raise TypeError("Argument field must be of type StructureField")
1876
c72a561f
JG
1877 try:
1878 self._s.packet_context_field = field._f
1879 except:
be5a4e67
PP
1880 raise ValueError("Invalid packet context field.")
1881
1882 def flush(self):
1883 """
898a14a5
PP
1884 Flushes the current packet of this stream to disk. Events
1885 subsequently appended to the stream will be added to a new
1886 packet.
1887
1888 :exc:`ValueError` is raised on error.
be5a4e67
PP
1889 """
1890
745a8c70
JG
1891 try:
1892 self._s.flush()
1893 except:
1894 raise ValueError('Failed to flush CTF writer stream')
be5a4e67
PP
1895
1896
1897class Writer:
40529d6d
PP
1898 """
1899 This object is the CTF writer API context. It oversees its streams
1900 and clocks, and is responsible for writing one CTF trace.
1901 """
1902
be5a4e67
PP
1903 def __init__(self, path):
1904 """
40529d6d
PP
1905 Creates a CTF writer, initializing a new CTF trace at path
1906 *path*.
1907
1908 *path* must be an existing directory, since a CTF trace is
1909 made of multiple files.
1910
1911 :exc:`ValueError` is raised if the creation fails.
be5a4e67
PP
1912 """
1913
c72a561f
JG
1914 try:
1915 self._w = bt2.CtfWriter(path)
1916 except:
be5a4e67
PP
1917 raise ValueError("Writer creation failed.")
1918
be5a4e67
PP
1919 def create_stream(self, stream_class):
1920 """
40529d6d
PP
1921 Creates and registers a new stream based on stream class
1922 *stream_class*.
1923
1924 This is the standard way of creating a :class:`Stream` object:
1925 the user is not allowed to instantiate this class.
1926
1927 Returns a new :class:`Stream` object.
be5a4e67
PP
1928 """
1929
1930 if not isinstance(stream_class, StreamClass):
1931 raise TypeError("Invalid stream_class type.")
1932
ce96d6eb
JG
1933 if stream_class._stream_class.trace is None:
1934 self._w.trace.add_stream_class(stream_class._stream_class)
be5a4e67 1935
c72a561f 1936 stream = Stream.__new__(Stream)
ce96d6eb
JG
1937 stream._s = stream_class._stream_class()
1938 stream.__class__ = Stream
be5a4e67
PP
1939 return stream
1940
1941 def add_environment_field(self, name, value):
1942 """
40529d6d
PP
1943 Sets the CTF environment variable named *name* to value *value*
1944 (converted to a string).
1945
d7503815 1946 :exc:`ValueError` or `TypeError` is raised on error.
be5a4e67
PP
1947 """
1948
d7503815
SM
1949 if type(name) != str:
1950 raise TypeError("Field name must be a string.")
1951
1952 t = type(value)
1953
c72a561f 1954 if type(value) != str and type(value) != int:
d7503815 1955 raise TypeError("Value type is not supported.")
be5a4e67 1956
c72a561f 1957 try:
0f8db238 1958 self._w.trace.env[name] = value
c72a561f 1959 except:
be5a4e67
PP
1960 raise ValueError("Could not add environment field to trace.")
1961
1962 def add_clock(self, clock):
1963 """
40529d6d
PP
1964 Registers :class:`Clock` object *clock* to the writer.
1965
1966 You *must* register CTF clocks assigned to stream classes
1967 to the writer.
1968
1969 :exc:`ValueError` is raised if the creation fails.
be5a4e67
PP
1970 """
1971
c72a561f 1972 try:
ce96d6eb 1973 self._w.add_clock(clock._clock)
c72a561f 1974 except:
be5a4e67
PP
1975 raise ValueError("Could not add clock to Writer.")
1976
1977 @property
1978 def metadata(self):
1979 """
40529d6d 1980 Current metadata of this trace (:class:`str`).
be5a4e67
PP
1981 """
1982
c72a561f 1983 return self._w.metadata_string
be5a4e67
PP
1984
1985 def flush_metadata(self):
1986 """
40529d6d 1987 Flushes the trace's metadata to the metadata file.
be5a4e67
PP
1988 """
1989
c72a561f 1990 self._w.flush_metadata()
be5a4e67
PP
1991
1992 @property
1993 def byte_order(self):
1994 """
40529d6d
PP
1995 Native byte order of this trace (one of
1996 :class:`babeltrace.common.ByteOrder` constants).
1997
1998 This is the actual byte order that is used when a field
1999 declaration has the
2000 :attr:`babeltrace.common.ByteOrder.BYTE_ORDER_NATIVE`
2001 value.
2002
2003 Set this attribute to change the trace's native byte order.
2004
2005 Defaults to the host machine's endianness.
2006
2007 :exc:`ValueError` is raised on error.
be5a4e67 2008 """
be5a4e67
PP
2009 raise NotImplementedError("Getter not implemented.")
2010
2011 @byte_order.setter
2012 def byte_order(self, byte_order):
c72a561f
JG
2013 try:
2014 self._w.trace.native_byte_order = _BYTE_ORDER_TO_BT2_BYTE_ORDER[byte_order]
2015 except:
40529d6d 2016 raise ValueError("Could not set trace byte order.")
c72a561f
JG
2017
2018
2019_BT2_FIELD_TYPE_TO_BT_DECLARATION = {
2020 bt2.IntegerFieldType: IntegerFieldDeclaration,
2021 bt2.FloatingPointNumberFieldType: FloatFieldDeclaration,
2022 bt2.EnumerationFieldType: EnumerationFieldDeclaration,
2023 bt2.StringFieldType: StringFieldDeclaration,
2024 bt2.StructureFieldType: StructureFieldDeclaration,
2025 bt2.ArrayFieldType: ArrayFieldDeclaration,
2026 bt2.SequenceFieldType: SequenceFieldDeclaration,
2027 bt2.VariantFieldType: VariantFieldDeclaration,
2028}
This page took 0.14506 seconds and 4 git commands to generate.