python: reimplement the babeltrace package as a bt2 wrapper
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 30 Aug 2017 20:01:57 +0000 (16:01 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 17 Sep 2017 17:58:06 +0000 (13:58 -0400)
This is how the old bindings work with the new bindings:

* A `babeltrace.TraceCollection` contains a set of
  `babeltrace.TraceHandle`, each of which only contains a CTF trace path
  and a generated ID, unique within the trace collection.

* When you call `babeltrace.TraceCollection.add_trace()`, the function
  makes sure that you're adding a single CTF trace. It creates a trace
  handle, adds it to the trace collection's set, and returns it.

* When you call `babeltrace.TraceCollection.remove_trace()`, the
  function removes the given trace handle from the trace collection's
  set.

* The `timestamp_begin()`, `timestamp_end()`, and `_has_intersection()`
  methods of `babeltrace.TraceHandle` perform the `trace-info` query
  with their path to retrieve the information.

* The `babeltrace.TraceHandle.events` property creates a `bt2` trace
  collection notification iterator, gets the first notification of the
  trace (which is expected to be a stream beginning notification), and
  finds the CTF IR trace object to generate all the event declarations
  from event classes using
  `babeltrace.reader_event_declaration._create_event_declaration()`.

* The `babeltrace.TraceCollection.events` property creates a `bt2` trace
  collection notification iterator, in stream intersection mode if
  needed, and with a beginning and end time if needed, and generates
  event objects using `babeltrace.reader_event._create_event()`.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
18 files changed:
bindings/python/Makefile.am
bindings/python/babeltrace/Makefile.am
bindings/python/babeltrace/__init__.py.in [deleted file]
bindings/python/babeltrace/babeltrace/__init__.py.in [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/common.py [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/reader.py [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/reader_event.py [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/reader_event_declaration.py [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/reader_field_declaration.py [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/reader_field_definition.py [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/reader_trace_collection.py [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/reader_trace_handle.py [new file with mode: 0644]
bindings/python/babeltrace/babeltrace/writer.py [new file with mode: 0644]
bindings/python/babeltrace/common.py [deleted file]
bindings/python/babeltrace/reader.py [deleted file]
bindings/python/babeltrace/setup.py.in [new file with mode: 0644]
bindings/python/babeltrace/writer.py [deleted file]
configure.ac

index f3cec072204e50156016b6423f948871ef0cdf08..fbc281304a401ff50f975b7284c364c7f9179beb 100644 (file)
@@ -1 +1 @@
-SUBDIRS = bt2
+SUBDIRS = bt2 babeltrace
index 1d693ae371245048d068e15d89619fe13e4c4ada..d766f4f320020a07e86ecc12018bb180347ba280 100644 (file)
@@ -1,29 +1,69 @@
-INIT_PY = __init__.py
-INIT_PY_IN = $(srcdir)/$(INIT_PY).in
+# Since the shared object used by the python bindings is not built with
+# libtool, we need to add the directory containing libbabeltrace to the
+# linker path.
+AM_LDFLAGS=-L$(top_builddir)/lib/.libs
 
-all-local: $(INIT_PY)
+INSTALLED_FILES=$(builddir)/installed_files.txt
 
-$(INIT_PY): $(INIT_PY_IN)
-       sed "s/BABELTRACE_VERSION_STR/$(PACKAGE_VERSION)/g" < $< > $@
+STATIC_BINDINGS_DEPS =                                         \
+       babeltrace/common.py                                    \
+       babeltrace/reader.py                                    \
+       babeltrace/reader_event_declaration.py  \
+       babeltrace/reader_event.py                              \
+       babeltrace/reader_field_declaration.py  \
+       babeltrace/reader_field_definition.py   \
+       babeltrace/reader_trace_collection.py   \
+       babeltrace/reader_trace_handle.py               \
+       babeltrace/writer.py
 
-EXTRA_DIST = common.py reader.py writer.py $(INIT_PY_IN)
-nodist_btpackage_PYTHON = $(INIT_PY) common.py reader.py writer.py
-SCRIPT_LIST = common.py reader.py writer.py
+GENERATED_BINDINGS_DEPS =              \
+       babeltrace/__init__.py                  \
+       setup.py
 
-btpackagedir = $(pythondir)/babeltrace
 
-CLEANFILES = $(INIT_PY)
+all-local: build-python-bindings.stamp
 
-all-local:
+copy-static-deps.stamp: $(STATIC_BINDINGS_DEPS)
        @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
-               for script in $(SCRIPT_LIST); do \
-                       cp -f $(srcdir)/$$script $(builddir); \
+               for file in $(STATIC_BINDINGS_DEPS); do \
+                       cp -f $(srcdir)/$$file $(builddir)/$$file; \
                done; \
        fi
+       touch $@
+
+build-python-bindings.stamp: copy-static-deps.stamp $(GENERATED_BINDINGS_DEPS)
+       $(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build_ext
+       $(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build
+       touch $@
+
+install-exec-local: build-python-bindings.stamp
+       @opts="--prefix=$(prefix) --record $(INSTALLED_FILES) --verbose --no-compile $(DISTSETUPOPTS)"; \
+       if [ "$(DESTDIR)" != "" ]; then \
+               opts="$$opts --root=$(DESTDIR)"; \
+       fi; \
+       $(PYTHON) $(builddir)/setup.py install $$opts;
 
 clean-local:
+       rm -rf $(builddir)/build
        @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
-               for script in $(SCRIPT_LIST); do \
-                       rm -f $(builddir)/$$script; \
+               for file in $(STATIC_BINDINGS_DEPS); do \
+                       rm -f $(builddir)/$$file; \
                done; \
        fi
+
+# Distutils' setup.py does not include an uninstall target, we thus need to do
+# it manually. We save the path of the files that were installed during the install target
+# and delete them during the uninstallation.
+uninstall-local:
+       if [ "$(DESTDIR)" != "" ]; then \
+               $(SED) -i "s|^|$(DESTDIR)/|g" $(INSTALLED_FILES); \
+       fi
+       cat $(INSTALLED_FILES) | xargs rm -rf || true
+       $(GREP) "__init__.py" $(INSTALLED_FILES) | xargs dirname | xargs rm -rf || true
+       rm -f $(INSTALLED_FILES)
+
+# distribute: extra Python modules and SWIG interface files
+EXTRA_DIST = $(STATIC_BINDINGS_DEPS)
+
+# clean: generated Python files and stamps
+CLEANFILES = babeltrace/__init__.py copy-static-deps.stamp
diff --git a/bindings/python/babeltrace/__init__.py.in b/bindings/python/babeltrace/__init__.py.in
deleted file mode 100644 (file)
index a1d4d17..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-# backward compatibility with old `babeltrace` module: import common members
-from .common import \
-    CTFStringEncoding, \
-    ByteOrder, \
-    CTFTypeId, \
-    CTFScope
-
-
-# backward compatibility with old `babeltrace` module: import reader API members
-from .reader import \
-    TraceCollection, \
-    TraceHandle, \
-    Event, \
-    FieldError, \
-    EventDeclaration, \
-    FieldDeclaration, \
-    IntegerFieldDeclaration, \
-    EnumerationFieldDeclaration, \
-    ArrayFieldDeclaration, \
-    SequenceFieldDeclaration, \
-    FloatFieldDeclaration, \
-    StructureFieldDeclaration, \
-    StringFieldDeclaration, \
-    VariantFieldDeclaration
-
-
-# backward compatibility with old `babeltrace` module: import CTF writer API
-# module as `CTFWriter`, since `CTFWriter` used to be a class in the
-# `babeltrace` module
-import babeltrace.writer as CTFWriter
-
-
-__version__ = 'BABELTRACE_VERSION_STR'
diff --git a/bindings/python/babeltrace/babeltrace/__init__.py.in b/bindings/python/babeltrace/babeltrace/__init__.py.in
new file mode 100644 (file)
index 0000000..d58185e
--- /dev/null
@@ -0,0 +1,33 @@
+# backward compatibility with old `babeltrace` module: import common members
+from .common import \
+    CTFStringEncoding, \
+    ByteOrder, \
+    CTFTypeId, \
+    CTFScope
+
+
+# backward compatibility with old `babeltrace` module: import reader API members
+from .reader import \
+    TraceCollection, \
+    TraceHandle, \
+    Event, \
+    FieldError, \
+    EventDeclaration, \
+    FieldDeclaration, \
+    IntegerFieldDeclaration, \
+    EnumerationFieldDeclaration, \
+    ArrayFieldDeclaration, \
+    SequenceFieldDeclaration, \
+    FloatFieldDeclaration, \
+    StructureFieldDeclaration, \
+    StringFieldDeclaration, \
+    VariantFieldDeclaration
+
+
+# backward compatibility with old `babeltrace` module: import CTF writer API
+# module as `CTFWriter`, since `CTFWriter` used to be a class in the
+# `babeltrace` module
+import babeltrace.writer as CTFWriter
+
+
+__version__ = '@PACKAGE_VERSION@'
diff --git a/bindings/python/babeltrace/babeltrace/common.py b/bindings/python/babeltrace/babeltrace/common.py
new file mode 100644 (file)
index 0000000..24e7e45
--- /dev/null
@@ -0,0 +1,163 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+class CTFStringEncoding:
+    """
+    CTF string encodings.
+    """
+
+    #: None
+    NONE = 0
+
+    #: UTF-8
+    UTF8 = 1
+
+    #: ASCII
+    ASCII = 2
+
+    #: Unknown
+    UNKNOWN = 3
+
+
+# Based on the enum in ctf-writer/writer.h
+class ByteOrder:
+    """
+    Byte orders.
+    """
+
+    #: Native byte order
+    BYTE_ORDER_NATIVE = 0
+
+    #: Little-endian
+    BYTE_ORDER_LITTLE_ENDIAN = 1
+
+    #: Big-endian
+    BYTE_ORDER_BIG_ENDIAN = 2
+
+    #: Network byte order (big-endian)
+    BYTE_ORDER_NETWORK = 3
+
+    #: Unknown byte order
+    BYTE_ORDER_UNKNOWN = 4  # Python-specific entry
+
+
+# enum equivalent, accessible constants
+# These are taken directly from ctf/events.h
+# All changes to enums must also be made here
+class CTFTypeId:
+    """
+    CTF numeric type identifiers.
+    """
+
+    #: Unknown type
+    UNKNOWN = 0
+
+    #: Integer
+    INTEGER = 1
+
+    #: Floating point number
+    FLOAT = 2
+
+    #: Enumeration
+    ENUM = 3
+
+    #: String
+    STRING = 4
+
+    #: Structure
+    STRUCT = 5
+
+    #: Untagged variant
+    UNTAGGED_VARIANT = 6
+
+    #: Variant
+    VARIANT = 7
+
+    #: Array
+    ARRAY = 8
+
+    #: Sequence
+    SEQUENCE = 9
+
+    NR_CTF_TYPES = 10
+
+    def type_name(id):
+        """
+        Returns the name of the CTF numeric type identifier *id*.
+        """
+
+        name = "UNKNOWN_TYPE"
+        constants = [
+            attr for attr in dir(CTFTypeId) if not callable(
+                getattr(
+                    CTFTypeId,
+                    attr)) and not attr.startswith("__")]
+
+        for attr in constants:
+            if getattr(CTFTypeId, attr) == id:
+                name = attr
+                break
+
+        return name
+
+
+class CTFScope:
+    """
+    CTF scopes.
+    """
+
+    #: Packet header
+    TRACE_PACKET_HEADER = 0
+
+    #: Packet context
+    STREAM_PACKET_CONTEXT = 1
+
+    #: Event header
+    STREAM_EVENT_HEADER = 2
+
+    #: Stream event context
+    STREAM_EVENT_CONTEXT = 3
+
+    #: Event context
+    EVENT_CONTEXT = 4
+
+    #: Event fields
+    EVENT_FIELDS = 5
+
+    def scope_name(scope):
+        """
+        Returns the name of the CTF scope *scope*.
+        """
+
+        name = "UNKNOWN_SCOPE"
+        constants = [
+            attr for attr in dir(CTFScope) if not callable(
+                getattr(
+                    CTFScope,
+                    attr)) and not attr.startswith("__")]
+
+        for attr in constants:
+            if getattr(CTFScope, attr) == scope:
+                name = attr
+                break
+
+        return name
diff --git a/bindings/python/babeltrace/babeltrace/reader.py b/bindings/python/babeltrace/babeltrace/reader.py
new file mode 100644 (file)
index 0000000..627cbd9
--- /dev/null
@@ -0,0 +1,34 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import babeltrace.common as common
+from babeltrace.reader_event_declaration import *
+from babeltrace.reader_event import *
+from babeltrace.reader_field_declaration import *
+from babeltrace.reader_field_definition import *
+from babeltrace.reader_trace_collection import *
+from babeltrace.reader_trace_handle import *
+
+# Based on enum bt_clock_type in clock-type.h
+class _ClockType:
+    CLOCK_CYCLES = 0
+    CLOCK_REAL = 1
diff --git a/bindings/python/babeltrace/babeltrace/reader_event.py b/bindings/python/babeltrace/babeltrace/reader_event.py
new file mode 100644 (file)
index 0000000..de2b23e
--- /dev/null
@@ -0,0 +1,351 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import bt2
+import babeltrace.common as common
+import babeltrace.reader_field_definition as field_definition
+import datetime
+import collections
+
+def _create_event(event_notification, trace_handle=None, trace_collection=None):
+    event = Event.__new__(Event)
+    event._event_notification = event_notification
+    event._trace_handle = trace_handle
+    event._trace_collection = trace_collection
+    return event
+
+class Event(collections.Mapping):
+    """
+    An :class:`Event` object represents a trace event. :class:`Event`
+    objects are returned by :attr:`TraceCollection.events` and are
+    not meant to be instantiated by the user.
+
+    :class:`Event` has a :class:`dict`-like interface for accessing
+    an event's field value by field name:
+
+    .. code-block:: python
+
+       event['my_field']
+
+    If a field name exists in multiple scopes, the value of the first
+    field found is returned. The scopes are searched in the following
+    order:
+
+    1. Event fields (:attr:`babeltrace.common.CTFScope.EVENT_FIELDS`)
+    2. Event context (:attr:`babeltrace.common.CTFScope.EVENT_CONTEXT`)
+    3. Stream event context (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_CONTEXT`)
+    4. Event header (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_HEADER`)
+    5. Packet context (:attr:`babeltrace.common.CTFScope.STREAM_PACKET_CONTEXT`)
+    6. Packet header (:attr:`babeltrace.common.CTFScope.TRACE_PACKET_HEADER`)
+
+    It is still possible to obtain a field's value from a specific
+    scope using :meth:`field_with_scope`.
+
+    Field values are returned as native Python types, that is:
+
+    +-----------------------+----------------------------------+
+    | Field type            | Python type                      |
+    +=======================+==================================+
+    | Integer               | :class:`int`                     |
+    +-----------------------+----------------------------------+
+    | Floating point number | :class:`float`                   |
+    +-----------------------+----------------------------------+
+    | Enumeration           | :class:`str` (enumeration label) |
+    +-----------------------+----------------------------------+
+    | String                | :class:`str`                     |
+    +-----------------------+----------------------------------+
+    | Array                 | :class:`list` of native Python   |
+    |                       | objects                          |
+    +-----------------------+----------------------------------+
+    | Sequence              | :class:`list` of native Python   |
+    |                       | objects                          |
+    +-----------------------+----------------------------------+
+    | Structure             | :class:`dict` mapping field      |
+    |                       | names to native Python objects   |
+    +-----------------------+----------------------------------+
+
+    For example, printing the third element of a sequence named ``seq``
+    in a structure named ``my_struct`` of the ``event``'s field named
+    ``my_field`` is done this way:
+
+    .. code-block:: python
+
+       print(event['my_field']['my_struct']['seq'][2])
+    """
+
+    def __init__(self):
+        raise NotImplementedError("Event cannot be instantiated")
+
+    @property
+    def name(self):
+        """
+        Event name or ``None`` on error.
+        """
+
+        try:
+            return self._event_notification.event.name
+        except bt2.Error:
+            pass
+
+    def _clock_value(self):
+        cc_prio_map = self._event_notification.clock_class_priority_map
+        clock_class = cc_prio_map.highest_priority_clock_class
+        if not clock_class:
+            return
+
+        return self._event_notification.event.clock_value(clock_class)
+
+    @property
+    def cycles(self):
+        """
+        Event timestamp in cycles or -1 on error.
+        """
+
+        try:
+            clock_value = self._clock_value()
+        except bt2.Error:
+            return -1
+
+        if clock_value is not None:
+            return clock_value.cycles
+        else:
+            return -1
+
+    @property
+    def timestamp(self):
+        """
+        Event timestamp (nanoseconds since Epoch).
+        """
+
+        try:
+            clock_value = self._clock_value()
+        except bt2.Error:
+            raise RuntimeError("Failed to get event timestamp")
+
+        if clock_value is not None:
+            return clock_value.ns_from_epoch
+        else:
+            raise RuntimeError("Failed to get event timestamp")
+
+    @property
+    def datetime(self):
+        """
+        Event timestamp as a standard :class:`datetime.datetime`
+        object.
+
+        Note that the :class:`datetime.datetime` class' precision
+        is limited to microseconds, whereas :attr:`timestamp` provides
+        the event's timestamp with a nanosecond resolution.
+        """
+
+        return datetime.date.fromtimestamp(self.timestamp / 1E9)
+
+    def field_with_scope(self, field_name, scope):
+        """
+        Returns the value of a field named *field_name* within the
+        scope *scope*, or ``None`` if the field cannot be found.
+
+        *scope* must be one of :class:`babeltrace.common.CTFScope`
+        constants.
+        """
+
+        if scope not in _SCOPES:
+            raise ValueError("Invalid scope provided")
+
+        field = self._field_with_scope(field_name, scope)
+
+        if field is not None:
+            return field.value
+
+    def field_list_with_scope(self, scope):
+        """
+        Returns a list of field names in the scope *scope*.
+        """
+
+        if scope not in _SCOPES:
+            raise ValueError("Invalid scope provided")
+
+        field_names = []
+
+        for field in self._field_list_with_scope(scope):
+            field_names.append(field.name)
+
+        return field_names
+
+    @property
+    def handle(self):
+        """
+        :class:`TraceHandle` object containing this event, or ``None``
+        on error.
+        """
+
+        try:
+            return self._trace_handle
+        except AttributeError:
+            return None
+
+    @property
+    def trace_collection(self):
+        """
+        :class:`TraceCollection` object containing this event, or
+        ``None`` on error.
+        """
+
+        try:
+            return self._trace_collection
+        except AttributeError:
+            return
+
+    def __getitem__(self, field_name):
+        field = self._field(field_name)
+        if field is None:
+            raise KeyError(field_name)
+        return field.value
+
+    def __iter__(self):
+        for key in self.keys():
+            yield key
+
+    def __len__(self):
+        count = 0
+        for scope in _SCOPES:
+            scope_field = self._get_scope_field(scope)
+            if scope_field is not None and isinstance(scope_field,
+                                                      bt2._StructureField):
+                count += len(scope_field)
+        return count
+
+    def __contains__(self, field_name):
+        return self._field(field_name) is not None
+
+    def keys(self):
+        """
+        Returns the list of field names.
+
+        Note: field names are unique within the returned list, although
+        a field name could exist in multiple scopes. Use
+        :meth:`field_list_with_scope` to obtain the list of field names
+        of a given scope.
+        """
+
+        field_names = set()
+
+        for scope in _SCOPES:
+            for name in self.field_list_with_scope(scope):
+                field_names.add(name)
+
+        return list(field_names)
+
+    def get(self, field_name, default=None):
+        """
+        Returns the value of the field named *field_name*, or *default*
+        when not found.
+
+        See :class:`Event` note about how fields are retrieved by
+        name when multiple fields share the same name in different
+        scopes.
+        """
+
+        field = self._field(field_name)
+
+        if field is None:
+            return default
+
+        return field.value
+
+    def items(self):
+        """
+        Generates pairs of (field name, field value).
+
+        This method iterates :meth:`keys` to find field names, which
+        means some fields could be unavailable if other fields share
+        their names in scopes with higher priorities.
+        """
+
+        for field in self.keys():
+            yield (field, self[field])
+
+    def _get_scope_field(self, scope):
+        try:
+            event = self._event_notification.event
+            if scope is common.CTFScope.EVENT_FIELDS:
+                return event.payload_field
+
+            if scope is common.CTFScope.EVENT_CONTEXT:
+                return event.context_field
+
+            if scope is common.CTFScope.STREAM_EVENT_CONTEXT:
+                return event.stream_event_context_field
+
+            if scope is common.CTFScope.STREAM_EVENT_HEADER:
+                return event.header_field
+
+            if scope is common.CTFScope.STREAM_PACKET_CONTEXT:
+                return event.packet.context_field
+
+            if scope is common.CTFScope.TRACE_PACKET_HEADER:
+                return event.packet.header_field
+        except bt2.Error:
+            return
+
+        raise ValueError("Invalid scope provided")
+
+    def _field_with_scope(self, field_name, scope):
+        scope_field = self._get_scope_field(scope)
+        if scope_field is not None:
+            try:
+                bt2_field = scope_field[field_name]
+                if bt2_field is not None:
+                    return field_definition._Definition(scope, bt2_field,
+                                                        field_name)
+            except (KeyError, bt2.Error):
+                return None
+
+    def _field(self, field_name):
+        for scope in _SCOPES:
+            field = self._field_with_scope(field_name, scope)
+            if field is not None:
+                return field
+
+    def _field_list_with_scope(self, scope):
+        fields = []
+        scope_field = self._get_scope_field(scope)
+
+        if scope_field is None or not isinstance(scope_field,
+                                                 bt2._StructureField):
+            return fields
+
+        for name, field in scope_field.items():
+            fields.append(field_definition._Definition(scope, field, name))
+
+        return fields
+
+
+# Priority of the scopes when searching for event fields
+_SCOPES = [
+    common.CTFScope.EVENT_FIELDS,
+    common.CTFScope.EVENT_CONTEXT,
+    common.CTFScope.STREAM_EVENT_CONTEXT,
+    common.CTFScope.STREAM_EVENT_HEADER,
+    common.CTFScope.STREAM_PACKET_CONTEXT,
+    common.CTFScope.TRACE_PACKET_HEADER
+]
diff --git a/bindings/python/babeltrace/babeltrace/reader_event_declaration.py b/bindings/python/babeltrace/babeltrace/reader_event_declaration.py
new file mode 100644 (file)
index 0000000..7959bf6
--- /dev/null
@@ -0,0 +1,149 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import bt2
+import babeltrace.common as common
+import babeltrace.reader_field_declaration as field_declaration
+import collections
+
+def _create_event_declaration(event_class):
+    event_declaration = EventDeclaration.__new__(EventDeclaration)
+    event_declaration._event_class = event_class
+    return event_declaration
+
+class EventDeclaration:
+    """
+    An event declaration contains the properties of a class of events,
+    that is, the common properties and fields layout of all the actual
+    recorded events associated with this declaration.
+
+    This class is not meant to be instantiated by the user. It is
+    returned by :attr:`TraceHandle.events`.
+    """
+    def __init__(self):
+        raise NotImplementedError("EventDeclaration cannot be instantiated")
+
+    def _get_scope_field_type(self, scope):
+        try:
+            ec = self._event_class
+            if scope is common.CTFScope.EVENT_FIELDS:
+                return ec.payload_field_type
+
+            if scope is common.CTFScope.EVENT_CONTEXT:
+                return ec.context_field_type
+
+            if scope is common.CTFScope.STREAM_EVENT_CONTEXT:
+                return ec.stream_class.event_context_field_type
+
+            if scope is common.CTFScope.STREAM_EVENT_HEADER:
+                return ec.stream_class.event_header_field_type
+
+            if scope is common.CTFScope.STREAM_PACKET_CONTEXT:
+                return ec.stream_class.packet_context_field_type
+
+            if scope is common.CTFScope.TRACE_PACKET_HEADER:
+                return ec.stream_class.trace.packet_header_field_type
+        except bt2.Error:
+            return
+
+        raise ValueError("Invalid scope provided")
+
+    @property
+    def name(self):
+        """
+        Event name, or ``None`` on error.
+        """
+
+        return self._event_class.name
+
+    @property
+    def id(self):
+        """
+        Event numeric ID, or -1 on error.
+        """
+
+        return self._event_class.id
+
+    @property
+    def fields(self):
+        """
+        Generates all the field declarations of this event, going
+        through each scope in the following order:
+
+        1. Event fields (:attr:`babeltrace.common.CTFScope.EVENT_FIELDS`)
+        2. Event context (:attr:`babeltrace.common.CTFScope.EVENT_CONTEXT`)
+        3. Stream event context (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_CONTEXT`)
+        4. Event header (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_HEADER`)
+        5. Packet context (:attr:`babeltrace.common.CTFScope.STREAM_PACKET_CONTEXT`)
+        6. Packet header (:attr:`babeltrace.common.CTFScope.TRACE_PACKET_HEADER`)
+
+        All the generated field declarations inherit
+        :class:`FieldDeclaration`, and are among:
+
+        * :class:`IntegerFieldDeclaration`
+        * :class:`FloatFieldDeclaration`
+        * :class:`EnumerationFieldDeclaration`
+        * :class:`StringFieldDeclaration`
+        * :class:`ArrayFieldDeclaration`
+        * :class:`SequenceFieldDeclaration`
+        * :class:`StructureFieldDeclaration`
+        * :class:`VariantFieldDeclaration`
+        """
+
+        for scope in _SCOPES:
+            for declaration in self.fields_scope(scope):
+                yield declaration
+
+    def fields_scope(self, scope):
+        """
+        Generates all the field declarations of the event's scope
+        *scope*.
+
+        *scope* must be one of :class:`babeltrace.common.CTFScope` constants.
+
+        All the generated field declarations inherit
+        :class:`FieldDeclaration`, and are among:
+
+        * :class:`IntegerFieldDeclaration`
+        * :class:`FloatFieldDeclaration`
+        * :class:`EnumerationFieldDeclaration`
+        * :class:`StringFieldDeclaration`
+        * :class:`ArrayFieldDeclaration`
+        * :class:`SequenceFieldDeclaration`
+        * :class:`StructureFieldDeclaration`
+        * :class:`VariantFieldDeclaration`
+        """
+
+        scope_field_type = self._get_scope_field_type(scope)
+        for name, field_type in scope_field_type.items():
+            yield field_declaration._create_field_declaration(field_type, name,
+                                                              scope)
+
+# Priority of the scopes when searching for event fields
+_SCOPES = [
+    common.CTFScope.EVENT_FIELDS,
+    common.CTFScope.EVENT_CONTEXT,
+    common.CTFScope.STREAM_EVENT_CONTEXT,
+    common.CTFScope.STREAM_EVENT_HEADER,
+    common.CTFScope.STREAM_PACKET_CONTEXT,
+    common.CTFScope.TRACE_PACKET_HEADER
+]
diff --git a/bindings/python/babeltrace/babeltrace/reader_field_declaration.py b/bindings/python/babeltrace/babeltrace/reader_field_declaration.py
new file mode 100644 (file)
index 0000000..6e6ef19
--- /dev/null
@@ -0,0 +1,340 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import bt2
+import babeltrace.common as common
+
+def _create_field_declaration(field_type, name, scope):
+    try:
+        if type(field_type) == bt2.IntegerFieldType:
+            declaration = IntegerFieldDeclaration.__new__(
+                IntegerFieldDeclaration)
+        elif type(field_type) == bt2.EnumerationFieldType:
+            declaration = EnumerationFieldDeclaration.__new__(
+                EnumerationFieldDeclaration)
+        elif type(field_type) == bt2.ArrayFieldType:
+            declaration = ArrayFieldDeclaration.__new__(
+                ArrayFieldDeclaration)
+        elif type(field_type) == bt2.SequenceFieldType:
+            declaration = SequenceFieldDeclaration.__new__(
+                SequenceFieldDeclaration)
+        elif type(field_type) == bt2.FloatingPointNumberFieldType:
+            declaration = FloatFieldDeclaration.__new__(
+                FloatFieldDeclaration)
+        elif type(field_type) == bt2.StructureFieldType:
+            declaration = StructureFieldDeclaration.__new__(
+                StructureFieldDeclaration)
+        elif type(field_type) == bt2.StringFieldType:
+            declaration = StringFieldDeclaration.__new__(
+                StringFieldDeclaration)
+        elif type(field_type) == bt2.VariantFieldType:
+            declaration = VariantFieldDeclaration.__new__(
+                VariantFieldDeclaration)
+        else:
+            return
+    except bt2.Error:
+        return
+
+    declaration._field_type = field_type
+    declaration._name = name
+    declaration._scope = scope
+    return declaration
+
+
+class FieldDeclaration:
+    """
+    Base class for concrete field declarations.
+
+    This class is not meant to be instantiated by the user.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("FieldDeclaration cannot be instantiated")
+
+    def __repr__(self):
+        return "({0}) {1} {2}".format(common.CTFScope.scope_name(self.scope),
+                                      common.CTFTypeId.type_name(self.type),
+                                      self.name)
+
+    @property
+    def name(self):
+        """
+        Field name, or ``None`` on error.
+        """
+
+        return self._name
+
+    @property
+    def type(self):
+        """
+        Field type (one of :class:`babeltrace.common.CTFTypeId`
+        constants).
+        """
+
+        return _OBJ_TO_TYPE_ID[type(self)]
+
+    @property
+    def scope(self):
+        """
+        Field scope (one of:class:`babeltrace.common.CTFScope`
+        constants).
+        """
+
+        return self._scope
+
+
+class IntegerFieldDeclaration(FieldDeclaration):
+    """
+    Integer field declaration.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("IntegerFieldDeclaration cannot be instantiated")
+
+    @property
+    def signedness(self):
+        """
+        0 if this integer is unsigned, 1 if signed, or -1 on error.
+        """
+
+        try:
+            if self._field_type.is_signed:
+                return 1
+            else:
+                return 0
+        except bt2.Error:
+            return -1
+
+    @property
+    def base(self):
+        """
+        Integer base (:class:`int`), or a negative value on error.
+        """
+
+        try:
+            return self._field_type.base
+        except AssertionError:
+            return -1
+
+    @property
+    def byte_order(self):
+        """
+        Integer byte order (one of
+        :class:`babeltrace.common.ByteOrder` constants).
+        """
+
+        try:
+            byte_order = self._field_type.byte_order
+        except AssertionError:
+            return common.ByteOrder.BYTE_ORDER_UNKNOWN
+
+        try:
+            return _BT2_BYTE_ORDER_TO_BYTE_ORDER[byte_order]
+        except KeyError:
+            return common.ByteOrder.BYTE_ORDER_UNKNOWN
+
+    @property
+    def size(self):
+        """
+        Integer size in bits, or a negative value on error.
+        """
+
+        try:
+            return self._field_type.size
+        except AssertionError:
+            return -1
+
+    @property
+    def length(self):
+        """
+        Integer size in bits, or a negative value on error.
+        """
+
+        return self.size
+
+    @property
+    def encoding(self):
+        """
+        Integer encoding (one of
+        :class:`babeltrace.common.CTFStringEncoding` constants).
+        """
+
+        try:
+            encoding = self._field_type.encoding
+        except bt2.Error:
+            return common.CTFStringEncoding.UNKNOWN
+
+        try:
+            return _BT2_ENCODING_TO_ENCODING[encoding]
+        except KeyError:
+            return common.CTFStringEncoding.UNKNOWN
+
+
+class EnumerationFieldDeclaration(FieldDeclaration):
+    """
+    Enumeration field declaration.
+
+    .. note::
+
+       As of this version, this class is missing some properties.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("EnumerationFieldDeclaration cannot be instantiated")
+
+
+class ArrayFieldDeclaration(FieldDeclaration):
+    """
+    Static array field declaration.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("ArrayFieldDeclaration cannot be instantiated")
+
+    @property
+    def length(self):
+        """
+        Fixed length of this static array (number of contained
+        elements), or a negative value on error.
+        """
+
+        try:
+            return self._field_type.length
+        except AssertionError:
+            return -1
+
+    @property
+    def element_declaration(self):
+        """
+        Field declaration of the underlying element.
+        """
+
+        try:
+            return _create_field_declaration(
+                self._field_type.element_field_type, name=None,
+                scope=self._scope)
+        except bt2.Error:
+            return
+
+
+class SequenceFieldDeclaration(FieldDeclaration):
+    """
+    Sequence (dynamic array) field declaration.
+
+    .. note::
+
+       As of this version, this class is missing some properties.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("SequenceFieldDeclaration cannot be instantiated")
+
+    @property
+    def element_declaration(self):
+        """
+        Field declaration of the underlying element.
+        """
+
+        try:
+            return _create_field_declaration(
+                self._field_type.element_field_type, name=None,
+                scope=self._scope)
+        except bt2.Error:
+            return
+
+
+class FloatFieldDeclaration(FieldDeclaration):
+    """
+    Floating point number field declaration.
+
+    .. note::
+
+       As of this version, this class is missing some properties.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("FloatFieldDeclaration cannot be instantiated")
+
+
+class StructureFieldDeclaration(FieldDeclaration):
+    """
+    Structure (ordered map of field names to field declarations) field
+    declaration.
+
+    .. note::
+
+       As of this version, this class is missing some properties.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("StructureFieldDeclaration cannot be instantiated")
+
+
+class StringFieldDeclaration(FieldDeclaration):
+    """
+    String (NULL-terminated array of bytes) field declaration.
+
+    .. note::
+
+       As of this version, this class is missing some properties.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("StringFieldDeclaration cannot be instantiated")
+
+
+class VariantFieldDeclaration(FieldDeclaration):
+    """
+    Variant (dynamic selection between different types) field declaration.
+
+    .. note::
+
+       As of this version, this class is missing some properties.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("VariantFieldDeclaration cannot be instantiated")
+
+
+_OBJ_TO_TYPE_ID = {
+    IntegerFieldDeclaration: common.CTFTypeId.INTEGER,
+    FloatFieldDeclaration: common.CTFTypeId.FLOAT,
+    EnumerationFieldDeclaration: common.CTFTypeId.ENUM,
+    StringFieldDeclaration: common.CTFTypeId.STRING,
+    StructureFieldDeclaration: common.CTFTypeId.STRUCT,
+    ArrayFieldDeclaration: common.CTFTypeId.ARRAY,
+    SequenceFieldDeclaration: common.CTFTypeId.SEQUENCE,
+    VariantFieldDeclaration: common.CTFTypeId.VARIANT,
+}
+
+_BT2_BYTE_ORDER_TO_BYTE_ORDER = {
+    bt2.ByteOrder.NATIVE: common.ByteOrder.BYTE_ORDER_NATIVE,
+    bt2.ByteOrder.LITTLE_ENDIAN: common.ByteOrder.BYTE_ORDER_LITTLE_ENDIAN,
+    bt2.ByteOrder.BIG_ENDIAN: common.ByteOrder.BYTE_ORDER_BIG_ENDIAN,
+    bt2.ByteOrder.NETWORK: common.ByteOrder.BYTE_ORDER_NETWORK,
+}
+
+_BT2_ENCODING_TO_ENCODING = {
+    bt2.Encoding.NONE: common.CTFStringEncoding.NONE,
+    bt2.Encoding.ASCII: common.CTFStringEncoding.ASCII,
+    bt2.Encoding.UTF8: common.CTFStringEncoding.UTF8,
+}
diff --git a/bindings/python/babeltrace/babeltrace/reader_field_definition.py b/bindings/python/babeltrace/babeltrace/reader_field_definition.py
new file mode 100644 (file)
index 0000000..1485e5b
--- /dev/null
@@ -0,0 +1,101 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import bt2
+import babeltrace.common as common
+import babeltrace.reader_field_declaration as reader_field_declaration
+
+class FieldError(Exception):
+    """
+    Field error, raised when the value of a field cannot be accessed.
+    """
+
+    def __init__(self, value):
+        self.value = value
+
+    def __str__(self):
+        return repr(self.value)
+
+class _Definition:
+    def __init__(self, scope_id, field, name):
+        self._scope_id = scope_id
+        self._field = field
+        self._name = name
+
+    @property
+    def name(self):
+        """Return the name of a field or None on error."""
+
+        return self._name
+
+    @property
+    def type(self):
+        """Return the type of a field or -1 if unknown."""
+
+        try:
+            return _OBJ_TO_TYPE_ID[type(self._field)]
+        except KeyError:
+            return -1
+
+    @property
+    def declaration(self):
+        """Return the associated Definition object."""
+
+        return reader_field_declaration._create_field_declaration(
+            self._field.field_type, self._name, self.scope)
+
+    @property
+    def value(self):
+        """
+        Return the value associated with the field according to its type.
+        Return None on error.
+        """
+
+        try:
+            if type(self._field) in (bt2._ArrayField, bt2._SequenceField):
+                elem_ft = self._field.field_type.element_field_type
+
+                if type(elem_ft) is bt2.IntegerFieldType:
+                    if elem_ft.size == 8 and elem_ft.encoding != bt2.Encoding.NONE:
+                        return bytes(x for x in self._field._value if x != 0).decode()
+
+            return self._field._value
+        except bt2.Error:
+            return
+
+    @property
+    def scope(self):
+        """Return the scope of a field or None on error."""
+
+        return self._scope_id
+
+
+_OBJ_TO_TYPE_ID = {
+    bt2._IntegerField: common.CTFTypeId.INTEGER,
+    bt2._FloatingPointNumberField: common.CTFTypeId.FLOAT,
+    bt2._EnumerationField: common.CTFTypeId.ENUM,
+    bt2._StringField: common.CTFTypeId.STRING,
+    bt2._StructureField: common.CTFTypeId.STRUCT,
+    bt2._ArrayField: common.CTFTypeId.ARRAY,
+    bt2._SequenceField: common.CTFTypeId.SEQUENCE,
+    bt2._VariantField: common.CTFTypeId.VARIANT,
+}
diff --git a/bindings/python/babeltrace/babeltrace/reader_trace_collection.py b/bindings/python/babeltrace/babeltrace/reader_trace_collection.py
new file mode 100644 (file)
index 0000000..d888f8d
--- /dev/null
@@ -0,0 +1,201 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import bt2
+import babeltrace.common as common
+from babeltrace import reader_trace_handle
+from babeltrace import reader_event
+import os
+
+
+class TraceCollection:
+    """
+    A :class:`TraceCollection` is a collection of opened traces.
+
+    Once a trace collection is created, you can add traces to the
+    collection by using the :meth:`add_trace` or
+    :meth:`add_traces_recursive`, and then iterate on the merged
+    events using :attr:`events`.
+
+    You may use :meth:`remove_trace` to close and remove a specific
+    trace from a trace collection.
+    """
+
+    def __init__(self, intersect_mode=False):
+        """
+        Creates an empty trace collection.
+        """
+
+        self._intersect_mode = intersect_mode
+        self._trace_handles = set()
+        self._next_th_id = 0
+        self._ctf_plugin = bt2.find_plugin('ctf')
+        assert(self._ctf_plugin is not None)
+        self._fs_comp_cls = self._ctf_plugin.source_component_classes['fs']
+
+    def add_trace(self, path, format_str):
+        """
+        Adds a trace to the trace collection.
+
+        *path* is the exact path of the trace on the filesystem.
+
+        *format_str* is a string indicating the type of trace to
+        add. ``ctf`` is currently the only supported trace format.
+
+        Returns the corresponding :class:`TraceHandle` instance for
+        this opened trace on success, or ``None`` on error.
+
+        This function **does not** recurse directories to find a
+        trace.  See :meth:`add_traces_recursive` for a recursive
+        version of this function.
+        """
+
+        if format_str != 'ctf':
+            raise ValueError('only the "ctf" format is supported')
+
+        if not os.path.isfile(os.path.join(path, 'metadata')):
+            raise ValueError('no "metadata" file found in "{}"'.format(path))
+
+        th = reader_trace_handle.TraceHandle.__new__(reader_trace_handle.TraceHandle)
+        th._id = self._next_th_id
+        self._next_th_id += 1
+        th._trace_collection = self
+        th._path = path
+        self._trace_handles.add(th)
+        return th
+
+    def add_traces_recursive(self, path, format_str):
+        """
+        Adds traces to this trace collection by recursively searching
+        in the *path* directory.
+
+        *format_str* is a string indicating the type of trace to add.
+        ``ctf`` is currently the only supported trace format.
+
+        Returns a :class:`dict` object mapping full paths to trace
+        handles for each trace found, or ``None`` on error.
+
+        See also :meth:`add_trace`.
+        """
+
+        trace_handles = {}
+        noTrace = True
+        error = False
+
+        for fullpath, dirs, files in os.walk(path):
+            if "metadata" in files:
+                trace_handle = self.add_trace(fullpath, format_str)
+
+                if trace_handle is None:
+                    error = True
+                    continue
+
+                trace_handles[fullpath] = trace_handle
+                noTrace = False
+
+        if noTrace and error:
+            return None
+
+        return trace_handles
+
+    def remove_trace(self, handle):
+        """
+        Removes a trace from the trace collection using its trace
+        handle *trace_handle*.
+
+        :class:`TraceHandle` objects are returned by :meth:`add_trace`
+        and :meth:`add_traces_recursive`.
+        """
+
+        if not isinstance(handle, reader_trace_handle.TraceHandle):
+            raise TypeError("'{}' is not a 'TraceHandle' object".format(
+                handle.__class__.__name__))
+
+        # this can raise but it would mean the trace handle is not part
+        # of this trace collection anyway
+        self._trace_handles.remove(handle)
+
+    @property
+    def intersect_mode(self):
+        return self._intersect_mode
+
+    @property
+    def has_intersection(self):
+        return any(th._has_intersection for th in self._trace_handles)
+
+    @property
+    def events(self):
+        """
+        Generates the ordered :class:`Event` objects of all the opened
+        traces contained in this trace collection.
+        """
+
+        return self._gen_events()
+
+    def events_timestamps(self, timestamp_begin, timestamp_end):
+        """
+        Generates the ordered :class:`Event` objects of all the opened
+        traces contained in this trace collection from *timestamp_begin*
+        to *timestamp_end*.
+
+        *timestamp_begin* and *timestamp_end* are given in nanoseconds
+        since Epoch.
+
+        See :attr:`events` for notes and limitations.
+        """
+
+        return self._gen_events(timestamp_begin / 1e9, timestamp_end / 1e9)
+
+    def _gen_events(self, begin_s=None, end_s=None):
+        specs = [bt2.SourceComponentSpec('ctf', 'fs', th.path) for th in self._trace_handles]
+
+        try:
+            iter_cls = bt2.TraceCollectionNotificationIterator
+            tc_iter = iter_cls(specs,
+                               stream_intersection_mode=self._intersect_mode,
+                               begin=begin_s, end=end_s,
+                               notification_types=[bt2.EventNotification])
+            return map(reader_event._create_event, tc_iter)
+        except:
+            raise ValueError
+
+    @property
+    def timestamp_begin(self):
+        """
+        Begin timestamp of this trace collection (nanoseconds since Epoch).
+        """
+
+        if not self._trace_handles:
+            return
+
+        return min(th.timestamp_begin for th in self._trace_handles)
+
+    @property
+    def timestamp_end(self):
+        """
+        End timestamp of this trace collection (nanoseconds since Epoch).
+        """
+
+        if not self._trace_handles:
+            return
+
+        return max(th.timestamp_end for th in self._trace_handles)
diff --git a/bindings/python/babeltrace/babeltrace/reader_trace_handle.py b/bindings/python/babeltrace/babeltrace/reader_trace_handle.py
new file mode 100644 (file)
index 0000000..07c36bb
--- /dev/null
@@ -0,0 +1,137 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import bt2
+import itertools
+from babeltrace import reader_event_declaration
+
+
+class TraceHandle:
+    """
+    A :class:`TraceHandle` is a handle allowing the user to manipulate
+    a specific trace directly. It is a unique identifier representing a
+    trace, and is not meant to be instantiated by the user.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("TraceHandle cannot be instantiated")
+
+    def __repr__(self):
+        # TODO print an id or some information about component / query result?
+        return "Babeltrace TraceHandle: trace_id('{0}')".format(self._id)
+
+    def __hash__(self):
+        return hash((self.path, self.id))
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        return (self.path, self.id) == (other.path, other.id)
+
+    @property
+    def id(self):
+        """
+        Numeric ID of this trace handle.
+        """
+
+        return self._id
+
+    @property
+    def path(self):
+        """
+        Path of the underlying trace.
+        """
+
+        return self._path
+
+    def _query_trace_info(self):
+        try:
+            result = bt2.QueryExecutor().query(self._trace_collection._fs_comp_cls,
+                                               'trace-info', {'path': self._path})
+        except:
+            raise ValueError
+
+        assert(len(result) == 1)
+        return result
+
+    @property
+    def timestamp_begin(self):
+        """
+        Buffers creation timestamp (nanoseconds since Epoch) of the
+        underlying trace.
+        """
+
+        result = self._query_trace_info()
+
+        try:
+            return int(result[0]['range-ns']['begin'])
+        except:
+            raise ValueError
+
+    @property
+    def timestamp_end(self):
+        """
+        Buffers destruction timestamp (nanoseconds since Epoch) of the
+        underlying trace.
+        """
+
+        result = self._query_trace_info()
+
+        try:
+            return int(result[0]['range-ns']['end'])
+        except:
+            raise ValueError
+
+    @property
+    def _has_intersection(self):
+        result = self._query_trace_info()
+
+        try:
+            return 'intersection-range-ns' in result[0]
+        except:
+            raise ValueError
+
+    def _get_event_declarations(self):
+        notif_iter = bt2.TraceCollectionNotificationIterator([
+            bt2.SourceComponentSpec('ctf', 'fs', self._path)
+        ])
+
+        # raises if the trace contains no streams
+        first_notif = next(notif_iter)
+        assert(type(first_notif) is bt2.StreamBeginningNotification)
+        trace = first_notif.stream.stream_class.trace
+        ec_iters = [sc.values() for sc in trace.values()]
+        return map(reader_event_declaration._create_event_declaration,
+                   itertools.chain(*ec_iters))
+
+    @property
+    def events(self):
+        """
+        Generates all the :class:`EventDeclaration` objects of the
+        underlying trace.
+        """
+
+        try:
+            return self._get_event_declarations()
+        except:
+            return
diff --git a/bindings/python/babeltrace/babeltrace/writer.py b/bindings/python/babeltrace/babeltrace/writer.py
new file mode 100644 (file)
index 0000000..7936f4f
--- /dev/null
@@ -0,0 +1,2003 @@
+# writer.py
+#
+# Babeltrace writer interface Python module
+#
+# Copyright 2012-2017 EfficiOS Inc.
+#
+# Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import babeltrace.common as common
+import bt2
+
+class EnumerationMapping:
+    """
+    Mapping from an enumeration label to a range of integers.
+    """
+
+    def __init__(self, name, start, end):
+        """
+        Creates an enumeration mapping, where label *name* is mapped to
+        the [*start*, *end*] range of integers (*end* is included).
+
+        Set *start* and *end* to the same value to create an enumeration
+        mapping to a single value.
+        """
+
+        self._enum_mapping = bt2._EnumerationFieldTypeMapping(self, start, end)
+
+    @property
+    def name(self):
+        return self._enum_mapping.name
+
+    @property
+    def start(self):
+        return self._enum_mapping.lower
+
+    @property
+    def end(self):
+        return self._enum_mapping.upper
+
+
+class Clock:
+    """
+    A CTF clock allows the description of the system's clock topology, as
+    well as the definition of each clock's parameters.
+
+    :class:`Clock` objects must be registered to a :class:`Writer`
+    object (see :meth:`Writer.add_clock`), as well as be registered to
+    a :class:`StreamClass` object (see :attr:`StreamClass.clock`).
+    """
+
+    def __init__(self, name):
+        """
+        Creates a default CTF clock named *name*.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            self._clock = bt2.CtfWriterClock(name)
+        except:
+            raise ValueError("Invalid clock name.")
+        assert self._clock
+
+    @property
+    def name(self):
+        """
+        Clock name.
+
+        Set this attribute to change the clock's name.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._clock.name
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @property
+    def description(self):
+        """
+        Clock description (string).
+
+        Set this attribute to change the clock's description.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._clock.description
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @description.setter
+    def description(self, desc):
+        try:
+            self._clock.description = desc
+        except:
+            raise ValueError("Invalid clock description.")
+
+    @property
+    def frequency(self):
+        """
+        Clock frequency in Hz (integer).
+
+        Set this attribute to change the clock's frequency.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._clock.frequency
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @frequency.setter
+    def frequency(self, freq):
+        try:
+            self._clock.frequency = freq
+        except:
+            raise ValueError("Invalid frequency value.")
+
+    @property
+    def precision(self):
+        """
+        Clock precision in clock ticks (integer).
+
+        Set this attribute to change the clock's precision.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._clock.precision
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @precision.setter
+    def precision(self, precision):
+        try:
+            self._clock.precision = precision
+        except:
+            raise ValueError("Invalid precision value.")
+
+    @property
+    def offset_seconds(self):
+        """
+        Clock offset in seconds since POSIX.1 Epoch (integer).
+
+        Set this attribute to change the clock's offset in seconds.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._clock.offset.seconds
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @offset_seconds.setter
+    def offset_seconds(self, offset_s):
+        try:
+            self._clock.offset = bt2.ClockClassOffet(offset_s,
+                                                     self._clock.offset.cycles)
+        except:
+            raise ValueError("Invalid offset value.")
+
+    @property
+    def offset(self):
+        """
+        Clock offset in ticks since (POSIX.1 Epoch +
+        :attr:`offset_seconds`).
+
+        Set this attribute to change the clock's offset.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._clock.offset.cycles
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @offset.setter
+    def offset(self, offset):
+        try:
+            self._clock.offset = bt2.ClockClassOffet(
+                self._clock.offset.seconds, offset)
+        except:
+            raise ValueError("Invalid offset value.")
+
+    @property
+    def absolute(self):
+        """
+        ``True`` if this clock is absolute, i.e. if the clock is a
+        global reference across the other clocks of the trace.
+
+        Set this attribute to change the clock's absolute state
+        (boolean).
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._clock.is_absolute
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @absolute.setter
+    def absolute(self, is_absolute):
+        try:
+            self._clock.is_absolute = is_absolute
+        except:
+            raise ValueError("Could not set the clock absolute attribute.")
+
+    @property
+    def uuid(self):
+        """
+        Clock UUID (an :class:`uuid.UUID` object).
+
+        Set this attribute to change the clock's UUID.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._clock.uuid
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @uuid.setter
+    def uuid(self, uuid):
+        uuid_bytes = uuid.bytes
+
+        if len(uuid_bytes) != 16:
+            raise ValueError(
+                "Invalid UUID provided. UUID length must be 16 bytes")
+
+        try:
+            self._clock.uuid = uuid
+        except:
+            raise ValueError("Invalid clock instance.")
+
+    @property
+    def time(self):
+        """
+        Clock current time; nanoseconds (integer) since clock origin
+        (POSIX.1 Epoch + :attr:`offset_seconds` + :attr:`offset`).
+
+        Set this attribute to change the clock's current time.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        raise NotImplementedError("Getter not implemented.")
+
+    @time.setter
+    def time(self, time):
+        try:
+            self._clock.time = time
+        except:
+            raise ValueError("Invalid time value.")
+
+
+class IntegerBase:
+    """
+    Display base of an integer.
+    """
+
+    #: Unknown
+    UNKNOWN = -1
+
+    #: Binary
+    BIN = 2
+
+    #: Octal
+    OCT = 8
+
+    #: Decimal
+    DEC = 10
+
+    #: Hexadecimal
+    HEX = 16
+
+    # keep this for backward compatibility
+    INTEGER_BASE_UNKNOWN = -1
+    INTEGER_BASE_BINARY = 2
+    INTEGER_BASE_OCTAL = 8
+    INTEGER_BASE_DECIMAL = 10
+    INTEGER_BASE_HEXADECIMAL = 16
+
+
+_BT2_BYTE_ORDER_TO_BYTE_ORDER = {
+    bt2.ByteOrder.NATIVE: common.ByteOrder.BYTE_ORDER_NATIVE,
+    bt2.ByteOrder.LITTLE_ENDIAN: common.ByteOrder.BYTE_ORDER_LITTLE_ENDIAN,
+    bt2.ByteOrder.BIG_ENDIAN: common.ByteOrder.BYTE_ORDER_BIG_ENDIAN,
+    bt2.ByteOrder.NETWORK: common.ByteOrder.BYTE_ORDER_NETWORK,
+}
+
+_BYTE_ORDER_TO_BT2_BYTE_ORDER = {
+    common.ByteOrder.BYTE_ORDER_NATIVE: bt2.ByteOrder.NATIVE,
+    common.ByteOrder.BYTE_ORDER_LITTLE_ENDIAN: bt2.ByteOrder.LITTLE_ENDIAN,
+    common.ByteOrder.BYTE_ORDER_BIG_ENDIAN: bt2.ByteOrder.BIG_ENDIAN,
+    common.ByteOrder.BYTE_ORDER_NETWORK: bt2.ByteOrder.NETWORK,
+}
+
+_BT2_ENCODING_TO_ENCODING = {
+    bt2.Encoding.NONE: common.CTFStringEncoding.NONE,
+    bt2.Encoding.ASCII: common.CTFStringEncoding.ASCII,
+    bt2.Encoding.UTF8: common.CTFStringEncoding.UTF8,
+}
+
+_ENCODING_TO_BT2_ENCODING = {
+    common.CTFStringEncoding.NONE: bt2.Encoding.NONE,
+    common.CTFStringEncoding.ASCII: bt2.Encoding.ASCII,
+    common.CTFStringEncoding.UTF8: bt2.Encoding.UTF8,
+}
+
+class FieldDeclaration:
+    """
+    Base class of all field declarations. This class is not meant to
+    be instantiated by the user; use one of the concrete field
+    declaration subclasses instead.
+    """
+
+    class IntegerBase(IntegerBase):
+        pass
+
+    def __init__(self):
+        if self._ft is None:
+            raise ValueError("FieldDeclaration creation failed.")
+
+    @staticmethod
+    def _create_field_declaration(field_type):
+
+        if type(field_type) not in _BT2_FIELD_TYPE_TO_BT_DECLARATION:
+            raise TypeError("Invalid field declaration instance.")
+
+        declaration = Field.__new__(Field)
+        declaration._ft = field_type
+        declaration.__class__ = _BT2_FIELD_TYPE_TO_BT_DECLARATION[
+            type(field_type)]
+        return declaration
+
+    @property
+    def alignment(self):
+        """
+        Field alignment in bits (integer).
+
+        Set this attribute to change this field's alignment.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._ft.alignment
+        except:
+            raise ValueError(
+                "Could not get alignment field declaration attribute.")
+
+    @alignment.setter
+    def alignment(self, alignment):
+        try:
+            self._ft.alignment = alignment
+        except:
+            raise ValueError("Invalid alignment value.")
+
+    @property
+    def byte_order(self):
+        """
+        Field byte order (one of :class:`babeltrace.common.ByteOrder`
+        constants).
+
+        Set this attribute to change this field's byte order.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return _BT2_BYTE_ORDER_TO_BYTE_ORDER[self._ft.byte_order]
+        except:
+            raise ValueError(
+                "Could not get byte order field declaration attribute.")
+
+    @byte_order.setter
+    def byte_order(self, byte_order):
+        try:
+            self._ft.byte_order = _BYTE_ORDER_TO_BT2_BYTE_ORDER[byte_order]
+        except:
+            raise ValueError("Could not set byte order value.")
+
+
+class _EncodingProp:
+    @property
+    def encoding(self):
+        """
+        Integer encoding (one of
+        :class:`babeltrace.common.CTFStringEncoding` constants).
+
+        Set this attribute to change this field's encoding.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return _BT2_ENCODING_TO_ENCODING[self._ft.encoding]
+        except:
+            raise ValueError("Could not get field encoding.")
+
+    @encoding.setter
+    def encoding(self, encoding):
+        try:
+            self._ft.encoding = _ENCODING_TO_BT2_ENCODING[encoding]
+        except:
+            raise ValueError("Could not set field encoding.")
+
+
+class IntegerFieldDeclaration(FieldDeclaration, _EncodingProp):
+    """
+    Integer field declaration.
+    """
+
+    def __init__(self, size):
+        """
+        Creates an integer field declaration of size *size* bits.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        self._ft = bt2.IntegerFieldType(size)
+        super().__init__()
+
+    @property
+    def size(self):
+        """
+        Integer size in bits (integer).
+
+        Set this attribute to change this integer's size.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._ft.size
+        except:
+            raise ValueError("Could not get Integer size attribute.")
+
+    @property
+    def signed(self):
+        """
+        ``True`` if this integer is signed.
+
+        Set this attribute to change this integer's signedness
+        (boolean).
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._ft.is_signed
+        except:
+            raise ValueError("Could not get Integer signed attribute.")
+
+    @signed.setter
+    def signed(self, signed):
+        try:
+            self._ft.is_signed = signed
+        except:
+            raise ValueError("Could not set Integer signed attribute.")
+
+    @property
+    def base(self):
+        """
+        Integer display base (one of :class:`IntegerBase` constants).
+
+        Set this attribute to change this integer's display base.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._ft.base
+        except:
+            raise ValueError("Could not get Integer base attribute.")
+
+    @base.setter
+    def base(self, base):
+        try:
+            self._ft.base = base
+        except:
+            raise ValueError("Could not set Integer base.")
+
+
+class EnumerationFieldDeclaration(FieldDeclaration):
+    """
+    Enumeration field declaration. A CTF enumeration maps labels to
+    ranges of integers.
+    """
+
+    def __init__(self, integer_type):
+        """
+        Creates an enumeration field declaration, with *integer_type*
+        being the underlying :class:`IntegerFieldDeclaration` for storing
+        the integer.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        isinst = isinstance(integer_type, IntegerFieldDeclaration)
+
+        if integer_type is None or not isinst:
+            raise TypeError("Invalid integer container.")
+
+        self._ft = bt2.EnumerationFieldType(integer_type._ft)
+        super().__init__()
+
+    @property
+    def container(self):
+        """
+        Underlying container (:class:`IntegerFieldDeclaration`).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return FieldDeclaration._create_field_declaration(
+                self._ft.integer_field_type)
+        except:
+            raise TypeError("Invalid enumeration declaration")
+
+    def add_mapping(self, name, range_start, range_end):
+        """
+        Adds a mapping to the enumeration field declaration, from the
+        label named *name* to range [*range_start*, *range_end*], where
+        *range_start* and *range_end* are integers included in the
+        range.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            self._ft.append_mapping(name, range_start, range_end)
+        except:
+            raise ValueError(
+                "Could not add mapping to enumeration declaration.")
+
+    @property
+    def mappings(self):
+        """
+        Generates the mappings of this enumeration field declaration
+        (:class:`EnumerationMapping` objects).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        for mapping in self._ft:
+            yield EnumerationMapping(mapping.name, mapping.lower,
+                                     mapping.upper)
+
+    def get_mapping_by_name(self, name):
+        """
+        Returns the :class:`EnumerationMapping` object for the label
+        named *name*.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            mappings = list(self._ft.mappings_by_name(name))
+        except:
+            raise TypeError(
+                'Could not get enumeration mappings by name \'{}\''.format(
+                    name))
+
+        if not mappings:
+            return None
+
+        mapping = mappings[0]
+        return EnumerationMapping(mapping.name, mapping.lower, mapping.upper)
+
+    def get_mapping_by_value(self, value):
+        """
+        Returns the :class:`EnumerationMapping` object for the value
+        *value* (integer).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            mappings = list(self._ft.mappings_by_value(value))
+        except:
+            raise TypeError(
+                'Could not get enumeration mappings by value \'{}\''.format(
+                    value))
+
+        if not mappings:
+            return None
+
+        mapping = mappings[0]
+        return EnumerationMapping(mapping.name, mapping.lower, mapping.upper)
+
+
+class FloatingPointFieldDeclaration(FieldDeclaration):
+    """
+    Floating point number field declaration.
+
+    A CTF floating point number is a made of three sections: the sign
+    bit, the exponent bits, and the mantissa bits. The most significant
+    bit of the resulting binary word is the sign bit, and is included
+    in the number of mantissa bits.
+
+    For example, the
+    `IEEE 754 <http://en.wikipedia.org/wiki/IEEE_floating_point>`_
+    single precision floating point number is represented on a 32-bit
+    word using an 8-bit exponent (``e``) and a 24-bit mantissa (``m``),
+    the latter count including the sign bit (``s``)::
+
+        s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
+
+    The IEEE 754 double precision floating point number uses an
+    11-bit exponent and a 53-bit mantissa.
+    """
+
+    #: IEEE 754 single precision floating point number exponent size
+    FLT_EXP_DIG = 8
+
+    #: IEEE 754 double precision floating point number exponent size
+    DBL_EXP_DIG = 11
+
+    #: IEEE 754 single precision floating point number mantissa size
+    FLT_MANT_DIG = 24
+
+    #: IEEE 754 double precision floating point number mantissa size
+    DBL_MANT_DIG = 53
+
+    def __init__(self):
+        """
+        Creates a floating point number field declaration.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        self._ft = bt2.FloatingPointNumberFieldType()
+        super().__init__()
+
+    @property
+    def exponent_digits(self):
+        """
+        Floating point number exponent section size in bits (integer).
+
+        Set this attribute to change the floating point number's
+        exponent section's size. You may use :attr:`FLT_EXP_DIG` or
+        :attr:`DBL_EXP_DIG` for IEEE 754 floating point numbers.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._ft.exponent_size
+        except:
+            raise TypeError(
+                "Could not get Floating point exponent digit count")
+
+
+    @exponent_digits.setter
+    def exponent_digits(self, exponent_digits):
+        try:
+            self._ft.exponent_size = exponent_digits
+        except:
+            raise ValueError("Could not set exponent digit count.")
+
+    @property
+    def mantissa_digits(self):
+        """
+        Floating point number mantissa section size in bits (integer).
+
+        Set this attribute to change the floating point number's
+        mantissa section's size. You may use :attr:`FLT_MANT_DIG` or
+        :attr:`DBL_MANT_DIG` for IEEE 754 floating point numbers.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._ft.mantissa_size
+        except:
+            raise TypeError(
+                "Could not get Floating point mantissa digit count")
+
+
+    @mantissa_digits.setter
+    def mantissa_digits(self, mantissa_digits):
+        try:
+            self._ft.mantissa_size = mantissa_digits
+        except:
+            raise ValueError("Could not set mantissa digit count.")
+
+
+class FloatFieldDeclaration(FloatingPointFieldDeclaration):
+    pass
+
+
+class StructureFieldDeclaration(FieldDeclaration):
+    """
+    Structure field declaration, i.e. an ordered mapping from field
+    names to field declarations.
+    """
+
+    def __init__(self):
+        """
+        Creates an empty structure field declaration.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        self._ft = bt2.StructureFieldType()
+        super().__init__()
+
+    def add_field(self, field_type, field_name):
+        """
+        Appends one :class:`FieldDeclaration` *field_type* named
+        *field_name* to the structure's ordered map.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            self._ft.append_field(field_name, field_type._ft)
+        except:
+            raise ValueError("Could not add field to structure.")
+
+    @property
+    def fields(self):
+        """
+        Generates the (field name, :class:`FieldDeclaration`) pairs
+        of this structure.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        for name, field_type in self._ft.items():
+            yield (name,
+                   FieldDeclaration._create_field_declaration(
+                       field_type))
+
+    def get_field_by_name(self, name):
+        """
+        Returns the :class:`FieldDeclaration` mapped to the field name
+        *name* in this structure.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        if name not in self._ft:
+            msg = "Could not find Structure field with name {}".format(name)
+            raise TypeError(msg)
+
+        field_type = self._ft[name]
+        return FieldDeclaration._create_field_declaration(
+            field_type)
+
+
+class VariantFieldDeclaration(FieldDeclaration):
+    """
+    Variant field declaration.
+
+    A CTF variant is a dynamic selection between different fields.
+    The value of a *tag* (a CTF enumeration) determines what is the
+    current selected field. All the possible fields must be added to
+    its field declaration before using an actual variant field.
+    """
+
+    def __init__(self, enum_tag, tag_name):
+        """
+        Creates an empty variant field declaration with tag field
+        declaration *enum_tag* (instance of
+        :class:`EnumerationFieldDeclaration`) named *tag_name*
+        (string).
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        isinst = isinstance(enum_tag, EnumerationFieldDeclaration)
+        if enum_tag is None or not isinst:
+            raise TypeError("Invalid tag type; must be of type EnumerationFieldDeclaration.")
+
+        self._ft = bt2.VariantFieldType(tag_name=tag_name,
+                                        tag_field_type=enum_tag._ft)
+        super().__init__()
+
+    @property
+    def tag_name(self):
+        """
+        Variant field declaration tag name.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            self._ft.tag_name
+        except:
+            raise TypeError("Could not get Variant tag name")
+
+    @property
+    def tag_type(self):
+        """
+        Variant field declaration tag field declaration
+        (:class:`EnumerationFieldDeclaration` object).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return FieldDeclaration._create_field_declaration(
+                self._ft.tag_field_type)
+        except:
+            raise TypeError("Could not get Variant tag type")
+
+    def add_field(self, field_type, field_name):
+        """
+        Registers the :class:`FieldDeclaration` object *field_type*
+        as the variant's selected type when the variant's tag's current
+        label is *field_name*.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            self._ft.append_field(name=field_name, field_type=field_type._ft)
+        except:
+            raise ValueError("Could not add field to variant.")
+
+    @property
+    def fields(self):
+        """
+        Generates the (field name, :class:`FieldDeclaration`) pairs
+        of this variant field declaration.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        for name, member in self._ft.items():
+            yield (name, FieldDeclaration._create_field_declaration(member))
+
+    def get_field_by_name(self, name):
+        """
+        Returns the :class:`FieldDeclaration` selected when the
+        variant's tag's current label is *name*.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        if name not in self._ft:
+            raise TypeError(
+                'Could not find Variant field with name {}'.format(name))
+
+        field_type = self._ft[name]
+        return FieldDeclaration._create_field_declaration(field_type)
+
+    def get_field_from_tag(self, tag):
+        """
+        Returns the :class:`FieldDeclaration` selected by the current
+        label of the :class:`EnumerationField` *tag*.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return create_field(self).field(tag).declaration
+        except:
+            raise TypeError('Could not get Variant field declaration.')
+
+
+class ArrayFieldDeclaration(FieldDeclaration):
+    """
+    Static array field declaration.
+    """
+
+    def __init__(self, element_type, length):
+        """
+        Creates a static array field declaration of *length*
+        elements of type *element_type* (:class:`FieldDeclaration`).
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            self._ft = bt2.ArrayFieldType(element_type._ft, length)
+        except:
+            raise ValueError('Failed to create ArrayFieldDeclaration.')
+        super().__init__()
+
+    @property
+    def element_type(self):
+        """
+        Type of the elements of this this static array (subclass of
+        :class:`FieldDeclaration`).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return FieldDeclaration._create_field_declaration(
+                self._ft.element_field_type)
+        except:
+            raise TypeError("Could not get Array element type")
+
+    @property
+    def length(self):
+        """
+        Length of this static array (integer).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return self._ft.length
+        except:
+            raise TypeError("Could not get Array length")
+
+
+class SequenceFieldDeclaration(FieldDeclaration):
+    """
+    Sequence (dynamic array) field declaration.
+    """
+
+    def __init__(self, element_type, length_field_name):
+        """
+        Creates a sequence field declaration of
+        elements of type *element_type* (:class:`FieldDeclaration`).
+        The length of a sequence field based on this sequence field
+        declaration is obtained by retrieving the dynamic integer
+        value of the field named *length_field_name*.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            self._ft = bt2.SequenceFieldType(element_type, length_field_name)
+        except:
+            raise ValueError('Failed to create SequenceFieldDeclaration.')
+        super().__init__()
+
+    @property
+    def element_type(self):
+        """
+        Type of the elements of this sequence (subclass of
+        :class:`FieldDeclaration`).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return FieldDeclaration._create_field_declaration(
+                self._ft.element_field_type)
+        except:
+            raise TypeError("Could not get Sequence element type")
+
+    @property
+    def length_field_name(self):
+        """
+        Name of the integer field defining the dynamic length of
+        sequence fields based on this sequence field declaration.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return self._ft.length_name
+        except:
+            raise TypeError("Could not get Sequence element type")
+
+
+class StringFieldDeclaration(FieldDeclaration, _EncodingProp):
+    """
+    String (NULL-terminated array of bytes) field declaration.
+    """
+
+    def __init__(self):
+        """
+        Creates a string field declaration.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        self._ft = bt2.StringFieldType()
+        super().__init__()
+
+
+@staticmethod
+def create_field(field_type):
+    """
+    Create an instance of a field.
+    """
+    isinst = isinstance(field_type, FieldDeclaration)
+
+    if field_type is None or not isinst:
+        raise TypeError("Invalid field_type. Type must be a FieldDeclaration-derived class.")
+
+    if isinstance(field_type, IntegerFieldDeclaration):
+        return IntegerField(field_type)
+    elif isinstance(field_type, EnumerationFieldDeclaration):
+        return EnumerationField(field_type)
+    elif isinstance(field_type, FloatFieldDeclaration):
+        return FloatingPointField(field_type)
+    elif isinstance(field_type, StructureFieldDeclaration):
+        return StructureField(field_type)
+    elif isinstance(field_type, VariantFieldDeclaration):
+        return VariantField(field_type)
+    elif isinstance(field_type, ArrayFieldDeclaration):
+        return ArrayField(field_type)
+    elif isinstance(field_type, SequenceFieldDeclaration):
+        return SequenceField(field_type)
+    elif isinstance(field_type, StringFieldDeclaration):
+        return StringField(field_type)
+
+
+class Field:
+    """
+    Base class of all fields. This class is not meant to be
+    instantiated by the user, and neither are its subclasses. Use
+    :meth:`Event.payload` to access specific, concrete fields of
+    an event.
+    """
+
+    def __init__(self, field_type):
+        if not isinstance(field_type, FieldDeclaration):
+            raise TypeError("Invalid field_type argument.")
+
+        try:
+            self._f = field_type._ft()
+        except:
+            raise ValueError("Field creation failed.")
+
+    @staticmethod
+    def _create_field(bt2_field):
+        type_dict = {
+            bt2._IntegerField: IntegerField,
+            bt2._FloatingPointNumberField: FloatingPointField,
+            bt2._EnumerationField: EnumerationField,
+            bt2._StringField: StringField,
+            bt2._StructureField: StructureField,
+            bt2._VariantField: VariantField,
+            bt2._ArrayField: ArrayField,
+            bt2._SequenceField: SequenceField
+        }
+
+        if type(bt2_field) not in type_dict:
+            raise TypeError("Invalid field instance.")
+
+        field = Field.__new__(Field)
+        field._f = bt2_field
+        field.__class__ = type_dict[type(bt2_field)]
+
+        return field
+
+    @property
+    def declaration(self):
+        """
+        Field declaration (subclass of :class:`FieldDeclaration`).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        return FieldDeclaration._create_field_declaration(self._f.field_type)
+
+
+class IntegerField(Field):
+    """
+    Integer field, based on an :class:`IntegerFieldDeclaration` object.
+    """
+
+    @property
+    def value(self):
+        """
+        Integer value (:class:`int`).
+
+        Set this attribute to change the integer field's value.
+
+        :exc:`ValueError` or :exc:`TypeError` are raised on error.
+        """
+
+        try:
+            return int(self._f)
+        except:
+            ValueError('Could not get integer field value.')
+
+    @value.setter
+    def value(self, value):
+        try:
+            self._f = value
+        except:
+            raise ValueError("Could not set integer field value.")
+
+
+class EnumerationField(Field):
+    """
+    Enumeration field, based on an
+    :class:`EnumerationFieldDeclaration` object.
+    """
+
+    @property
+    def container(self):
+        """
+        Underlying container (:class:`IntegerField`).
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return Field._create_field(self._f.integer_field)
+        except:
+            raise TypeError("Invalid enumeration field type.")
+
+    @property
+    def value(self):
+        """
+        Current label of this enumeration field (:class:`str`).
+
+        Set this attribute to an integer (:class:`int`) to change the
+        enumeration field's value.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            bt2_enum_ft = self._f.field_type
+            mappings = list(bt2_enum_ft.mappings_by_value(self._f.value))
+            return mappings[0].name
+        except:
+            raise ValueError("Could not get enumeration mapping name.")
+
+    @value.setter
+    def value(self, value):
+        if not isinstance(value, int):
+            raise TypeError("EnumerationField value must be an int")
+
+        self._f.value = value
+
+
+class FloatingPointField(Field):
+    """
+    Floating point number field, based on a
+    :class:`FloatingPointFieldDeclaration` object.
+    """
+
+    @property
+    def value(self):
+        """
+        Floating point number value (:class:`float`).
+
+        Set this attribute to change the floating point number field's
+        value.
+
+        :exc:`ValueError` or :exc:`TypeError` are raised on error.
+        """
+
+        try:
+            float(self._f)
+        except:
+            raise ValueError("Could not get floating point field value.")
+
+    @value.setter
+    def value(self, value):
+        try:
+            self._f.value = value
+        except:
+            raise ValueError("Could not set floating point field value.")
+
+
+# This class is provided to ensure backward-compatibility since a stable
+# release publicly exposed this... abomination.
+class FloatFieldingPoint(FloatingPointField):
+    pass
+
+
+class StructureField(Field):
+    """
+    Structure field, based on a
+    :class:`StructureFieldDeclaration` object.
+    """
+
+    def field(self, field_name):
+        """
+        Returns the structure :class:`Field` named *field_name*.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            Field._create_field(self._f[field_name])
+        except:
+            raise ValueError("Invalid field_name provided.")
+
+
+class VariantField(Field):
+    """
+    Variant field, based on a
+    :class:`VariantFieldDeclaration` object.
+    """
+
+    def field(self, tag):
+        """
+        Returns the :class:`Field` selected by the current label of
+        *tag* (:class:`EnumerationField`).
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return Field._create_field(self._f.field(tag._f))
+        except:
+            raise ValueError("Invalid tag provided.")
+
+
+class ArrayField(Field):
+    """
+    Static array field, based on an
+    :class:`ArrayFieldDeclaration` object.
+    """
+
+    def field(self, index):
+        """
+        Returns the :class:`Field` at index *index* in this static
+        array.
+
+        :exc:`IndexError` is raised on error.
+        """
+
+        try:
+            return Field._create_field(self._f[index])
+        except:
+            raise IndexError("Invalid index provided.")
+
+
+class SequenceField(Field):
+    """
+    Sequence (dynamic array) field, based on a
+    :class:`SequenceFieldDeclaration` object.
+    """
+
+    @property
+    def length(self):
+        """
+        Sequence length (:class:`IntegerField`).
+
+        Set this attribute to change the sequence length's integer
+        field (integer must be unsigned).
+
+        :exc:`ValueError` or :exc:`TypeError` are raised on error.
+        """
+
+        try:
+            length_field = self._f.length_field
+            if length_field is None:
+                return
+            return Field._create_field(length_field)
+        except:
+            raise ValueError('Invalid sequence field.')
+
+    @length.setter
+    def length(self, length_field):
+        if not isinstance(length_field, IntegerField):
+            raise TypeError("Invalid length field.")
+
+        if length_field.declaration.signed:
+            raise TypeError("Sequence field length must be unsigned")
+
+        try:
+            self._f.length_field = length_field._f
+        except:
+            raise ValueError("Could not set sequence length.")
+
+    def field(self, index):
+        """
+        Returns the :class:`Field` at index *index* in this sequence.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return Field._create_field(self._f[index])
+        except:
+            raise IndexError("Invalid index provided.")
+
+
+class StringField(Field):
+    """
+    String (NULL-terminated array of bytes) field.
+    """
+
+    @property
+    def value(self):
+        """
+        String value (:class:`str`).
+
+        Set this attribute to change the string's value.
+
+        :exc:`ValueError` or :exc:`TypeError` are raised on error.
+        """
+
+        try:
+            str(self._f)
+        except:
+            raise ValueError('Could not get string field value.')
+
+    @value.setter
+    def value(self, value):
+        try:
+            self._f.value = value
+        except:
+            raise ValueError("Could not set string field value.")
+
+
+class EventClass:
+    """
+    An event class contains the properties of specific
+    events (:class:`Event`). Any concrete event must be linked with an
+    :class:`EventClass`.
+
+    Some attributes are automatically set when creating an event class.
+    For example, if no numeric ID is explicitly set using the
+    :attr:`id` attribute, a default, unique ID within the stream class
+    containing this event class will be created when needed.
+    """
+
+    def __init__(self, name):
+        """
+        Creates an event class named *name*.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        self._ec = bt2.EventClass(name)
+
+        if self._ec is None:
+            raise ValueError("Event class creation failed.")
+
+    def add_field(self, field_type, field_name):
+        """
+        Adds a field declaration *field_type* named *field_name* to
+        this event class.
+
+        *field_type* must be one of:
+
+        * :class:`IntegerFieldDeclaration`
+        * :class:`FloatingPointFieldDeclaration`
+        * :class:`EnumerationFieldDeclaration`
+        * :class:`StringFieldDeclaration`
+        * :class:`ArrayFieldDeclaration`
+        * :class:`SequenceFieldDeclaration`
+        * :class:`StructureFieldDeclaration`
+        * :class:`VariantFieldDeclaration`
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            self._ec.payload_field_type.append_field(field_name,
+                                                     field_type._ft)
+        except:
+            raise ValueError("Could not add field to event class.")
+
+    @property
+    def name(self):
+        """
+        Event class' name.
+        """
+
+        try:
+            return self._ec.name
+        except:
+            raise TypeError("Could not get EventClass name")
+
+    @property
+    def id(self):
+        """
+        Event class' numeric ID.
+
+        Set this attribute to assign a numeric ID to this event class.
+        This ID must be unique amongst all the event class IDs of a
+        given stream class.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return self._ec.id
+        except:
+            raise TypeError("Could not get EventClass id")
+
+    @id.setter
+    def id(self, id):
+        try:
+            self._ec.id = id
+        except:
+            raise TypeError("Can't change an EventClass id after it has been assigned to a stream class.")
+
+    @property
+    def stream_class(self):
+        """
+        :class:`StreamClass` object containing this event class,
+        or ``None`` if not set.
+        """
+
+        bt2_stream_class = self._ec.stream_class
+        if bt2_stream_class is None:
+            return
+
+        stream_class = StreamClass.__new__(StreamClass)
+        stream_class._sc = bt2_stream_class
+
+        return stream_class
+
+    @property
+    def fields(self):
+        """
+        Generates the (field name, :class:`FieldDeclaration`) pairs of
+        this event class.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        return FieldDeclaration._create_field_declaration(
+            self._ec.payload_field_type).fields
+
+    def get_field_by_name(self, name):
+        """
+        Returns the :class:`FieldDeclaration` object named *name* in
+        this event class.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        return FieldDeclaration._create_field_declaration(
+            self._ec.payload_field_type)[name]
+
+
+class Event:
+    """
+    Events are specific instances of event classes
+    (:class:`EventClass`), which means they may contain actual,
+    concrete field values.
+    """
+
+    def __init__(self, event_class):
+        """
+        Creates an event linked with the :class:`EventClass`
+        *event_class*.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        if not isinstance(event_class, EventClass):
+            raise TypeError("Invalid event_class argument.")
+
+        try:
+            self._e = event_class._ec()
+        except:
+            raise ValueError("Event creation failed.")
+
+    @property
+    def event_class(self):
+        """
+        :class:`EventClass` object to which this event is linked.
+        """
+
+        event_class = EventClass.__new__(EventClass)
+        event_class._ec = self._e.event_class
+        return event_class
+
+    def clock(self):
+        """
+        :class:`Clock` object used by this object, or ``None`` if
+        the event class is not registered to a stream class.
+        """
+
+        try:
+            bt2_clock = self._e.event_class.stream_class.clock
+        except:
+            return
+
+        clock = Clock.__new__(Clock)
+        clock._c = bt2_clock
+        return clock
+
+    def payload(self, field_name):
+        """
+        Returns the :class:`Field` object named *field_name* in this
+        event.
+
+        The returned field object is created using the event class'
+        field declaration named *field_name*.
+
+        The return type is one of:
+
+        * :class:`IntegerField`
+        * :class:`FloatingPointField`
+        * :class:`EnumerationField`
+        * :class:`StringField`
+        * :class:`ArrayField`
+        * :class:`SequenceField`
+        * :class:`StructureField`
+        * :class:`VariantField`
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return Field._create_field(self._e.payload_field[field_name])
+        except:
+            raise TypeError('Could not get field from event.')
+
+    def set_payload(self, field_name, value_field):
+        """
+        Set the event's field named *field_name* to the manually
+        created :class:`Field` object *value_field*.
+
+        *value_field*'s type must be one of:
+
+        * :class:`IntegerField`
+        * :class:`FloatingPointField`
+        * :class:`EnumerationField`
+        * :class:`StringField`
+        * :class:`ArrayField`
+        * :class:`SequenceField`
+        * :class:`StructureField`
+        * :class:`VariantField`
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        if not isinstance(value_field, Field):
+            raise TypeError("Invalid value type.")
+
+        try:
+            self._e.payload_field[field_name] = value_field._f
+        except:
+            raise ValueError("Could not set event field payload.")
+
+    @property
+    def stream_context(self):
+        """
+        Stream event context field (instance of
+        :class:`StructureField`).
+
+        Set this attribute to assign a stream event context field
+        to this stream.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return Field._create_field(self._e.context_field)
+        except:
+            raise ValueError("Invalid Stream.")
+
+    @stream_context.setter
+    def stream_context(self, field):
+        if not isinstance(field, StructureField):
+            raise TypeError("Argument field must be of type StructureField")
+
+        try:
+            self._e.context_field = field._f
+        except:
+            raise ValueError("Invalid stream context field.")
+
+class StreamClass:
+    """
+    A stream class contains the properties of specific
+    streams (:class:`Stream`). Any concrete stream must be linked with
+    a :class:`StreamClass`, usually by calling
+    :meth:`Writer.create_stream`.
+
+    Some attributes are automatically set when creating a stream class.
+    For example, if no clock is explicitly set using the
+    :attr:`clock` attribute, a default clock will be created
+    when needed.
+    """
+
+    def __init__(self, name):
+        """
+        Creates a stream class named *name*.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            self._sc = bt2.StreamClass()
+        except:
+            raise ValueError("Stream class creation failed.")
+
+    @property
+    def name(self):
+        """
+        Stream class' name.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        try:
+            return self._sc.name
+        except:
+            raise TypeError("Could not get StreamClass name")
+
+    @property
+    def clock(self):
+        """
+        Stream class' clock (:class:`Clock` object).
+
+        Set this attribute to change the clock of this stream class.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        if self._sc.clock is None:
+            return
+
+        clock = Clock.__new__(Clock)
+        clock._c = self._sc.clock
+        return clock
+
+    @clock.setter
+    def clock(self, clock):
+        if not isinstance(clock, Clock):
+            raise TypeError("Invalid clock type.")
+
+        try:
+            self._sc.clock = clock._c
+        except:
+            raise ValueError("Could not set stream class clock.")
+
+    @property
+    def id(self):
+        """
+        Stream class' numeric ID.
+
+        Set this attribute to change the ID of this stream class.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._sc.id
+        except:
+            raise TypeError("Could not get StreamClass id")
+
+    @id.setter
+    def id(self, id):
+        try:
+            self._sc.id = id
+        except:
+            raise TypeError("Could not set stream class id.")
+
+    @property
+    def event_classes(self):
+        """
+        Generates the event classes (:class:`EventClass` objects) of
+        this stream class.
+
+        :exc:`TypeError` is raised on error.
+        """
+
+        for bt2_ec in self._sc.values():
+            event_class = EventClass.__new__(EventClass)
+            event_class._ec = bt2_ec
+            yield event_class
+
+    def add_event_class(self, event_class):
+        """
+        Registers the :class:`EventClass` *event_class* to this stream
+        class.
+
+        Once the event class is registered, it will be generated as one
+        of the event classes generated by :attr:`event_classes`.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        if not isinstance(event_class, EventClass):
+            raise TypeError("Invalid event_class type.")
+
+        try:
+            self._sc.add_event_class(event_class._ec)
+        except:
+            raise ValueError("Could not add event class.")
+
+    @property
+    def packet_context_type(self):
+        """
+        Stream packet context declaration.
+
+        Set this attribute to change the stream packet context
+        declaration (must be an instance of
+        :class:`StructureFieldDeclaration`).
+
+        :exc:`ValueError` is raised on error.
+
+        """
+
+        try:
+            bt2_field_type = self._sc.packet_context_field_type
+            if bt2_field_type is None:
+                raise ValueError("Invalid StreamClass")
+
+            field_type = FieldDeclaration._create_field_declaration(
+                bt2_field_type)
+            return field_type
+        except:
+            raise ValueError("Invalid StreamClass")
+
+    @packet_context_type.setter
+    def packet_context_type(self, field_type):
+        if not isinstance(field_type, StructureFieldDeclaration):
+            raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
+
+        try:
+            self._sc.packet_context_field_type = field_type._ft
+        except:
+            raise ValueError("Failed to set packet context type.")
+
+    @property
+    def event_context_type(self):
+        """
+        Stream event context declaration.
+
+        Set this attribute to change the stream event context
+        declaration (must be an instance of
+        :class:`StructureFieldDeclaration`).
+
+        :exc:`ValueError` is raised on error.
+
+        """
+
+        try:
+            bt2_field_type = self._sc.event_context_field_type
+            if bt2_field_type is None:
+                raise ValueError("Invalid StreamClass")
+
+            field_type = FieldDeclaration._create_field_declaration(
+                bt2_field_type)
+            return field_type
+        except:
+            raise ValueError("Invalid StreamClass")
+
+    @event_context_type.setter
+    def event_context_type(self, field_type):
+        if not isinstance(field_type, StructureFieldDeclaration):
+            raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
+
+        try:
+            self._sc.event_context_field_type = field_type._ft
+        except:
+            raise ValueError("Failed to set event context type.")
+
+
+class Stream:
+    """
+    Streams are specific instances of stream classes, which means they
+    may contain actual, concrete events.
+
+    :class:`Stream` objects are returned by
+    :meth:`Writer.create_stream`; they are not meant to be
+    instantiated by the user.
+
+    Concrete :class:`Event` objects are appended to
+    :class:`Stream` objects using :meth:`append_event`.
+
+    When :meth:`flush` is called, a CTF packet is created, containing
+    all the appended events since the last flush. Although the stream
+    is flushed on object destruction, it is **strongly recommended**
+    that the user call :meth:`flush` manually before exiting the
+    script, as :meth:`__del__` is not always reliable.
+    """
+
+    def __init__(self):
+        raise NotImplementedError("Stream cannot be instantiated; use Writer.create_stream()")
+
+    @property
+    def discarded_events(self):
+        """
+        Number of discarded (lost) events in this stream so far.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        try:
+            return self._s.discarded_events_count
+        except:
+            raise ValueError("Could not get the stream discarded events count")
+
+    def append_discarded_events(self, event_count):
+        """
+        Appends *event_count* discarded events to this stream.
+        """
+
+        self._s.append_discarded_events(event_count)
+
+    def append_event(self, event):
+        """
+        Appends event *event* (:class:`Event` object) to this stream.
+
+        The stream's associated clock will be sampled during this call.
+        *event* **shall not** be modified after being appended to this
+        stream.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        ret = nbt._bt_ctf_stream_append_event(self._s, event._e)
+
+        if ret < 0:
+            raise ValueError("Could not append event to stream.")
+
+    @property
+    def packet_context(self):
+        """
+        Stream packet context field (instance of
+        :class:`StructureField`).
+
+        Set this attribute to assign a stream packet context field
+        to this stream.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        bt2_field = self._s.packet_context_field
+        if bt2_field is None:
+            raise ValueError("Invalid Stream.")
+
+        return Field._create_field(bt2_field)
+
+    @packet_context.setter
+    def packet_context(self, field):
+        if not isinstance(field, StructureField):
+            raise TypeError("Argument field must be of type StructureField")
+
+        try:
+            self._s.packet_context_field = field._f
+        except:
+            raise ValueError("Invalid packet context field.")
+
+    def flush(self):
+        """
+        Flushes the current packet of this stream to disk. Events
+        subsequently appended to the stream will be added to a new
+        packet.
+
+        :exc:`ValueError` is raised on error.
+        """
+
+        self._s.flush()
+
+
+class Writer:
+    """
+    This object is the CTF writer API context. It oversees its streams
+    and clocks, and is responsible for writing one CTF trace.
+    """
+
+    def __init__(self, path):
+        """
+        Creates a CTF writer, initializing a new CTF trace at path
+        *path*.
+
+        *path* must be an existing directory, since a CTF trace is
+        made of multiple files.
+
+        :exc:`ValueError` is raised if the creation fails.
+        """
+
+        try:
+            self._w = bt2.CtfWriter(path)
+        except:
+            raise ValueError("Writer creation failed.")
+
+    def create_stream(self, stream_class):
+        """
+        Creates and registers a new stream based on stream class
+        *stream_class*.
+
+        This is the standard way of creating a :class:`Stream` object:
+        the user is not allowed to instantiate this class.
+
+        Returns a new :class:`Stream` object.
+        """
+
+        if not isinstance(stream_class, StreamClass):
+            raise TypeError("Invalid stream_class type.")
+
+        if stream_class.sc.trace is None:
+            self._w.trace.add_stream_class(stream_class._sc)
+
+        stream = Stream.__new__(Stream)
+        stream._s = stream_class._sc()
+        return stream
+
+    def add_environment_field(self, name, value):
+        """
+        Sets the CTF environment variable named *name* to value *value*
+        (converted to a string).
+
+        :exc:`ValueError` or `TypeError` is raised on error.
+        """
+
+        if type(name) != str:
+            raise TypeError("Field name must be a string.")
+
+        t = type(value)
+
+        if type(value) != str and type(value) != int:
+            raise TypeError("Value type is not supported.")
+
+        try:
+            self._w.trace.env += {name: value}
+        except:
+            raise ValueError("Could not add environment field to trace.")
+
+    def add_clock(self, clock):
+        """
+        Registers :class:`Clock` object *clock* to the writer.
+
+        You *must* register CTF clocks assigned to stream classes
+        to the writer.
+
+        :exc:`ValueError` is raised if the creation fails.
+        """
+
+        try:
+            self._w.trace.add_clock(clock._c)
+        except:
+            raise ValueError("Could not add clock to Writer.")
+
+    @property
+    def metadata(self):
+        """
+        Current metadata of this trace (:class:`str`).
+        """
+
+        return self._w.metadata_string
+
+    def flush_metadata(self):
+        """
+        Flushes the trace's metadata to the metadata file.
+        """
+
+        self._w.flush_metadata()
+
+    @property
+    def byte_order(self):
+        """
+        Native byte order of this trace (one of
+        :class:`babeltrace.common.ByteOrder` constants).
+
+        This is the actual byte order that is used when a field
+        declaration has the
+        :attr:`babeltrace.common.ByteOrder.BYTE_ORDER_NATIVE`
+        value.
+
+        Set this attribute to change the trace's native byte order.
+
+        Defaults to the host machine's endianness.
+
+        :exc:`ValueError` is raised on error.
+        """
+        raise NotImplementedError("Getter not implemented.")
+
+    @byte_order.setter
+    def byte_order(self, byte_order):
+        try:
+            self._w.trace.native_byte_order = _BYTE_ORDER_TO_BT2_BYTE_ORDER[byte_order]
+        except:
+            raise ValueError("Could not set trace byte order.")
+
+
+_BT2_FIELD_TYPE_TO_BT_DECLARATION = {
+    bt2.IntegerFieldType: IntegerFieldDeclaration,
+    bt2.FloatingPointNumberFieldType: FloatFieldDeclaration,
+    bt2.EnumerationFieldType: EnumerationFieldDeclaration,
+    bt2.StringFieldType: StringFieldDeclaration,
+    bt2.StructureFieldType: StructureFieldDeclaration,
+    bt2.ArrayFieldType: ArrayFieldDeclaration,
+    bt2.SequenceFieldType: SequenceFieldDeclaration,
+    bt2.VariantFieldType: VariantFieldDeclaration,
+}
diff --git a/bindings/python/babeltrace/common.py b/bindings/python/babeltrace/common.py
deleted file mode 100644 (file)
index 466f2c6..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-# common.py
-#
-# Babeltrace Python module common definitions
-#
-# Copyright 2012-2015 EfficiOS Inc.
-#
-# Author: Danny Serres <danny.serres@efficios.com>
-# Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-
-class CTFStringEncoding:
-    """
-    CTF string encodings.
-    """
-
-    #: None
-    NONE = 0
-
-    #: UTF-8
-    UTF8 = 1
-
-    #: ASCII
-    ASCII = 2
-
-    #: Unknown
-    UNKNOWN = 3
-
-
-# Based on the enum in ctf-writer/writer.h
-class ByteOrder:
-    """
-    Byte orders.
-    """
-
-    #: Native byte order
-    BYTE_ORDER_NATIVE = 0
-
-    #: Little-endian
-    BYTE_ORDER_LITTLE_ENDIAN = 1
-
-    #: Big-endian
-    BYTE_ORDER_BIG_ENDIAN = 2
-
-    #: Network byte order (big-endian)
-    BYTE_ORDER_NETWORK = 3
-
-    #: Unknown byte order
-    BYTE_ORDER_UNKNOWN = 4  # Python-specific entry
-
-
-# enum equivalent, accessible constants
-# These are taken directly from ctf/events.h
-# All changes to enums must also be made here
-class CTFTypeId:
-    """
-    CTF numeric type identifiers.
-    """
-
-    #: Unknown type
-    UNKNOWN = 0
-
-    #: Integer
-    INTEGER = 1
-
-    #: Floating point number
-    FLOAT = 2
-
-    #: Enumeration
-    ENUM = 3
-
-    #: String
-    STRING = 4
-
-    #: Structure
-    STRUCT = 5
-
-    #: Untagged variant
-    UNTAGGED_VARIANT = 6
-
-    #: Variant
-    VARIANT = 7
-
-    #: Array
-    ARRAY = 8
-
-    #: Sequence
-    SEQUENCE = 9
-
-    NR_CTF_TYPES = 10
-
-    def type_name(id):
-        """
-        Returns the name of the CTF numeric type identifier *id*.
-        """
-
-        name = "UNKNOWN_TYPE"
-        constants = [
-            attr for attr in dir(CTFTypeId) if not callable(
-                getattr(
-                    CTFTypeId,
-                    attr)) and not attr.startswith("__")]
-
-        for attr in constants:
-            if getattr(CTFTypeId, attr) == id:
-                name = attr
-                break
-
-        return name
-
-
-class CTFScope:
-    """
-    CTF scopes.
-    """
-
-    #: Packet header
-    TRACE_PACKET_HEADER = 0
-
-    #: Packet context
-    STREAM_PACKET_CONTEXT = 1
-
-    #: Event header
-    STREAM_EVENT_HEADER = 2
-
-    #: Stream event context
-    STREAM_EVENT_CONTEXT = 3
-
-    #: Event context
-    EVENT_CONTEXT = 4
-
-    #: Event fields
-    EVENT_FIELDS = 5
-
-    def scope_name(scope):
-        """
-        Returns the name of the CTF scope *scope*.
-        """
-
-        name = "UNKNOWN_SCOPE"
-        constants = [
-            attr for attr in dir(CTFScope) if not callable(
-                getattr(
-                    CTFScope,
-                    attr)) and not attr.startswith("__")]
-
-        for attr in constants:
-            if getattr(CTFScope, attr) == scope:
-                name = attr
-                break
-
-        return name
diff --git a/bindings/python/babeltrace/reader.py b/bindings/python/babeltrace/reader.py
deleted file mode 100644 (file)
index 7756db1..0000000
+++ /dev/null
@@ -1,1266 +0,0 @@
-# reader.py
-#
-# Babeltrace reader interface Python module
-#
-# Copyright 2012-2015 EfficiOS Inc.
-#
-# Author: Danny Serres <danny.serres@efficios.com>
-# Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import babeltrace.nativebt as nbt
-import babeltrace.common as common
-import collections
-import os
-from datetime import datetime
-
-
-class TraceCollection:
-    """
-    A :class:`TraceCollection` is a collection of opened traces.
-
-    Once a trace collection is created, you can add traces to the
-    collection by using the :meth:`add_trace` or
-    :meth:`add_traces_recursive`, and then iterate on the merged
-    events using :attr:`events`.
-
-    You may use :meth:`remove_trace` to close and remove a specific
-    trace from a trace collection.
-    """
-
-    def __init__(self, intersect_mode=False):
-        """
-        Creates an empty trace collection.
-        """
-
-        self._tc = nbt._bt_context_create()
-        self._intersect_mode = intersect_mode
-
-    def __del__(self):
-        nbt._bt_context_put(self._tc)
-
-    def add_trace(self, path, format_str):
-        """
-        Adds a trace to the trace collection.
-
-        *path* is the exact path of the trace on the filesystem.
-
-        *format_str* is a string indicating the type of trace to
-        add. ``ctf`` is currently the only supported trace format.
-
-        Returns the corresponding :class:`TraceHandle` instance for
-        this opened trace on success, or ``None`` on error.
-
-        This function **does not** recurse directories to find a
-        trace.  See :meth:`add_traces_recursive` for a recursive
-        version of this function.
-        """
-
-        ret = nbt._bt_context_add_trace(self._tc, path, format_str,
-                                        None, None, None)
-
-        if ret < 0:
-            return None
-
-        th = TraceHandle.__new__(TraceHandle)
-        th._id = ret
-        th._trace_collection = self
-
-        return th
-
-    def add_traces_recursive(self, path, format_str):
-        """
-        Adds traces to this trace collection by recursively searching
-        in the *path* directory.
-
-        *format_str* is a string indicating the type of trace to add.
-        ``ctf`` is currently the only supported trace format.
-
-        Returns a :class:`dict` object mapping full paths to trace
-        handles for each trace found, or ``None`` on error.
-
-        See also :meth:`add_trace`.
-        """
-
-        trace_handles = {}
-        noTrace = True
-        error = False
-
-        for fullpath, dirs, files in os.walk(path):
-            if "metadata" in files:
-                trace_handle = self.add_trace(fullpath, format_str)
-
-                if trace_handle is None:
-                    error = True
-                    continue
-
-                trace_handles[fullpath] = trace_handle
-                noTrace = False
-
-        if noTrace and error:
-            return None
-
-        return trace_handles
-
-    def remove_trace(self, trace_handle):
-        """
-        Removes a trace from the trace collection using its trace
-        handle *trace_handle*.
-
-        :class:`TraceHandle` objects are returned by :meth:`add_trace`
-        and :meth:`add_traces_recursive`.
-        """
-
-        try:
-            nbt._bt_context_remove_trace(self._tc, trace_handle._id)
-        except AttributeError:
-            raise TypeError("in remove_trace, argument 2 must be a TraceHandle instance")
-
-    @property
-    def intersect_mode(self):
-        return self._intersect_mode
-
-    @property
-    def has_intersection(self):
-        return nbt._bt_python_trace_collection_has_intersection(self._tc)
-
-    @property
-    def events(self):
-        """
-        Generates the ordered :class:`Event` objects of all the opened
-        traces contained in this trace collection.
-
-        Due to limitations of the native Babeltrace API, only one event
-        may be "alive" at a given time, i.e. a user **should never**
-        store a copy of the events returned by this function for
-        ulterior use. Users shall make sure to copy the information
-        they need *from* an event before accessing the next one.
-        """
-
-        begin_pos_ptr = nbt._bt_python_create_iter_pos()
-        end_pos_ptr = nbt._bt_python_create_iter_pos()
-
-        if not self.intersect_mode:
-            begin_pos_ptr.type = nbt.SEEK_BEGIN
-            end_pos_ptr.type = nbt.SEEK_LAST
-
-        for event in self._events(begin_pos_ptr, end_pos_ptr):
-            yield event
-
-        nbt._bt_iter_free_pos(begin_pos_ptr)
-        nbt._bt_iter_free_pos(end_pos_ptr)
-
-    def events_timestamps(self, timestamp_begin, timestamp_end):
-        """
-        Generates the ordered :class:`Event` objects of all the opened
-        traces contained in this trace collection from *timestamp_begin*
-        to *timestamp_end*.
-
-        *timestamp_begin* and *timestamp_end* are given in nanoseconds
-        since Epoch.
-
-        See :attr:`events` for notes and limitations.
-        """
-
-        begin_pos_ptr = nbt._bt_python_create_iter_pos()
-        end_pos_ptr = nbt._bt_python_create_iter_pos()
-        begin_pos_ptr.type = end_pos_ptr.type = nbt.SEEK_TIME
-        begin_pos_ptr.u.seek_time = timestamp_begin
-        end_pos_ptr.u.seek_time = timestamp_end
-
-        for event in self._events(begin_pos_ptr, end_pos_ptr):
-            yield event
-
-        nbt._bt_iter_free_pos(begin_pos_ptr)
-        nbt._bt_iter_free_pos(end_pos_ptr)
-
-    @property
-    def timestamp_begin(self):
-        """
-        Begin timestamp of this trace collection (nanoseconds since
-        Epoch).
-        """
-
-        pos_ptr = nbt._bt_iter_pos()
-        pos_ptr.type = nbt.SEEK_BEGIN
-
-        return self._timestamp_at_pos(pos_ptr)
-
-    @property
-    def timestamp_end(self):
-        """
-        End timestamp of this trace collection (nanoseconds since
-        Epoch).
-        """
-
-        pos_ptr = nbt._bt_iter_pos()
-        pos_ptr.type = nbt.SEEK_LAST
-
-        return self._timestamp_at_pos(pos_ptr)
-
-    def _timestamp_at_pos(self, pos_ptr):
-        ctf_it_ptr = nbt._bt_ctf_iter_create(self._tc, pos_ptr, pos_ptr)
-
-        if ctf_it_ptr is None:
-            raise NotImplementedError("Creation of multiple iterators is unsupported.")
-
-        ev_ptr = nbt._bt_ctf_iter_read_event(ctf_it_ptr)
-        nbt._bt_ctf_iter_destroy(ctf_it_ptr)
-
-        ev = Event.__new__(Event)
-        ev._e = ev_ptr
-
-        return ev.timestamp
-
-    def _events(self, begin_pos_ptr, end_pos_ptr):
-        if self.intersect_mode:
-            if not self.has_intersection:
-                # There are no events to provide.
-                return
-
-            ctf_it_ptr = nbt._bt_python_ctf_iter_create_intersect(
-                self._tc, begin_pos_ptr, end_pos_ptr
-            )
-        else:
-            ctf_it_ptr = nbt._bt_ctf_iter_create(
-                self._tc, begin_pos_ptr, end_pos_ptr
-            )
-
-        if ctf_it_ptr is None:
-            raise NotImplementedError("Creation of multiple iterators is unsupported.")
-
-        while True:
-            ev_ptr = nbt._bt_ctf_iter_read_event(ctf_it_ptr)
-
-            if ev_ptr is None:
-                break
-
-            ev = Event.__new__(Event)
-            ev._e = ev_ptr
-
-            try:
-                yield ev
-            except GeneratorExit:
-                break
-
-            ret = nbt._bt_iter_next(nbt._bt_ctf_get_iter(ctf_it_ptr))
-
-            if ret != 0:
-                break
-
-        nbt._bt_ctf_iter_destroy(ctf_it_ptr)
-
-
-# Based on enum bt_clock_type in clock-type.h
-class _ClockType:
-    CLOCK_CYCLES = 0
-    CLOCK_REAL = 1
-
-
-class TraceHandle:
-    """
-    A :class:`TraceHandle` is a handle allowing the user to manipulate
-    a specific trace directly. It is a unique identifier representing a
-    trace, and is not meant to be instantiated by the user.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("TraceHandle cannot be instantiated")
-
-    def __repr__(self):
-        return "Babeltrace TraceHandle: trace_id('{0}')".format(self._id)
-
-    @property
-    def id(self):
-        """
-        Numeric ID of this trace handle.
-        """
-
-        return self._id
-
-    @property
-    def path(self):
-        """
-        Path of the underlying trace.
-        """
-
-        return nbt._bt_trace_handle_get_path(self._trace_collection._tc,
-                                             self._id)
-
-    @property
-    def timestamp_begin(self):
-        """
-        Buffers creation timestamp (nanoseconds since Epoch) of the
-        underlying trace.
-        """
-
-        ret, value = nbt._bt_trace_handle_get_timestamp_begin(
-            self._trace_collection._tc, self._id, _ClockType.CLOCK_REAL)
-        if ret != 0:
-            raise ValueError("Invalid TraceHandle")
-        return value
-
-    @property
-    def timestamp_end(self):
-        """
-        Buffers destruction timestamp (nanoseconds since Epoch) of the
-        underlying trace.
-        """
-
-        ret, value = nbt._bt_trace_handle_get_timestamp_end(
-            self._trace_collection._tc, self._id, _ClockType.CLOCK_REAL)
-        if ret != 0:
-            raise ValueError("Invalid TraceHandle")
-        return value
-
-    @property
-    def events(self):
-        """
-        Generates all the :class:`EventDeclaration` objects of the
-        underlying trace.
-        """
-
-        ret = nbt._bt_python_event_decl_listcaller(self.id,
-                                                   self._trace_collection._tc)
-
-        if not isinstance(ret, list):
-            return
-
-        ptr_list, count = ret
-
-        for i in range(count):
-            tmp = EventDeclaration.__new__(EventDeclaration)
-            tmp._ed = nbt._bt_python_decl_one_from_list(ptr_list, i)
-            yield tmp
-
-
-
-
-# Priority of the scopes when searching for event fields
-_scopes = [
-    common.CTFScope.EVENT_FIELDS,
-    common.CTFScope.EVENT_CONTEXT,
-    common.CTFScope.STREAM_EVENT_CONTEXT,
-    common.CTFScope.STREAM_EVENT_HEADER,
-    common.CTFScope.STREAM_PACKET_CONTEXT,
-    common.CTFScope.TRACE_PACKET_HEADER
-]
-
-
-class Event(collections.Mapping):
-    """
-    An :class:`Event` object represents a trace event. :class:`Event`
-    objects are returned by :attr:`TraceCollection.events` and are
-    not meant to be instantiated by the user.
-
-    :class:`Event` has a :class:`dict`-like interface for accessing
-    an event's field value by field name:
-
-    .. code-block:: python
-
-       event['my_field']
-
-    If a field name exists in multiple scopes, the value of the first
-    field found is returned. The scopes are searched in the following
-    order:
-
-    1. Event fields (:attr:`babeltrace.common.CTFScope.EVENT_FIELDS`)
-    2. Event context (:attr:`babeltrace.common.CTFScope.EVENT_CONTEXT`)
-    3. Stream event context (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_CONTEXT`)
-    4. Event header (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_HEADER`)
-    5. Packet context (:attr:`babeltrace.common.CTFScope.STREAM_PACKET_CONTEXT`)
-    6. Packet header (:attr:`babeltrace.common.CTFScope.TRACE_PACKET_HEADER`)
-
-    It is still possible to obtain a field's value from a specific
-    scope using :meth:`field_with_scope`.
-
-    Field values are returned as native Python types, that is:
-
-    +-----------------------+----------------------------------+
-    | Field type            | Python type                      |
-    +=======================+==================================+
-    | Integer               | :class:`int`                     |
-    +-----------------------+----------------------------------+
-    | Floating point number | :class:`float`                   |
-    +-----------------------+----------------------------------+
-    | Enumeration           | :class:`str` (enumeration label) |
-    +-----------------------+----------------------------------+
-    | String                | :class:`str`                     |
-    +-----------------------+----------------------------------+
-    | Array                 | :class:`list` of native Python   |
-    |                       | objects                          |
-    +-----------------------+----------------------------------+
-    | Sequence              | :class:`list` of native Python   |
-    |                       | objects                          |
-    +-----------------------+----------------------------------+
-    | Structure             | :class:`dict` mapping field      |
-    |                       | names to native Python objects   |
-    +-----------------------+----------------------------------+
-
-    For example, printing the third element of a sequence named ``seq``
-    in a structure named ``my_struct`` of the ``event``'s field named
-    ``my_field`` is done this way:
-
-    .. code-block:: python
-
-       print(event['my_field']['my_struct']['seq'][2])
-    """
-
-    def __init__(self):
-        raise NotImplementedError("Event cannot be instantiated")
-
-    @property
-    def name(self):
-        """
-        Event name or ``None`` on error.
-        """
-
-        return nbt._bt_ctf_event_name(self._e)
-
-    @property
-    def cycles(self):
-        """
-        Event timestamp in cycles or -1 on error.
-        """
-
-        return nbt._bt_ctf_get_cycles(self._e)
-
-    @property
-    def timestamp(self):
-        """
-        Event timestamp (nanoseconds since Epoch).
-        """
-
-        ret, value = nbt._bt_ctf_get_timestamp(self._e)
-        if ret < 0:
-            raise RuntimeError("Failed to get event timestamp")
-        return value
-
-    @property
-    def datetime(self):
-        """
-        Event timestamp as a standard :class:`datetime.datetime`
-        object.
-
-        Note that the :class:`datetime.datetime` class' precision
-        is limited to microseconds, whereas :attr:`timestamp` provides
-        the event's timestamp with a nanosecond resolution.
-        """
-
-        return datetime.fromtimestamp(self.timestamp / 1E9)
-
-    def field_with_scope(self, field_name, scope):
-        """
-        Returns the value of a field named *field_name* within the
-        scope *scope*, or ``None`` if the field cannot be found.
-
-        *scope* must be one of :class:`babeltrace.common.CTFScope`
-        constants.
-        """
-
-        if scope not in _scopes:
-            raise ValueError("Invalid scope provided")
-
-        field = self._field_with_scope(field_name, scope)
-
-        if field is not None:
-            return field.value
-
-    def field_list_with_scope(self, scope):
-        """
-        Returns a list of field names in the scope *scope*.
-        """
-
-        if scope not in _scopes:
-            raise ValueError("Invalid scope provided")
-
-        field_names = []
-
-        for field in self._field_list_with_scope(scope):
-            field_names.append(field.name)
-
-        return field_names
-
-    @property
-    def handle(self):
-        """
-        :class:`TraceHandle` object containing this event, or ``None``
-        on error.
-        """
-
-        ret = nbt._bt_ctf_event_get_handle_id(self._e)
-
-        if ret < 0:
-            return None
-
-        th = TraceHandle.__new__(TraceHandle)
-        th._id = ret
-        th._trace_collection = self.get_trace_collection()
-
-        return th
-
-    @property
-    def trace_collection(self):
-        """
-        :class:`TraceCollection` object containing this event, or
-        ``None`` on error.
-        """
-
-        trace_collection = TraceCollection()
-        trace_collection._tc = nbt._bt_ctf_event_get_context(self._e)
-
-        if trace_collection._tc is not None:
-            return trace_collection
-
-    def __getitem__(self, field_name):
-        field = self._field(field_name)
-
-        if field is not None:
-            return field.value
-
-        raise KeyError(field_name)
-
-    def __iter__(self):
-        for key in self.keys():
-            yield key
-
-    def __len__(self):
-        count = 0
-
-        for scope in _scopes:
-            scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
-            ret = nbt._bt_python_field_listcaller(self._e, scope_ptr)
-
-            if isinstance(ret, list):
-                count += ret[1]
-
-        return count
-
-    def __contains__(self, field_name):
-        return self._field(field_name) is not None
-
-    def keys(self):
-        """
-        Returns the list of field names.
-
-        Note: field names are unique within the returned list, although
-        a field name could exist in multiple scopes. Use
-        :meth:`field_list_with_scope` to obtain the list of field names
-        of a given scope.
-        """
-
-        field_names = set()
-
-        for scope in _scopes:
-            for name in self.field_list_with_scope(scope):
-                field_names.add(name)
-
-        return list(field_names)
-
-    def get(self, field_name, default=None):
-        """
-        Returns the value of the field named *field_name*, or *default*
-        when not found.
-
-        See :class:`Event` note about how fields are retrieved by
-        name when multiple fields share the same name in different
-        scopes.
-        """
-
-        field = self._field(field_name)
-
-        if field is None:
-            return default
-
-        return field.value
-
-    def items(self):
-        """
-        Generates pairs of (field name, field value).
-
-        This method iterates :meth:`keys` to find field names, which
-        means some fields could be unavailable if other fields share
-        their names in scopes with higher priorities.
-        """
-
-        for field in self.keys():
-            yield (field, self[field])
-
-    def _field_with_scope(self, field_name, scope):
-        scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
-
-        if scope_ptr is None:
-            return None
-
-        definition_ptr = nbt._bt_ctf_get_field(self._e, scope_ptr, field_name)
-
-        if definition_ptr is None:
-            return None
-
-        field = _Definition(definition_ptr, scope)
-
-        return field
-
-    def _field(self, field_name):
-        field = None
-
-        for scope in _scopes:
-            field = self._field_with_scope(field_name, scope)
-
-            if field is not None:
-                break
-
-        return field
-
-    def _field_list_with_scope(self, scope):
-        fields = []
-        scope_ptr = nbt._bt_ctf_get_top_level_scope(self._e, scope)
-
-        # Returns a list [list_ptr, count]. If list_ptr is NULL, SWIG will only
-        # provide the "count" return value
-        count = 0
-        list_ptr = None
-        ret = nbt._bt_python_field_listcaller(self._e, scope_ptr)
-
-        if isinstance(ret, list):
-            list_ptr, count = ret
-
-        for i in range(count):
-            definition_ptr = nbt._bt_python_field_one_from_list(list_ptr, i)
-
-            if definition_ptr is not None:
-                definition = _Definition(definition_ptr, scope)
-                fields.append(definition)
-
-        return fields
-
-
-class FieldError(Exception):
-    """
-    Field error, raised when the value of a field cannot be accessed.
-    """
-
-    def __init__(self, value):
-        self.value = value
-
-    def __str__(self):
-        return repr(self.value)
-
-
-class EventDeclaration:
-    """
-    An event declaration contains the properties of a class of events,
-    that is, the common properties and fields layout of all the actual
-    recorded events associated with this declaration.
-
-    This class is not meant to be instantiated by the user. It is
-    returned by :attr:`TraceHandle.events`.
-    """
-
-    MAX_UINT64 = 0xFFFFFFFFFFFFFFFF
-
-    def __init__(self):
-        raise NotImplementedError("EventDeclaration cannot be instantiated")
-
-    @property
-    def name(self):
-        """
-        Event name, or ``None`` on error.
-        """
-
-        return nbt._bt_ctf_get_decl_event_name(self._ed)
-
-    @property
-    def id(self):
-        """
-        Event numeric ID, or -1 on error.
-        """
-
-        id = nbt._bt_ctf_get_decl_event_id(self._ed)
-
-        if id == self.MAX_UINT64:
-            id = -1
-
-        return id
-
-    @property
-    def fields(self):
-        """
-        Generates all the field declarations of this event, going
-        through each scope in the following order:
-
-        1. Event fields (:attr:`babeltrace.common.CTFScope.EVENT_FIELDS`)
-        2. Event context (:attr:`babeltrace.common.CTFScope.EVENT_CONTEXT`)
-        3. Stream event context (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_CONTEXT`)
-        4. Event header (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_HEADER`)
-        5. Packet context (:attr:`babeltrace.common.CTFScope.STREAM_PACKET_CONTEXT`)
-        6. Packet header (:attr:`babeltrace.common.CTFScope.TRACE_PACKET_HEADER`)
-
-        All the generated field declarations inherit
-        :class:`FieldDeclaration`, and are among:
-
-        * :class:`IntegerFieldDeclaration`
-        * :class:`FloatFieldDeclaration`
-        * :class:`EnumerationFieldDeclaration`
-        * :class:`StringFieldDeclaration`
-        * :class:`ArrayFieldDeclaration`
-        * :class:`SequenceFieldDeclaration`
-        * :class:`StructureFieldDeclaration`
-        * :class:`VariantFieldDeclaration`
-        """
-
-        for scope in _scopes:
-            for declaration in self.fields_scope(scope):
-                yield declaration
-
-    def fields_scope(self, scope):
-        """
-        Generates all the field declarations of the event's scope
-        *scope*.
-
-        *scope* must be one of :class:`babeltrace.common.CTFScope` constants.
-
-        All the generated field declarations inherit
-        :class:`FieldDeclaration`, and are among:
-
-        * :class:`IntegerFieldDeclaration`
-        * :class:`FloatFieldDeclaration`
-        * :class:`EnumerationFieldDeclaration`
-        * :class:`StringFieldDeclaration`
-        * :class:`ArrayFieldDeclaration`
-        * :class:`SequenceFieldDeclaration`
-        * :class:`StructureFieldDeclaration`
-        * :class:`VariantFieldDeclaration`
-        """
-        ret = nbt._by_python_field_decl_listcaller(self._ed, scope)
-
-        if not isinstance(ret, list):
-            return
-
-        list_ptr, count = ret
-
-        for i in range(count):
-            field_decl_ptr = nbt._bt_python_field_decl_one_from_list(list_ptr, i)
-
-            if field_decl_ptr is not None:
-                decl_ptr = nbt._bt_ctf_get_decl_from_field_decl(field_decl_ptr)
-                name = nbt._bt_ctf_get_decl_field_name(field_decl_ptr)
-                field_declaration = _create_field_declaration(decl_ptr, name,
-                                                              scope)
-                yield field_declaration
-
-
-class FieldDeclaration:
-    """
-    Base class for concrete field declarations.
-
-    This class is not meant to be instantiated by the user.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("FieldDeclaration cannot be instantiated")
-
-    def __repr__(self):
-        return "({0}) {1} {2}".format(common.CTFScope.scope_name(self.scope),
-                                      common.CTFTypeId.type_name(self.type),
-                                      self.name)
-
-    @property
-    def name(self):
-        """
-        Field name, or ``None`` on error.
-        """
-
-        return self._name
-
-    @property
-    def type(self):
-        """
-        Field type (one of :class:`babeltrace.common.CTFTypeId`
-        constants).
-        """
-
-        return nbt._bt_ctf_field_type(self._fd)
-
-    @property
-    def scope(self):
-        """
-        Field scope (one of:class:`babeltrace.common.CTFScope`
-        constants).
-        """
-
-        return self._s
-
-
-class IntegerFieldDeclaration(FieldDeclaration):
-    """
-    Integer field declaration.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("IntegerFieldDeclaration cannot be instantiated")
-
-    @property
-    def signedness(self):
-        """
-        0 if this integer is unsigned, 1 if signed, or -1 on error.
-        """
-
-        return nbt._bt_ctf_get_int_signedness(self._fd)
-
-    @property
-    def base(self):
-        """
-        Integer base (:class:`int`), or a negative value on error.
-        """
-
-        return nbt._bt_ctf_get_int_base(self._fd)
-
-    @property
-    def byte_order(self):
-        """
-        Integer byte order (one of
-        :class:`babeltrace.common.ByteOrder` constants).
-        """
-
-        ret = nbt._bt_ctf_get_int_byte_order(self._fd)
-
-        if ret == 1234:
-            return common.ByteOrder.BYTE_ORDER_LITTLE_ENDIAN
-        elif ret == 4321:
-            return common.ByteOrder.BYTE_ORDER_BIG_ENDIAN
-        else:
-            return common.ByteOrder.BYTE_ORDER_UNKNOWN
-
-    @property
-    def size(self):
-        """
-        Integer size in bits, or a negative value on error.
-        """
-        return nbt._bt_ctf_get_int_len(self._fd)
-
-    @property
-    def length(self):
-        return self.size
-
-    @property
-    def encoding(self):
-        """
-        Integer encoding (one of
-        :class:`babeltrace.common.CTFStringEncoding` constants).
-        """
-
-        return nbt._bt_ctf_get_encoding(self._fd)
-
-
-class EnumerationFieldDeclaration(FieldDeclaration):
-    """
-    Enumeration field declaration.
-
-    .. note::
-
-       As of this version, this class is missing some properties.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("EnumerationFieldDeclaration cannot be instantiated")
-
-
-class ArrayFieldDeclaration(FieldDeclaration):
-    """
-    Static array field declaration.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("ArrayFieldDeclaration cannot be instantiated")
-
-    @property
-    def length(self):
-        """
-        Fixed length of this static array (number of contained
-        elements), or a negative value on error.
-        """
-
-        return nbt._bt_ctf_get_array_len(self._fd)
-
-    @property
-    def element_declaration(self):
-        """
-        Field declaration of the underlying element.
-        """
-
-        field_decl_ptr = nbt._bt_python_get_array_element_declaration(self._fd)
-
-        return _create_field_declaration(field_decl_ptr, "", self.scope)
-
-
-class SequenceFieldDeclaration(FieldDeclaration):
-    """
-    Sequence (dynamic array) field declaration.
-
-    .. note::
-
-       As of this version, this class is missing some properties.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("SequenceFieldDeclaration cannot be instantiated")
-
-    @property
-    def element_declaration(self):
-        """
-        Field declaration of the underlying element.
-        """
-
-        field_decl_ptr = nbt._bt_python_get_sequence_element_declaration(self._fd)
-
-        return _create_field_declaration(field_decl_ptr, "", self.scope)
-
-
-class FloatFieldDeclaration(FieldDeclaration):
-    """
-    Floating point number field declaration.
-
-    .. note::
-
-       As of this version, this class is missing some properties.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("FloatFieldDeclaration cannot be instantiated")
-
-
-class StructureFieldDeclaration(FieldDeclaration):
-    """
-    Structure (ordered map of field names to field declarations) field
-    declaration.
-
-    .. note::
-
-       As of this version, this class is missing some properties.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("StructureFieldDeclaration cannot be instantiated")
-
-
-class StringFieldDeclaration(FieldDeclaration):
-    """
-    String (NULL-terminated array of bytes) field declaration.
-
-    .. note::
-
-       As of this version, this class is missing some properties.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("StringFieldDeclaration cannot be instantiated")
-
-
-class VariantFieldDeclaration(FieldDeclaration):
-    """
-    Variant (dynamic selection between different types) field declaration.
-
-    .. note::
-
-       As of this version, this class is missing some properties.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("VariantFieldDeclaration cannot be instantiated")
-
-
-def field_error():
-    """
-    Return the last error code encountered while
-    accessing a field and reset the error flag.
-    Return 0 if no error, a negative value otherwise.
-    """
-
-    return nbt._bt_ctf_field_get_error()
-
-
-def _create_field_declaration(declaration_ptr, name, scope):
-    """
-    Private field declaration factory.
-    """
-
-    if declaration_ptr is None:
-        raise ValueError("declaration_ptr must be valid")
-    if scope not in _scopes:
-        raise ValueError("Invalid scope provided")
-
-    type = nbt._bt_ctf_field_type(declaration_ptr)
-    declaration = None
-
-    if type == common.CTFTypeId.INTEGER:
-        declaration = IntegerFieldDeclaration.__new__(IntegerFieldDeclaration)
-    elif type == common.CTFTypeId.ENUM:
-        declaration = EnumerationFieldDeclaration.__new__(EnumerationFieldDeclaration)
-    elif type == common.CTFTypeId.ARRAY:
-        declaration = ArrayFieldDeclaration.__new__(ArrayFieldDeclaration)
-    elif type == common.CTFTypeId.SEQUENCE:
-        declaration = SequenceFieldDeclaration.__new__(SequenceFieldDeclaration)
-    elif type == common.CTFTypeId.FLOAT:
-        declaration = FloatFieldDeclaration.__new__(FloatFieldDeclaration)
-    elif type == common.CTFTypeId.STRUCT:
-        declaration = StructureFieldDeclaration.__new__(StructureFieldDeclaration)
-    elif type == common.CTFTypeId.STRING:
-        declaration = StringFieldDeclaration.__new__(StringFieldDeclaration)
-    elif type == common.CTFTypeId.VARIANT:
-        declaration = VariantFieldDeclaration.__new__(VariantFieldDeclaration)
-    else:
-        return declaration
-
-    declaration._fd = declaration_ptr
-    declaration._s = scope
-    declaration._name = name
-
-    return declaration
-
-
-class _Definition:
-    def __init__(self, definition_ptr, scope):
-        self._d = definition_ptr
-        self._s = scope
-
-        if scope not in _scopes:
-            ValueError("Invalid scope provided")
-
-    @property
-    def name(self):
-        """Return the name of a field or None on error."""
-
-        return nbt._bt_ctf_field_name(self._d)
-
-    @property
-    def type(self):
-        """Return the type of a field or -1 if unknown."""
-
-        return nbt._bt_ctf_field_type(nbt._bt_ctf_get_decl_from_def(self._d))
-
-    @property
-    def declaration(self):
-        """Return the associated Definition object."""
-
-        return _create_field_declaration(
-            nbt._bt_ctf_get_decl_from_def(self._d), self.name, self.scope)
-
-    def _get_enum_str(self):
-        """
-        Return the string matching the current enumeration.
-        Return None on error.
-        """
-
-        return nbt._bt_ctf_get_enum_str(self._d)
-
-    def _get_array_element_at(self, index):
-        """
-        Return the array's element at position index.
-        Return None on error
-        """
-
-        array_ptr = nbt._bt_python_get_array_from_def(self._d)
-
-        if array_ptr is None:
-            return None
-
-        definition_ptr = nbt._bt_array_index(array_ptr, index)
-
-        if definition_ptr is None:
-            return None
-
-        return _Definition(definition_ptr, self.scope)
-
-    def _get_sequence_len(self):
-        """
-        Return the len of a sequence or a negative
-        value on error.
-        """
-
-        seq = nbt._bt_python_get_sequence_from_def(self._d)
-
-        return nbt._bt_sequence_len(seq)
-
-    def _get_sequence_element_at(self, index):
-        """
-        Return the sequence's element at position index,
-        otherwise return None
-        """
-
-        seq = nbt._bt_python_get_sequence_from_def(self._d)
-
-        if seq is not None:
-            definition_ptr = nbt._bt_sequence_index(seq, index)
-
-            if definition_ptr is not None:
-                return _Definition(definition_ptr, self.scope)
-
-    def _get_uint64(self):
-        """
-        Return the value associated with the field.
-        If the field does not exist or is not of the type requested,
-        the value returned is undefined. To check if an error occured,
-        use the field_error() function after accessing a field.
-        """
-
-        return nbt._bt_ctf_get_uint64(self._d)
-
-    def _get_int64(self):
-        """
-        Return the value associated with the field.
-        If the field does not exist or is not of the type requested,
-        the value returned is undefined. To check if an error occured,
-        use the field_error() function after accessing a field.
-        """
-
-        return nbt._bt_ctf_get_int64(self._d)
-
-    def _get_char_array(self):
-        """
-        Return the value associated with the field.
-        If the field does not exist or is not of the type requested,
-        the value returned is undefined. To check if an error occurred,
-        use the field_error() function after accessing a field.
-        """
-
-        return nbt._bt_ctf_get_char_array(self._d)
-
-    def _get_str(self):
-        """
-        Return the value associated with the field.
-        If the field does not exist or is not of the type requested,
-        the value returned is undefined. To check if an error occurred,
-        use the field_error() function after accessing a field.
-        """
-
-        return nbt._bt_ctf_get_string(self._d)
-
-    def _get_float(self):
-        """
-        Return the value associated with the field.
-        If the field does not exist or is not of the type requested,
-        the value returned is undefined. To check if an error occurred,
-        use the field_error() function after accessing a field.
-        """
-
-        return nbt._bt_ctf_get_float(self._d)
-
-    def _get_variant(self):
-        """
-        Return the variant's selected field.
-        If the field does not exist or is not of the type requested,
-        the value returned is undefined. To check if an error occurred,
-        use the field_error() function after accessing a field.
-        """
-
-        return nbt._bt_ctf_get_variant(self._d)
-
-    def _get_struct_field_count(self):
-        """
-        Return the number of fields contained in the structure.
-        If the field does not exist or is not of the type requested,
-        the value returned is undefined.
-        """
-
-        return nbt._bt_ctf_get_struct_field_count(self._d)
-
-    def _get_struct_field_at(self, i):
-        """
-        Return the structure's field at position i.
-        If the field does not exist or is not of the type requested,
-        the value returned is undefined. To check if an error occurred,
-        use the field_error() function after accessing a field.
-        """
-
-        return nbt._bt_ctf_get_struct_field_index(self._d, i)
-
-    @property
-    def value(self):
-        """
-        Return the value associated with the field according to its type.
-        Return None on error.
-        """
-
-        id = self.type
-        value = None
-
-        if id == common.CTFTypeId.STRING:
-            value = self._get_str()
-        elif id == common.CTFTypeId.ARRAY:
-            element_decl = self.declaration.element_declaration
-
-            if ((element_decl.type == common.CTFTypeId.INTEGER
-                    and element_decl.length == 8)
-                    and (element_decl.encoding == common.CTFStringEncoding.ASCII or element_decl.encoding == common.CTFStringEncoding.UTF8)):
-                value = nbt._bt_python_get_array_string(self._d)
-            else:
-                value = []
-
-                for i in range(self.declaration.length):
-                    element = self._get_array_element_at(i)
-                    value.append(element.value)
-        elif id == common.CTFTypeId.INTEGER:
-            if self.declaration.signedness == 0:
-                value = self._get_uint64()
-            else:
-                value = self._get_int64()
-        elif id == common.CTFTypeId.ENUM:
-            value = self._get_enum_str()
-        elif id == common.CTFTypeId.SEQUENCE:
-            element_decl = self.declaration.element_declaration
-
-            if ((element_decl.type == common.CTFTypeId.INTEGER
-                    and element_decl.length == 8)
-                    and (element_decl.encoding == common.CTFStringEncoding.ASCII or element_decl.encoding == common.CTFStringEncoding.UTF8)):
-                value = nbt._bt_python_get_sequence_string(self._d)
-            else:
-                seq_len = self._get_sequence_len()
-                value = []
-
-                for i in range(seq_len):
-                    evDef = self._get_sequence_element_at(i)
-                    value.append(evDef.value)
-        elif id == common.CTFTypeId.FLOAT:
-            value = self._get_float()
-        elif id == common.CTFTypeId.VARIANT:
-            variant = _Definition.__new__(_Definition)
-            variant._d = self._get_variant()
-            value = variant.value
-        elif id == common.CTFTypeId.STRUCT:
-            value = {}
-
-            for i in range(self._get_struct_field_count()):
-                member = _Definition(self._get_struct_field_at(i), self.scope)
-                value[member.name] = member.value
-
-        if field_error():
-            raise FieldError(
-                "Error occurred while accessing field {} of type {}".format(
-                    self.name,
-                    common.CTFTypeId.type_name(id)))
-
-        return value
-
-    @property
-    def scope(self):
-        """Return the scope of a field or None on error."""
-
-        return self._s
diff --git a/bindings/python/babeltrace/setup.py.in b/bindings/python/babeltrace/setup.py.in
new file mode 100644 (file)
index 0000000..59052d7
--- /dev/null
@@ -0,0 +1,75 @@
+# The MIT License (MIT)
+#
+# Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import sys
+
+from distutils.core import setup, Extension
+
+PY_PATH_WARN_MSG = """
+-------------------------------------WARNING------------------------------------
+The install directory used:\n ({})\nis not included in your PYTHONPATH.
+
+To add this directory to your Python search path permanently you can add the
+following command to your .bashrc/.zshrc:
+    export PYTHONPATH="${{PYTHONPATH}}:{}"
+--------------------------------------------------------------------------------
+"""
+
+def main():
+    dist = setup(name='babeltrace',
+            version='@PACKAGE_VERSION@',
+            description='Babeltrace Python Bindings',
+            packages=['babeltrace'],
+            package_dir={'babeltrace': 'babeltrace'},
+            options={'build':
+                {
+                    'build_base': 'build',
+                    'build_lib': 'build/build_lib'
+                },
+            },
+            url='http://diamon.org/babeltrace',
+            license='MIT',
+            classifiers=[
+                'Development Status :: 5 - Production/Stable',
+                'Intended Audience :: Developers',
+                'License :: OSI Approved :: The MIT License',
+                'Programming Language :: Python :: 3'
+                'Topic :: System :: Logging',
+                ])
+
+# After the installation, we check that the install directory is included in
+# the Python search path and we print a warning message when it's not.
+# We need to do this because Python search path differs depending on the distro
+# and some distros don't include any /usr/local/ in the search path. This is
+# also useful for out-of-tree installs and tests.
+# It's only relevant to make this check on the `install` command.
+
+    if 'install' in dist.command_obj:
+        install_dir = dist.command_obj['install'].install_libbase
+        if install_dir not in sys.path:
+            # We can't consider this an error because if affects every
+            # distro differently. We only warn the user that some
+            # extra configuration is needed to use the bindings
+            print(PY_PATH_WARN_MSG.format(install_dir, install_dir))
+
+if __name__ == "__main__":
+    main()
diff --git a/bindings/python/babeltrace/writer.py b/bindings/python/babeltrace/writer.py
deleted file mode 100644 (file)
index 8ed18c6..0000000
+++ /dev/null
@@ -1,2220 +0,0 @@
-# writer.py
-#
-# Babeltrace writer interface Python module
-#
-# Copyright 2012-2015 EfficiOS Inc.
-#
-# Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import babeltrace.nativebt as nbt
-import babeltrace.common as common
-from uuid import UUID
-
-
-# Used to compare to -1ULL in error checks
-_MAX_UINT64 = 0xFFFFFFFFFFFFFFFF
-
-
-class EnumerationMapping:
-    """
-    Mapping from an enumeration label to a range of integers.
-    """
-
-    def __init__(self, name, start, end):
-        """
-        Creates an enumeration mapping, where label *name* is mapped to
-        the [*start*, *end*] range of integers (*end* is included).
-
-        Set *start* and *end* to the same value to create an enumeration
-        mapping to a single value.
-        """
-
-        self.name = name
-        self.start = start
-        self.end = end
-
-
-class Clock:
-    """
-    A CTF clock allows the description of the system's clock topology, as
-    well as the definition of each clock's parameters.
-
-    :class:`Clock` objects must be registered to a :class:`Writer`
-    object (see :meth:`Writer.add_clock`), as well as be registered to
-    a :class:`StreamClass` object (see :attr:`StreamClass.clock`).
-    """
-
-    def __init__(self, name):
-        """
-        Creates a default CTF clock named *name*.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._c = nbt._bt_ctf_clock_create(name)
-
-        if self._c is None:
-            raise ValueError("Invalid clock name.")
-
-    def __del__(self):
-        nbt._bt_ctf_clock_put(self._c)
-
-    @property
-    def name(self):
-        """
-        Clock name.
-
-        Set this attribute to change the clock's name.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        name = nbt._bt_ctf_clock_get_name(self._c)
-
-        if name is None:
-            raise ValueError("Invalid clock instance.")
-
-        return name
-
-    @property
-    def description(self):
-        """
-        Clock description (string).
-
-        Set this attribute to change the clock's description.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        return nbt._bt_ctf_clock_get_description(self._c)
-
-    @description.setter
-    def description(self, desc):
-        ret = nbt._bt_ctf_clock_set_description(self._c, str(desc))
-
-        if ret < 0:
-            raise ValueError("Invalid clock description.")
-
-    @property
-    def frequency(self):
-        """
-        Clock frequency in Hz (integer).
-
-        Set this attribute to change the clock's frequency.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        freq = nbt._bt_ctf_clock_get_frequency(self._c)
-
-        if freq == _MAX_UINT64:
-            raise ValueError("Invalid clock instance")
-
-        return freq
-
-    @frequency.setter
-    def frequency(self, freq):
-        ret = nbt._bt_ctf_clock_set_frequency(self._c, freq)
-
-        if ret < 0:
-            raise ValueError("Invalid frequency value.")
-
-    @property
-    def precision(self):
-        """
-        Clock precision in clock ticks (integer).
-
-        Set this attribute to change the clock's precision.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        precision = nbt._bt_ctf_clock_get_precision(self._c)
-
-        if precision == _MAX_UINT64:
-            raise ValueError("Invalid clock instance")
-
-        return precision
-
-    @precision.setter
-    def precision(self, precision):
-        ret = nbt._bt_ctf_clock_set_precision(self._c, precision)
-
-        if ret < 0:
-            raise ValueError("Invalid precision value.")
-
-    @property
-    def offset_seconds(self):
-        """
-        Clock offset in seconds since POSIX.1 Epoch (integer).
-
-        Set this attribute to change the clock's offset in seconds.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret, offset_s = nbt._bt_ctf_clock_get_offset_s(self._c)
-
-        if ret < 0:
-            raise ValueError("Invalid clock instance")
-
-        return offset_s
-
-    @offset_seconds.setter
-    def offset_seconds(self, offset_s):
-        ret = nbt._bt_ctf_clock_set_offset_s(self._c, offset_s)
-
-        if ret < 0:
-            raise ValueError("Invalid offset value.")
-
-    @property
-    def offset(self):
-        """
-        Clock offset in ticks since (POSIX.1 Epoch +
-        :attr:`offset_seconds`).
-
-        Set this attribute to change the clock's offset.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret, offset = nbt._bt_ctf_clock_get_offset(self._c)
-
-        if ret < 0:
-            raise ValueError("Invalid clock instance")
-
-        return offset
-
-    @offset.setter
-    def offset(self, offset):
-        ret = nbt._bt_ctf_clock_set_offset(self._c, offset)
-
-        if ret < 0:
-            raise ValueError("Invalid offset value.")
-
-    @property
-    def absolute(self):
-        """
-        ``True`` if this clock is absolute, i.e. if the clock is a
-        global reference across the other clocks of the trace.
-
-        Set this attribute to change the clock's absolute state
-        (boolean).
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        is_absolute = nbt._bt_ctf_clock_get_is_absolute(self._c)
-
-        if is_absolute == -1:
-            raise ValueError("Invalid clock instance")
-
-        return False if is_absolute == 0 else True
-
-    @absolute.setter
-    def absolute(self, is_absolute):
-        ret = nbt._bt_ctf_clock_set_is_absolute(self._c, int(is_absolute))
-
-        if ret < 0:
-            raise ValueError("Could not set the clock absolute attribute.")
-
-    @property
-    def uuid(self):
-        """
-        Clock UUID (an :class:`uuid.UUID` object).
-
-        Set this attribute to change the clock's UUID.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        uuid_list = []
-
-        for i in range(16):
-            ret, value = nbt._bt_python_ctf_clock_get_uuid_index(self._c, i)
-
-            if ret < 0:
-                raise ValueError("Invalid clock instance")
-
-            uuid_list.append(value)
-
-        return UUID(bytes=bytes(uuid_list))
-
-    @uuid.setter
-    def uuid(self, uuid):
-        uuid_bytes = uuid.bytes
-
-        if len(uuid_bytes) != 16:
-            raise ValueError("Invalid UUID provided. UUID length must be 16 bytes")
-
-        for i in range(len(uuid_bytes)):
-            ret = nbt._bt_python_ctf_clock_set_uuid_index(self._c, i,
-                                                          uuid_bytes[i])
-
-            if ret < 0:
-                raise ValueError("Invalid clock instance")
-
-    @property
-    def time(self):
-        """
-        Clock current time; nanoseconds (integer) since clock origin
-        (POSIX.1 Epoch + :attr:`offset_seconds` + :attr:`offset`).
-
-        Set this attribute to change the clock's current time.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret, time = nbt._bt_ctf_clock_get_time(self._c)
-
-        if ret < 0:
-            raise ValueError("Invalid clock instance")
-
-        return time
-
-    @time.setter
-    def time(self, time):
-        ret = nbt._bt_ctf_clock_set_time(self._c, time)
-
-        if ret < 0:
-            raise ValueError("Invalid time value.")
-
-
-class IntegerBase:
-    """
-    Display base of an integer.
-    """
-
-    #: Unknown
-    UNKNOWN = -1
-
-    #: Binary
-    BIN = 2
-
-    #: Octal
-    OCT = 8
-
-    #: Decimal
-    DEC = 10
-
-    #: Hexadecimal
-    HEX = 16
-
-    # keep this for backward compatibility
-    INTEGER_BASE_UNKNOWN = -1
-    INTEGER_BASE_BINARY = 2
-    INTEGER_BASE_OCTAL = 8
-    INTEGER_BASE_DECIMAL = 10
-    INTEGER_BASE_HEXADECIMAL = 16
-
-
-class FieldDeclaration:
-    """
-    Base class of all field declarations. This class is not meant to
-    be instantiated by the user; use one of the concrete field
-    declaration subclasses instead.
-    """
-
-    class IntegerBase(IntegerBase):
-        pass
-
-    def __init__(self):
-        if self._ft is None:
-            raise ValueError("FieldDeclaration creation failed.")
-
-    def __del__(self):
-        nbt._bt_ctf_field_type_put(self._ft)
-
-    @staticmethod
-    def _create_field_declaration_from_native_instance(
-            native_field_declaration):
-        type_dict = {
-            common.CTFTypeId.INTEGER: IntegerFieldDeclaration,
-            common.CTFTypeId.FLOAT: FloatFieldDeclaration,
-            common.CTFTypeId.ENUM: EnumerationFieldDeclaration,
-            common.CTFTypeId.STRING: StringFieldDeclaration,
-            common.CTFTypeId.STRUCT: StructureFieldDeclaration,
-            common.CTFTypeId.VARIANT: VariantFieldDeclaration,
-            common.CTFTypeId.ARRAY: ArrayFieldDeclaration,
-            common.CTFTypeId.SEQUENCE: SequenceFieldDeclaration
-        }
-
-        field_type_id = nbt._bt_ctf_field_type_get_type_id(native_field_declaration)
-
-        if field_type_id == common.CTFTypeId.UNKNOWN:
-            raise TypeError("Invalid field instance")
-
-        declaration = Field.__new__(Field)
-        declaration._ft = native_field_declaration
-        declaration.__class__ = type_dict[field_type_id]
-
-        return declaration
-
-    @property
-    def alignment(self):
-        """
-        Field alignment in bits (integer).
-
-        Set this attribute to change this field's alignment.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        return nbt._bt_ctf_field_type_get_alignment(self._ft)
-
-    @alignment.setter
-    def alignment(self, alignment):
-        ret = nbt._bt_ctf_field_type_set_alignment(self._ft, alignment)
-
-        if ret < 0:
-            raise ValueError("Invalid alignment value.")
-
-    @property
-    def byte_order(self):
-        """
-        Field byte order (one of :class:`babeltrace.common.ByteOrder`
-        constants).
-
-        Set this attribute to change this field's byte order.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        return nbt._bt_ctf_field_type_get_byte_order(self._ft)
-
-    @byte_order.setter
-    def byte_order(self, byte_order):
-        ret = nbt._bt_ctf_field_type_set_byte_order(self._ft, byte_order)
-
-        if ret < 0:
-            raise ValueError("Could not set byte order value.")
-
-
-class IntegerFieldDeclaration(FieldDeclaration):
-    """
-    Integer field declaration.
-    """
-
-    def __init__(self, size):
-        """
-        Creates an integer field declaration of size *size* bits.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._ft = nbt._bt_ctf_field_type_integer_create(size)
-        super().__init__()
-
-    @property
-    def size(self):
-        """
-        Integer size in bits (integer).
-
-        Set this attribute to change this integer's size.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_integer_get_size(self._ft)
-
-        if ret < 0:
-            raise ValueError("Could not get Integer size attribute.")
-        else:
-            return ret
-
-    @property
-    def signed(self):
-        """
-        ``True`` if this integer is signed.
-
-        Set this attribute to change this integer's signedness
-        (boolean).
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_integer_get_signed(self._ft)
-
-        if ret < 0:
-            raise ValueError("Could not get Integer signed attribute.")
-        elif ret > 0:
-            return True
-        else:
-            return False
-
-    @signed.setter
-    def signed(self, signed):
-        ret = nbt._bt_ctf_field_type_integer_set_signed(self._ft, signed)
-
-        if ret < 0:
-            raise ValueError("Could not set Integer signed attribute.")
-
-    @property
-    def base(self):
-        """
-        Integer display base (one of :class:`IntegerBase` constants).
-
-        Set this attribute to change this integer's display base.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        return nbt._bt_ctf_field_type_integer_get_base(self._ft)
-
-    @base.setter
-    def base(self, base):
-        ret = nbt._bt_ctf_field_type_integer_set_base(self._ft, base)
-
-        if ret < 0:
-            raise ValueError("Could not set Integer base.")
-
-    @property
-    def encoding(self):
-        """
-        Integer encoding (one of
-        :class:`babeltrace.common.CTFStringEncoding` constants).
-
-        Set this attribute to change this integer's encoding.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        return nbt._bt_ctf_field_type_integer_get_encoding(self._ft)
-
-    @encoding.setter
-    def encoding(self, encoding):
-        ret = nbt._bt_ctf_field_type_integer_set_encoding(self._ft, encoding)
-
-        if ret < 0:
-            raise ValueError("Could not set Integer encoding.")
-
-
-class EnumerationFieldDeclaration(FieldDeclaration):
-    """
-    Enumeration field declaration. A CTF enumeration maps labels to
-    ranges of integers.
-    """
-
-    def __init__(self, integer_type):
-        """
-        Creates an enumeration field declaration, with *integer_type*
-        being the underlying :class:`IntegerFieldDeclaration` for storing
-        the integer.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        isinst = isinstance(integer_type, IntegerFieldDeclaration)
-
-        if integer_type is None or not isinst:
-            raise TypeError("Invalid integer container.")
-
-        self._ft = nbt._bt_ctf_field_type_enumeration_create(integer_type._ft)
-        super().__init__()
-
-    @property
-    def container(self):
-        """
-        Underlying container (:class:`IntegerFieldDeclaration`).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_enumeration_get_container_type(self._ft)
-
-        if ret is None:
-            raise TypeError("Invalid enumeration declaration")
-
-        return FieldDeclaration._create_field_declaration_from_native_instance(ret)
-
-    def add_mapping(self, name, range_start, range_end):
-        """
-        Adds a mapping to the enumeration field declaration, from the
-        label named *name* to range [*range_start*, *range_end*], where
-        *range_start* and *range_end* are integers included in the
-        range.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        if range_start < 0 or range_end < 0:
-            ret = nbt._bt_ctf_field_type_enumeration_add_mapping(self._ft,
-                                                                 str(name),
-                                                                 range_start,
-                                                                 range_end)
-        else:
-            ret = nbt._bt_ctf_field_type_enumeration_add_mapping_unsigned(self._ft,
-                                                                          str(name),
-                                                                          range_start,
-                                                                          range_end)
-
-        if ret < 0:
-            raise ValueError("Could not add mapping to enumeration declaration.")
-
-    @property
-    def mappings(self):
-        """
-        Generates the mappings of this enumeration field declaration
-        (:class:`EnumerationMapping` objects).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        signed = self.container.signed
-
-        count = nbt._bt_ctf_field_type_enumeration_get_mapping_count(self._ft)
-
-        for i in range(count):
-            if signed:
-                ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, i)
-            else:
-                ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, i)
-
-            if len(ret) != 3:
-                msg = "Could not get Enumeration mapping at index {}".format(i)
-                raise TypeError(msg)
-
-            name, range_start, range_end = ret
-            yield EnumerationMapping(name, range_start, range_end)
-
-    def get_mapping_by_name(self, name):
-        """
-        Returns the :class:`EnumerationMapping` object for the label
-        named *name*.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_name(self._ft, name)
-
-        if index < 0:
-            return None
-
-        if self.container.signed:
-            ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, index)
-        else:
-            ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, index)
-
-        if len(ret) != 3:
-            msg = "Could not get Enumeration mapping at index {}".format(i)
-            raise TypeError(msg)
-
-        name, range_start, range_end = ret
-
-        return EnumerationMapping(name, range_start, range_end)
-
-    def get_mapping_by_value(self, value):
-        """
-        Returns the :class:`EnumerationMapping` object for the value
-        *value* (integer).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        if value < 0:
-            index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_value(self._ft, value)
-        else:
-            index = nbt._bt_ctf_field_type_enumeration_get_mapping_index_by_unsigned_value(self._ft, value)
-
-        if index < 0:
-            return None
-
-        if self.container.signed:
-            ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping(self._ft, index)
-        else:
-            ret = nbt._bt_python_ctf_field_type_enumeration_get_mapping_unsigned(self._ft, index)
-
-        if len(ret) != 3:
-            msg = "Could not get Enumeration mapping at index {}".format(i)
-            raise TypeError(msg)
-
-        name, range_start, range_end = ret
-
-        return EnumerationMapping(name, range_start, range_end)
-
-
-class FloatingPointFieldDeclaration(FieldDeclaration):
-    """
-    Floating point number field declaration.
-
-    A CTF floating point number is a made of three sections: the sign
-    bit, the exponent bits, and the mantissa bits. The most significant
-    bit of the resulting binary word is the sign bit, and is included
-    in the number of mantissa bits.
-
-    For example, the
-    `IEEE 754 <http://en.wikipedia.org/wiki/IEEE_floating_point>`_
-    single precision floating point number is represented on a 32-bit
-    word using an 8-bit exponent (``e``) and a 24-bit mantissa (``m``),
-    the latter count including the sign bit (``s``)::
-
-        s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
-
-    The IEEE 754 double precision floating point number uses an
-    11-bit exponent and a 53-bit mantissa.
-    """
-
-    #: IEEE 754 single precision floating point number exponent size
-    FLT_EXP_DIG = 8
-
-    #: IEEE 754 double precision floating point number exponent size
-    DBL_EXP_DIG = 11
-
-    #: IEEE 754 single precision floating point number mantissa size
-    FLT_MANT_DIG = 24
-
-    #: IEEE 754 double precision floating point number mantissa size
-    DBL_MANT_DIG = 53
-
-    def __init__(self):
-        """
-        Creates a floating point number field declaration.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._ft = nbt._bt_ctf_field_type_floating_point_create()
-        super().__init__()
-
-    @property
-    def exponent_digits(self):
-        """
-        Floating point number exponent section size in bits (integer).
-
-        Set this attribute to change the floating point number's
-        exponent section's size. You may use :attr:`FLT_EXP_DIG` or
-        :attr:`DBL_EXP_DIG` for IEEE 754 floating point numbers.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_floating_point_get_exponent_digits(self._ft)
-
-        if ret < 0:
-            raise TypeError(
-                "Could not get Floating point exponent digit count")
-
-        return ret
-
-    @exponent_digits.setter
-    def exponent_digits(self, exponent_digits):
-        ret = nbt._bt_ctf_field_type_floating_point_set_exponent_digits(self._ft,
-                                                                        exponent_digits)
-
-        if ret < 0:
-            raise ValueError("Could not set exponent digit count.")
-
-    @property
-    def mantissa_digits(self):
-        """
-        Floating point number mantissa section size in bits (integer).
-
-        Set this attribute to change the floating point number's
-        mantissa section's size. You may use :attr:`FLT_MANT_DIG` or
-        :attr:`DBL_MANT_DIG` for IEEE 754 floating point numbers.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_floating_point_get_mantissa_digits(self._ft)
-
-        if ret < 0:
-            raise TypeError("Could not get Floating point mantissa digit count")
-
-        return ret
-
-    @mantissa_digits.setter
-    def mantissa_digits(self, mantissa_digits):
-        ret = nbt._bt_ctf_field_type_floating_point_set_mantissa_digits(self._ft,
-                                                                        mantissa_digits)
-
-        if ret < 0:
-            raise ValueError("Could not set mantissa digit count.")
-
-
-class FloatFieldDeclaration(FloatingPointFieldDeclaration):
-    pass
-
-
-class StructureFieldDeclaration(FieldDeclaration):
-    """
-    Structure field declaration, i.e. an ordered mapping from field
-    names to field declarations.
-    """
-
-    def __init__(self):
-        """
-        Creates an empty structure field declaration.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._ft = nbt._bt_ctf_field_type_structure_create()
-        super().__init__()
-
-    def add_field(self, field_type, field_name):
-        """
-        Appends one :class:`FieldDeclaration` *field_type* named
-        *field_name* to the structure's ordered map.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_structure_add_field(self._ft,
-                                                         field_type._ft,
-                                                         str(field_name))
-
-        if ret < 0:
-            raise ValueError("Could not add field to structure.")
-
-    @property
-    def fields(self):
-        """
-        Generates the (field name, :class:`FieldDeclaration`) pairs
-        of this structure.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        count = nbt._bt_ctf_field_type_structure_get_field_count(self._ft)
-
-        if count < 0:
-            raise TypeError("Could not get Structure field count")
-
-        for i in range(count):
-            field_name = nbt._bt_python_ctf_field_type_structure_get_field_name(self._ft, i)
-
-            if field_name is None:
-                msg = "Could not get Structure field name at index {}".format(i)
-                raise TypeError(msg)
-
-            field_type_native = nbt._bt_python_ctf_field_type_structure_get_field_type(self._ft, i)
-
-            if field_type_native is None:
-                msg = "Could not get Structure field type at index {}".format(i)
-                raise TypeError(msg)
-
-            field_type = FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-            yield (field_name, field_type)
-
-    def get_field_by_name(self, name):
-        """
-        Returns the :class:`FieldDeclaration` mapped to the field name
-        *name* in this structure.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        field_type_native = nbt._bt_ctf_field_type_structure_get_field_type_by_name(self._ft, name)
-
-        if field_type_native is None:
-            msg = "Could not find Structure field with name {}".format(name)
-            raise TypeError(msg)
-
-        return FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-
-
-class VariantFieldDeclaration(FieldDeclaration):
-    """
-    Variant field declaration.
-
-    A CTF variant is a dynamic selection between different fields.
-    The value of a *tag* (a CTF enumeration) determines what is the
-    current selected field. All the possible fields must be added to
-    its field declaration before using an actual variant field.
-    """
-
-    def __init__(self, enum_tag, tag_name):
-        """
-        Creates an empty variant field declaration with tag field
-        declaration *enum_tag* (instance of
-        :class:`EnumerationFieldDeclaration`) named *tag_name*
-        (string).
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        isinst = isinstance(enum_tag, EnumerationFieldDeclaration)
-        if enum_tag is None or not isinst:
-            raise TypeError("Invalid tag type; must be of type EnumerationFieldDeclaration.")
-
-        self._ft = nbt._bt_ctf_field_type_variant_create(enum_tag._ft,
-                                                         str(tag_name))
-        super().__init__()
-
-    @property
-    def tag_name(self):
-        """
-        Variant field declaration tag name.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_variant_get_tag_name(self._ft)
-
-        if ret is None:
-            raise TypeError("Could not get Variant tag name")
-
-        return ret
-
-    @property
-    def tag_type(self):
-        """
-        Variant field declaration tag field declaration
-        (:class:`EnumerationFieldDeclaration` object).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_variant_get_tag_type(self._ft)
-
-        if ret is None:
-            raise TypeError("Could not get Variant tag type")
-
-        return FieldDeclaration._create_field_declaration_from_native_instance(ret)
-
-    def add_field(self, field_type, field_name):
-        """
-        Registers the :class:`FieldDeclaration` object *field_type*
-        as the variant's selected type when the variant's tag's current
-        label is *field_name*.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_variant_add_field(self._ft,
-                                                       field_type._ft,
-                                                       str(field_name))
-
-        if ret < 0:
-            raise ValueError("Could not add field to variant.")
-
-    @property
-    def fields(self):
-        """
-        Generates the (field name, :class:`FieldDeclaration`) pairs
-        of this variant field declaration.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        count = nbt._bt_ctf_field_type_variant_get_field_count(self._ft)
-
-        if count < 0:
-            raise TypeError("Could not get Variant field count")
-
-        for i in range(count):
-            field_name = nbt._bt_python_ctf_field_type_variant_get_field_name(self._ft, i)
-
-            if field_name is None:
-                msg = "Could not get Variant field name at index {}".format(i)
-                raise TypeError(msg)
-
-            field_type_native = nbt._bt_python_ctf_field_type_variant_get_field_type(self._ft, i)
-
-            if field_type_native is None:
-                msg = "Could not get Variant field type at index {}".format(i)
-                raise TypeError(msg)
-
-            field_type = FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-            yield (field_name, field_type)
-
-    def get_field_by_name(self, name):
-        """
-        Returns the :class:`FieldDeclaration` selected when the
-        variant's tag's current label is *name*.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        field_type_native = nbt._bt_ctf_field_type_variant_get_field_type_by_name(self._ft,
-                                                                                  name)
-
-        if field_type_native is None:
-            msg = "Could not find Variant field with name {}".format(name)
-            raise TypeError(msg)
-
-        return FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-
-    def get_field_from_tag(self, tag):
-        """
-        Returns the :class:`FieldDeclaration` selected by the current
-        label of the :class:`EnumerationField` *tag*.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        field_type_native = nbt._bt_ctf_field_type_variant_get_field_type_from_tag(self._ft, tag._f)
-
-        if field_type_native is None:
-            msg = "Could not find Variant field with tag value {}".format(tag.value)
-            raise TypeError(msg)
-
-        return FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-
-
-class ArrayFieldDeclaration(FieldDeclaration):
-    """
-    Static array field declaration.
-    """
-
-    def __init__(self, element_type, length):
-        """
-        Creates a static array field declaration of *length*
-        elements of type *element_type* (:class:`FieldDeclaration`).
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._ft = nbt._bt_ctf_field_type_array_create(element_type._ft,
-                                                       length)
-        super().__init__()
-
-    @property
-    def element_type(self):
-        """
-        Type of the elements of this this static array (subclass of
-        :class:`FieldDeclaration`).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_array_get_element_type(self._ft)
-
-        if ret is None:
-            raise TypeError("Could not get Array element type")
-
-        return FieldDeclaration._create_field_declaration_from_native_instance(ret)
-
-    @property
-    def length(self):
-        """
-        Length of this static array (integer).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_array_get_length(self._ft)
-
-        if ret < 0:
-            raise TypeError("Could not get Array length")
-
-        return ret
-
-
-class SequenceFieldDeclaration(FieldDeclaration):
-    """
-    Sequence (dynamic array) field declaration.
-    """
-
-    def __init__(self, element_type, length_field_name):
-        """
-        Creates a sequence field declaration of
-        elements of type *element_type* (:class:`FieldDeclaration`).
-        The length of a sequence field based on this sequence field
-        declaration is obtained by retrieving the dynamic integer
-        value of the field named *length_field_name*.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._ft = nbt._bt_ctf_field_type_sequence_create(element_type._ft,
-                                                          str(length_field_name))
-        super().__init__()
-
-    @property
-    def element_type(self):
-        """
-        Type of the elements of this sequence (subclass of
-        :class:`FieldDeclaration`).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_sequence_get_element_type(self._ft)
-
-        if ret is None:
-            raise TypeError("Could not get Sequence element type")
-
-        return FieldDeclaration._create_field_declaration_from_native_instance(ret)
-
-    @property
-    def length_field_name(self):
-        """
-        Name of the integer field defining the dynamic length of
-        sequence fields based on this sequence field declaration.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_field_type_sequence_get_length_field_name(self._ft)
-
-        if ret is None:
-            raise TypeError("Could not get Sequence length field name")
-
-        return ret
-
-
-class StringFieldDeclaration(FieldDeclaration):
-    """
-    String (NULL-terminated array of bytes) field declaration.
-    """
-
-    def __init__(self):
-        """
-        Creates a string field declaration.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._ft = nbt._bt_ctf_field_type_string_create()
-        super().__init__()
-
-    @property
-    def encoding(self):
-        """
-        String encoding (one of
-        :class:`babeltrace.common.CTFStringEncoding` constants).
-
-        Set this attribute to change this string's encoding.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        return nbt._bt_ctf_field_type_string_get_encoding(self._ft)
-
-    @encoding.setter
-    def encoding(self, encoding):
-        ret = nbt._bt_ctf_field_type_string_set_encoding(self._ft, encoding)
-        if ret < 0:
-            raise ValueError("Could not set string encoding.")
-
-
-@staticmethod
-def create_field(field_type):
-    """
-    Create an instance of a field.
-    """
-    isinst = isinstance(field_type, FieldDeclaration)
-
-    if field_type is None or not isinst:
-        raise TypeError("Invalid field_type. Type must be a FieldDeclaration-derived class.")
-
-    if isinstance(field_type, IntegerFieldDeclaration):
-        return IntegerField(field_type)
-    elif isinstance(field_type, EnumerationFieldDeclaration):
-        return EnumerationField(field_type)
-    elif isinstance(field_type, FloatFieldDeclaration):
-        return FloatingPointField(field_type)
-    elif isinstance(field_type, StructureFieldDeclaration):
-        return StructureField(field_type)
-    elif isinstance(field_type, VariantFieldDeclaration):
-        return VariantField(field_type)
-    elif isinstance(field_type, ArrayFieldDeclaration):
-        return ArrayField(field_type)
-    elif isinstance(field_type, SequenceFieldDeclaration):
-        return SequenceField(field_type)
-    elif isinstance(field_type, StringFieldDeclaration):
-        return StringField(field_type)
-
-
-class Field:
-    """
-    Base class of all fields. This class is not meant to be
-    instantiated by the user, and neither are its subclasses. Use
-    :meth:`Event.payload` to access specific, concrete fields of
-    an event.
-    """
-
-    def __init__(self, field_type):
-        if not isinstance(field_type, FieldDeclaration):
-            raise TypeError("Invalid field_type argument.")
-
-        self._f = nbt._bt_ctf_field_create(field_type._ft)
-
-        if self._f is None:
-            raise ValueError("Field creation failed.")
-
-    def __del__(self):
-        nbt._bt_ctf_field_put(self._f)
-
-    @staticmethod
-    def _create_field_from_native_instance(native_field_instance):
-        type_dict = {
-            common.CTFTypeId.INTEGER: IntegerField,
-            common.CTFTypeId.FLOAT: FloatingPointField,
-            common.CTFTypeId.ENUM: EnumerationField,
-            common.CTFTypeId.STRING: StringField,
-            common.CTFTypeId.STRUCT: StructureField,
-            common.CTFTypeId.VARIANT: VariantField,
-            common.CTFTypeId.ARRAY: ArrayField,
-            common.CTFTypeId.SEQUENCE: SequenceField
-        }
-
-        field_type = nbt._bt_python_get_field_type(native_field_instance)
-
-        if field_type == common.CTFTypeId.UNKNOWN:
-            raise TypeError("Invalid field instance")
-
-        field = Field.__new__(Field)
-        field._f = native_field_instance
-        field.__class__ = type_dict[field_type]
-
-        return field
-
-    @property
-    def declaration(self):
-        """
-        Field declaration (subclass of :class:`FieldDeclaration`).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        native_field_type = nbt._bt_ctf_field_get_type(self._f)
-
-        if native_field_type is None:
-            raise TypeError("Invalid field instance")
-        return FieldDeclaration._create_field_declaration_from_native_instance(
-            native_field_type)
-
-
-class IntegerField(Field):
-    """
-    Integer field, based on an :class:`IntegerFieldDeclaration` object.
-    """
-
-    @property
-    def value(self):
-        """
-        Integer value (:class:`int`).
-
-        Set this attribute to change the integer field's value.
-
-        :exc:`ValueError` or :exc:`TypeError` are raised on error.
-        """
-
-        signedness = nbt._bt_python_field_integer_get_signedness(self._f)
-
-        if signedness < 0:
-            raise TypeError("Invalid integer instance.")
-
-        if signedness == 0:
-            ret, value = nbt._bt_ctf_field_unsigned_integer_get_value(self._f)
-        else:
-            ret, value = nbt._bt_ctf_field_signed_integer_get_value(self._f)
-
-        if ret < 0:
-            raise ValueError("Could not get integer field value.")
-
-        return value
-
-    @value.setter
-    def value(self, value):
-        if not isinstance(value, int):
-            raise TypeError("IntegerField's value must be an int")
-
-        signedness = nbt._bt_python_field_integer_get_signedness(self._f)
-        if signedness < 0:
-            raise TypeError("Invalid integer instance.")
-
-        if signedness == 0:
-            ret = nbt._bt_ctf_field_unsigned_integer_set_value(self._f, value)
-        else:
-            ret = nbt._bt_ctf_field_signed_integer_set_value(self._f, value)
-
-        if ret < 0:
-            raise ValueError("Could not set integer field value.")
-
-
-class EnumerationField(Field):
-    """
-    Enumeration field, based on an
-    :class:`EnumerationFieldDeclaration` object.
-    """
-
-    @property
-    def container(self):
-        """
-        Underlying container (:class:`IntegerField`).
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        container = IntegerField.__new__(IntegerField)
-        container._f = nbt._bt_ctf_field_enumeration_get_container(self._f)
-
-        if container._f is None:
-            raise TypeError("Invalid enumeration field type.")
-
-        return container
-
-    @property
-    def value(self):
-        """
-        Current label of this enumeration field (:class:`str`).
-
-        Set this attribute to an integer (:class:`int`) to change the
-        enumeration field's value.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        value = nbt._bt_ctf_field_enumeration_get_mapping_name(self._f)
-
-        if value is None:
-            raise ValueError("Could not get enumeration mapping name.")
-
-        return value
-
-    @value.setter
-    def value(self, value):
-        if not isinstance(value, int):
-            raise TypeError("EnumerationField value must be an int")
-
-        self.container.value = value
-
-
-class FloatingPointField(Field):
-    """
-    Floating point number field, based on a
-    :class:`FloatingPointFieldDeclaration` object.
-    """
-
-    @property
-    def value(self):
-        """
-        Floating point number value (:class:`float`).
-
-        Set this attribute to change the floating point number field's
-        value.
-
-        :exc:`ValueError` or :exc:`TypeError` are raised on error.
-        """
-
-        ret, value = nbt._bt_ctf_field_floating_point_get_value(self._f)
-
-        if ret < 0:
-            raise ValueError("Could not get floating point field value.")
-
-        return value
-
-    @value.setter
-    def value(self, value):
-        if not isinstance(value, int) and not isinstance(value, float):
-            raise TypeError("Value must be either a float or an int")
-
-        ret = nbt._bt_ctf_field_floating_point_set_value(self._f, float(value))
-
-        if ret < 0:
-            raise ValueError("Could not set floating point field value.")
-
-
-# oops!! This class is provided to ensure backward-compatibility since
-# a stable release publicly exposed this abomination.
-class FloatFieldingPoint(FloatingPointField):
-    pass
-
-
-class StructureField(Field):
-    """
-    Structure field, based on a
-    :class:`StructureFieldDeclaration` object.
-    """
-
-    def field(self, field_name):
-        """
-        Returns the structure :class:`Field` named *field_name*.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        native_instance = nbt._bt_ctf_field_structure_get_field(self._f,
-                                                                str(field_name))
-
-        if native_instance is None:
-            raise ValueError("Invalid field_name provided.")
-
-        return Field._create_field_from_native_instance(native_instance)
-
-
-class VariantField(Field):
-    """
-    Variant field, based on a
-    :class:`VariantFieldDeclaration` object.
-    """
-
-    def field(self, tag):
-        """
-        Returns the :class:`Field` selected by the current label of
-        *tag* (:class:`EnumerationField`).
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        native_instance = nbt._bt_ctf_field_variant_get_field(self._f, tag._f)
-
-        if native_instance is None:
-            raise ValueError("Invalid tag provided.")
-
-        return Field._create_field_from_native_instance(native_instance)
-
-
-class ArrayField(Field):
-    """
-    Static array field, based on an
-    :class:`ArrayFieldDeclaration` object.
-    """
-
-    def field(self, index):
-        """
-        Returns the :class:`Field` at index *index* in this static
-        array.
-
-        :exc:`IndexError` is raised on error.
-        """
-
-        native_instance = nbt._bt_ctf_field_array_get_field(self._f, index)
-
-        if native_instance is None:
-            raise IndexError("Invalid index provided.")
-
-        return Field._create_field_from_native_instance(native_instance)
-
-
-class SequenceField(Field):
-    """
-    Sequence (dynamic array) field, based on a
-    :class:`SequenceFieldDeclaration` object.
-    """
-
-    @property
-    def length(self):
-        """
-        Sequence length (:class:`IntegerField`).
-
-        Set this attribute to change the sequence length's integer
-        field (integer must be unsigned).
-
-        :exc:`ValueError` or :exc:`TypeError` are raised on error.
-        """
-
-        native_instance = nbt._bt_ctf_field_sequence_get_length(self._f)
-
-        if native_instance is None:
-            length = -1
-
-        return Field._create_field_from_native_instance(native_instance)
-
-    @length.setter
-    def length(self, length_field):
-        if not isinstance(length_field, IntegerField):
-            raise TypeError("Invalid length field.")
-
-        if length_field.declaration.signed:
-            raise TypeError("Sequence field length must be unsigned")
-
-        ret = nbt._bt_ctf_field_sequence_set_length(self._f, length_field._f)
-
-        if ret < 0:
-            raise ValueError("Could not set sequence length.")
-
-    def field(self, index):
-        """
-        Returns the :class:`Field` at index *index* in this sequence.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        native_instance = nbt._bt_ctf_field_sequence_get_field(self._f, index)
-
-        if native_instance is None:
-            raise ValueError("Could not get sequence element at index.")
-
-        return Field._create_field_from_native_instance(native_instance)
-
-
-class StringField(Field):
-    """
-    String (NULL-terminated array of bytes) field.
-    """
-
-    @property
-    def value(self):
-        """
-        String value (:class:`str`).
-
-        Set this attribute to change the string's value.
-
-        :exc:`ValueError` or :exc:`TypeError` are raised on error.
-        """
-
-        return nbt._bt_ctf_field_string_get_value(self._f)
-
-    @value.setter
-    def value(self, value):
-        ret = nbt._bt_ctf_field_string_set_value(self._f, str(value))
-
-        if ret < 0:
-            raise ValueError("Could not set string field value.")
-
-
-class EventClass:
-    """
-    An event class contains the properties of specific
-    events (:class:`Event`). Any concrete event must be linked with an
-    :class:`EventClass`.
-
-    Some attributes are automatically set when creating an event class.
-    For example, if no numeric ID is explicitly set using the
-    :attr:`id` attribute, a default, unique ID within the stream class
-    containing this event class will be created when needed.
-    """
-
-    def __init__(self, name):
-        """
-        Creates an event class named *name*.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._ec = nbt._bt_ctf_event_class_create(name)
-
-        if self._ec is None:
-            raise ValueError("Event class creation failed.")
-
-    def __del__(self):
-        nbt._bt_ctf_event_class_put(self._ec)
-
-    def add_field(self, field_type, field_name):
-        """
-        Adds a field declaration *field_type* named *field_name* to
-        this event class.
-
-        *field_type* must be one of:
-
-        * :class:`IntegerFieldDeclaration`
-        * :class:`FloatingPointFieldDeclaration`
-        * :class:`EnumerationFieldDeclaration`
-        * :class:`StringFieldDeclaration`
-        * :class:`ArrayFieldDeclaration`
-        * :class:`SequenceFieldDeclaration`
-        * :class:`StructureFieldDeclaration`
-        * :class:`VariantFieldDeclaration`
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_event_class_add_field(self._ec, field_type._ft,
-                                                str(field_name))
-
-        if ret < 0:
-            raise ValueError("Could not add field to event class.")
-
-    @property
-    def name(self):
-        """
-        Event class' name.
-        """
-
-        name = nbt._bt_ctf_event_class_get_name(self._ec)
-
-        if name is None:
-            raise TypeError("Could not get EventClass name")
-
-        return name
-
-    @property
-    def id(self):
-        """
-        Event class' numeric ID.
-
-        Set this attribute to assign a numeric ID to this event class.
-        This ID must be unique amongst all the event class IDs of a
-        given stream class.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        id = nbt._bt_ctf_event_class_get_id(self._ec)
-
-        if id < 0:
-            raise TypeError("Could not get EventClass id")
-
-        return id
-
-    @id.setter
-    def id(self, id):
-        ret = nbt._bt_ctf_event_class_set_id(self._ec, id)
-
-        if ret < 0:
-            raise TypeError("Can't change an Event Class id after it has been assigned to a stream class")
-
-    @property
-    def stream_class(self):
-        """
-        :class:`StreamClass` object containing this event class,
-        or ``None`` if not set.
-        """
-
-        stream_class_native = nbt._bt_ctf_event_class_get_stream_class(self._ec)
-
-        if stream_class_native is None:
-            return None
-
-        stream_class = StreamClass.__new__(StreamClass)
-        stream_class._sc = stream_class_native
-
-        return stream_class
-
-    @property
-    def fields(self):
-        """
-        Generates the (field name, :class:`FieldDeclaration`) pairs of
-        this event class.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        count = nbt._bt_ctf_event_class_get_field_count(self._ec)
-
-        if count < 0:
-            raise TypeError("Could not get EventClass' field count")
-
-        for i in range(count):
-            field_name = nbt._bt_python_ctf_event_class_get_field_name(self._ec, i)
-
-            if field_name is None:
-                msg = "Could not get EventClass' field name at index {}".format(i)
-                raise TypeError(msg)
-
-            field_type_native = nbt._bt_python_ctf_event_class_get_field_type(self._ec, i)
-
-            if field_type_native is None:
-                msg = "Could not get EventClass' field type at index {}".format(i)
-                raise TypeError(msg)
-
-            field_type = FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-            yield (field_name, field_type)
-
-    def get_field_by_name(self, name):
-        """
-        Returns the :class:`FieldDeclaration` object named *name* in
-        this event class.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        field_type_native = nbt._bt_ctf_event_class_get_field_by_name(self._ec, name)
-
-        if field_type_native is None:
-            msg = "Could not find EventClass field with name {}".format(name)
-            raise TypeError(msg)
-
-        return FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-
-
-class Event:
-    """
-    Events are specific instances of event classes
-    (:class:`EventClass`), which means they may contain actual,
-    concrete field values.
-    """
-
-    def __init__(self, event_class):
-        """
-        Creates an event linked with the :class:`EventClass`
-        *event_class*.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        if not isinstance(event_class, EventClass):
-            raise TypeError("Invalid event_class argument.")
-
-        self._e = nbt._bt_ctf_event_create(event_class._ec)
-
-        if self._e is None:
-            raise ValueError("Event creation failed.")
-
-    def __del__(self):
-        nbt._bt_ctf_event_put(self._e)
-
-    @property
-    def event_class(self):
-        """
-        :class:`EventClass` object to which this event is linked.
-        """
-
-        event_class_native = nbt._bt_ctf_event_get_class(self._e)
-
-        if event_class_native is None:
-            return None
-
-        event_class = EventClass.__new__(EventClass)
-        event_class._ec = event_class_native
-
-        return event_class
-
-    def clock(self):
-        """
-        :class:`Clock` object used by this object, or ``None`` if
-        the event class is not registered to a stream class.
-        """
-
-        clock_instance = nbt._bt_ctf_event_get_clock(self._e)
-
-        if clock_instance is None:
-            return None
-
-        clock = Clock.__new__(Clock)
-        clock._c = clock_instance
-
-        return clock
-
-    def payload(self, field_name):
-        """
-        Returns the :class:`Field` object named *field_name* in this
-        event.
-
-        The returned field object is created using the event class'
-        field declaration named *field_name*.
-
-        The return type is one of:
-
-        * :class:`IntegerField`
-        * :class:`FloatingPointField`
-        * :class:`EnumerationField`
-        * :class:`StringField`
-        * :class:`ArrayField`
-        * :class:`SequenceField`
-        * :class:`StructureField`
-        * :class:`VariantField`
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        native_instance = nbt._bt_ctf_event_get_payload(self._e,
-                                                        str(field_name))
-
-        if native_instance is None:
-            raise ValueError("Could not get event payload.")
-
-        return Field._create_field_from_native_instance(native_instance)
-
-    def set_payload(self, field_name, value_field):
-        """
-        Set the event's field named *field_name* to the manually
-        created :class:`Field` object *value_field*.
-
-        *value_field*'s type must be one of:
-
-        * :class:`IntegerField`
-        * :class:`FloatingPointField`
-        * :class:`EnumerationField`
-        * :class:`StringField`
-        * :class:`ArrayField`
-        * :class:`SequenceField`
-        * :class:`StructureField`
-        * :class:`VariantField`
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        if not isinstance(value, Field):
-            raise TypeError("Invalid value type.")
-
-        ret = nbt._bt_ctf_event_set_payload(self._e, str(field_name),
-                                            value_field._f)
-
-        if ret < 0:
-            raise ValueError("Could not set event field payload.")
-
-    @property
-    def stream_context(self):
-        """
-        Stream event context field (instance of
-        :class:`StructureField`).
-
-        Set this attribute to assign a stream event context field
-        to this stream.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        native_field = nbt._bt_ctf_event_get_stream_event_context(self._e)
-
-        if native_field is None:
-            raise ValueError("Invalid Stream.")
-
-        return Field._create_field_from_native_instance(native_field)
-
-    @stream_context.setter
-    def stream_context(self, field):
-        if not isinstance(field, StructureField):
-            raise TypeError("Argument field must be of type StructureField")
-
-        ret = nbt._bt_ctf_event_set_stream_event_context(self._e, field._f)
-
-        if ret < 0:
-            raise ValueError("Invalid stream context field.")
-
-class StreamClass:
-    """
-    A stream class contains the properties of specific
-    streams (:class:`Stream`). Any concrete stream must be linked with
-    a :class:`StreamClass`, usually by calling
-    :meth:`Writer.create_stream`.
-
-    Some attributes are automatically set when creating a stream class.
-    For example, if no clock is explicitly set using the
-    :attr:`clock` attribute, a default clock will be created
-    when needed.
-    """
-
-    def __init__(self, name):
-        """
-        Creates a stream class named *name*.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        self._sc = nbt._bt_ctf_stream_class_create(name)
-
-        if self._sc is None:
-            raise ValueError("Stream class creation failed.")
-
-    def __del__(self):
-        nbt._bt_ctf_stream_class_put(self._sc)
-
-    @property
-    def name(self):
-        """
-        Stream class' name.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        name = nbt._bt_ctf_stream_class_get_name(self._sc)
-
-        if name is None:
-            raise TypeError("Could not get StreamClass name")
-
-        return name
-
-    @property
-    def clock(self):
-        """
-        Stream class' clock (:class:`Clock` object).
-
-        Set this attribute to change the clock of this stream class.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        clock_instance = nbt._bt_ctf_stream_class_get_clock(self._sc)
-
-        if clock_instance is None:
-            return None
-
-        clock = Clock.__new__(Clock)
-        clock._c = clock_instance
-
-        return clock
-
-    @clock.setter
-    def clock(self, clock):
-        if not isinstance(clock, Clock):
-            raise TypeError("Invalid clock type.")
-
-        ret = nbt._bt_ctf_stream_class_set_clock(self._sc, clock._c)
-
-        if ret < 0:
-            raise ValueError("Could not set stream class clock.")
-
-    @property
-    def id(self):
-        """
-        Stream class' numeric ID.
-
-        Set this attribute to change the ID of this stream class.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_stream_class_get_id(self._sc)
-
-        if ret < 0:
-            raise TypeError("Could not get StreamClass id")
-
-        return ret
-
-    @id.setter
-    def id(self, id):
-        ret = nbt._bt_ctf_stream_class_set_id(self._sc, id)
-
-        if ret < 0:
-            raise TypeError("Could not set stream class id.")
-
-    @property
-    def event_classes(self):
-        """
-        Generates the event classes (:class:`EventClass` objects) of
-        this stream class.
-
-        :exc:`TypeError` is raised on error.
-        """
-
-        count = nbt._bt_ctf_stream_class_get_event_class_count(self._sc)
-
-        if count < 0:
-            raise TypeError("Could not get StreamClass' event class count")
-
-        for i in range(count):
-            event_class_native = nbt._bt_ctf_stream_class_get_event_class(self._sc, i)
-
-            if event_class_native is None:
-                msg = "Could not get StreamClass' event class at index {}".format(i)
-                raise TypeError(msg)
-
-            event_class = EventClass.__new__(EventClass)
-            event_class._ec = event_class_native
-            yield event_class
-
-    def add_event_class(self, event_class):
-        """
-        Registers the :class:`EventClass` *event_class* to this stream
-        class.
-
-        Once the event class is registered, it will be generated as one
-        of the event classes generated by :attr:`event_classes`.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        if not isinstance(event_class, EventClass):
-            raise TypeError("Invalid event_class type.")
-
-        ret = nbt._bt_ctf_stream_class_add_event_class(self._sc,
-                                                       event_class._ec)
-
-        if ret < 0:
-            raise ValueError("Could not add event class.")
-
-    @property
-    def packet_context_type(self):
-        """
-        Stream packet context declaration.
-
-        Set this attribute to change the stream packet context
-        declaration (must be an instance of
-        :class:`StructureFieldDeclaration`).
-
-        :exc:`ValueError` is raised on error.
-
-        """
-
-        field_type_native = nbt._bt_ctf_stream_class_get_packet_context_type(self._sc)
-
-        if field_type_native is None:
-            raise ValueError("Invalid StreamClass")
-
-        field_type = FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-
-        return field_type
-
-    @packet_context_type.setter
-    def packet_context_type(self, field_type):
-        if not isinstance(field_type, StructureFieldDeclaration):
-            raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
-
-        ret = nbt._bt_ctf_stream_class_set_packet_context_type(self._sc,
-                                                               field_type._ft)
-
-        if ret < 0:
-            raise ValueError("Failed to set packet context type.")
-
-    @property
-    def event_context_type(self):
-        """
-        Stream event context declaration.
-
-        Set this attribute to change the stream event context
-        declaration (must be an instance of
-        :class:`StructureFieldDeclaration`).
-
-        :exc:`ValueError` is raised on error.
-
-        """
-
-        field_type_native = nbt._bt_ctf_stream_class_get_event_context_type(self._sc)
-
-        if field_type_native is None:
-            raise ValueError("Invalid StreamClass")
-
-        field_type = FieldDeclaration._create_field_declaration_from_native_instance(field_type_native)
-
-        return field_type
-
-    @event_context_type.setter
-    def event_context_type(self, field_type):
-        if not isinstance(field_type, StructureFieldDeclaration):
-            raise TypeError("field_type argument must be of type StructureFieldDeclaration.")
-
-        ret = nbt._bt_ctf_stream_class_set_event_context_type(self._sc,
-                                                              field_type._ft)
-
-        if ret < 0:
-            raise ValueError("Failed to set event context type.")
-
-
-class Stream:
-    """
-    Streams are specific instances of stream classes, which means they
-    may contain actual, concrete events.
-
-    :class:`Stream` objects are returned by
-    :meth:`Writer.create_stream`; they are not meant to be
-    instantiated by the user.
-
-    Concrete :class:`Event` objects are appended to
-    :class:`Stream` objects using :meth:`append_event`.
-
-    When :meth:`flush` is called, a CTF packet is created, containing
-    all the appended events since the last flush. Although the stream
-    is flushed on object destruction, it is **strongly recommended**
-    that the user call :meth:`flush` manually before exiting the
-    script, as :meth:`__del__` is not always reliable.
-    """
-
-    def __init__(self):
-        raise NotImplementedError("Stream cannot be instantiated; use Writer.create_stream()")
-
-    def __del__(self):
-        nbt._bt_ctf_stream_put(self._s)
-
-    @property
-    def discarded_events(self):
-        """
-        Number of discarded (lost) events in this stream so far.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret, count = nbt._bt_ctf_stream_get_discarded_events_count(self._s)
-
-        if ret < 0:
-            raise ValueError("Could not get the stream discarded events count")
-
-        return count
-
-    def append_discarded_events(self, event_count):
-        """
-        Appends *event_count* discarded events to this stream.
-        """
-
-        nbt._bt_ctf_stream_append_discarded_events(self._s, event_count)
-
-    def append_event(self, event):
-        """
-        Appends event *event* (:class:`Event` object) to this stream.
-
-        The stream's associated clock will be sampled during this call.
-        *event* **shall not** be modified after being appended to this
-        stream.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_stream_append_event(self._s, event._e)
-
-        if ret < 0:
-            raise ValueError("Could not append event to stream.")
-
-    @property
-    def packet_context(self):
-        """
-        Stream packet context field (instance of
-        :class:`StructureField`).
-
-        Set this attribute to assign a stream packet context field
-        to this stream.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        native_field = nbt._bt_ctf_stream_get_packet_context(self._s)
-
-        if native_field is None:
-            raise ValueError("Invalid Stream.")
-
-        return Field._create_field_from_native_instance(native_field)
-
-    @packet_context.setter
-    def packet_context(self, field):
-        if not isinstance(field, StructureField):
-            raise TypeError("Argument field must be of type StructureField")
-
-        ret = nbt._bt_ctf_stream_set_packet_context(self._s, field._f)
-
-        if ret < 0:
-            raise ValueError("Invalid packet context field.")
-
-    def flush(self):
-        """
-        Flushes the current packet of this stream to disk. Events
-        subsequently appended to the stream will be added to a new
-        packet.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        ret = nbt._bt_ctf_stream_flush(self._s)
-
-        if ret < 0:
-            raise ValueError("Could not flush stream.")
-
-
-class Writer:
-    """
-    This object is the CTF writer API context. It oversees its streams
-    and clocks, and is responsible for writing one CTF trace.
-    """
-
-    def __init__(self, path):
-        """
-        Creates a CTF writer, initializing a new CTF trace at path
-        *path*.
-
-        *path* must be an existing directory, since a CTF trace is
-        made of multiple files.
-
-        :exc:`ValueError` is raised if the creation fails.
-        """
-
-        self._w = nbt._bt_ctf_writer_create(path)
-
-        if self._w is None:
-            raise ValueError("Writer creation failed.")
-
-    def __del__(self):
-        nbt._bt_ctf_writer_put(self._w)
-
-    def create_stream(self, stream_class):
-        """
-        Creates and registers a new stream based on stream class
-        *stream_class*.
-
-        This is the standard way of creating a :class:`Stream` object:
-        the user is not allowed to instantiate this class.
-
-        Returns a new :class:`Stream` object.
-        """
-
-        if not isinstance(stream_class, StreamClass):
-            raise TypeError("Invalid stream_class type.")
-
-        stream = Stream.__new__(Stream)
-        stream._s = nbt._bt_ctf_writer_create_stream(self._w, stream_class._sc)
-
-        return stream
-
-    def add_environment_field(self, name, value):
-        """
-        Sets the CTF environment variable named *name* to value *value*
-        (converted to a string).
-
-        :exc:`ValueError` or `TypeError` is raised on error.
-        """
-
-        if type(name) != str:
-            raise TypeError("Field name must be a string.")
-
-        t = type(value)
-
-        if t == str:
-            ret = nbt._bt_ctf_writer_add_environment_field(self._w, name,
-                                                           value)
-        elif t == int:
-            ret = nbt._bt_ctf_writer_add_environment_field_int64(self._w,
-                                                                 name,
-                                                                 value)
-        else:
-            raise TypeError("Value type is not supported.")
-
-        if ret < 0:
-            raise ValueError("Could not add environment field to trace.")
-
-    def add_clock(self, clock):
-        """
-        Registers :class:`Clock` object *clock* to the writer.
-
-        You *must* register CTF clocks assigned to stream classes
-        to the writer.
-
-        :exc:`ValueError` is raised if the creation fails.
-        """
-
-        ret = nbt._bt_ctf_writer_add_clock(self._w, clock._c)
-
-        if ret < 0:
-            raise ValueError("Could not add clock to Writer.")
-
-    @property
-    def metadata(self):
-        """
-        Current metadata of this trace (:class:`str`).
-        """
-
-        return nbt._bt_ctf_writer_get_metadata_string(self._w)
-
-    def flush_metadata(self):
-        """
-        Flushes the trace's metadata to the metadata file.
-        """
-
-        nbt._bt_ctf_writer_flush_metadata(self._w)
-
-    @property
-    def byte_order(self):
-        """
-        Native byte order of this trace (one of
-        :class:`babeltrace.common.ByteOrder` constants).
-
-        This is the actual byte order that is used when a field
-        declaration has the
-        :attr:`babeltrace.common.ByteOrder.BYTE_ORDER_NATIVE`
-        value.
-
-        Set this attribute to change the trace's native byte order.
-
-        Defaults to the host machine's endianness.
-
-        :exc:`ValueError` is raised on error.
-        """
-
-        raise NotImplementedError("Getter not implemented.")
-
-    @byte_order.setter
-    def byte_order(self, byte_order):
-        ret = nbt._bt_ctf_writer_set_byte_order(self._w, byte_order)
-
-        if ret < 0:
-            raise ValueError("Could not set trace byte order.")
index 749e2d23babfb882e149a95d9cbc5857d42cf7b6..c4ea8242bf1d0fa18a2b6025be31f6a54cb889b4 100644 (file)
@@ -642,6 +642,9 @@ AC_SUBST(program_transform_name)
 AC_CONFIG_FILES([
        Makefile
        bindings/python/Makefile
+       bindings/python/babeltrace/Makefile
+       bindings/python/babeltrace/setup.py
+       bindings/python/babeltrace/babeltrace/__init__.py
        bindings/python/bt2/Makefile
        bindings/python/bt2/setup.py
        bindings/python/bt2/bt2/__init__.py
This page took 0.108996 seconds and 4 git commands to generate.