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