Build Python bindings with distutils for consistent installs
authorMichael Jeanson <mjeanson@efficios.com>
Wed, 23 Aug 2017 15:43:05 +0000 (11:43 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 29 Aug 2017 21:47:59 +0000 (17:47 -0400)
This patch changes the build system used to compile and install the
Python Bindings. Distutils is used to find the right install directory.
When the install directory generated from the install prefix is not in
the Python search path (PYTHONPATH), we print a warning explaining what
can be done to include it.
It uses Distutils which is part of the Python standard library.

Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
105 files changed:
bindings/python/bt2/.gitignore
bindings/python/bt2/Makefile.am
bindings/python/bt2/__init__.py.in [deleted file]
bindings/python/bt2/bt2/__init__.py.in [new file with mode: 0644]
bindings/python/bt2/bt2/clock_class.py [new file with mode: 0644]
bindings/python/bt2/bt2/clock_class_priority_map.py [new file with mode: 0644]
bindings/python/bt2/bt2/component.py [new file with mode: 0644]
bindings/python/bt2/bt2/connection.py [new file with mode: 0644]
bindings/python/bt2/bt2/ctf_writer.py [new file with mode: 0644]
bindings/python/bt2/bt2/event.py [new file with mode: 0644]
bindings/python/bt2/bt2/event_class.py [new file with mode: 0644]
bindings/python/bt2/bt2/field_types.py [new file with mode: 0644]
bindings/python/bt2/bt2/fields.py [new file with mode: 0644]
bindings/python/bt2/bt2/graph.py [new file with mode: 0644]
bindings/python/bt2/bt2/logging.c [new file with mode: 0644]
bindings/python/bt2/bt2/logging.h [new file with mode: 0644]
bindings/python/bt2/bt2/logging.py [new file with mode: 0644]
bindings/python/bt2/bt2/native_bt.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btccpriomap.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btclockclass.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btcomponent.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btcomponentclass.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btconnection.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btctfwriter.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btevent.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_bteventclass.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btfields.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btft.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btgraph.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btlogging.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btnotification.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btnotifiter.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btpacket.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btplugin.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btport.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btref.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btstream.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btstreamclass.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_bttrace.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btvalues.i [new file with mode: 0644]
bindings/python/bt2/bt2/native_btversion.i [new file with mode: 0644]
bindings/python/bt2/bt2/notification.py [new file with mode: 0644]
bindings/python/bt2/bt2/notification_iterator.py [new file with mode: 0644]
bindings/python/bt2/bt2/object.py [new file with mode: 0644]
bindings/python/bt2/bt2/packet.py [new file with mode: 0644]
bindings/python/bt2/bt2/plugin.py [new file with mode: 0644]
bindings/python/bt2/bt2/port.py [new file with mode: 0644]
bindings/python/bt2/bt2/py_plugin.py [new file with mode: 0644]
bindings/python/bt2/bt2/stream.py [new file with mode: 0644]
bindings/python/bt2/bt2/stream_class.py [new file with mode: 0644]
bindings/python/bt2/bt2/trace.py [new file with mode: 0644]
bindings/python/bt2/bt2/utils.py [new file with mode: 0644]
bindings/python/bt2/bt2/values.py [new file with mode: 0644]
bindings/python/bt2/clock_class.py [deleted file]
bindings/python/bt2/clock_class_priority_map.py [deleted file]
bindings/python/bt2/component.py [deleted file]
bindings/python/bt2/connection.py [deleted file]
bindings/python/bt2/ctf_writer.py [deleted file]
bindings/python/bt2/event.py [deleted file]
bindings/python/bt2/event_class.py [deleted file]
bindings/python/bt2/field_types.py [deleted file]
bindings/python/bt2/fields.py [deleted file]
bindings/python/bt2/graph.py [deleted file]
bindings/python/bt2/logging.c [deleted file]
bindings/python/bt2/logging.h [deleted file]
bindings/python/bt2/logging.py [deleted file]
bindings/python/bt2/native_bt.i [deleted file]
bindings/python/bt2/native_btccpriomap.i [deleted file]
bindings/python/bt2/native_btclockclass.i [deleted file]
bindings/python/bt2/native_btcomponent.i [deleted file]
bindings/python/bt2/native_btcomponentclass.i [deleted file]
bindings/python/bt2/native_btconnection.i [deleted file]
bindings/python/bt2/native_btctfwriter.i [deleted file]
bindings/python/bt2/native_btevent.i [deleted file]
bindings/python/bt2/native_bteventclass.i [deleted file]
bindings/python/bt2/native_btfields.i [deleted file]
bindings/python/bt2/native_btft.i [deleted file]
bindings/python/bt2/native_btgraph.i [deleted file]
bindings/python/bt2/native_btlogging.i [deleted file]
bindings/python/bt2/native_btnotification.i [deleted file]
bindings/python/bt2/native_btnotifiter.i [deleted file]
bindings/python/bt2/native_btpacket.i [deleted file]
bindings/python/bt2/native_btplugin.i [deleted file]
bindings/python/bt2/native_btport.i [deleted file]
bindings/python/bt2/native_btref.i [deleted file]
bindings/python/bt2/native_btstream.i [deleted file]
bindings/python/bt2/native_btstreamclass.i [deleted file]
bindings/python/bt2/native_bttrace.i [deleted file]
bindings/python/bt2/native_btvalues.i [deleted file]
bindings/python/bt2/native_btversion.i [deleted file]
bindings/python/bt2/notification.py [deleted file]
bindings/python/bt2/notification_iterator.py [deleted file]
bindings/python/bt2/object.py [deleted file]
bindings/python/bt2/packet.py [deleted file]
bindings/python/bt2/plugin.py [deleted file]
bindings/python/bt2/port.py [deleted file]
bindings/python/bt2/py_plugin.py [deleted file]
bindings/python/bt2/setup.py.in [new file with mode: 0644]
bindings/python/bt2/stream.py [deleted file]
bindings/python/bt2/stream_class.py [deleted file]
bindings/python/bt2/trace.py [deleted file]
bindings/python/bt2/utils.py [deleted file]
bindings/python/bt2/values.py [deleted file]
configure.ac
tests/bindings/python/bt2/test_python_bt2.in

index 56bd6e98f6ffb6a2fb72ee3c776f11153a4d7c06..b893bced7dbf0b4b3ea157025765bf5d4594cb6f 100644 (file)
@@ -1,3 +1,7 @@
-__init__.py
-native_bt.py
-native_bt_wrap.c
+bt2/__init__.py
+bt2/native_bt.py
+bt2/native_bt_wrap.c
+build
+build-python-bindings.stamp
+installed_files.txt
+setup.py
index 7b20517f7c231e2b4b1aadea39c0af7d15d12279..f41e2c07ce6e92ede4f1c42f0da39a9a3596c397 100644 (file)
-# native module name (without `.i` extension)
-NATIVE_MODULE = native_bt
+# 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
 
-# interface dependencies (without `native_bt` prefix and `.i` extension)
-NATIVE_MODULE_DEPS =   \
-       ccpriomap       \
-       clockclass      \
-       component       \
-       componentclass  \
-       connection      \
-       ctfwriter       \
-       event           \
-       eventclass      \
-       fields          \
-       ft              \
-       graph           \
-       logging         \
-       notification    \
-       notifiter       \
-       packet          \
-       plugin          \
-       port            \
-       ref             \
-       stream          \
-       streamclass     \
-       trace           \
-       values          \
-       version
+INSTALLED_FILES=$(builddir)/installed_files.txt
 
-# Python modules (without `.py` extension)
-EXTRA_MODULES =                        \
-       clock_class                     \
-       clock_class_priority_map        \
-       component                       \
-       connection                      \
-       ctf_writer                      \
-       event                           \
-       event_class                     \
-       field_types                     \
-       fields                          \
-       graph                           \
-       logging                         \
-       notification                    \
-       notification_iterator           \
-       object                          \
-       packet                          \
-       plugin                          \
-       port                            \
-       py_plugin                       \
-       stream                          \
-       stream_class                    \
-       trace                           \
-       utils                           \
-       values
+STATIC_BINDINGS_DEPS =                 \
+       bt2/logging.c                   \
+       bt2/logging.h                   \
+       bt2/native_btccpriomap.i        \
+       bt2/native_btclockclass.i       \
+       bt2/native_btcomponentclass.i   \
+       bt2/native_btcomponent.i        \
+       bt2/native_btconnection.i       \
+       bt2/native_btctfwriter.i        \
+       bt2/native_bteventclass.i       \
+       bt2/native_btevent.i            \
+       bt2/native_btfields.i           \
+       bt2/native_btft.i               \
+       bt2/native_btgraph.i            \
+       bt2/native_bt.i                 \
+       bt2/native_btlogging.i          \
+       bt2/native_btnotification.i     \
+       bt2/native_btnotifiter.i        \
+       bt2/native_btpacket.i           \
+       bt2/native_btplugin.i           \
+       bt2/native_btport.i             \
+       bt2/native_btref.i              \
+       bt2/native_btstreamclass.i      \
+       bt2/native_btstream.i           \
+       bt2/native_bttrace.i            \
+       bt2/native_btvalues.i           \
+       bt2/native_btversion.i          \
+       bt2/clock_class_priority_map.py \
+       bt2/clock_class.py              \
+       bt2/component.py                \
+       bt2/connection.py               \
+       bt2/ctf_writer.py               \
+       bt2/event_class.py              \
+       bt2/event.py                    \
+       bt2/fields.py                   \
+       bt2/field_types.py              \
+       bt2/graph.py                    \
+       bt2/logging.py                  \
+       bt2/notification_iterator.py    \
+       bt2/notification.py             \
+       bt2/object.py                   \
+       bt2/packet.py                   \
+       bt2/plugin.py                   \
+       bt2/port.py                     \
+       bt2/py_plugin.py                \
+       bt2/stream_class.py             \
+       bt2/stream.py                   \
+       bt2/trace.py                    \
+       bt2/utils.py                    \
+       bt2/values.py
 
-# automatically generated file lists
-EXTRA_MODULES_PY = $(addprefix $(srcdir)/,$(addsuffix .py,$(EXTRA_MODULES)))
-NATIVE_MODULE_I = $(srcdir)/$(NATIVE_MODULE).i
-NATIVE_MODULE_PY = $(NATIVE_MODULE).py
-NATIVE_MODULE_C = $(NATIVE_MODULE)_wrap.c
-NATIVE_MODULE_DEPS_I = $(addprefix $(srcdir)/native_bt,$(addsuffix .i,$(NATIVE_MODULE_DEPS)))
+GENERATED_BINDINGS_DEPS =              \
+       bt2/__init__.py                 \
+       setup.py
 
-# installed Python package
-nodist_bt2package_PYTHON = __init__.py $(EXTRA_MODULES_PY) $(NATIVE_MODULE_PY)
+BUILD_FLAGS=CC="$(CC)" \
+               CFLAGS="$(GLIB_CFLAGS) $(AM_CFLAGS) $(CFLAGS)" \
+               CPPFLAGS="$(AM_CPPFLAGS) $(CPPFLAGS)" \
+               LDFLAGS="$(AM_LDFLAGS) $(LDFLAGS) $(GLIB_LIBS) $(LIBS)"
 
-# native libraries to build
-nativelibs_LTLIBRARIES = _native_bt.la
+all-local: build-python-bindings.stamp
 
-# installation directory for the `bt2` package
-bt2packagedir = $(pythondir)/bt2
-nativelibsdir = $(bt2packagedir)
+build-python-bindings.stamp: $(STATIC_BINDINGS_DEPS) $(GENERATED_BINDINGS_DEPS)
+       $(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build_ext
+       $(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build
+       touch $@
 
-# SWIG to C wrapper (and Python file)
-$(NATIVE_MODULE_C): $(NATIVE_MODULE_I) $(NATIVE_MODULE_DEPS_I)
-       $(SWIG) -python -Wall -I$(srcdir) -I$(top_srcdir)/include -module $(NATIVE_MODULE) -outcurrentdir $(NATIVE_MODULE_I)
+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;
 
-# native_bt module
-_native_bt_la_SOURCES = logging.h logging.c
-nodist__native_bt_la_SOURCES = native_bt_wrap.c
-_native_bt_la_LDFLAGS = -module
-_native_bt_la_CFLAGS = $(PYTHON_INCLUDE) -I$(srcdir) $(AM_CFLAGS)
-_native_bt_la_LIBADD = \
-       $(top_builddir)/lib/libbabeltrace.la \
-       $(top_builddir)/logging/libbabeltrace-logging.la \
-       $(top_builddir)/common/libbabeltrace-common.la
-
-# extra module sources -> build directory
-all-local:
-       @if [ x"$(srcdir)" != x"$(builddir)" ]; then            \
-               for file in $(EXTRA_MODULES_PY); do             \
-                       cp -f "$(srcdir)/$$file" "$(builddir)"; \
-               done;                                           \
-       fi
-
-# clean extra module sources in build directory
 clean-local:
-       @if [ x"$(srcdir)" != x"$(builddir)" ]; then            \
-               for file in $(EXTRA_MODULES_PY); do             \
-                       rm -f "$(srcdir)/$$file" "$(builddir)"; \
-               done;                                           \
+       rm -rf $(builddir)/build
+
+# 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 = __init__.py.in $(EXTRA_MODULES_PY) $(NATIVE_MODULE_I) $(NATIVE_MODULE_DEPS_I)
+EXTRA_DIST = $(STATIC_BINDINGS_DEPS)
 
 # clean: generated C and Python files (by SWIG)
-CLEANFILES = $(NATIVE_MODULE_PY) $(NATIVE_MODULE_C)
+CLEANFILES = bt2/native_bt.py bt2/native_bt_wrap.c build-python-bindings.stamp
diff --git a/bindings/python/bt2/__init__.py.in b/bindings/python/bt2/__init__.py.in
deleted file mode 100644 (file)
index ebab24a..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@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.
-
-__version__ = '@PACKAGE_VERSION@'
-
-
-from bt2.clock_class import *
-from bt2.clock_class import _ClockValue
-from bt2.clock_class_priority_map import *
-from bt2.component import *
-from bt2.component import _FilterComponent
-from bt2.component import _GenericFilterComponentClass
-from bt2.component import _GenericSinkComponentClass
-from bt2.component import _GenericSourceComponentClass
-from bt2.component import _SinkComponent
-from bt2.component import _SourceComponent
-from bt2.component import _UserFilterComponent
-from bt2.component import _UserSinkComponent
-from bt2.component import _UserSourceComponent
-from bt2.connection import *
-from bt2.connection import _Connection
-from bt2.connection import _PrivateConnection
-from bt2.ctf_writer import *
-from bt2.ctf_writer import _CtfWriterStream
-from bt2.event import _Event
-from bt2.event_class import *
-from bt2.field_types import *
-from bt2.field_types import _FieldType
-from bt2.fields import *
-from bt2.fields import _ArrayField
-from bt2.fields import _EnumerationField
-from bt2.fields import _Field
-from bt2.fields import _FloatingPointNumberField
-from bt2.fields import _IntegerField
-from bt2.fields import _SequenceField
-from bt2.fields import _StringField
-from bt2.fields import _StructureField
-from bt2.fields import _VariantField
-from bt2.graph import *
-from bt2.logging import *
-from bt2.notification import *
-from bt2.notification import _DiscardedEventsNotification
-from bt2.notification import _DiscardedPacketsNotification
-from bt2.notification_iterator import *
-from bt2.notification_iterator import _UserNotificationIterator
-from bt2.packet import _Packet
-from bt2.plugin import *
-from bt2.port import *
-from bt2.port import _InputPort
-from bt2.port import _OutputPort
-from bt2.port import _Port
-from bt2.port import _PrivateInputPort
-from bt2.port import _PrivateOutputPort
-from bt2.port import _PrivatePort
-from bt2.py_plugin import *
-from bt2.stream import _Stream
-from bt2.stream_class import *
-from bt2.trace import *
-from bt2.values import *
-from bt2.values import _Value
-
-
-class Error(Exception):
-    pass
-
-
-class CreationError(Error):
-    pass
-
-
-class Frozen(Error):
-    pass
-
-
-class NoSuchPlugin(Error):
-    pass
-
-
-class UnsupportedFeature(Exception):
-    pass
-
-
-class NoSinkComponent(Exception):
-    pass
-
-
-class TryAgain(Exception):
-    pass
-
-
-class Stop(StopIteration):
-    pass
-
-
-class PortConnectionRefused(Exception):
-    pass
-
-
-class IncompleteUserClass(Error):
-    pass
-
-
-class GraphCanceled(Exception):
-    pass
-
-
-class NotificationIteratorCanceled(Exception):
-    pass
-
-
-class ConnectionEnded(Exception):
-    pass
-
-
-class _ListenerHandle:
-    def __init__(self, listener_id, obj):
-        self._listener_id = listener_id
-        self._obj = obj
-
-
-import bt2.native_bt as _native_bt
-import atexit
-
-atexit.register(_native_bt.py3_cc_exit_handler)
-version = (_native_bt.version_get_major(), _native_bt.version_get_minor(),
-           _native_bt.version_get_patch(), _native_bt.version_get_extra())
-_native_bt.py3_cc_init_from_bt2()
-del _native_bt
-
-try:
-    del native_bt
-except:
-    pass
diff --git a/bindings/python/bt2/bt2/__init__.py.in b/bindings/python/bt2/bt2/__init__.py.in
new file mode 100644 (file)
index 0000000..ebab24a
--- /dev/null
@@ -0,0 +1,152 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+__version__ = '@PACKAGE_VERSION@'
+
+
+from bt2.clock_class import *
+from bt2.clock_class import _ClockValue
+from bt2.clock_class_priority_map import *
+from bt2.component import *
+from bt2.component import _FilterComponent
+from bt2.component import _GenericFilterComponentClass
+from bt2.component import _GenericSinkComponentClass
+from bt2.component import _GenericSourceComponentClass
+from bt2.component import _SinkComponent
+from bt2.component import _SourceComponent
+from bt2.component import _UserFilterComponent
+from bt2.component import _UserSinkComponent
+from bt2.component import _UserSourceComponent
+from bt2.connection import *
+from bt2.connection import _Connection
+from bt2.connection import _PrivateConnection
+from bt2.ctf_writer import *
+from bt2.ctf_writer import _CtfWriterStream
+from bt2.event import _Event
+from bt2.event_class import *
+from bt2.field_types import *
+from bt2.field_types import _FieldType
+from bt2.fields import *
+from bt2.fields import _ArrayField
+from bt2.fields import _EnumerationField
+from bt2.fields import _Field
+from bt2.fields import _FloatingPointNumberField
+from bt2.fields import _IntegerField
+from bt2.fields import _SequenceField
+from bt2.fields import _StringField
+from bt2.fields import _StructureField
+from bt2.fields import _VariantField
+from bt2.graph import *
+from bt2.logging import *
+from bt2.notification import *
+from bt2.notification import _DiscardedEventsNotification
+from bt2.notification import _DiscardedPacketsNotification
+from bt2.notification_iterator import *
+from bt2.notification_iterator import _UserNotificationIterator
+from bt2.packet import _Packet
+from bt2.plugin import *
+from bt2.port import *
+from bt2.port import _InputPort
+from bt2.port import _OutputPort
+from bt2.port import _Port
+from bt2.port import _PrivateInputPort
+from bt2.port import _PrivateOutputPort
+from bt2.port import _PrivatePort
+from bt2.py_plugin import *
+from bt2.stream import _Stream
+from bt2.stream_class import *
+from bt2.trace import *
+from bt2.values import *
+from bt2.values import _Value
+
+
+class Error(Exception):
+    pass
+
+
+class CreationError(Error):
+    pass
+
+
+class Frozen(Error):
+    pass
+
+
+class NoSuchPlugin(Error):
+    pass
+
+
+class UnsupportedFeature(Exception):
+    pass
+
+
+class NoSinkComponent(Exception):
+    pass
+
+
+class TryAgain(Exception):
+    pass
+
+
+class Stop(StopIteration):
+    pass
+
+
+class PortConnectionRefused(Exception):
+    pass
+
+
+class IncompleteUserClass(Error):
+    pass
+
+
+class GraphCanceled(Exception):
+    pass
+
+
+class NotificationIteratorCanceled(Exception):
+    pass
+
+
+class ConnectionEnded(Exception):
+    pass
+
+
+class _ListenerHandle:
+    def __init__(self, listener_id, obj):
+        self._listener_id = listener_id
+        self._obj = obj
+
+
+import bt2.native_bt as _native_bt
+import atexit
+
+atexit.register(_native_bt.py3_cc_exit_handler)
+version = (_native_bt.version_get_major(), _native_bt.version_get_minor(),
+           _native_bt.version_get_patch(), _native_bt.version_get_extra())
+_native_bt.py3_cc_init_from_bt2()
+del _native_bt
+
+try:
+    del native_bt
+except:
+    pass
diff --git a/bindings/python/bt2/bt2/clock_class.py b/bindings/python/bt2/bt2/clock_class.py
new file mode 100644 (file)
index 0000000..24b1db6
--- /dev/null
@@ -0,0 +1,279 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import uuid as uuidp
+import numbers
+import bt2
+
+
+class ClockClassOffset:
+    def __init__(self, seconds=0, cycles=0):
+        utils._check_int64(seconds)
+        utils._check_int64(cycles)
+        self._seconds = seconds
+        self._cycles = cycles
+
+    @property
+    def seconds(self):
+        return self._seconds
+
+    @property
+    def cycles(self):
+        return self._cycles
+
+    def __hash__(self):
+        return hash((self.seconds, self.cycles))
+
+    def __eq__(self, other):
+        if not isinstance(other, self.__class__):
+            # not comparing apples to apples
+            return False
+
+        return (self.seconds, self.cycles) == (other.seconds, other.cycles)
+
+
+class ClockClass(object._Object):
+    def __init__(self, name, frequency, description=None, precision=None,
+                 offset=None, is_absolute=None, uuid=None):
+        utils._check_str(name)
+        utils._check_uint64(frequency)
+        ptr = native_bt.ctf_clock_class_create(name, frequency)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create clock class object')
+
+        super().__init__(ptr)
+
+        if description is not None:
+            self.description = description
+
+        if frequency is not None:
+            self.frequency = frequency
+
+        if precision is not None:
+            self.precision = precision
+
+        if offset is not None:
+            self.offset = offset
+
+        if is_absolute is not None:
+            self.is_absolute = is_absolute
+
+        if uuid is not None:
+            self.uuid = uuid
+
+    def __eq__(self, other):
+        if type(self) is not type(other):
+            # not comparing apples to apples
+            return False
+
+        self_props = (
+            self.name,
+            self.description,
+            self.frequency,
+            self.precision,
+            self.offset,
+            self.is_absolute,
+            self.uuid
+        )
+        other_props = (
+            other.name,
+            other.description,
+            other.frequency,
+            other.precision,
+            other.offset,
+            other.is_absolute,
+            other.uuid
+        )
+        return self_props == other_props
+
+    def __copy__(self):
+        return ClockClass(name=self.name, description=self.description,
+                          frequency=self.frequency, precision=self.precision,
+                          offset=self.offset, is_absolute=self.is_absolute,
+                          uuid=self.uuid)
+
+    def __deepcopy__(self, memo):
+        cpy = self.__copy__()
+        memo[id(self)] = cpy
+        return cpy
+
+    def __hash__(self):
+        return hash((
+            self.name,
+            self.description,
+            self.frequency,
+            self.precision,
+            self.offset.seconds,
+            self.offset.cycles,
+            self.is_absolute,
+            self.uuid))
+
+    @property
+    def name(self):
+        name = native_bt.ctf_clock_class_get_name(self._ptr)
+        assert(name is not None)
+        return name
+
+    @name.setter
+    def name(self, name):
+        utils._check_str(name)
+        ret = native_bt.ctf_clock_class_set_name(self._ptr, name)
+        utils._handle_ret(ret, "cannot set clock class object's name")
+
+    @property
+    def description(self):
+        return native_bt.ctf_clock_class_get_description(self._ptr)
+
+    @description.setter
+    def description(self, description):
+        utils._check_str(description)
+        ret = native_bt.ctf_clock_class_set_description(self._ptr, description)
+        utils._handle_ret(ret, "cannot set clock class object's description")
+
+    @property
+    def frequency(self):
+        frequency = native_bt.ctf_clock_class_get_frequency(self._ptr)
+        assert(frequency >= 1)
+        return frequency
+
+    @frequency.setter
+    def frequency(self, frequency):
+        utils._check_uint64(frequency)
+        ret = native_bt.ctf_clock_class_set_frequency(self._ptr, frequency)
+        utils._handle_ret(ret, "cannot set clock class object's frequency")
+
+    @property
+    def precision(self):
+        precision = native_bt.ctf_clock_class_get_precision(self._ptr)
+        assert(precision >= 0)
+        return precision
+
+    @precision.setter
+    def precision(self, precision):
+        utils._check_uint64(precision)
+        ret = native_bt.ctf_clock_class_set_precision(self._ptr, precision)
+        utils._handle_ret(ret, "cannot set clock class object's precision")
+
+    @property
+    def offset(self):
+        ret, offset_s = native_bt.ctf_clock_class_get_offset_s(self._ptr)
+        assert(ret == 0)
+        ret, offset_cycles = native_bt.ctf_clock_class_get_offset_cycles(self._ptr)
+        assert(ret == 0)
+        return ClockClassOffset(offset_s, offset_cycles)
+
+    @offset.setter
+    def offset(self, offset):
+        utils._check_type(offset, ClockClassOffset)
+        ret = native_bt.ctf_clock_class_set_offset_s(self._ptr, offset.seconds)
+        utils._handle_ret(ret, "cannot set clock class object's offset (seconds)")
+        ret = native_bt.ctf_clock_class_set_offset_cycles(self._ptr, offset.cycles)
+        utils._handle_ret(ret, "cannot set clock class object's offset (cycles)")
+
+    @property
+    def is_absolute(self):
+        is_absolute = native_bt.ctf_clock_class_is_absolute(self._ptr)
+        assert(is_absolute >= 0)
+        return is_absolute > 0
+
+    @is_absolute.setter
+    def is_absolute(self, is_absolute):
+        utils._check_bool(is_absolute)
+        ret = native_bt.ctf_clock_class_set_is_absolute(self._ptr, int(is_absolute))
+        utils._handle_ret(ret, "cannot set clock class object's absoluteness")
+
+    @property
+    def uuid(self):
+        uuid_bytes = native_bt.ctf_clock_class_get_uuid(self._ptr)
+
+        if uuid_bytes is None:
+            return
+
+        return uuidp.UUID(bytes=uuid_bytes)
+
+    @uuid.setter
+    def uuid(self, uuid):
+        utils._check_type(uuid, uuidp.UUID)
+        ret = native_bt.ctf_clock_class_set_uuid(self._ptr, uuid.bytes)
+        utils._handle_ret(ret, "cannot set clock class object's UUID")
+
+    def __call__(self, cycles):
+        return _ClockValue(self._ptr, cycles)
+
+
+def _create_clock_value_from_ptr(ptr):
+    clock_value = _ClockValue._create_from_ptr(ptr)
+    return clock_value
+
+
+class _ClockValue(object._Object):
+    def __init__(self, clock_class_ptr, cycles):
+        utils._check_uint64(cycles)
+        ptr = native_bt.ctf_clock_value_create(clock_class_ptr, cycles)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create clock value object')
+
+        super().__init__(ptr)
+
+    @property
+    def clock_class(self):
+        ptr = native_bt.ctf_clock_value_get_class(self._ptr)
+        assert(ptr)
+        return ClockClass._create_from_ptr(ptr)
+
+    @property
+    def cycles(self):
+        ret, cycles = native_bt.ctf_clock_value_get_value(self._ptr)
+        assert(ret == 0)
+        return cycles
+
+    @property
+    def ns_from_epoch(self):
+        ret, ns = native_bt.ctf_clock_value_get_value_ns_from_epoch(self._ptr)
+        utils._handle_ret(ret, "cannot get clock value object's nanoseconds from Epoch")
+        return ns
+
+    def __eq__(self, other):
+        if isinstance(other, numbers.Integral):
+            return int(other) == self.cycles
+
+        if not isinstance(other, self.__class__):
+            # not comparing apples to apples
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        self_props = self.clock_class, self.cycles
+        other_props = other.clock_class, other.cycles
+        return self_props == other_props
+
+    def __copy__(self):
+        return self.clock_class(self.cycles)
+
+    def __deepcopy__(self, memo):
+        cpy = self.__copy__()
+        memo[id(self)] = cpy
+        return cpy
diff --git a/bindings/python/bt2/bt2/clock_class_priority_map.py b/bindings/python/bt2/bt2/clock_class_priority_map.py
new file mode 100644 (file)
index 0000000..af4ac26
--- /dev/null
@@ -0,0 +1,129 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import collections.abc
+import bt2.clock_class
+import copy
+import bt2
+
+
+class _ClockClassIterator(collections.abc.Iterator):
+    def __init__(self, cc_prio_map):
+        self._cc_prio_map = cc_prio_map
+        self._at = 0
+
+    def __next__(self):
+        if self._at == len(self._cc_prio_map):
+            raise StopIteration
+
+        cc_ptr = native_bt.clock_class_priority_map_get_clock_class_by_index(self._cc_prio_map._ptr,
+                                                                             self._at)
+        assert(cc_ptr)
+        clock_class = bt2.ClockClass._create_from_ptr(cc_ptr)
+        self._at += 1
+        return clock_class
+
+
+class ClockClassPriorityMap(object._Object, collections.abc.MutableMapping):
+    def __init__(self, clock_class_priorities=None):
+        ptr = native_bt.clock_class_priority_map_create()
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create clock class priority map object')
+
+        super().__init__(ptr)
+
+        if clock_class_priorities is not None:
+            for clock_class, priority in clock_class_priorities.items():
+                self[clock_class] = priority
+
+    def __getitem__(self, key):
+        utils._check_type(key, bt2.ClockClass)
+        ret, prio = native_bt.clock_class_priority_map_get_clock_class_priority(self._ptr,
+                                                                                key._ptr)
+
+        if ret != 0:
+            raise KeyError(key)
+
+        return prio
+
+    def __len__(self):
+        count = native_bt.clock_class_priority_map_get_clock_class_count(self._ptr)
+        assert(count >= 0)
+        return count
+
+    def __delitem__(self):
+        raise NotImplementedError
+
+    def __setitem__(self, key, value):
+        utils._check_type(key, bt2.ClockClass)
+        utils._check_uint64(value)
+        ret = native_bt.clock_class_priority_map_add_clock_class(self._ptr,
+                                                                 key._ptr,
+                                                                 value)
+        utils._handle_ret(ret, "cannot set clock class's priority in clock class priority map object")
+
+    def __iter__(self):
+        return _ClockClassIterator(self)
+
+    @property
+    def highest_priority_clock_class(self):
+        cc_ptr = native_bt.clock_class_priority_map_get_highest_priority_clock_class(self._ptr)
+
+        if cc_ptr is None:
+            return
+
+        return bt2.ClockClass._create_from_ptr(cc_ptr)
+
+    def _get_prios(self):
+        prios = {}
+
+        for clock_class, prio in self.items():
+            prios[clock_class] = prio
+
+        return prios
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        return self._get_prios() == other._get_prios()
+
+    def _copy(self, cc_copy_func):
+        cpy = ClockClassPriorityMap()
+
+        for clock_class, prio in self.items():
+            cpy[cc_copy_func(clock_class)] = prio
+
+        return cpy
+
+    def __copy__(self):
+        return self._copy(lambda obj: obj)
+
+    def __deepcopy__(self, memo):
+        cpy = self._copy(copy.deepcopy)
+        memo[id(self)] = cpy
+        return cpy
diff --git a/bindings/python/bt2/bt2/component.py b/bindings/python/bt2/bt2/component.py
new file mode 100644 (file)
index 0000000..927fd06
--- /dev/null
@@ -0,0 +1,693 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.notification_iterator
+import collections.abc
+import bt2.values
+import traceback
+import bt2.port
+import sys
+import bt2
+import os
+
+
+_env_var = os.environ.get('BABELTRACE_PYTHON_BT2_NO_TRACEBACK')
+_NO_PRINT_TRACEBACK = _env_var == '1'
+
+
+# This class wraps a component class pointer. This component class could
+# have been created by Python code, but since we only have the pointer,
+# we can only wrap it in a generic way and lose the original Python
+# class.
+class _GenericComponentClass(object._Object):
+    @property
+    def name(self):
+        name = native_bt.component_class_get_name(self._ptr)
+        assert(name is not None)
+        return name
+
+    @property
+    def description(self):
+        return native_bt.component_class_get_description(self._ptr)
+
+    @property
+    def help(self):
+        return native_bt.component_class_get_help(self._ptr)
+
+    def query(self, obj, params=None):
+        return _query(self._ptr, obj, params)
+
+    def __eq__(self, other):
+        if not isinstance(other, _GenericComponentClass):
+            try:
+                if not issubclass(other, _UserComponent):
+                    return False
+            except TypeError:
+                return False
+
+        return self.addr == other.addr
+
+
+class _GenericSourceComponentClass(_GenericComponentClass):
+    pass
+
+
+class _GenericFilterComponentClass(_GenericComponentClass):
+    pass
+
+
+class _GenericSinkComponentClass(_GenericComponentClass):
+    pass
+
+
+def _handle_component_status(status, gen_error_msg):
+    if status == native_bt.COMPONENT_STATUS_END:
+        raise bt2.Stop
+    elif status == native_bt.COMPONENT_STATUS_AGAIN:
+        raise bt2.TryAgain
+    elif status == native_bt.COMPONENT_STATUS_UNSUPPORTED:
+        raise bt2.UnsupportedFeature
+    elif status == native_bt.COMPONENT_STATUS_REFUSE_PORT_CONNECTION:
+        raise bt2.PortConnectionRefused
+    elif status == native_bt.COMPONENT_STATUS_GRAPH_IS_CANCELED:
+        raise bt2.GraphCanceled
+    elif status < 0:
+        raise bt2.Error(gen_error_msg)
+
+
+class _PortIterator(collections.abc.Iterator):
+    def __init__(self, comp_ports):
+        self._comp_ports = comp_ports
+        self._at = 0
+
+    def __next__(self):
+        if self._at == len(self._comp_ports):
+            raise StopIteration
+
+        comp_ports = self._comp_ports
+        comp_ptr = comp_ports._component._ptr
+        port_ptr = comp_ports._get_port_at_index_fn(comp_ptr, self._at)
+        assert(port_ptr)
+
+        if comp_ports._is_private:
+            port_pub_ptr = native_bt.port_from_private_port(port_ptr)
+            name = native_bt.port_get_name(port_pub_ptr)
+            native_bt.put(port_pub_ptr)
+        else:
+            name = native_bt.port_get_name(port_ptr)
+
+        assert(name is not None)
+        native_bt.put(port_ptr)
+        self._at += 1
+        return name
+
+
+class _ComponentPorts(collections.abc.Mapping):
+    def __init__(self, is_private, component,
+                 get_port_by_name_fn, get_port_at_index_fn,
+                 get_port_count_fn):
+        self._is_private = is_private
+        self._component = component
+        self._get_port_by_name_fn = get_port_by_name_fn
+        self._get_port_at_index_fn = get_port_at_index_fn
+        self._get_port_count_fn = get_port_count_fn
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        port_ptr = self._get_port_by_name_fn(self._component._ptr, key)
+
+        if port_ptr is None:
+            raise KeyError(key)
+
+        if self._is_private:
+            return bt2.port._create_private_from_ptr(port_ptr)
+        else:
+            return bt2.port._create_from_ptr(port_ptr)
+
+    def __len__(self):
+        if self._is_private:
+            pub_ptr = native_bt.component_from_private_component(self._component._ptr)
+            count = self._get_port_count_fn(pub_ptr)
+            native_bt.put(pub_ptr)
+        else:
+            count = self._get_port_count_fn(self._component._ptr)
+
+        assert(count >= 0)
+        return count
+
+    def __iter__(self):
+        return _PortIterator(self)
+
+
+# This class holds the methods which are common to both generic
+# component objects and Python user component objects. They use the
+# internal native _ptr, however it was set, to call native API
+# functions.
+class _Component:
+    @property
+    def name(self):
+        name = native_bt.component_get_name(self._ptr)
+        assert(name is not None)
+        return name
+
+    @property
+    def graph(self):
+        ptr = native_bt.component_get_graph(self._ptr)
+        assert(ptr)
+        return bt2.Graph._create_from_ptr(ptr)
+
+    @property
+    def component_class(self):
+        cc_ptr = native_bt.component_get_class(self._ptr)
+        assert(cc_ptr)
+        return _create_generic_component_class_from_ptr(cc_ptr)
+
+    def __eq__(self, other):
+        if not hasattr(other, 'addr'):
+            return False
+
+        return self.addr == other.addr
+
+
+class _SourceComponent(_Component):
+    pass
+
+
+class _FilterComponent(_Component):
+    pass
+
+
+class _SinkComponent(_Component):
+    pass
+
+
+# This is analogous to _GenericSourceComponentClass, but for source
+# component objects.
+class _GenericSourceComponent(object._Object, _SourceComponent):
+    @property
+    def output_ports(self):
+        return _ComponentPorts(False, self,
+                               native_bt.component_source_get_output_port_by_name,
+                               native_bt.component_source_get_output_port_by_index,
+                               native_bt.component_source_get_output_port_count)
+
+
+# This is analogous to _GenericFilterComponentClass, but for filter
+# component objects.
+class _GenericFilterComponent(object._Object, _FilterComponent):
+    @property
+    def output_ports(self):
+        return _ComponentPorts(False, self,
+                               native_bt.component_filter_get_output_port_by_name,
+                               native_bt.component_filter_get_output_port_by_index,
+                               native_bt.component_filter_get_output_port_count)
+
+    @property
+    def input_ports(self):
+        return _ComponentPorts(False, self,
+                               native_bt.component_filter_get_input_port_by_name,
+                               native_bt.component_filter_get_input_port_by_index,
+                               native_bt.component_filter_get_input_port_count)
+
+
+# This is analogous to _GenericSinkComponentClass, but for sink
+# component objects.
+class _GenericSinkComponent(object._Object, _SinkComponent):
+    @property
+    def input_ports(self):
+        return _ComponentPorts(False, self,
+                               native_bt.component_sink_get_input_port_by_name,
+                               native_bt.component_sink_get_input_port_by_index,
+                               native_bt.component_sink_get_input_port_count)
+
+
+_COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS = {
+    native_bt.COMPONENT_CLASS_TYPE_SOURCE: _GenericSourceComponent,
+    native_bt.COMPONENT_CLASS_TYPE_FILTER: _GenericFilterComponent,
+    native_bt.COMPONENT_CLASS_TYPE_SINK: _GenericSinkComponent,
+}
+
+
+_COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS = {
+    native_bt.COMPONENT_CLASS_TYPE_SOURCE: _GenericSourceComponentClass,
+    native_bt.COMPONENT_CLASS_TYPE_FILTER: _GenericFilterComponentClass,
+    native_bt.COMPONENT_CLASS_TYPE_SINK: _GenericSinkComponentClass,
+}
+
+
+def _create_generic_component_from_ptr(ptr):
+    comp_cls_type = native_bt.component_get_class_type(ptr)
+    return _COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS[comp_cls_type]._create_from_ptr(ptr)
+
+
+def _create_generic_component_class_from_ptr(ptr):
+    comp_cls_type = native_bt.component_class_get_type(ptr)
+    return _COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS[comp_cls_type]._create_from_ptr(ptr)
+
+
+def _trim_docstring(docstring):
+    lines = docstring.expandtabs().splitlines()
+    indent = sys.maxsize
+
+    for line in lines[1:]:
+        stripped = line.lstrip()
+
+        if stripped:
+            indent = min(indent, len(line) - len(stripped))
+
+    trimmed = [lines[0].strip()]
+
+    if indent < sys.maxsize:
+        for line in lines[1:]:
+            trimmed.append(line[indent:].rstrip())
+
+    while trimmed and not trimmed[-1]:
+        trimmed.pop()
+
+    while trimmed and not trimmed[0]:
+        trimmed.pop(0)
+
+    return '\n'.join(trimmed)
+
+
+def _query(comp_cls_ptr, obj, params):
+    utils._check_str(obj)
+
+    if params is None:
+        params_ptr = native_bt.value_null
+    else:
+        params = bt2.create_value(params)
+        params_ptr = params._ptr
+
+    results_ptr = native_bt.component_class_query(comp_cls_ptr, obj,
+                                                  params_ptr)
+
+    if results_ptr is None:
+        raise bt2.Error('cannot query info with object "{}"'.format(obj))
+
+    return bt2.values._create_from_ptr(results_ptr)
+
+
+# Metaclass for component classes defined by Python code.
+#
+# The Python user can create a standard Python class which inherits one
+# of the three base classes (_UserSourceComponent, _UserFilterComponent,
+# or _UserSinkComponent). Those base classes set this class
+# (_UserComponentType) as their metaclass.
+#
+# Once the body of a user-defined component class is executed, this
+# metaclass is used to create and initialize the class. The metaclass
+# creates a native BT component class of the corresponding type and
+# associates it with this user-defined class. The metaclass also defines
+# class methods like the `name` and `description` properties to match
+# the _GenericComponentClass interface.
+#
+# The component class name which is used is either:
+#
+# * The `name` parameter of the class:
+#
+#       class MySink(bt2.SinkComponent, name='my-custom-sink'):
+#           ...
+#
+# * If the `name` class parameter is not used: the name of the class
+#   itself (`MySink` in the example above).
+#
+# The component class description which is used is the user-defined
+# class's docstring:
+#
+#     class MySink(bt2.SinkComponent):
+#         'Description goes here'
+#         ...
+#
+# A user-defined Python component class can have an __init__() method
+# which must at least accept the `params` and `name` arguments:
+#
+#     def __init__(self, params, name, something_else):
+#         ...
+#
+# The user-defined component class can also have a _finalize() method
+# (do NOT use __del__()) to be notified when the component object is
+# finalized.
+#
+# User-defined source and filter component classes must use the
+# `notification_iterator_class` class parameter to specify the
+# notification iterator class to use for this component class:
+#
+#     class MyNotificationIterator(bt2._UserNotificationIterator):
+#         ...
+#
+#     class MySource(bt2._UserSourceComponent,
+#                    notification_iterator_class=MyNotificationIterator):
+#         ...
+#
+# This notification iterator class must inherit
+# bt2._UserNotificationIterator, and it must define the _get() and
+# _next() methods. The notification iterator class can also define an
+# __init__() method: this method has access to the original Python
+# component object which was used to create it as the `component`
+# property. The notification iterator class can also define a
+# _finalize() method (again, do NOT use __del__()): this is called when
+# the notification iterator is (really) destroyed.
+#
+# When the user-defined class is destroyed, this metaclass's __del__()
+# method is called: the native BT component class pointer is put (not
+# needed anymore, at least not by any Python code since all references
+# are dropped for __del__() to be called).
+class _UserComponentType(type):
+    # __new__() is used to catch custom class parameters
+    def __new__(meta_cls, class_name, bases, attrs, **kwargs):
+        return super().__new__(meta_cls, class_name, bases, attrs)
+
+    def __init__(cls, class_name, bases, namespace, **kwargs):
+        super().__init__(class_name, bases, namespace)
+
+        # skip our own bases; they are never directly instantiated by the user
+        own_bases = (
+            '_UserComponent',
+            '_UserFilterSinkComponent',
+            '_UserSourceComponent',
+            '_UserFilterComponent',
+            '_UserSinkComponent',
+        )
+
+        if class_name in own_bases:
+            return
+
+        comp_cls_name = kwargs.get('name', class_name)
+        utils._check_str(comp_cls_name)
+        comp_cls_descr = None
+        comp_cls_help = None
+
+        if hasattr(cls, '__doc__') and cls.__doc__ is not None:
+            utils._check_str(cls.__doc__)
+            docstring = _trim_docstring(cls.__doc__)
+            lines = docstring.splitlines()
+
+            if len(lines) >= 1:
+                comp_cls_descr = lines[0]
+
+            if len(lines) >= 3:
+                comp_cls_help = '\n'.join(lines[2:])
+
+        iter_cls = kwargs.get('notification_iterator_class')
+
+        if _UserSourceComponent in bases:
+            _UserComponentType._set_iterator_class(cls, iter_cls)
+            cc_ptr = native_bt.py3_component_class_source_create(cls,
+                                                                 comp_cls_name,
+                                                                 comp_cls_descr,
+                                                                 comp_cls_help)
+        elif _UserFilterComponent in bases:
+            _UserComponentType._set_iterator_class(cls, iter_cls)
+            cc_ptr = native_bt.py3_component_class_filter_create(cls,
+                                                                 comp_cls_name,
+                                                                 comp_cls_descr,
+                                                                 comp_cls_help)
+        elif _UserSinkComponent in bases:
+            if not hasattr(cls, '_consume'):
+                raise bt2.IncompleteUserClass("cannot create component class '{}': missing a _consume() method".format(class_name))
+
+            cc_ptr = native_bt.py3_component_class_sink_create(cls,
+                                                               comp_cls_name,
+                                                               comp_cls_descr,
+                                                               comp_cls_help)
+        else:
+            raise bt2.IncompleteUserClass("cannot find a known component class base in the bases of '{}'".format(class_name))
+
+        if cc_ptr is None:
+            raise bt2.CreationError("cannot create component class '{}'".format(class_name))
+
+        cls._cc_ptr = cc_ptr
+
+    def _init_from_native(cls, comp_ptr, params_ptr):
+        # create instance, not user-initialized yet
+        self = cls.__new__(cls)
+
+        # pointer to native private component object (weak/borrowed)
+        self._ptr = comp_ptr
+
+        # call user's __init__() method
+        if params_ptr is not None:
+            native_bt.get(params_ptr)
+            params = bt2.values._create_from_ptr(params_ptr)
+        else:
+            params = None
+
+        self.__init__(params)
+        return self
+
+    def __call__(cls, *args, **kwargs):
+        raise bt2.Error('cannot directly instantiate a user component from a Python module')
+
+    @staticmethod
+    def _set_iterator_class(cls, iter_cls):
+        if iter_cls is None:
+            raise bt2.IncompleteUserClass("cannot create component class '{}': missing notification iterator class".format(cls.__name__))
+
+        if not issubclass(iter_cls, bt2.notification_iterator._UserNotificationIterator):
+            raise bt2.IncompleteUserClass("cannot create component class '{}': notification iterator class does not inherit bt2._UserNotificationIterator".format(cls.__name__))
+
+        if not hasattr(iter_cls, '__next__'):
+            raise bt2.IncompleteUserClass("cannot create component class '{}': notification iterator class is missing a __next__() method".format(cls.__name__))
+
+        cls._iter_cls = iter_cls
+
+    @property
+    def name(cls):
+        return native_bt.component_class_get_name(cls._cc_ptr)
+
+    @property
+    def description(cls):
+        return native_bt.component_class_get_description(cls._cc_ptr)
+
+    @property
+    def help(cls):
+        return native_bt.component_class_get_help(cls._cc_ptr)
+
+    @property
+    def addr(cls):
+        return int(cls._cc_ptr)
+
+    def query(cls, obj, params=None):
+        return _query(cls._cc_ptr, obj, params)
+
+    def _query_from_native(cls, obj, params_ptr):
+        # this can raise, in which case the native call to
+        # bt_component_class_query() returns NULL
+        if params_ptr is not None:
+            native_bt.get(params_ptr)
+            params = bt2.values._create_from_ptr(params_ptr)
+        else:
+            params = None
+
+        try:
+            results = cls._query(obj, params)
+        except:
+            if not _NO_PRINT_TRACEBACK:
+                traceback.print_exc()
+
+            return
+
+        if results is NotImplemented:
+            return results
+
+        try:
+            results = bt2.create_value(results)
+        except:
+            if not _NO_PRINT_TRACEBACK:
+                traceback.print_exc()
+
+            return
+
+        if results is None:
+            results_addr = int(native_bt.value_null)
+        else:
+            # return new reference
+            results._get()
+            results_addr = int(results._ptr)
+
+        return results_addr
+
+    @classmethod
+    def _query(cls, obj, params):
+        # BT catches this and returns NULL to the user
+        return NotImplemented
+
+    def __eq__(self, other):
+        if not hasattr(other, 'addr'):
+            return False
+
+        return self.addr == other.addr
+
+    def __del__(cls):
+        if hasattr(cls, '_cc_ptr'):
+            native_bt.put(cls._cc_ptr)
+
+
+class _UserComponent(metaclass=_UserComponentType):
+    @property
+    def name(self):
+        pub_ptr = native_bt.component_from_private_component(self._ptr)
+        name = native_bt.component_get_name(pub_ptr)
+        native_bt.put(pub_ptr)
+        assert(name is not None)
+        return name
+
+    @property
+    def graph(self):
+        pub_ptr = native_bt.component_from_private_component(self._ptr)
+        ptr = native_bt.component_get_graph(pub_ptr)
+        native_bt.put(pub_ptr)
+        assert(ptr)
+        return bt2.Graph._create_from_ptr(ptr)
+
+    @property
+    def component_class(self):
+        pub_ptr = native_bt.component_from_private_component(self._ptr)
+        cc_ptr = native_bt.component_get_class(pub_ptr)
+        native_bt.put(pub_ptr)
+        assert(cc_ptr)
+        return _create_generic_component_class_from_ptr(cc_ptr)
+
+    @property
+    def addr(self):
+        return int(self._ptr)
+
+    def __init__(self, params=None):
+        pass
+
+    def _finalize(self):
+        pass
+
+    def _accept_port_connection(self, port, other_port):
+        return True
+
+    def _accept_port_connection_from_native(self, port_ptr, other_port_ptr):
+        native_bt.get(port_ptr)
+        native_bt.get(other_port_ptr)
+        port = bt2.port._create_private_from_ptr(port_ptr)
+        other_port = bt2.port._create_from_ptr(other_port_ptr)
+        res = self._accept_port_connection(port, other_port_ptr)
+
+        if type(res) is not bool:
+            raise TypeError("'{}' is not a 'bool' object")
+
+        return res
+
+    def _port_connected(self, port, other_port):
+        pass
+
+    def _port_connected_from_native(self, port_ptr, other_port_ptr):
+        native_bt.get(port_ptr)
+        native_bt.get(other_port_ptr)
+        port = bt2.port._create_private_from_ptr(port_ptr)
+        other_port = bt2.port._create_from_ptr(other_port_ptr)
+
+        try:
+            self._port_connected(port, other_port_ptr)
+        except:
+            if not _NO_PRINT_TRACEBACK:
+                traceback.print_exc()
+
+    def _port_disconnected(self, port):
+        pass
+
+    def _port_disconnected_from_native(self, port_ptr):
+        native_bt.get(port_ptr)
+        port = bt2.port._create_private_from_ptr(port_ptr)
+
+        try:
+            self._port_disconnected(port)
+        except:
+            if not _NO_PRINT_TRACEBACK:
+                traceback.print_exc()
+
+
+class _UserSourceComponent(_UserComponent, _SourceComponent):
+    @property
+    def _output_ports(self):
+        return _ComponentPorts(True, self,
+                               native_bt.private_component_source_get_output_private_port_by_name,
+                               native_bt.private_component_source_get_output_private_port_by_index,
+                               native_bt.component_source_get_output_port_count)
+
+    def _add_output_port(self, name):
+        utils._check_str(name)
+        fn = native_bt.private_component_source_add_output_private_port
+        comp_status, priv_port_ptr = fn(self._ptr, name, None)
+        _handle_component_status(comp_status,
+                                 'cannot add output port to source component object')
+        assert(priv_port_ptr)
+        return bt2.port._create_private_from_ptr(priv_port_ptr)
+
+
+class _UserFilterComponent(_UserComponent, _FilterComponent):
+    @property
+    def _output_ports(self):
+        return _ComponentPorts(True, self,
+                               native_bt.private_component_filter_get_output_private_port_by_name,
+                               native_bt.private_component_filter_get_output_private_port_by_index,
+                               native_bt.component_filter_get_output_port_count)
+
+    @property
+    def _input_ports(self):
+        return _ComponentPorts(True, self,
+                               native_bt.private_component_filter_get_input_private_port_by_name,
+                               native_bt.private_component_filter_get_input_private_port_by_index,
+                               native_bt.component_filter_get_input_port_count)
+
+    def _add_output_port(self, name):
+        utils._check_str(name)
+        fn = native_bt.private_component_filter_add_output_private_port
+        comp_status, priv_port_ptr = fn(self._ptr, name, None)
+        _handle_component_status(comp_status,
+                                 'cannot add output port to filter component object')
+        assert(priv_port_ptr)
+        return bt2.port._create_private_from_ptr(priv_port_ptr)
+
+    def _add_input_port(self, name):
+        utils._check_str(name)
+        fn = native_bt.private_component_filter_add_input_private_port
+        comp_status, priv_port_ptr = fn(self._ptr, name, None)
+        _handle_component_status(comp_status,
+                                 'cannot add input port to filter component object')
+        assert(priv_port_ptr)
+        return bt2.port._create_private_from_ptr(priv_port_ptr)
+
+
+class _UserSinkComponent(_UserComponent, _SinkComponent):
+    @property
+    def _input_ports(self):
+        return _ComponentPorts(True, self,
+                               native_bt.private_component_sink_get_input_private_port_by_name,
+                               native_bt.private_component_sink_get_input_private_port_by_index,
+                               native_bt.component_sink_get_input_port_count)
+
+    def _add_input_port(self, name):
+        utils._check_str(name)
+        fn = native_bt.private_component_sink_add_input_private_port
+        comp_status, priv_port_ptr = fn(self._ptr, name, None)
+        _handle_component_status(comp_status,
+                                 'cannot add input port to sink component object')
+        assert(priv_port_ptr)
+        return bt2.port._create_private_from_ptr(priv_port_ptr)
diff --git a/bindings/python/bt2/bt2/connection.py b/bindings/python/bt2/bt2/connection.py
new file mode 100644 (file)
index 0000000..09092af
--- /dev/null
@@ -0,0 +1,110 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.notification_iterator
+import collections.abc
+import bt2.port
+import copy
+import bt2
+
+
+def _handle_status(status, gen_error_msg):
+    if status == native_bt.CONNECTION_STATUS_GRAPH_IS_CANCELED:
+        raise bt2.GraphCanceled
+    elif status == native_bt.CONNECTION_STATUS_IS_ENDED:
+        raise bt2.ConnectionEnded
+    elif status < 0:
+        raise bt2.Error(gen_error_msg)
+
+
+def _create_private_from_ptr(ptr):
+    obj = _PrivateConnection._create_from_ptr(ptr)
+    obj._pub_ptr = native_bt.connection_from_private_connection(ptr)
+    assert(obj._pub_ptr)
+    return obj
+
+
+class _Connection(object._Object):
+    @staticmethod
+    def _downstream_port(ptr):
+        port_ptr = native_bt.connection_get_downstream_port(ptr)
+        utils._handle_ptr(port_ptr, "cannot get connection object's downstream port object")
+        return bt2.port._create_from_ptr(port_ptr)
+
+    @staticmethod
+    def _upstream_port(ptr):
+        port_ptr = native_bt.connection_get_upstream_port(ptr)
+        utils._handle_ptr(port_ptr, "cannot get connection object's upstream port object")
+        return bt2.port._create_from_ptr(port_ptr)
+
+    @property
+    def downstream_port(self):
+        return self._downstream_port(self._ptr)
+
+    @property
+    def upstream_port(self):
+        return self._upstream_port(self._ptr)
+
+    @staticmethod
+    def _is_ended(ptr):
+        return native_bt.connection_is_ended(ptr) == 1
+
+    @property
+    def is_ended(self):
+        return self._is_ended(self._ptr)
+
+    def __eq__(self, other):
+        if type(other) not in (_Connection, _PrivateConnection):
+            return False
+
+        return self.addr == other.addr
+
+
+class _PrivateConnection(object._PrivateObject, _Connection):
+    def create_notification_iterator(self, notification_types=None):
+        if notification_types is None:
+            notif_types = None
+        else:
+            for notif_cls in notification_types:
+                if notif_cls not in bt2.notification._NOTIF_TYPE_TO_CLS.values():
+                    raise ValueError("'{}' is not a notification class".format(notif_cls))
+
+            notif_types = [notif_cls._TYPE for notif_cls in notification_types]
+
+        status, notif_iter_ptr = native_bt.py3_create_notif_iter(int(self._ptr),
+                                                                notif_types)
+        _handle_status(status, 'cannot create notification iterator object')
+        assert(notif_iter_ptr)
+        return bt2.notification_iterator._GenericNotificationIterator._create_from_ptr(notif_iter_ptr)
+
+    @property
+    def is_ended(self):
+        return self._is_ended(self._pub_ptr)
+
+    @property
+    def downstream_port(self):
+        return self._downstream_port(self._pub_ptr)
+
+    @property
+    def upstream_port(self):
+        return self._upstream_port(self._pub_ptr)
diff --git a/bindings/python/bt2/bt2/ctf_writer.py b/bindings/python/bt2/bt2/ctf_writer.py
new file mode 100644 (file)
index 0000000..0bbabaf
--- /dev/null
@@ -0,0 +1,314 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2016-2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, stream, utils
+import uuid as uuidp
+import bt2.event
+import abc
+import bt2
+
+
+class CtfWriterClock(object._Object):
+    def __init__(self, name, description=None, frequency=None, precision=None,
+                 offset=None, is_absolute=None, uuid=None):
+        utils._check_str(name)
+        ptr = native_bt.ctf_clock_create(name)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create CTF writer clock object')
+
+        super().__init__(ptr)
+
+        if description is not None:
+            self.description = description
+
+        if frequency is not None:
+            self.frequency = frequency
+
+        if precision is not None:
+            self.precision = precision
+
+        if offset is not None:
+            self.offset = offset
+
+        if is_absolute is not None:
+            self.is_absolute = is_absolute
+
+        if uuid is not None:
+            self.uuid = uuid
+
+    def __eq__(self, other):
+        if type(self) is not type(other):
+            # not comparing apples to apples
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        self_props = (
+            self.name,
+            self.description,
+            self.frequency,
+            self.precision,
+            self.offset,
+            self.is_absolute,
+            self.uuid
+        )
+        other_props = (
+            other.name,
+            other.description,
+            other.frequency,
+            other.precision,
+            other.offset,
+            other.is_absolute,
+            other.uuid
+        )
+        return self_props == other_props
+
+    def __copy__(self):
+        return CtfWriterClock(name=self.name, description=self.description,
+                              frequency=self.frequency,
+                              precision=self.precision, offset=self.offset,
+                              is_absolute=self.is_absolute, uuid=self.uuid)
+
+    def __deepcopy__(self, memo):
+        cpy = self.__copy__()
+        memo[id(self)] = cpy
+        return cpy
+
+    @property
+    def name(self):
+        name = native_bt.ctf_clock_get_name(self._ptr)
+        assert(name is not None)
+        return name
+
+    @property
+    def description(self):
+        description = native_bt.ctf_clock_get_description(self._ptr)
+        return description
+
+    @description.setter
+    def description(self, description):
+        utils._check_str(description)
+        ret = native_bt.ctf_clock_set_description(self._ptr, description)
+        utils._handle_ret(ret, "cannot set CTF writer clock object's description")
+
+    @property
+    def frequency(self):
+        frequency = native_bt.ctf_clock_get_frequency(self._ptr)
+        assert(frequency >= 1)
+        return frequency
+
+    @frequency.setter
+    def frequency(self, frequency):
+        utils._check_uint64(frequency)
+        ret = native_bt.ctf_clock_set_frequency(self._ptr, frequency)
+        utils._handle_ret(ret, "cannot set CTF writer clock object's frequency")
+
+    @property
+    def precision(self):
+        precision = native_bt.ctf_clock_get_precision(self._ptr)
+        assert(precision >= 0)
+        return precision
+
+    @precision.setter
+    def precision(self, precision):
+        utils._check_uint64(precision)
+        ret = native_bt.ctf_clock_set_precision(self._ptr, precision)
+        utils._handle_ret(ret, "cannot set CTF writer clock object's precision")
+
+    @property
+    def offset(self):
+        ret, offset_s = native_bt.ctf_clock_get_offset_s(self._ptr)
+        assert(ret == 0)
+        ret, offset_cycles = native_bt.ctf_clock_get_offset(self._ptr)
+        assert(ret == 0)
+        return bt2.ClockClassOffset(offset_s, offset_cycles)
+
+    @offset.setter
+    def offset(self, offset):
+        utils._check_type(offset, bt2.ClockClassOffset)
+        ret = native_bt.ctf_clock_set_offset_s(self._ptr, offset.seconds)
+        utils._handle_ret(ret, "cannot set CTF writer clock object's offset (seconds)")
+        ret = native_bt.ctf_clock_set_offset(self._ptr, offset.cycles)
+        utils._handle_ret(ret, "cannot set CTF writer clock object's offset (cycles)")
+
+    @property
+    def is_absolute(self):
+        is_absolute = native_bt.ctf_clock_get_is_absolute(self._ptr)
+        assert(is_absolute >= 0)
+        return is_absolute > 0
+
+    @is_absolute.setter
+    def is_absolute(self, is_absolute):
+        utils._check_bool(is_absolute)
+        ret = native_bt.ctf_clock_set_is_absolute(self._ptr, int(is_absolute))
+        utils._handle_ret(ret, "cannot set CTF writer clock object's absoluteness")
+
+    @property
+    def uuid(self):
+        uuid_bytes = native_bt.ctf_clock_get_uuid(self._ptr)
+        assert(uuid_bytes is not None)
+        return uuidp.UUID(bytes=uuid_bytes)
+
+    @uuid.setter
+    def uuid(self, uuid):
+        utils._check_type(uuid, uuidp.UUID)
+        ret = native_bt.ctf_clock_set_uuid(self._ptr, uuid.bytes)
+        utils._handle_ret(ret, "cannot set CTF writer clock object's UUID")
+
+    def _time(self, time):
+        utils._check_int64(time)
+        ret = native_bt.ctf_clock_set_time(self._ptr, time)
+
+    time = property(fset=_time)
+
+
+class _CtfWriterStream(stream._StreamBase):
+    @property
+    def discarded_events_count(self):
+        ret, count = native_bt.ctf_stream_get_discarded_events_count(self._ptr)
+        utils._handle_ret(ret, "cannot get CTF writer stream object's discarded events count")
+        return count
+
+    def append_discarded_events(self, count):
+        utils._check_uint64(count)
+        native_bt.ctf_stream_append_discarded_events(self._ptr, count)
+
+    def append_event(self, event):
+        utils._check_type(event, bt2.event._Event)
+        ret = native_bt.ctf_stream_append_event(self._ptr, event._ptr)
+        utils._handle_ret(ret, 'cannot append event object to CTF writer stream object')
+
+    def flush(self):
+        ret = native_bt.ctf_stream_flush(self._ptr)
+        utils._handle_ret(ret, 'cannot cannot flush CTF writer stream object')
+
+    @property
+    def packet_header_field(self):
+        field_ptr = native_bt.ctf_stream_get_packet_header(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return fields._create_from_ptr(field_ptr)
+
+    @packet_header_field.setter
+    def packet_header_field(self, packet_header_field):
+        packet_header_field_ptr = None
+
+        if packet_header_field is not None:
+            utils._check_type(packet_header_field, fields._Field)
+            packet_header_field_ptr = packet_header_field._ptr
+
+        ret = native_bt.ctf_stream_set_packet_header(self._ptr,
+                                                     packet_header_field_ptr)
+        utils._handle_ret(ret, "cannot set CTF writer stream object's packet header field")
+
+    @property
+    def packet_context_field(self):
+        field_ptr = native_bt.ctf_stream_get_packet_context(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return fields._create_from_ptr(field_ptr)
+
+    @packet_context_field.setter
+    def packet_context_field(self, packet_context_field):
+        packet_context_field_ptr = None
+
+        if packet_context_field is not None:
+            utils._check_type(packet_context_field, fields._Field)
+            packet_context_field_ptr = packet_context_field._ptr
+
+        ret = native_bt.ctf_stream_set_packet_context(self._ptr,
+                                                      packet_context_field_ptr)
+        utils._handle_ret(ret, "cannot set CTF writer stream object's packet context field")
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        if not _StreamBase.__eq__(self, other):
+            return False
+
+        self_props = (
+            self.discarded_events_count,
+            self.packet_header_field,
+            self.packet_context_field,
+        )
+        other_props = (
+            other.discarded_events_count,
+            other.packet_header_field,
+            other.packet_context_field,
+        )
+        return self_props == other_props
+
+    def _copy(self, copy_func):
+        cpy = self.stream_class(self.name)
+        cpy.append_discarded_events(self.discarded_events_count)
+        cpy.packet_header_field = copy_func(self.packet_header_field)
+        cpy.packet_context_field = copy_func(self.packet_context_field)
+        return cpy
+
+    def __copy__(self):
+        return self._copy(copy.copy)
+
+    def __deepcopy__(self, memo):
+        cpy = self._copy(copy.deepcopy)
+        memo[id(self)] = cpy
+        return cpy
+
+
+class CtfWriter(object._Object):
+    def __init__(self, path):
+        utils._check_str(path)
+        ptr = native_bt.ctf_writer_create(path)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create CTF writer object')
+
+        super().__init__(ptr)
+
+    @property
+    def trace(self):
+        trace_ptr = native_bt.ctf_writer_get_trace(self._ptr)
+        assert(trace_ptr)
+        return bt2.Trace._create_from_ptr(trace_ptr)
+
+    @property
+    def metadata_string(self):
+        metadata_string = native_bt.ctf_writer_get_metadata_string(self._ptr)
+        assert(metadata_string is not None)
+        return metadata_string
+
+    def flush_metadata(self):
+        native_bt.ctf_writer_flush_metadata(self._ptr)
+
+    def add_clock(self, clock):
+        utils._check_type(clock, CtfWriterClock)
+        ret = native_bt.ctf_writer_add_clock(self._ptr, clock._ptr)
+        utils._handle_ret(ret, 'cannot add CTF writer clock object to CTF writer object')
diff --git a/bindings/python/bt2/bt2/event.py b/bindings/python/bt2/bt2/event.py
new file mode 100644 (file)
index 0000000..2e11de0
--- /dev/null
@@ -0,0 +1,315 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2016-2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.clock_class
+import bt2.packet
+import bt2.stream
+import bt2.fields
+import numbers
+import copy
+import abc
+import bt2
+
+
+def _create_from_ptr(ptr):
+    # recreate the event class wrapper of this event's class (the
+    # identity could be different, but the underlying address should be
+    # the same)
+    event_class_ptr = native_bt.ctf_event_get_class(ptr)
+    utils._handle_ptr(event_class_ptr, "cannot get event object's class")
+    event_class = bt2.EventClass._create_from_ptr(event_class_ptr)
+    event = _Event._create_from_ptr(ptr)
+    event._event_class = event_class
+    return event
+
+
+class _Event(object._Object):
+    @property
+    def event_class(self):
+        return self._event_class
+
+    @property
+    def name(self):
+        return self._event_class.name
+
+    @property
+    def id(self):
+        return self._event_class.id
+
+    @property
+    def packet(self):
+        packet_ptr = native_bt.ctf_event_get_packet(self._ptr)
+
+        if packet_ptr is None:
+            return packet_ptr
+
+        return bt2.packet._Packet._create_from_ptr(packet_ptr)
+
+    @packet.setter
+    def packet(self, packet):
+        utils._check_type(packet, bt2.packet._Packet)
+        ret = native_bt.ctf_event_set_packet(self._ptr, packet._ptr)
+        utils._handle_ret(ret, "cannot set event object's packet object")
+
+    @property
+    def stream(self):
+        stream_ptr = native_bt.ctf_event_get_stream(self._ptr)
+
+        if stream_ptr is None:
+            return stream_ptr
+
+        return bt2.stream._Stream._create_from_ptr(stream_ptr)
+
+    @property
+    def header_field(self):
+        field_ptr = native_bt.ctf_event_get_header(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.fields._create_from_ptr(field_ptr)
+
+    @header_field.setter
+    def header_field(self, header_field):
+        header_field_ptr = None
+
+        if header_field is not None:
+            utils._check_type(header_field, bt2.fields._Field)
+            header_field_ptr = header_field._ptr
+
+        ret = native_bt.ctf_event_set_header(self._ptr, header_field_ptr)
+        utils._handle_ret(ret, "cannot set event object's header field")
+
+    @property
+    def stream_event_context_field(self):
+        field_ptr = native_bt.ctf_event_get_stream_event_context(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.fields._create_from_ptr(field_ptr)
+
+    @stream_event_context_field.setter
+    def stream_event_context_field(self, stream_event_context):
+        stream_event_context_ptr = None
+
+        if stream_event_context is not None:
+            utils._check_type(stream_event_context, bt2.fields._Field)
+            stream_event_context_ptr = stream_event_context._ptr
+
+        ret = native_bt.ctf_event_set_stream_event_context(self._ptr,
+                                                           stream_event_context_ptr)
+        utils._handle_ret(ret, "cannot set event object's stream event context field")
+
+    @property
+    def context_field(self):
+        field_ptr = native_bt.ctf_event_get_event_context(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.fields._create_from_ptr(field_ptr)
+
+    @context_field.setter
+    def context_field(self, context):
+        context_ptr = None
+
+        if context is not None:
+            utils._check_type(context, bt2.fields._Field)
+            context_ptr = context._ptr
+
+        ret = native_bt.ctf_event_set_event_context(self._ptr, context_ptr)
+        utils._handle_ret(ret, "cannot set event object's context field")
+
+    @property
+    def payload_field(self):
+        field_ptr = native_bt.ctf_event_get_event_payload(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.fields._create_from_ptr(field_ptr)
+
+    @payload_field.setter
+    def payload_field(self, payload):
+        payload_ptr = None
+
+        if payload is not None:
+            utils._check_type(payload, bt2.fields._Field)
+            payload_ptr = payload._ptr
+
+        ret = native_bt.ctf_event_set_event_payload(self._ptr, payload_ptr)
+        utils._handle_ret(ret, "cannot set event object's payload field")
+
+    def _get_clock_value_cycles(self, clock_class_ptr):
+        clock_value_ptr = native_bt.ctf_event_get_clock_value(self._ptr,
+                                                              clock_class_ptr)
+
+        if clock_value_ptr is None:
+            return
+
+        ret, cycles = native_bt.ctf_clock_value_get_value(clock_value_ptr)
+        native_bt.put(clock_value_ptr)
+        utils._handle_ret(ret, "cannot get clock value object's cycles")
+        return cycles
+
+    def clock_value(self, clock_class):
+        utils._check_type(clock_class, bt2.ClockClass)
+        clock_value_ptr = native_bt.ctf_event_get_clock_value(self._ptr,
+                                                              clock_class._ptr)
+
+        if clock_value_ptr is None:
+            return
+
+        clock_value = bt2.clock_class._create_clock_value_from_ptr(clock_value_ptr)
+        return clock_value
+
+    def add_clock_value(self, clock_value):
+        utils._check_type(clock_value, bt2.clock_class._ClockValue)
+        ret = native_bt.ctf_event_set_clock_value(self._ptr,
+                                                  clock_value._ptr)
+        utils._handle_ret(ret, "cannot set event object's clock value")
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        payload_field = self.payload_field
+
+        if payload_field is not None and key in payload_field:
+            return payload_field[key]
+
+        context_field = self.context_field
+
+        if context_field is not None and key in context_field:
+            return context_field[key]
+
+        sec_field = self.stream_event_context_field
+
+        if sec_field is not None and key in sec_field:
+            return sec_field[key]
+
+        header_field = self.header_field
+
+        if header_field is not None and key in header_field:
+            return header_field[key]
+
+        packet = self.packet
+
+        if packet is None:
+            raise KeyError(key)
+
+        pkt_context_field = packet.context_field
+
+        if pkt_context_field is not None and key in pkt_context_field:
+            return pkt_context_field[key]
+
+        pkt_header_field = packet.header_field
+
+        if pkt_header_field is not None and key in pkt_header_field:
+            return pkt_header_field[key]
+
+        raise KeyError(key)
+
+    @property
+    def _clock_classes(self):
+        stream_class = self.event_class.stream_class
+
+        if stream_class is None:
+            return []
+
+        trace = stream_class.trace
+
+        if trace is None:
+            return []
+
+        clock_classes = []
+
+        for clock_class in trace.clock_classes.values():
+            clock_classes.append(clock_class)
+
+        return clock_classes
+
+    @property
+    def _clock_class_ptrs(self):
+        return [cc._ptr for cc in self._clock_classes]
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        self_clock_values = {}
+        other_clock_values = {}
+
+        for clock_class_ptr in self._clock_class_ptrs:
+            self_clock_values[int(clock_class_ptr)] = self._get_clock_value_cycles(clock_class_ptr)
+
+        for clock_class_ptr in other._clock_class_ptrs:
+            other_clock_values[int(clock_class_ptr)] = self._get_clock_value_cycles(clock_class_ptr)
+
+        self_props = (
+            self.header_field,
+            self.stream_event_context_field,
+            self.context_field,
+            self.payload_field,
+            self_clock_values,
+        )
+        other_props = (
+            other.header_field,
+            other.stream_event_context_field,
+            other.context_field,
+            other.payload_field,
+            other_clock_values,
+        )
+        return self_props == other_props
+
+    def _copy(self, copy_func):
+        cpy = self.event_class()
+
+        # copy fields
+        cpy.header_field = copy_func(self.header_field)
+        cpy.stream_event_context_field = copy_func(self.stream_event_context_field)
+        cpy.context_field = copy_func(self.context_field)
+        cpy.payload_field = copy_func(self.payload_field)
+
+        # Copy known clock value references. It's not necessary to copy
+        # clock class or clock value objects because once a clock value
+        # is created from a clock class, the clock class is frozen.
+        # Thus even if we copy the clock class, the user cannot modify
+        # it, therefore it's useless to copy it.
+        for clock_class in self._clock_classes:
+            clock_value = self.clock_value(clock_class)
+
+            if clock_value is not None:
+                cpy.add_clock_value(clock_value)
+
+        return cpy
+
+    def __copy__(self):
+        return self._copy(copy.copy)
+
+    def __deepcopy__(self, memo):
+        cpy = self._copy(copy.deepcopy)
+        memo[id(self)] = cpy
+        return cpy
diff --git a/bindings/python/bt2/bt2/event_class.py b/bindings/python/bt2/bt2/event_class.py
new file mode 100644 (file)
index 0000000..fb527ad
--- /dev/null
@@ -0,0 +1,235 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.field_types
+import collections.abc
+import bt2.values
+import bt2.event
+import copy
+import bt2
+
+
+class EventClassLogLevel:
+    UNKNOWN = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_UNKNOWN
+    UNSPECIFIED = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED
+    EMERGENCY = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_EMERGENCY
+    ALERT = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_ALERT
+    CRITICAL = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_CRITICAL
+    ERROR = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_ERROR
+    WARNING = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_WARNING
+    NOTICE = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_NOTICE
+    INFO = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_INFO
+    DEBUG_SYSTEM = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM
+    DEBUG_PROGRAM = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM
+    DEBUG_PROCESS = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS
+    DEBUG_MODULE = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE
+    DEBUG_UNIT = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT
+    DEBUG_FUNCTION = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION
+    DEBUG_LINE = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE
+    DEBUG = native_bt.CTF_EVENT_CLASS_LOG_LEVEL_DEBUG
+
+
+class EventClass(object._Object):
+    def __init__(self, name, id=None, log_level=None, emf_uri=None,
+                 context_field_type=None, payload_field_type=None):
+        utils._check_str(name)
+        ptr = native_bt.ctf_event_class_create(name)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create event class object')
+
+        super().__init__(ptr)
+
+        if id is not None:
+            self.id = id
+
+        if log_level is not None:
+            self.log_level = log_level
+
+        if emf_uri is not None:
+            self.emf_uri = emf_uri
+
+        if context_field_type is not None:
+            self.context_field_type = context_field_type
+
+        if payload_field_type is not None:
+            self.payload_field_type = payload_field_type
+
+    @property
+    def stream_class(self):
+        sc_ptr = native_bt.ctf_event_class_get_stream_class(self._ptr)
+
+        if sc_ptr is not None:
+            return bt2.StreamClass._create_from_ptr(sc_ptr)
+
+    @property
+    def name(self):
+        return native_bt.ctf_event_class_get_name(self._ptr)
+
+    @property
+    def id(self):
+        id = native_bt.ctf_event_class_get_id(self._ptr)
+        return id if id >= 0 else None
+
+    @id.setter
+    def id(self, id):
+        utils._check_int64(id)
+        ret = native_bt.ctf_event_class_set_id(self._ptr, id)
+        utils._handle_ret(ret, "cannot set event class object's ID")
+
+    @property
+    def log_level(self):
+        log_level = native_bt.ctf_event_class_get_log_level(self._ptr)
+        return log_level if log_level >= 0 else None
+
+    @log_level.setter
+    def log_level(self, log_level):
+        log_levels = (
+            EventClassLogLevel.UNSPECIFIED,
+            EventClassLogLevel.EMERGENCY,
+            EventClassLogLevel.ALERT,
+            EventClassLogLevel.CRITICAL,
+            EventClassLogLevel.ERROR,
+            EventClassLogLevel.WARNING,
+            EventClassLogLevel.NOTICE,
+            EventClassLogLevel.INFO,
+            EventClassLogLevel.DEBUG_SYSTEM,
+            EventClassLogLevel.DEBUG_PROGRAM,
+            EventClassLogLevel.DEBUG_PROCESS,
+            EventClassLogLevel.DEBUG_MODULE,
+            EventClassLogLevel.DEBUG_UNIT,
+            EventClassLogLevel.DEBUG_FUNCTION,
+            EventClassLogLevel.DEBUG_LINE,
+            EventClassLogLevel.DEBUG,
+        )
+
+        if log_level not in log_levels:
+            raise ValueError("'{}' is not a valid log level".format(log_level))
+
+        ret = native_bt.ctf_event_class_set_log_level(self._ptr, log_level)
+        utils._handle_ret(ret, "cannot set event class object's log level")
+
+    @property
+    def emf_uri(self):
+        return native_bt.ctf_event_class_get_emf_uri(self._ptr)
+
+    @emf_uri.setter
+    def emf_uri(self, emf_uri):
+        utils._check_str(emf_uri)
+        ret = native_bt.ctf_event_class_set_emf_uri(self._ptr, emf_uri)
+        utils._handle_ret(ret, "cannot set event class object's EMF URI")
+
+    @property
+    def context_field_type(self):
+        ft_ptr = native_bt.ctf_event_class_get_context_type(self._ptr)
+
+        if ft_ptr is None:
+            return
+
+        return bt2.field_types._create_from_ptr(ft_ptr)
+
+    @context_field_type.setter
+    def context_field_type(self, context_field_type):
+        context_field_type_ptr = None
+
+        if context_field_type is not None:
+            utils._check_type(context_field_type, bt2.field_types._FieldType)
+            context_field_type_ptr = context_field_type._ptr
+
+        ret = native_bt.ctf_event_class_set_context_type(self._ptr, context_field_type_ptr)
+        utils._handle_ret(ret, "cannot set event class object's context field type")
+
+    @property
+    def payload_field_type(self):
+        ft_ptr = native_bt.ctf_event_class_get_payload_type(self._ptr)
+
+        if ft_ptr is None:
+            return
+
+        return bt2.field_types._create_from_ptr(ft_ptr)
+
+    @payload_field_type.setter
+    def payload_field_type(self, payload_field_type):
+        payload_field_type_ptr = None
+
+        if payload_field_type is not None:
+            utils._check_type(payload_field_type, bt2.field_types._FieldType)
+            payload_field_type_ptr = payload_field_type._ptr
+
+        ret = native_bt.ctf_event_class_set_payload_type(self._ptr, payload_field_type_ptr)
+        utils._handle_ret(ret, "cannot set event class object's payload field type")
+
+    def __call__(self):
+        event_ptr = native_bt.ctf_event_create(self._ptr)
+
+        if event_ptr is None:
+            raise bt2.CreationError('cannot create event field object')
+
+        return bt2.event._create_from_ptr(event_ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        self_props = (
+            self.name,
+            self.id,
+            self.log_level,
+            self.emf_uri,
+            self.context_field_type,
+            self.payload_field_type
+        )
+        other_props = (
+            other.name,
+            other.id,
+            other.log_level,
+            other.emf_uri,
+            other.context_field_type,
+            other.payload_field_type
+        )
+        return self_props == other_props
+
+    def _copy(self, ft_copy_func):
+        cpy = EventClass(self.name)
+        cpy.id = self.id
+
+        if self.log_level is not None:
+            cpy.log_level = self.log_level
+
+        if self.emf_uri is not None:
+            cpy.emf_uri = self.emf_uri
+
+        cpy.context_field_type = ft_copy_func(self.context_field_type)
+        cpy.payload_field_type = ft_copy_func(self.payload_field_type)
+        return cpy
+
+    def __copy__(self):
+        return self._copy(lambda ft: ft)
+
+    def __deepcopy__(self, memo):
+        cpy = self._copy(copy.deepcopy)
+        memo[id(self)] = cpy
+        return cpy
diff --git a/bindings/python/bt2/bt2/field_types.py b/bindings/python/bt2/bt2/field_types.py
new file mode 100644 (file)
index 0000000..3a4e820
--- /dev/null
@@ -0,0 +1,700 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import collections.abc
+import bt2.fields
+import abc
+import bt2
+
+
+def _create_from_ptr(ptr):
+    typeid = native_bt.ctf_field_type_get_type_id(ptr)
+    return _TYPE_ID_TO_OBJ[typeid]._create_from_ptr(ptr)
+
+
+class _FieldType(object._Object, metaclass=abc.ABCMeta):
+    def __init__(self, ptr):
+        super().__init__(ptr)
+
+    def __eq__(self, other):
+        if not isinstance(other, self.__class__):
+            # not comparing apples to apples
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        ret = native_bt.ctf_field_type_compare(self._ptr, other._ptr)
+        utils._handle_ret(ret, "cannot compare field types")
+        return ret == 0
+
+    def _check_create_status(self, ptr):
+        if ptr is None:
+            raise bt2.CreationError('cannot create {} field type object'.format(self._NAME.lower()))
+
+    def __copy__(self):
+        ptr = native_bt.ctf_field_type_copy(self._ptr)
+        utils._handle_ptr(ptr, 'cannot copy {} field type object'.format(self._NAME.lower()))
+        return _create_from_ptr(ptr)
+
+    def __deepcopy__(self, memo):
+        cpy = self.__copy__()
+        memo[id(self)] = cpy
+        return cpy
+
+    def __call__(self, value=None):
+        field_ptr = native_bt.ctf_field_create(self._ptr)
+
+        if field_ptr is None:
+            raise bt2.CreationError('cannot create {} field object'.format(self._NAME.lower()))
+
+        field = bt2.fields._create_from_ptr(field_ptr)
+
+        if value is not None:
+            if not isinstance(field, (bt2.fields._IntegerField, bt2.fields._FloatingPointNumberField, bt2.fields._StringField)):
+                raise bt2.Error('cannot assign an initial value to a {} field object'.format(field._NAME))
+
+            field.value = value
+
+        return field
+
+
+class ByteOrder:
+    NATIVE = native_bt.CTF_BYTE_ORDER_NATIVE
+    LITTLE_ENDIAN = native_bt.CTF_BYTE_ORDER_LITTLE_ENDIAN
+    BIG_ENDIAN = native_bt.CTF_BYTE_ORDER_BIG_ENDIAN
+    NETWORK = native_bt.CTF_BYTE_ORDER_NETWORK
+
+
+class Encoding:
+    NONE = native_bt.CTF_STRING_ENCODING_NONE
+    UTF8 = native_bt.CTF_STRING_ENCODING_UTF8
+    ASCII = native_bt.CTF_STRING_ENCODING_ASCII
+
+
+class Base:
+    BINARY = native_bt.CTF_INTEGER_BASE_BINARY
+    OCTAL = native_bt.CTF_INTEGER_BASE_OCTAL
+    DECIMAL = native_bt.CTF_INTEGER_BASE_DECIMAL
+    HEXADECIMAL = native_bt.CTF_INTEGER_BASE_HEXADECIMAL
+
+
+class _AlignmentProp:
+    @property
+    def alignment(self):
+        alignment = native_bt.ctf_field_type_get_alignment(self._ptr)
+        assert(alignment >= 0)
+        return alignment
+
+    @alignment.setter
+    def alignment(self, alignment):
+        utils._check_alignment(alignment)
+        ret = native_bt.ctf_field_type_set_alignment(self._ptr, alignment)
+        utils._handle_ret(ret, "cannot set field type object's alignment")
+
+
+class _ByteOrderProp:
+    @property
+    def byte_order(self):
+        bo = native_bt.ctf_field_type_get_byte_order(self._ptr)
+        assert(bo >= 0)
+        return bo
+
+    @byte_order.setter
+    def byte_order(self, byte_order):
+        utils._check_int(byte_order)
+        ret = native_bt.ctf_field_type_set_byte_order(self._ptr, byte_order)
+        utils._handle_ret(ret, "cannot set field type object's byte order")
+
+
+class IntegerFieldType(_FieldType, _AlignmentProp, _ByteOrderProp):
+    _NAME = 'Integer'
+
+    def __init__(self, size, alignment=None, byte_order=None, is_signed=None,
+                 base=None, encoding=None, mapped_clock_class=None):
+        utils._check_uint64(size)
+
+        if size == 0:
+            raise ValueError('size is 0 bits')
+
+        ptr = native_bt.ctf_field_type_integer_create(size)
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+        if alignment is not None:
+            self.alignment = alignment
+
+        if byte_order is not None:
+            self.byte_order = byte_order
+
+        if is_signed is not None:
+            self.is_signed = is_signed
+
+        if base is not None:
+            self.base = base
+
+        if encoding is not None:
+            self.encoding = encoding
+
+        if mapped_clock_class is not None:
+            self.mapped_clock_class = mapped_clock_class
+
+    @property
+    def size(self):
+        size = native_bt.ctf_field_type_integer_get_size(self._ptr)
+        assert(size >= 1)
+        return size
+
+    @property
+    def is_signed(self):
+        is_signed = native_bt.ctf_field_type_integer_is_signed(self._ptr)
+        assert(is_signed >= 0)
+        return is_signed > 0
+
+    @is_signed.setter
+    def is_signed(self, is_signed):
+        utils._check_bool(is_signed)
+        ret = native_bt.ctf_field_type_integer_set_is_signed(self._ptr, int(is_signed))
+        utils._handle_ret(ret, "cannot set integer field type object's signedness")
+
+    @property
+    def base(self):
+        base = native_bt.ctf_field_type_integer_get_base(self._ptr)
+        assert(base >= 0)
+        return base
+
+    @base.setter
+    def base(self, base):
+        utils._check_int(base)
+        ret = native_bt.ctf_field_type_integer_set_base(self._ptr, base)
+        utils._handle_ret(ret, "cannot set integer field type object's base")
+
+    @property
+    def encoding(self):
+        encoding = native_bt.ctf_field_type_integer_get_encoding(self._ptr)
+        assert(encoding >= 0)
+        return encoding
+
+    @encoding.setter
+    def encoding(self, encoding):
+        utils._check_int(encoding)
+        ret = native_bt.ctf_field_type_integer_set_encoding(self._ptr, encoding)
+        utils._handle_ret(ret, "cannot set integer field type object's encoding")
+
+    @property
+    def mapped_clock_class(self):
+        ptr = native_bt.ctf_field_type_integer_get_mapped_clock_class(self._ptr)
+
+        if ptr is None:
+            return
+
+        return bt2.ClockClass._create_from_ptr(ptr)
+
+    @mapped_clock_class.setter
+    def mapped_clock_class(self, clock_class):
+        utils._check_type(clock_class, bt2.ClockClass)
+        ret = native_bt.ctf_field_type_integer_set_mapped_clock_class(self._ptr, clock_class._ptr)
+        utils._handle_ret(ret, "cannot set integer field type object's mapped clock class")
+
+
+class FloatingPointNumberFieldType(_FieldType, _AlignmentProp, _ByteOrderProp):
+    _NAME = 'Floating point number'
+
+    def __init__(self, alignment=None, byte_order=None, exponent_size=None,
+                 mantissa_size=None):
+        ptr = native_bt.ctf_field_type_floating_point_create()
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+        if alignment is not None:
+            self.alignment = alignment
+
+        if byte_order is not None:
+            self.byte_order = byte_order
+
+        if exponent_size is not None:
+            self.exponent_size = exponent_size
+
+        if mantissa_size is not None:
+            self.mantissa_size = mantissa_size
+
+    @property
+    def exponent_size(self):
+        exp_size = native_bt.ctf_field_type_floating_point_get_exponent_digits(self._ptr)
+        assert(exp_size >= 0)
+        return exp_size
+
+    @exponent_size.setter
+    def exponent_size(self, exponent_size):
+        utils._check_uint64(exponent_size)
+        ret = native_bt.ctf_field_type_floating_point_set_exponent_digits(self._ptr, exponent_size)
+        utils._handle_ret(ret, "cannot set floating point number field type object's exponent size")
+
+    @property
+    def mantissa_size(self):
+        mant_size = native_bt.ctf_field_type_floating_point_get_mantissa_digits(self._ptr)
+        assert(mant_size >= 0)
+        return mant_size
+
+    @mantissa_size.setter
+    def mantissa_size(self, mantissa_size):
+        utils._check_uint64(mantissa_size)
+        ret = native_bt.ctf_field_type_floating_point_set_mantissa_digits(self._ptr, mantissa_size)
+        utils._handle_ret(ret, "cannot set floating point number field type object's mantissa size")
+
+
+class _EnumerationFieldTypeMapping:
+    def __init__(self, name, lower, upper):
+        self._name = name
+        self._lower = lower
+        self._upper = upper
+
+    @property
+    def name(self):
+        return self._name
+
+    @property
+    def lower(self):
+        return self._lower
+
+    @property
+    def upper(self):
+        return self._upper
+
+    def __eq__(self, other):
+        if type(other) is not self.__class__:
+            return False
+
+        return (self.name, self.lower, self.upper) == (other.name, other.lower, other.upper)
+
+
+class _EnumerationFieldTypeMappingIterator(object._Object,
+                                           collections.abc.Iterator):
+    def __init__(self, iter_ptr, is_signed):
+        super().__init__(iter_ptr)
+        self._is_signed = is_signed
+        self._done = (iter_ptr is None)
+
+    def __next__(self):
+        if self._done:
+            raise StopIteration
+
+        if self._is_signed:
+            ret, name, lower, upper = native_bt.ctf_field_type_enumeration_mapping_iterator_get_signed(self._ptr)
+        else:
+            ret, name, lower, upper = native_bt.ctf_field_type_enumeration_mapping_iterator_get_unsigned(self._ptr)
+
+        assert(ret == 0)
+        mapping = _EnumerationFieldTypeMapping(name, lower, upper)
+        ret = native_bt.ctf_field_type_enumeration_mapping_iterator_next(self._ptr)
+
+        if ret < 0:
+            self._done = True
+
+        return mapping
+
+
+class EnumerationFieldType(IntegerFieldType, collections.abc.Sequence):
+    _NAME = 'Enumeration'
+
+    def __init__(self, int_field_type=None, size=None, alignment=None,
+                 byte_order=None, is_signed=None, base=None, encoding=None,
+                 mapped_clock_class=None):
+        if int_field_type is None:
+            int_field_type = IntegerFieldType(size=size, alignment=alignment,
+                                              byte_order=byte_order,
+                                              is_signed=is_signed, base=base,
+                                              encoding=encoding,
+                                              mapped_clock_class=mapped_clock_class)
+
+        utils._check_type(int_field_type, IntegerFieldType)
+        ptr = native_bt.ctf_field_type_enumeration_create(int_field_type._ptr)
+        self._check_create_status(ptr)
+        _FieldType.__init__(self, ptr)
+
+    @property
+    def integer_field_type(self):
+        ptr = native_bt.ctf_field_type_enumeration_get_container_type(self._ptr)
+        assert(ptr)
+        return _create_from_ptr(ptr)
+
+    @property
+    def size(self):
+        return self.integer_field_type.size
+
+    @property
+    def alignment(self):
+        return self.integer_field_type.alignment
+
+    @alignment.setter
+    def alignment(self, alignment):
+        self.integer_field_type.alignment = alignment
+
+    @property
+    def byte_order(self):
+        return self.integer_field_type.byte_order
+
+    @byte_order.setter
+    def byte_order(self, byte_order):
+        self.integer_field_type.byte_order = byte_order
+
+    @property
+    def is_signed(self):
+        return self.integer_field_type.is_signed
+
+    @is_signed.setter
+    def is_signed(self, is_signed):
+        self.integer_field_type.is_signed = is_signed
+
+    @property
+    def base(self):
+        return self.integer_field_type.base
+
+    @base.setter
+    def base(self, base):
+        self.integer_field_type.base = base
+
+    @property
+    def encoding(self):
+        return self.integer_field_type.encoding
+
+    @encoding.setter
+    def encoding(self, encoding):
+        self.integer_field_type.encoding = encoding
+
+    @property
+    def mapped_clock_class(self):
+        return self.integer_field_type.mapped_clock_class
+
+    @mapped_clock_class.setter
+    def mapped_clock_class(self, mapped_clock_class):
+        self.integer_field_type.mapped_clock_class = mapped_clock_class
+
+    def __len__(self):
+        count = native_bt.ctf_field_type_enumeration_get_mapping_count(self._ptr)
+        assert(count >= 0)
+        return count
+
+    def __getitem__(self, index):
+        utils._check_uint64(index)
+
+        if index >= len(self):
+            raise IndexError
+
+        if self.is_signed:
+            get_fn = native_bt.ctf_field_type_enumeration_get_mapping_signed
+        else:
+            get_fn = native_bt.ctf_field_type_enumeration_get_mapping_unsigned
+
+        ret, name, lower, upper = get_fn(self._ptr, index)
+        assert(ret == 0)
+        return _EnumerationFieldTypeMapping(name, lower, upper)
+
+    def _get_mapping_iter(self, iter_ptr):
+        return _EnumerationFieldTypeMappingIterator(iter_ptr, self.is_signed)
+
+    def mappings_by_name(self, name):
+        utils._check_str(name)
+        iter_ptr = native_bt.ctf_field_type_enumeration_find_mappings_by_name(self._ptr, name)
+        return self._get_mapping_iter(iter_ptr)
+
+    def mappings_by_value(self, value):
+        if self.is_signed:
+            utils._check_int64(value)
+            iter_ptr = native_bt.ctf_field_type_enumeration_find_mappings_by_signed_value(self._ptr, value)
+        else:
+            utils._check_uint64(value)
+            iter_ptr = native_bt.ctf_field_type_enumeration_find_mappings_by_unsigned_value(self._ptr, value)
+
+        return self._get_mapping_iter(iter_ptr)
+
+    def append_mapping(self, name, lower, upper=None):
+        utils._check_str(name)
+
+        if upper is None:
+            upper = lower
+
+        if self.is_signed:
+            add_fn = native_bt.ctf_field_type_enumeration_add_mapping_signed
+            utils._check_int64(lower)
+            utils._check_int64(upper)
+        else:
+            add_fn = native_bt.ctf_field_type_enumeration_add_mapping_unsigned
+            utils._check_uint64(lower)
+            utils._check_uint64(upper)
+
+        ret = add_fn(self._ptr, name, lower, upper)
+        utils._handle_ret(ret, "cannot add mapping to enumeration field type object")
+
+    def __iadd__(self, mappings):
+        for mapping in mappings:
+            self.append_mapping(mapping.name, mapping.lower, mapping.upper)
+
+        return self
+
+
+class StringFieldType(_FieldType):
+    _NAME = 'String'
+
+    def __init__(self, encoding=None):
+        ptr = native_bt.ctf_field_type_string_create()
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+        if encoding is not None:
+            self.encoding = encoding
+
+    @property
+    def encoding(self):
+        encoding = native_bt.ctf_field_type_string_get_encoding(self._ptr)
+        assert(encoding >= 0)
+        return encoding
+
+    @encoding.setter
+    def encoding(self, encoding):
+        utils._check_int(encoding)
+        ret = native_bt.ctf_field_type_string_set_encoding(self._ptr, encoding)
+        utils._handle_ret(ret, "cannot set string field type object's encoding")
+
+
+class _FieldContainer(collections.abc.Mapping):
+    def __len__(self):
+        count = self._count()
+        assert(count >= 0)
+        return count
+
+    def __getitem__(self, key):
+        if not isinstance(key, str):
+            raise TypeError("'{}' is not a 'str' object".format(key.__class__.__name__))
+
+        ptr = self._get_field_by_name(key)
+
+        if ptr is None:
+            raise KeyError(key)
+
+        return _create_from_ptr(ptr)
+
+    def __iter__(self):
+        return self._ITER_CLS(self)
+
+    def append_field(self, name, field_type):
+        utils._check_str(name)
+        utils._check_type(field_type, _FieldType)
+        ret = self._add_field(field_type._ptr, name)
+        utils._handle_ret(ret, "cannot add field to {} field type object".format(self._NAME.lower()))
+
+    def __iadd__(self, fields):
+        for name, field_type in fields.items():
+            self.append_field(name, field_type)
+
+        return self
+
+    def at_index(self, index):
+        utils._check_uint64(index)
+        return self._at(index)
+
+
+class _StructureFieldTypeFieldIterator(collections.abc.Iterator):
+    def __init__(self, struct_field_type):
+        self._struct_field_type = struct_field_type
+        self._at = 0
+
+    def __next__(self):
+        if self._at == len(self._struct_field_type):
+            raise StopIteration
+
+        get_ft_by_index = native_bt.ctf_field_type_structure_get_field_by_index
+        ret, name, field_type_ptr = get_ft_by_index(self._struct_field_type._ptr,
+                                                    self._at)
+        assert(ret == 0)
+        native_bt.put(field_type_ptr)
+        self._at += 1
+        return name
+
+
+class StructureFieldType(_FieldType, _FieldContainer, _AlignmentProp):
+    _NAME = 'Structure'
+    _ITER_CLS = _StructureFieldTypeFieldIterator
+
+    def __init__(self, min_alignment=None):
+        ptr = native_bt.ctf_field_type_structure_create()
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+        if min_alignment is not None:
+            self.min_alignment = min_alignment
+
+    def _count(self):
+        return native_bt.ctf_field_type_structure_get_field_count(self._ptr)
+
+    def _get_field_by_name(self, key):
+        return native_bt.ctf_field_type_structure_get_field_type_by_name(self._ptr, key)
+
+    def _add_field(self, ptr, name):
+        return native_bt.ctf_field_type_structure_add_field(self._ptr, ptr,
+                                                            name)
+
+    def _at(self, index):
+        if index < 0 or index >= len(self):
+            raise IndexError
+
+        ret, name, field_type_ptr = native_bt.ctf_field_type_structure_get_field_by_index(self._ptr, index)
+        assert(ret == 0)
+        return _create_from_ptr(field_type_ptr)
+
+
+StructureFieldType.min_alignment = property(fset=StructureFieldType.alignment.fset)
+StructureFieldType.alignment = property(fget=StructureFieldType.alignment.fget)
+
+
+class _VariantFieldTypeFieldIterator(collections.abc.Iterator):
+    def __init__(self, variant_field_type):
+        self._variant_field_type = variant_field_type
+        self._at = 0
+
+    def __next__(self):
+        if self._at == len(self._variant_field_type):
+            raise StopIteration
+
+        ret, name, field_type_ptr = native_bt.ctf_field_type_variant_get_field_by_index(self._variant_field_type._ptr,
+                                                                                        self._at)
+        assert(ret == 0)
+        native_bt.put(field_type_ptr)
+        self._at += 1
+        return name
+
+
+class VariantFieldType(_FieldType, _FieldContainer, _AlignmentProp):
+    _NAME = 'Variant'
+    _ITER_CLS = _VariantFieldTypeFieldIterator
+
+    def __init__(self, tag_name, tag_field_type=None):
+        utils._check_str(tag_name)
+
+        if tag_field_type is None:
+            tag_ft_ptr = None
+        else:
+            utils._check_type(tag_field_type, EnumerationFieldType)
+            tag_ft_ptr = tag_field_type._ptr
+
+        ptr = native_bt.ctf_field_type_variant_create(tag_ft_ptr,
+                                                      tag_name)
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+    @property
+    def tag_name(self):
+        tag_name = native_bt.ctf_field_type_variant_get_tag_name(self._ptr)
+        assert(tag_name is not None)
+        return tag_name
+
+    @tag_name.setter
+    def tag_name(self, tag_name):
+        utils._check_str(tag_name)
+        ret = native_bt.ctf_field_type_variant_set_tag_name(self._ptr, tag_name)
+        utils._handle_ret(ret, "cannot set variant field type object's tag name")
+
+    @property
+    def tag_field_type(self):
+        ft_ptr = native_bt.ctf_field_type_variant_get_tag_type(self._ptr)
+
+        if ft_ptr is None:
+            return
+
+        return _create_from_ptr(ft_ptr)
+
+    def _count(self):
+        return native_bt.ctf_field_type_variant_get_field_count(self._ptr)
+
+    def _get_field_by_name(self, key):
+        return native_bt.ctf_field_type_variant_get_field_type_by_name(self._ptr, key)
+
+    def _add_field(self, ptr, name):
+        return native_bt.ctf_field_type_variant_add_field(self._ptr, ptr, name)
+
+    def _at(self, index):
+        if index < 0 or index >= len(self):
+            raise IndexError
+
+        ret, name, field_type_ptr = native_bt.ctf_field_type_variant_get_field_by_index(self._ptr, index)
+        assert(ret == 0)
+        return _create_from_ptr(field_type_ptr)
+
+
+class ArrayFieldType(_FieldType):
+    _NAME = 'Array'
+
+    def __init__(self, element_field_type, length):
+        utils._check_type(element_field_type, _FieldType)
+        utils._check_uint64(length)
+        ptr = native_bt.ctf_field_type_array_create(element_field_type._ptr, length)
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+    @property
+    def length(self):
+        length = native_bt.ctf_field_type_array_get_length(self._ptr)
+        assert(length >= 0)
+        return length
+
+    @property
+    def element_field_type(self):
+        ptr = native_bt.ctf_field_type_array_get_element_type(self._ptr)
+        assert(ptr)
+        return _create_from_ptr(ptr)
+
+
+class SequenceFieldType(_FieldType):
+    _NAME = 'Sequence'
+
+    def __init__(self, element_field_type, length_name):
+        utils._check_type(element_field_type, _FieldType)
+        utils._check_str(length_name)
+        ptr = native_bt.ctf_field_type_sequence_create(element_field_type._ptr,
+                                                       length_name)
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+    @property
+    def length_name(self):
+        length_name = native_bt.ctf_field_type_sequence_get_length_field_name(self._ptr)
+        assert(length_name is not None)
+        return length_name
+
+    @property
+    def element_field_type(self):
+        ptr = native_bt.ctf_field_type_sequence_get_element_type(self._ptr)
+        assert(ptr)
+        return _create_from_ptr(ptr)
+
+
+_TYPE_ID_TO_OBJ = {
+    native_bt.CTF_FIELD_TYPE_ID_INTEGER: IntegerFieldType,
+    native_bt.CTF_FIELD_TYPE_ID_FLOAT: FloatingPointNumberFieldType,
+    native_bt.CTF_FIELD_TYPE_ID_ENUM: EnumerationFieldType,
+    native_bt.CTF_FIELD_TYPE_ID_STRING: StringFieldType,
+    native_bt.CTF_FIELD_TYPE_ID_STRUCT: StructureFieldType,
+    native_bt.CTF_FIELD_TYPE_ID_ARRAY: ArrayFieldType,
+    native_bt.CTF_FIELD_TYPE_ID_SEQUENCE: SequenceFieldType,
+    native_bt.CTF_FIELD_TYPE_ID_VARIANT: VariantFieldType,
+}
diff --git a/bindings/python/bt2/bt2/fields.py b/bindings/python/bt2/bt2/fields.py
new file mode 100644 (file)
index 0000000..44d6a38
--- /dev/null
@@ -0,0 +1,616 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.field_types
+import collections.abc
+import functools
+import numbers
+import math
+import abc
+import bt2
+
+
+def _create_from_ptr(ptr):
+    # recreate the field type wrapper of this field's type (the identity
+    # could be different, but the underlying address should be the
+    # same)
+    field_type_ptr = native_bt.ctf_field_get_type(ptr)
+    utils._handle_ptr(field_type_ptr, "cannot get field object's type")
+    field_type = bt2.field_types._create_from_ptr(field_type_ptr)
+    typeid = native_bt.ctf_field_type_get_type_id(field_type._ptr)
+    field = _TYPE_ID_TO_OBJ[typeid]._create_from_ptr(ptr)
+    field._field_type = field_type
+    return field
+
+
+class _Field(object._Object, metaclass=abc.ABCMeta):
+    def __copy__(self):
+        ptr = native_bt.ctf_field_copy(self._ptr)
+        utils._handle_ptr(ptr, 'cannot copy {} field object'.format(self._NAME.lower()))
+        return _create_from_ptr(ptr)
+
+    def __deepcopy__(self, memo):
+        cpy = self.__copy__()
+        memo[id(self)] = cpy
+        return cpy
+
+    @property
+    def field_type(self):
+        return self._field_type
+
+
+@functools.total_ordering
+class _NumericField(_Field):
+    @staticmethod
+    def _extract_value(other):
+        if other is True or other is False:
+            return other
+
+        if isinstance(other, numbers.Integral):
+            return int(other)
+
+        if isinstance(other, numbers.Real):
+            return float(other)
+
+        if isinstance(other, numbers.Complex):
+            return complex(other)
+
+        raise TypeError("'{}' object is not a number object".format(other.__class__.__name__))
+
+    def __int__(self):
+        return int(self.value)
+
+    def __float__(self):
+        return float(self.value)
+
+    def __str__(self):
+        return str(self.value)
+
+    def __lt__(self, other):
+        if not isinstance(other, numbers.Number):
+            raise TypeError('unorderable types: {}() < {}()'.format(self.__class__.__name__,
+                                                                    other.__class__.__name__))
+
+        return self.value < float(other)
+
+    def __le__(self, other):
+        if not isinstance(other, numbers.Number):
+            raise TypeError('unorderable types: {}() <= {}()'.format(self.__class__.__name__,
+                                                                     other.__class__.__name__))
+
+        return self.value <= float(other)
+
+    def __eq__(self, other):
+        if not isinstance(other, numbers.Number):
+            return False
+
+        return self.value == complex(other)
+
+    def __rmod__(self, other):
+        return self._extract_value(other) % self.value
+
+    def __mod__(self, other):
+        return self.value % self._extract_value(other)
+
+    def __rfloordiv__(self, other):
+        return self._extract_value(other) // self.value
+
+    def __floordiv__(self, other):
+        return self.value // self._extract_value(other)
+
+    def __round__(self, ndigits=None):
+        if ndigits is None:
+            return round(self.value)
+        else:
+            return round(self.value, ndigits)
+
+    def __ceil__(self):
+        return math.ceil(self.value)
+
+    def __floor__(self):
+        return math.floor(self.value)
+
+    def __trunc__(self):
+        return int(self.value)
+
+    def __abs__(self):
+        return abs(self.value)
+
+    def __add__(self, other):
+        return self.value + self._extract_value(other)
+
+    def __radd__(self, other):
+        return self.__add__(other)
+
+    def __neg__(self):
+        return -self.value
+
+    def __pos__(self):
+        return +self.value
+
+    def __mul__(self, other):
+        return self.value * self._extract_value(other)
+
+    def __rmul__(self, other):
+        return self.__mul__(other)
+
+    def __truediv__(self, other):
+        return self.value / self._extract_value(other)
+
+    def __rtruediv__(self, other):
+        return self._extract_value(other) / self.value
+
+    def __pow__(self, exponent):
+        return self.value ** self._extract_value(exponent)
+
+    def __rpow__(self, base):
+        return self._extract_value(base) ** self.value
+
+    def __iadd__(self, other):
+        self.value = self + other
+        return self
+
+    def __isub__(self, other):
+        self.value = self - other
+        return self
+
+    def __imul__(self, other):
+        self.value = self * other
+        return self
+
+    def __itruediv__(self, other):
+        self.value = self / other
+        return self
+
+    def __ifloordiv__(self, other):
+        self.value = self // other
+        return self
+
+    def __imod__(self, other):
+        self.value = self % other
+        return self
+
+    def __ipow__(self, other):
+        self.value = self ** other
+        return self
+
+
+class _IntegralField(_NumericField, numbers.Integral):
+    def __lshift__(self, other):
+        return self.value << self._extract_value(other)
+
+    def __rlshift__(self, other):
+        return self._extract_value(other) << self.value
+
+    def __rshift__(self, other):
+        return self.value >> self._extract_value(other)
+
+    def __rrshift__(self, other):
+        return self._extract_value(other) >> self.value
+
+    def __and__(self, other):
+        return self.value & self._extract_value(other)
+
+    def __rand__(self, other):
+        return self._extract_value(other) & self.value
+
+    def __xor__(self, other):
+        return self.value ^ self._extract_value(other)
+
+    def __rxor__(self, other):
+        return self._extract_value(other) ^ self.value
+
+    def __or__(self, other):
+        return self.value | self._extract_value(other)
+
+    def __ror__(self, other):
+        return self._extract_value(other) | self.value
+
+    def __invert__(self):
+        return ~self.value
+
+    def __ilshift__(self, other):
+        self.value = self << other
+        return self
+
+    def __irshift__(self, other):
+        self.value = self >> other
+        return self
+
+    def __iand__(self, other):
+        self.value = self & other
+        return self
+
+    def __ixor__(self, other):
+        self.value = self ^ other
+        return self
+
+    def __ior__(self, other):
+        self.value = self | other
+        return self
+
+
+class _RealField(_NumericField, numbers.Real):
+    pass
+
+
+class _IntegerField(_IntegralField):
+    _NAME = 'Integer'
+
+    def _value_to_int(self, value):
+        if not isinstance(value, numbers.Real):
+            raise TypeError('expecting a real number object')
+
+        value = int(value)
+
+        if self.field_type.is_signed:
+            utils._check_int64(value)
+        else:
+            utils._check_uint64(value)
+
+        return value
+
+    @property
+    def value(self):
+        if self.field_type.is_signed:
+            ret, value = native_bt.ctf_field_signed_integer_get_value(self._ptr)
+        else:
+            ret, value = native_bt.ctf_field_unsigned_integer_get_value(self._ptr)
+
+        if ret < 0:
+            # field is not set
+            return
+
+        return value
+
+    @value.setter
+    def value(self, value):
+        value = self._value_to_int(value)
+
+        if self.field_type.is_signed:
+            ret = native_bt.ctf_field_signed_integer_set_value(self._ptr, value)
+        else:
+            ret = native_bt.ctf_field_unsigned_integer_set_value(self._ptr, value)
+
+        utils._handle_ret(ret, "cannot set integer field object's value")
+
+
+class _FloatingPointNumberField(_RealField):
+    _NAME = 'Floating point number'
+
+    def _value_to_float(self, value):
+        if not isinstance(value, numbers.Real):
+            raise TypeError("expecting a real number object")
+
+        return float(value)
+
+    @property
+    def value(self):
+        ret, value = native_bt.ctf_field_floating_point_get_value(self._ptr)
+
+        if ret < 0:
+            # field is not set
+            return
+
+        return value
+
+    @value.setter
+    def value(self, value):
+        value = self._value_to_float(value)
+        ret = native_bt.ctf_field_floating_point_set_value(self._ptr, value)
+        utils._handle_ret(ret, "cannot set floating point number field object's value")
+
+
+class _EnumerationField(_IntegerField):
+    _NAME = 'Enumeration'
+
+    @property
+    def integer_field(self):
+        int_field_ptr = native_bt.ctf_field_enumeration_get_container(self._ptr)
+        assert(int_field_ptr)
+        return _create_from_ptr(int_field_ptr)
+
+    @property
+    def value(self):
+        return self.integer_field.value
+
+    @value.setter
+    def value(self, value):
+        self.integer_field.value = value
+
+    @property
+    def mappings(self):
+        iter_ptr = native_bt.ctf_field_enumeration_get_mappings(self._ptr)
+        assert(iter_ptr)
+        return bt2.field_types._EnumerationFieldTypeMappingIterator(iter_ptr,
+                                                                    self.field_type.is_signed)
+
+
+@functools.total_ordering
+class _StringField(_Field, collections.abc.Sequence):
+    _NAME = 'String'
+
+    def _value_to_str(self, value):
+        if isinstance(value, self.__class__):
+            value = value.value
+
+        if not isinstance(value, str):
+            raise TypeError("expecting a 'str' object")
+
+        return value
+
+    @property
+    def value(self):
+        value = native_bt.ctf_field_string_get_value(self._ptr)
+
+        if value is None:
+            # field is not set
+            return
+
+        return value
+
+    @value.setter
+    def value(self, value):
+        value = self._value_to_str(value)
+        ret = native_bt.ctf_field_string_set_value(self._ptr, value)
+        utils._handle_ret(ret, "cannot set string field object's value")
+
+    def __eq__(self, other):
+        try:
+            other = self._value_to_str(other)
+        except:
+            return False
+
+        return self.value == other
+
+    def __le__(self, other):
+        return self.value <= self._value_to_str(other)
+
+    def __lt__(self, other):
+        return self.value < self._value_to_str(other)
+
+    def __bool__(self):
+        return bool(self.value)
+
+    def __str__(self):
+        return self.value
+
+    def __getitem__(self, index):
+        return self.value[index]
+
+    def __len__(self):
+        return len(self.value)
+
+    def __iadd__(self, value):
+        value = self._value_to_str(value)
+        ret = native_bt.ctf_field_string_append(self._ptr, value)
+        utils._handle_ret(ret, "cannot append to string field object's value")
+        return self
+
+
+class _ContainerField(_Field):
+    def __bool__(self):
+        return len(self) != 0
+
+    def __len__(self):
+        count = self._count()
+        assert(count >= 0)
+        return count
+
+    def __delitem__(self, index):
+        raise NotImplementedError
+
+
+class _StructureField(_ContainerField, collections.abc.MutableMapping):
+    _NAME = 'Structure'
+
+    def _count(self):
+        return len(self.field_type)
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        ptr = native_bt.ctf_field_structure_get_field_by_name(self._ptr, key)
+
+        if ptr is None:
+            raise KeyError(key)
+
+        return _create_from_ptr(ptr)
+
+    def __setitem__(self, key, value):
+        # we can only set numbers and strings
+        if not isinstance(value, (numbers.Number, str)):
+            raise TypeError('expecting number object or string')
+
+        # raises if index is somehow invalid
+        field = self[key]
+
+        if not isinstance(field, (_NumericField, _StringField)):
+            raise TypeError('can only set the value of a number or string field')
+
+        # the field's property does the appropriate conversion or raises
+        # the appropriate exception
+        field.value = value
+
+    def at_index(self, index):
+        utils._check_uint64(index)
+
+        if index >= len(self):
+            raise IndexError
+
+        field_ptr = native_bt.ctf_field_structure_get_field_by_index(self._ptr, index)
+        assert(field_ptr)
+        return _create_from_ptr(field_ptr)
+
+    def __iter__(self):
+        # same name iterator
+        return iter(self.field_type)
+
+    def __eq__(self, other):
+        if not isinstance(other, collections.abc.Mapping):
+            return False
+
+        if len(self) != len(other):
+            return False
+
+        for self_key, self_value in self.items():
+            if self_key not in other:
+                return False
+
+            other_value = other[self_key]
+
+            if self_value != other_value:
+                return False
+
+        return True
+
+
+class _VariantField(_Field):
+    _NAME = 'Variant'
+
+    @property
+    def tag_field(self):
+        field_ptr = native_bt.ctf_field_variant_get_tag(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return _create_from_ptr(field_ptr)
+
+    @property
+    def selected_field(self):
+        return self.field()
+
+    def field(self, tag_field=None):
+        if tag_field is None:
+            field_ptr = native_bt.ctf_field_variant_get_current_field(self._ptr)
+
+            if field_ptr is None:
+                return
+        else:
+            utils._check_type(tag_field, _EnumerationField)
+            field_ptr = native_bt.ctf_field_variant_get_field(self._ptr, tag_field._ptr)
+            utils._handle_ptr(field_ptr, "cannot select variant field object's field")
+
+        return _create_from_ptr(field_ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        return self.selected_field == other.selected_field
+
+    def __bool__(self):
+        return bool(self.selected_field)
+
+
+class _ArraySequenceField(_ContainerField, collections.abc.MutableSequence):
+    def __getitem__(self, index):
+        if not isinstance(index, numbers.Integral):
+            raise TypeError("'{}' is not an integral number object: invalid index".format(index.__class__.__name__))
+
+        index = int(index)
+
+        if index < 0 or index >= len(self):
+            raise IndexError('{} field object index is out of range'.format(self._NAME))
+
+        field_ptr = self._get_field_ptr_at_index(index)
+        assert(field_ptr)
+        return _create_from_ptr(field_ptr)
+
+    def __setitem__(self, index, value):
+        # we can only set numbers and strings
+        if not isinstance(value, (numbers.Number, _StringField, str)):
+            raise TypeError('expecting number or string object')
+
+        # raises if index is somehow invalid
+        field = self[index]
+
+        if not isinstance(field, (_NumericField, _StringField)):
+            raise TypeError('can only set the value of a number or string field')
+
+        # the field's property does the appropriate conversion or raises
+        # the appropriate exception
+        field.value = value
+
+    def insert(self, index, value):
+        raise NotImplementedError
+
+    def __eq__(self, other):
+        if not isinstance(other, collections.abc.Sequence):
+            return False
+
+        if len(self) != len(other):
+            return False
+
+        for self_field, other_field in zip(self, other):
+            if self_field != other_field:
+                return False
+
+        return True
+
+
+class _ArrayField(_ArraySequenceField):
+    _NAME = 'Array'
+
+    def _count(self):
+        return self.field_type.length
+
+    def _get_field_ptr_at_index(self, index):
+        return native_bt.ctf_field_array_get_field(self._ptr, index)
+
+
+class _SequenceField(_ArraySequenceField):
+    _NAME = 'Sequence'
+
+    def _count(self):
+        return self.length_field.value
+
+    @property
+    def length_field(self):
+        field_ptr = native_bt.ctf_field_sequence_get_length(self._ptr)
+        utils._handle_ptr("cannot get sequence field object's length field")
+        return _create_from_ptr(field_ptr)
+
+    @length_field.setter
+    def length_field(self, length_field):
+        utils._check_type(length_field, _IntegerField)
+        ret = native_bt.ctf_field_sequence_set_length(self._ptr, length_field._ptr)
+        utils._handle_ret(ret, "cannot set sequence field object's length field")
+
+    def _get_field_ptr_at_index(self, index):
+        return native_bt.ctf_field_sequence_get_field(self._ptr, index)
+
+
+_TYPE_ID_TO_OBJ = {
+    native_bt.CTF_FIELD_TYPE_ID_INTEGER: _IntegerField,
+    native_bt.CTF_FIELD_TYPE_ID_FLOAT: _FloatingPointNumberField,
+    native_bt.CTF_FIELD_TYPE_ID_ENUM: _EnumerationField,
+    native_bt.CTF_FIELD_TYPE_ID_STRING: _StringField,
+    native_bt.CTF_FIELD_TYPE_ID_STRUCT: _StructureField,
+    native_bt.CTF_FIELD_TYPE_ID_ARRAY: _ArrayField,
+    native_bt.CTF_FIELD_TYPE_ID_SEQUENCE: _SequenceField,
+    native_bt.CTF_FIELD_TYPE_ID_VARIANT: _VariantField,
+}
diff --git a/bindings/python/bt2/bt2/graph.py b/bindings/python/bt2/bt2/graph.py
new file mode 100644 (file)
index 0000000..5614839
--- /dev/null
@@ -0,0 +1,193 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.connection
+import bt2.component
+import functools
+import bt2.port
+import bt2
+
+
+class GraphListenerType:
+    PORT_ADDED = 0
+    PORT_REMOVED = 1
+    PORTS_CONNECTED = 2
+    PORTS_DISCONNECTED = 3
+
+
+def _graph_port_added_listener_from_native(user_listener, port_ptr):
+    try:
+        port = bt2.port._create_from_ptr(port_ptr)
+        port._get()
+        user_listener(port)
+    except:
+        pass
+
+
+def _graph_port_removed_listener_from_native(user_listener, port_ptr):
+    try:
+        port = bt2.port._create_from_ptr(port_ptr)
+        port._get()
+        user_listener(port)
+    except:
+        pass
+
+
+def _graph_ports_connected_listener_from_native(user_listener,
+                                                upstream_port_ptr,
+                                                downstream_port_ptr):
+    try:
+        upstream_port = bt2.port._create_from_ptr(upstream_port_ptr)
+        upstream_port._get()
+        downstream_port = bt2.port._create_from_ptr(downstream_port_ptr)
+        downstream_port._get()
+        user_listener(upstream_port, downstream_port)
+    except:
+        pass
+
+
+def _graph_ports_disconnected_listener_from_native(user_listener,
+                                                   upstream_comp_ptr,
+                                                   downstream_comp_ptr,
+                                                   upstream_port_ptr,
+                                                   downstream_port_ptr):
+    try:
+        upstream_comp = bt2.component._create_generic_component_from_ptr(upstream_comp_ptr)
+        upstream_comp._get()
+        downstream_comp = bt2.component._create_generic_component_from_ptr(downstream_comp_ptr)
+        downstream_comp._get()
+        upstream_port = bt2.port._create_from_ptr(upstream_port_ptr)
+        upstream_port._get()
+        downstream_port = bt2.port._create_from_ptr(downstream_port_ptr)
+        downstream_port._get()
+        user_listener(upstream_comp, downstream_comp, upstream_port,
+                      downstream_port)
+    except:
+        pass
+
+
+class Graph(object._Object):
+    def __init__(self):
+        ptr = native_bt.graph_create()
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create graph object')
+
+        super().__init__(ptr)
+
+    def _handle_status(self, status, gen_error_msg):
+        if status == native_bt.GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
+            raise bt2.PortConnectionRefused
+        elif status == native_bt.GRAPH_STATUS_CANCELED:
+            raise bt2.GraphCanceled
+        elif status == native_bt.GRAPH_STATUS_END:
+            raise bt2.Stop
+        elif status == native_bt.GRAPH_STATUS_AGAIN:
+            raise bt2.TryAgain
+        elif status == native_bt.GRAPH_STATUS_NO_SINK:
+            raise bt2.NoSinkComponent
+        elif status < 0:
+            raise bt2.Error(gen_error_msg)
+
+    def add_component(self, component_class, name, params=None):
+        if isinstance(component_class, bt2.component._GenericComponentClass):
+            cc_ptr = component_class._ptr
+        elif issubclass(component_class, bt2.component._UserComponent):
+            cc_ptr = component_class._cc_ptr
+        else:
+            raise TypeError("'{}' is not a component class".format(component_class.__class__.__name__))
+
+        utils._check_str(name)
+        params = bt2.create_value(params)
+
+        if params is None:
+            params_ptr = None
+        else:
+            params_ptr = params._ptr
+
+        status, comp_ptr = native_bt.graph_add_component(self._ptr, cc_ptr,
+                                                         name, params_ptr)
+        self._handle_status(status, 'cannot add component to graph')
+        assert(comp_ptr)
+        return bt2.component._create_generic_component_from_ptr(comp_ptr)
+
+    def connect_ports(self, upstream_port, downstream_port):
+        utils._check_type(upstream_port, bt2.port._OutputPort)
+        utils._check_type(downstream_port, bt2.port._InputPort)
+        status, conn_ptr = native_bt.graph_connect_ports(self._ptr,
+                                                         upstream_port._ptr,
+                                                         downstream_port._ptr)
+        self._handle_status(status, 'cannot connect component ports within graph')
+        assert(conn_ptr)
+        return bt2.connection._Connection._create_from_ptr(conn_ptr)
+
+    def add_listener(self, listener_type, listener):
+        if not hasattr(listener, '__call__'):
+            raise TypeError("'listener' parameter is not callable")
+
+        if listener_type == GraphListenerType.PORT_ADDED:
+            fn = native_bt.py3_graph_add_port_added_listener
+            listener_from_native = functools.partial(_graph_port_added_listener_from_native,
+                                                     listener)
+        elif listener_type == GraphListenerType.PORT_REMOVED:
+            fn = native_bt.py3_graph_add_port_removed_listener
+            listener_from_native = functools.partial(_graph_port_removed_listener_from_native,
+                                                     listener)
+        elif listener_type == GraphListenerType.PORTS_CONNECTED:
+            fn = native_bt.py3_graph_add_ports_connected_listener
+            listener_from_native = functools.partial(_graph_ports_connected_listener_from_native,
+                                                     listener)
+        elif listener_type == GraphListenerType.PORTS_DISCONNECTED:
+            fn = native_bt.py3_graph_add_ports_disconnected_listener
+            listener_from_native = functools.partial(_graph_ports_disconnected_listener_from_native,
+                                                     listener)
+        else:
+            raise TypeError
+
+        listener_id = fn(self._ptr, listener_from_native)
+        utils._handle_ret(listener_id, 'cannot add listener to graph object')
+        return bt2._ListenerHandle(listener_id, self)
+
+    def run(self):
+        status = native_bt.graph_run(self._ptr)
+
+        if status == native_bt.GRAPH_STATUS_END:
+            return
+
+        self._handle_status(status, 'graph object stopped running because of an unexpected error')
+
+    def cancel(self):
+        status = native_bt.graph_cancel(self._ptr)
+        self._handle_status(status, 'cannot cancel graph object')
+
+    @property
+    def is_canceled(self):
+        is_canceled = native_bt.graph_is_canceled(self._ptr)
+        assert(is_canceled >= 0)
+        return is_canceled > 0
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        return self.addr == other.addr
diff --git a/bindings/python/bt2/bt2/logging.c b/bindings/python/bt2/bt2/logging.c
new file mode 100644 (file)
index 0000000..52d531c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_cli_log_level
+#include <babeltrace/logging-internal.h>
+
+BT_LOG_INIT_LOG_LEVEL(bt_cli_log_level, "BABELTRACE_CLI_LOG_LEVEL");
diff --git a/bindings/python/bt2/bt2/logging.h b/bindings/python/bt2/bt2/logging.h
new file mode 100644 (file)
index 0000000..ccc6c52
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef CLI_LOGGING_H
+#define CLI_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_cli_log_level
+#include <babeltrace/logging-internal.h>
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_cli_log_level);
+
+#endif /* CLI_LOGGING_H */
diff --git a/bindings/python/bt2/bt2/logging.py b/bindings/python/bt2/bt2/logging.py
new file mode 100644 (file)
index 0000000..51d898c
--- /dev/null
@@ -0,0 +1,59 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2
+
+
+class LoggingLevel:
+    VERBOSE = native_bt.LOGGING_LEVEL_VERBOSE
+    DEBUG = native_bt.LOGGING_LEVEL_DEBUG
+    INFO = native_bt.LOGGING_LEVEL_INFO
+    WARN = native_bt.LOGGING_LEVEL_WARN
+    ERROR = native_bt.LOGGING_LEVEL_ERROR
+    FATAL = native_bt.LOGGING_LEVEL_FATAL
+    NONE = native_bt.LOGGING_LEVEL_NONE
+
+
+def get_minimal_logging_level():
+    return native_bt.logging_get_minimal_level()
+
+
+def get_global_logging_level():
+    return native_bt.logging_get_global_level()
+
+
+def set_global_logging_level(level):
+    levels = (
+        LoggingLevel.VERBOSE,
+        LoggingLevel.DEBUG,
+        LoggingLevel.INFO,
+        LoggingLevel.WARN,
+        LoggingLevel.ERROR,
+        LoggingLevel.FATAL,
+        LoggingLevel.NONE,
+    )
+
+    if level not in levels:
+        raise TypeError("'{}' is not a valid logging level".format(level))
+
+    return native_bt.logging_set_global_level(level)
diff --git a/bindings/python/bt2/bt2/native_bt.i b/bindings/python/bt2/bt2/native_bt.i
new file mode 100644 (file)
index 0000000..c7ae8d6
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+#ifndef SWIGPYTHON
+# error Unsupported output language
+#endif
+
+%module native_bt
+
+%{
+#define BT_LOG_TAG "PY-NATIVE"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+
+typedef const unsigned char *BTUUID;
+%}
+
+typedef int bt_bool;
+
+/* For uint*_t/int*_t */
+%include "stdint.i"
+
+/* Remove `bt_` and `BT_` prefixes from function names and enumeration items */
+%rename("%(strip:[bt_])s", %$isfunction) "";
+%rename("%(strip:[BT_])s", %$isenumitem) "";
+
+/* Output argument typemap for string output (always appends) */
+%typemap(in, numinputs=0) const char **BTOUTSTR (char *temp_value = NULL) {
+       $1 = &temp_value;
+}
+
+%typemap(argout) const char **BTOUTSTR {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result, SWIG_Python_str_FromChar(*$1));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for field type output (always appends) */
+%typemap(in, numinputs=0) struct bt_ctf_field_type **BTOUTFT (struct bt_ctf_field_type *temp_ft = NULL) {
+       $1 = &temp_ft;
+}
+
+%typemap(argout) struct bt_ctf_field_type **BTOUTFT {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_bt_ctf_field_type, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for component output (always appends) */
+%typemap(in, numinputs=0) struct bt_component **BTOUTCOMP (struct bt_component *temp_comp = NULL) {
+       $1 = &temp_comp;
+}
+
+%typemap(argout) struct bt_component **BTOUTCOMP {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_bt_component, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for connection output (always appends) */
+%typemap(in, numinputs=0) struct bt_connection **BTOUTCONN (struct bt_connection *temp_conn = NULL) {
+       $1 = &temp_conn;
+}
+
+%typemap(argout) struct bt_connection **BTOUTCONN {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_bt_connection, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for private port output (always appends) */
+%typemap(in, numinputs=0) struct bt_private_port **BTOUTPRIVPORT (struct bt_private_port *temp_priv_port = NULL) {
+       $1 = &temp_priv_port;
+}
+
+%typemap(argout) struct bt_private_port **BTOUTPRIVPORT {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_bt_private_port, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for initialized uint64_t output parameter (always appends) */
+%typemap(in, numinputs=0) uint64_t *OUTPUTINIT (uint64_t temp = -1ULL) {
+       $1 = &temp;
+}
+
+%typemap(argout) uint64_t *OUTPUTINIT {
+       $result = SWIG_Python_AppendOutput(resultobj, SWIG_From_unsigned_SS_long_SS_long((*$1)));
+}
+
+/* Output argument typemap for initialized unsigned int output parameter (always appends) */
+%typemap(in, numinputs=0) unsigned int *OUTPUTINIT (unsigned int temp = -1) {
+       $1 = &temp;
+}
+
+%typemap(argout) unsigned int *OUTPUTINIT {
+       $result = SWIG_Python_AppendOutput(resultobj, SWIG_From_unsigned_SS_long_SS_long((uint64_t) (*$1)));
+}
+
+/* Input argument typemap for UUID bytes */
+%typemap(in) BTUUID {
+       $1 = (unsigned char *) PyBytes_AsString($input);
+}
+
+/* Output argument typemap for UUID bytes */
+%typemap(out) BTUUID {
+       if (!$1) {
+               Py_INCREF(Py_None);
+               $result = Py_None;
+       } else {
+               $result = PyBytes_FromStringAndSize((const char *) $1, 16);
+       }
+}
+
+/*
+ * Input and output argument typemaps for raw Python objects (direct).
+ *
+ * Those typemaps honor the convention of Python C function calls with
+ * respect to reference counting: parameters are passed as borrowed
+ * references, and objects are returned as new references. The wrapped
+ * C function must ensure that the return value is always a new
+ * reference, and never steal parameter references.
+ */
+%typemap(in) PyObject * {
+       $1 = $input;
+}
+
+%typemap(out) PyObject * {
+       $result = $1;
+}
+
+/* Per-module interface files */
+%include "native_btccpriomap.i"
+%include "native_btclockclass.i"
+%include "native_btcomponent.i"
+%include "native_btcomponentclass.i"
+%include "native_btconnection.i"
+%include "native_btctfwriter.i"
+%include "native_btevent.i"
+%include "native_bteventclass.i"
+%include "native_btfields.i"
+%include "native_btft.i"
+%include "native_btgraph.i"
+%include "native_btlogging.i"
+%include "native_btnotification.i"
+%include "native_btnotifiter.i"
+%include "native_btpacket.i"
+%include "native_btplugin.i"
+%include "native_btport.i"
+%include "native_btref.i"
+%include "native_btstream.i"
+%include "native_btstreamclass.i"
+%include "native_bttrace.i"
+%include "native_btvalues.i"
+%include "native_btversion.i"
diff --git a/bindings/python/bt2/bt2/native_btccpriomap.i b/bindings/python/bt2/bt2/native_btccpriomap.i
new file mode 100644 (file)
index 0000000..e128cd9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+%{
+#include <babeltrace/graph/clock-class-priority-map.h>
+%}
+
+/* Type */
+struct bt_clock_class_priority_map;
+
+/* Functions */
+struct bt_clock_class_priority_map *bt_clock_class_priority_map_create();
+int64_t bt_clock_class_priority_map_get_clock_class_count(
+               struct bt_clock_class_priority_map *clock_class_priority_map);
+struct bt_ctf_clock_class *
+bt_clock_class_priority_map_get_clock_class_by_index(
+               struct bt_clock_class_priority_map *clock_class_priority_map,
+               uint64_t index);
+struct bt_ctf_clock_class *
+bt_clock_class_priority_map_get_clock_class_by_name(
+               struct bt_clock_class_priority_map *clock_class_priority_map,
+               const char *name);
+struct bt_ctf_clock_class *
+bt_clock_class_priority_map_get_highest_priority_clock_class(
+               struct bt_clock_class_priority_map *clock_class_priority_map);
+int bt_clock_class_priority_map_get_clock_class_priority(
+               struct bt_clock_class_priority_map *clock_class_priority_map,
+               struct bt_ctf_clock_class *clock_class, uint64_t *OUTPUTINIT);
+int bt_clock_class_priority_map_add_clock_class(
+               struct bt_clock_class_priority_map *clock_class_priority_map,
+               struct bt_ctf_clock_class *clock_class, uint64_t priority);
+struct bt_clock_class_priority_map *bt_clock_class_priority_map_copy(
+               struct bt_clock_class_priority_map *clock_class_priority_map);
diff --git a/bindings/python/bt2/bt2/native_btclockclass.i b/bindings/python/bt2/bt2/native_btclockclass.i
new file mode 100644 (file)
index 0000000..5a09e89
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Types */
+struct bt_ctf_clock_class;
+struct bt_ctf_clock_value;
+
+/* Clock class functions */
+struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name,
+               uint64_t freq);
+const char *bt_ctf_clock_class_get_name(struct bt_ctf_clock_class *clock_class);
+int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class, const char *name);
+const char *bt_ctf_clock_class_get_description(struct bt_ctf_clock_class *clock_class);
+int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class,
+               const char *desc);
+uint64_t bt_ctf_clock_class_get_frequency(struct bt_ctf_clock_class *clock_class);
+int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class,
+               uint64_t freq);
+uint64_t bt_ctf_clock_class_get_precision(struct bt_ctf_clock_class *clock_class);
+int bt_ctf_clock_class_set_precision(struct bt_ctf_clock_class *clock_class,
+               uint64_t precision);
+int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class,
+               int64_t *OUTPUT);
+int bt_ctf_clock_class_set_offset_s(struct bt_ctf_clock_class *clock_class,
+               int64_t offset_s);
+int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_clock_class *clock_class,
+               int64_t *OUTPUT);
+int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class,
+               int64_t offset);
+int bt_ctf_clock_class_is_absolute(struct bt_ctf_clock_class *clock_class);
+int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_clock_class *clock_class,
+               int is_absolute);
+BTUUID bt_ctf_clock_class_get_uuid(struct bt_ctf_clock_class *clock_class);
+int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class,
+               BTUUID uuid);
+
+/* Clock value functions */
+struct bt_ctf_clock_value *bt_ctf_clock_value_create(
+               struct bt_ctf_clock_class *clock_class, uint64_t value);
+int bt_ctf_clock_value_get_value(
+               struct bt_ctf_clock_value *clock_value, uint64_t *OUTPUT);
+int bt_ctf_clock_value_get_value_ns_from_epoch(
+               struct bt_ctf_clock_value *clock_value, int64_t *OUTPUT);
+struct bt_ctf_clock_class *bt_ctf_clock_value_get_class(
+               struct bt_ctf_clock_value *clock_value);
diff --git a/bindings/python/bt2/bt2/native_btcomponent.i b/bindings/python/bt2/bt2/native_btcomponent.i
new file mode 100644 (file)
index 0000000..ea3e0f8
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Types */
+struct bt_component;
+
+/* Status */
+enum bt_component_status {
+       BT_COMPONENT_STATUS_OK = 0,
+       BT_COMPONENT_STATUS_END = 1,
+       BT_COMPONENT_STATUS_AGAIN = 11,
+       BT_COMPONENT_STATUS_REFUSE_PORT_CONNECTION = 111,
+       BT_COMPONENT_STATUS_ERROR = -1,
+       BT_COMPONENT_STATUS_UNSUPPORTED = -2,
+       BT_COMPONENT_STATUS_INVALID = -22,
+       BT_COMPONENT_STATUS_NOMEM = -12,
+       BT_COMPONENT_STATUS_NOT_FOUND = -19,
+       BT_COMPONENT_STATUS_GRAPH_IS_CANCELED = 125,
+};
+
+/* General functions */
+const char *bt_component_get_name(struct bt_component *component);
+struct bt_component_class *bt_component_get_class(
+               struct bt_component *component);
+enum bt_component_class_type bt_component_get_class_type(
+               struct bt_component *component);
+struct bt_graph *bt_component_get_graph(struct bt_component *component);
+struct bt_component *bt_component_from_private_component(
+               struct bt_private_component *private_component);
+
+/* Source component functions */
+int64_t bt_component_source_get_output_port_count(
+               struct bt_component *component);
+struct bt_port *bt_component_source_get_output_port_by_name(
+               struct bt_component *component, const char *name);
+struct bt_port *bt_component_source_get_output_port_by_index(
+               struct bt_component *component, uint64_t index);
+
+/* Private source component functions */
+struct bt_private_port *
+bt_private_component_source_get_output_private_port_by_name(
+               struct bt_private_component *private_component,
+               const char *name);
+struct bt_private_port *
+bt_private_component_source_get_output_private_port_by_index(
+               struct bt_private_component *private_component,
+               uint64_t index);
+enum bt_component_status
+bt_private_component_source_add_output_private_port(
+               struct bt_private_component *private_component,
+               const char *name, void *user_data,
+               struct bt_private_port **BTOUTPRIVPORT);
+
+/* Filter component functions */
+int64_t bt_component_filter_get_input_port_count(
+               struct bt_component *component);
+struct bt_port *bt_component_filter_get_input_port_by_name(
+               struct bt_component *component, const char *name);
+struct bt_port *bt_component_filter_get_input_port_by_index(
+               struct bt_component *component, uint64_t index);
+int64_t bt_component_filter_get_output_port_count(
+               struct bt_component *component);
+struct bt_port *bt_component_filter_get_output_port_by_name(
+               struct bt_component *component, const char *name);
+struct bt_port *bt_component_filter_get_output_port_by_index(
+               struct bt_component *component, uint64_t index);
+
+/* Private filter component functions */
+struct bt_private_port *
+bt_private_component_filter_get_output_private_port_by_name(
+               struct bt_private_component *private_component,
+               const char *name);
+struct bt_private_port *
+bt_private_component_filter_get_output_private_port_by_index(
+               struct bt_private_component *private_component, uint64_t index);
+enum bt_component_status
+bt_private_component_filter_add_output_private_port(
+               struct bt_private_component *private_component,
+               const char *name, void *user_data,
+               struct bt_private_port **BTOUTPRIVPORT);
+struct bt_private_port *
+bt_private_component_filter_get_input_private_port_by_name(
+               struct bt_private_component *private_component,
+               const char *name);
+struct bt_private_port *
+bt_private_component_filter_get_input_private_port_by_index(
+               struct bt_private_component *private_component, uint64_t index);
+enum bt_component_status
+bt_private_component_filter_add_input_private_port(
+               struct bt_private_component *private_component,
+               const char *name, void *user_data,
+               struct bt_private_port **BTOUTPRIVPORT);
+
+/* Sink component functions */
+int64_t bt_component_sink_get_input_port_count(
+               struct bt_component *component);
+struct bt_port *bt_component_sink_get_input_port_by_name(
+               struct bt_component *component, const char *name);
+struct bt_port *bt_component_sink_get_input_port_by_index(
+               struct bt_component *component, uint64_t index);
+
+/* Private sink component functions */
+struct bt_private_port *
+bt_private_component_sink_get_input_private_port_by_name(
+               struct bt_private_component *private_component,
+               const char *name);
+struct bt_private_port *
+bt_private_component_sink_get_input_private_port_by_index(
+               struct bt_private_component *private_component, uint64_t index);
+enum bt_component_status
+bt_private_component_sink_add_input_private_port(
+               struct bt_private_component *private_component,
+               const char *name, void *user_data,
+               struct bt_private_port **BTOUTPRIVPORT);
diff --git a/bindings/python/bt2/bt2/native_btcomponentclass.i b/bindings/python/bt2/bt2/native_btcomponentclass.i
new file mode 100644 (file)
index 0000000..195ca38
--- /dev/null
@@ -0,0 +1,932 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Types */
+struct bt_component_class;
+
+/* Status */
+enum bt_component_class_type {
+       BT_COMPONENT_CLASS_TYPE_UNKNOWN = -1,
+       BT_COMPONENT_CLASS_TYPE_SOURCE = 0,
+       BT_COMPONENT_CLASS_TYPE_SINK = 1,
+       BT_COMPONENT_CLASS_TYPE_FILTER = 2,
+};
+
+/* General functions */
+const char *bt_component_class_get_name(
+               struct bt_component_class *component_class);
+const char *bt_component_class_get_description(
+               struct bt_component_class *component_class);
+const char *bt_component_class_get_help(
+               struct bt_component_class *component_class);
+struct bt_value *bt_component_class_query(
+               struct bt_component_class *component_class,
+               const char *object, struct bt_value *params);
+enum bt_component_class_type bt_component_class_get_type(
+               struct bt_component_class *component_class);
+
+%{
+/*
+ * This hash table associates a BT component class object address to a
+ * user-defined Python class (PyObject *). The keys and values are NOT
+ * owned by this hash table. The Python class objects are owned by the
+ * Python module, which should not be unloaded until it is not possible
+ * to create a user Python component anyway.
+ *
+ * This hash table is written to when a user-defined Python component
+ * class is created by one of the bt_py3_component_class_*_create()
+ * functions.
+ *
+ * This function is read from when a user calls bt_component_create()
+ * with a component class pointer created by one of the functions above.
+ * In this case, the original Python class needs to be found to
+ * instantiate it and associate the created Python component object with
+ * a BT component object instance.
+ */
+
+static GHashTable *bt_cc_ptr_to_py_cls;
+
+static void register_cc_ptr_to_py_cls(struct bt_component_class *bt_cc,
+               PyObject *py_cls)
+{
+       if (!bt_cc_ptr_to_py_cls) {
+               /*
+                * Lazy-initializing this GHashTable because GLib
+                * might not be initialized yet and it needs to be
+                * before we call g_hash_table_new()
+                */
+               BT_LOGD_STR("Creating native component class to Python component class hash table.");
+               bt_cc_ptr_to_py_cls = g_hash_table_new(g_direct_hash, g_direct_equal);
+               assert(bt_cc_ptr_to_py_cls);
+       }
+
+       g_hash_table_insert(bt_cc_ptr_to_py_cls, (gpointer) bt_cc,
+               (gpointer) py_cls);
+}
+
+static PyObject *lookup_cc_ptr_to_py_cls(struct bt_component_class *bt_cc)
+{
+       if (!bt_cc_ptr_to_py_cls) {
+               BT_LOGW("Cannot look up Python component class because hash table is NULL: "
+                       "comp-cls-addr=%p", bt_cc);
+               return NULL;
+       }
+
+       return (PyObject *) g_hash_table_lookup(bt_cc_ptr_to_py_cls,
+               (gconstpointer) bt_cc);
+}
+
+
+/*
+ * Useful Python objects.
+ */
+
+static PyObject *py_mod_bt2 = NULL;
+static PyObject *py_mod_bt2_exc_error_type = NULL;
+static PyObject *py_mod_bt2_exc_unsupported_feature_type = NULL;
+static PyObject *py_mod_bt2_exc_try_again_type = NULL;
+static PyObject *py_mod_bt2_exc_stop_type = NULL;
+static PyObject *py_mod_bt2_exc_port_connection_refused_type = NULL;
+static PyObject *py_mod_bt2_exc_graph_canceled_type = NULL;
+static PyObject *py_mod_bt2_exc_notif_iter_canceled_type = NULL;
+static PyObject *py_mod_bt2_exc_connection_ended_type = NULL;
+
+static void bt_py3_cc_init_from_bt2(void)
+{
+       /*
+        * This is called once the bt2 package is loaded.
+        *
+        * Those modules and functions are needed while the package is
+        * used. Loading them here is safe because we know the bt2
+        * package is imported, and we know that the user cannot use the
+        * code here without importing bt2 first.
+        */
+       py_mod_bt2 = PyImport_ImportModule("bt2");
+       assert(py_mod_bt2);
+       py_mod_bt2_exc_error_type =
+               PyObject_GetAttrString(py_mod_bt2, "Error");
+       assert(py_mod_bt2_exc_error_type);
+       py_mod_bt2_exc_unsupported_feature_type =
+               PyObject_GetAttrString(py_mod_bt2, "UnsupportedFeature");
+       py_mod_bt2_exc_try_again_type =
+               PyObject_GetAttrString(py_mod_bt2, "TryAgain");
+       py_mod_bt2_exc_stop_type =
+               PyObject_GetAttrString(py_mod_bt2, "Stop");
+       py_mod_bt2_exc_port_connection_refused_type =
+               PyObject_GetAttrString(py_mod_bt2, "PortConnectionRefused");
+       py_mod_bt2_exc_graph_canceled_type =
+               PyObject_GetAttrString(py_mod_bt2, "GraphCanceled");
+       py_mod_bt2_exc_connection_ended_type =
+               PyObject_GetAttrString(py_mod_bt2, "ConnectionEnded");
+       assert(py_mod_bt2_exc_stop_type);
+}
+
+static void bt_py3_cc_exit_handler(void)
+{
+       /*
+        * This is an exit handler (set by the bt2 package).
+        *
+        * We only give back the references that we took in
+        * bt_py3_cc_init_from_bt2() here. The global variables continue
+        * to exist for the code of this file, but they are now borrowed
+        * references. If this code is executed, it means that somehow
+        * the modules are still loaded, so it should be safe to use
+        * them even without a strong reference.
+        *
+        * We cannot do this in the library's destructor because it
+        * gets executed once Python is already finalized.
+        */
+       Py_XDECREF(py_mod_bt2);
+       Py_XDECREF(py_mod_bt2_exc_error_type);
+       Py_XDECREF(py_mod_bt2_exc_unsupported_feature_type);
+       Py_XDECREF(py_mod_bt2_exc_try_again_type);
+       Py_XDECREF(py_mod_bt2_exc_stop_type);
+       Py_XDECREF(py_mod_bt2_exc_port_connection_refused_type);
+       Py_XDECREF(py_mod_bt2_exc_graph_canceled_type);
+       Py_XDECREF(py_mod_bt2_exc_notif_iter_canceled_type);
+       Py_XDECREF(py_mod_bt2_exc_connection_ended_type);
+}
+
+
+/* Library destructor */
+
+__attribute__((destructor))
+static void bt_py3_native_comp_class_dtor(void) {
+       /* Destroy component class association hash table */
+       if (bt_cc_ptr_to_py_cls) {
+               BT_LOGD_STR("Destroying native component class to Python component class hash table.");
+               g_hash_table_destroy(bt_cc_ptr_to_py_cls);
+       }
+}
+
+
+/* Component class proxy methods (delegate to the attached Python object) */
+
+static enum bt_notification_iterator_status bt_py3_exc_to_notif_iter_status(void)
+{
+       enum bt_notification_iterator_status status =
+               BT_NOTIFICATION_ITERATOR_STATUS_OK;
+       PyObject *exc = PyErr_Occurred();
+
+       if (!exc) {
+               goto end;
+       }
+
+       if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_unsupported_feature_type)) {
+               status = BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_stop_type)) {
+               status = BT_NOTIFICATION_ITERATOR_STATUS_END;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_try_again_type)) {
+               status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN;
+       } else {
+               status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
+       }
+
+end:
+       PyErr_Clear();
+       return status;
+}
+
+static enum bt_component_status bt_py3_exc_to_component_status(void)
+{
+       enum bt_component_status status = BT_COMPONENT_STATUS_OK;
+       PyObject *exc = PyErr_Occurred();
+
+       if (!exc) {
+               goto end;
+       }
+
+       if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_unsupported_feature_type)) {
+               status = BT_COMPONENT_STATUS_UNSUPPORTED;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_try_again_type)) {
+               status = BT_COMPONENT_STATUS_AGAIN;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_stop_type)) {
+               status = BT_COMPONENT_STATUS_END;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_port_connection_refused_type)) {
+               status = BT_COMPONENT_STATUS_REFUSE_PORT_CONNECTION;
+       } else {
+               status = BT_COMPONENT_STATUS_ERROR;
+       }
+
+end:
+       PyErr_Clear();
+       return status;
+}
+
+static enum bt_component_status bt_py3_cc_init(
+               struct bt_private_component *priv_comp,
+               struct bt_value *params, void *init_method_data)
+{
+       struct bt_component *comp =
+               bt_component_from_private_component(priv_comp);
+       struct bt_component_class *comp_cls = bt_component_get_class(comp);
+       enum bt_component_status status = BT_COMPONENT_STATUS_OK;
+       PyObject *py_cls = NULL;
+       PyObject *py_comp = NULL;
+       PyObject *py_params_ptr = NULL;
+       PyObject *py_comp_ptr = NULL;
+
+       (void) init_method_data;
+       assert(comp);
+       assert(comp_cls);
+
+       /*
+        * Get the user-defined Python class which created this
+        * component's class in the first place (borrowed
+        * reference).
+        */
+       py_cls = lookup_cc_ptr_to_py_cls(comp_cls);
+       if (!py_cls) {
+               BT_LOGE("Cannot find Python class associated to native component class: "
+                       "comp-cls-addr=%p", comp_cls);
+               goto error;
+       }
+
+       /* Parameters pointer -> SWIG pointer Python object */
+       py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params),
+               SWIGTYPE_p_bt_value, 0);
+       if (!py_params_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       /* Private component pointer -> SWIG pointer Python object */
+       py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(priv_comp),
+               SWIGTYPE_p_bt_private_component, 0);
+       if (!py_comp_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       /*
+        * Do the equivalent of this:
+        *
+        *     py_comp = py_cls._init_from_native(py_comp_ptr, py_params_ptr)
+        *
+        * _UserComponentType._init_from_native() calls the Python
+        * component object's __init__() function.
+        */
+       py_comp = PyObject_CallMethod(py_cls,
+               "_init_from_native", "(OO)", py_comp_ptr, py_params_ptr);
+       if (!py_comp) {
+               BT_LOGE("Failed to call Python class's _init_from_native() method: "
+                       "py-cls-addr=%p", py_cls);
+               goto error;
+       }
+
+       /*
+        * Our user Python component object is now fully created and
+        * initialized by the user. Since we just created it, this
+        * native component is its only (persistent) owner.
+        */
+       bt_private_component_set_user_data(priv_comp, py_comp);
+       py_comp = NULL;
+       goto end;
+
+error:
+       status = BT_COMPONENT_STATUS_ERROR;
+
+       /*
+        * Clear any exception: we're returning a bad status anyway. If
+        * this call originated from Python (creation from a plugin's
+        * component class, for example), then the user gets an
+        * appropriate creation error.
+        */
+       PyErr_Clear();
+
+end:
+       bt_put(comp_cls);
+       bt_put(comp);
+       Py_XDECREF(py_comp);
+       Py_XDECREF(py_params_ptr);
+       Py_XDECREF(py_comp_ptr);
+       return status;
+}
+
+static void bt_py3_cc_finalize(struct bt_private_component *priv_comp)
+{
+       PyObject *py_comp = bt_private_component_get_user_data(priv_comp);
+       PyObject *py_method_result = NULL;
+
+       assert(py_comp);
+
+       /* Call user's _finalize() method */
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_finalize", NULL);
+
+       if (PyErr_Occurred()) {
+               BT_LOGW("User's _finalize() method raised an exception: ignoring.");
+       }
+
+       /*
+        * Ignore any exception raised by the _finalize() method because
+        * it won't change anything at this point: the component is
+        * being destroyed anyway.
+        */
+       PyErr_Clear();
+       Py_XDECREF(py_method_result);
+       Py_DECREF(py_comp);
+}
+
+static enum bt_component_status bt_py3_cc_accept_port_connection(
+               struct bt_private_component *priv_comp,
+               struct bt_private_port *self_priv_port,
+               struct bt_port *other_port)
+{
+       enum bt_component_status status;
+       PyObject *py_comp = NULL;
+       PyObject *py_self_port_ptr = NULL;
+       PyObject *py_other_port_ptr = NULL;
+       PyObject *py_method_result = NULL;
+
+       py_comp = bt_private_component_get_user_data(priv_comp);
+       assert(py_comp);
+       py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_priv_port),
+               SWIGTYPE_p_bt_private_port, 0);
+       if (!py_self_port_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port),
+               SWIGTYPE_p_bt_port, 0);
+       if (!py_other_port_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_accept_port_connection_from_native", "(OO)", py_self_port_ptr,
+               py_other_port_ptr);
+       status = bt_py3_exc_to_component_status();
+       if (!py_method_result && status == BT_COMPONENT_STATUS_OK) {
+               /* Pretty sure this should never happen, but just in case */
+               BT_LOGE("User's _accept_port_connection() method failed without raising an exception: "
+                       "status=%d", status);
+               goto error;
+       }
+
+       if (status == BT_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
+               /*
+                * Looks like the user method raised
+                * PortConnectionRefused: accept this like if it
+                * returned False.
+                */
+               goto end;
+       } else if (status != BT_COMPONENT_STATUS_OK) {
+               BT_LOGE("User's _accept_port_connection() raised an unexpected exception: "
+                       "status=%d", status);
+               goto error;
+       }
+
+       assert(PyBool_Check(py_method_result));
+
+       if (py_method_result == Py_True) {
+               status = BT_COMPONENT_STATUS_OK;
+       } else {
+               status = BT_COMPONENT_STATUS_REFUSE_PORT_CONNECTION;
+       }
+
+       goto end;
+
+error:
+       status = BT_COMPONENT_STATUS_ERROR;
+
+       /*
+        * Clear any exception: we're returning a bad status anyway. If
+        * this call originated from Python, then the user gets an
+        * appropriate error.
+        */
+       PyErr_Clear();
+
+end:
+       Py_XDECREF(py_self_port_ptr);
+       Py_XDECREF(py_other_port_ptr);
+       Py_XDECREF(py_method_result);
+       return status;
+}
+
+static void bt_py3_cc_port_connected(
+               struct bt_private_component *priv_comp,
+               struct bt_private_port *self_priv_port,
+               struct bt_port *other_port)
+{
+       PyObject *py_comp = NULL;
+       PyObject *py_self_port_ptr = NULL;
+       PyObject *py_other_port_ptr = NULL;
+       PyObject *py_method_result = NULL;
+
+       py_comp = bt_private_component_get_user_data(priv_comp);
+       assert(py_comp);
+       py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_priv_port),
+               SWIGTYPE_p_bt_private_port, 0);
+       if (!py_self_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port),
+               SWIGTYPE_p_bt_port, 0);
+       if (!py_other_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_port_connected_from_native", "(OO)", py_self_port_ptr,
+               py_other_port_ptr);
+       assert(py_method_result == Py_None);
+       Py_XDECREF(py_self_port_ptr);
+       Py_XDECREF(py_other_port_ptr);
+       Py_XDECREF(py_method_result);
+}
+
+static void bt_py3_cc_port_disconnected(
+               struct bt_private_component *priv_comp,
+               struct bt_private_port *priv_port)
+{
+       PyObject *py_comp = NULL;
+       PyObject *py_port_ptr = NULL;
+       PyObject *py_method_result = NULL;
+
+       py_comp = bt_private_component_get_user_data(priv_comp);
+       assert(py_comp);
+       py_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(priv_port),
+               SWIGTYPE_p_bt_private_port, 0);
+       if (!py_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_port_disconnected_from_native", "(O)", py_port_ptr);
+       assert(py_method_result == Py_None);
+       Py_XDECREF(py_port_ptr);
+       Py_XDECREF(py_method_result);
+}
+
+static struct bt_value *bt_py3_cc_query(
+               struct bt_component_class *comp_cls,
+               const char *object, struct bt_value *params)
+{
+       PyObject *py_cls = NULL;
+       PyObject *py_params_ptr = NULL;
+       PyObject *py_query_func = NULL;
+       PyObject *py_object = NULL;
+       PyObject *py_results_addr = NULL;
+       struct bt_value *results = NULL;
+
+       py_cls = lookup_cc_ptr_to_py_cls(comp_cls);
+       if (!py_cls) {
+               BT_LOGE("Cannot find Python class associated to native component class: "
+                       "comp-cls-addr=%p", comp_cls);
+               goto error;
+       }
+
+       py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params),
+               SWIGTYPE_p_bt_value, 0);
+       if (!py_params_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_object = SWIG_FromCharPtr(object);
+       if (!py_object) {
+               BT_LOGE_STR("Failed to create a Python string.");
+               goto error;
+       }
+
+       py_results_addr = PyObject_CallMethod(py_cls,
+               "_query_from_native", "(OO)", py_object, py_params_ptr);
+       if (!py_results_addr || py_results_addr == Py_None) {
+               BT_LOGE_STR("User's _query() method failed.");
+               goto error;
+       }
+
+       if (py_results_addr == Py_NotImplemented) {
+               BT_LOGE_STR("User's _query() method is not implemented.");
+               goto error;
+       }
+
+       /*
+        * The returned object, on success, is an integer object
+        * (PyLong) containing the address of a BT value object (new
+        * reference).
+        */
+       results = (void *) PyLong_AsUnsignedLongLong(py_results_addr);
+       assert(!PyErr_Occurred());
+       assert(results);
+       goto end;
+
+error:
+       BT_PUT(results);
+       PyErr_Clear();
+
+end:
+       Py_XDECREF(py_params_ptr);
+       Py_XDECREF(py_query_func);
+       Py_XDECREF(py_object);
+       Py_XDECREF(py_results_addr);
+       return results;
+}
+
+static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_init(
+               struct bt_private_notification_iterator *priv_notif_iter,
+               struct bt_private_port *priv_port)
+{
+       enum bt_notification_iterator_status status =
+               BT_NOTIFICATION_ITERATOR_STATUS_OK;
+       PyObject *py_comp_cls = NULL;
+       PyObject *py_iter_cls = NULL;
+       PyObject *py_iter_ptr = NULL;
+       PyObject *py_init_method_result = NULL;
+       PyObject *py_iter = NULL;
+       struct bt_private_component *priv_comp =
+               bt_private_notification_iterator_get_private_component(
+                       priv_notif_iter);
+       PyObject *py_comp;
+
+       assert(priv_comp);
+       py_comp = bt_private_component_get_user_data(priv_comp);
+
+       /* Find user's Python notification iterator class */
+       py_comp_cls = PyObject_GetAttrString(py_comp, "__class__");
+       if (!py_comp_cls) {
+               BT_LOGE_STR("Cannot get Python object's `__class__` attribute.");
+               goto error;
+       }
+
+       py_iter_cls = PyObject_GetAttrString(py_comp_cls, "_iter_cls");
+       if (!py_iter_cls) {
+               BT_LOGE_STR("Cannot get Python class's `_iter_cls` attribute.");
+               goto error;
+       }
+
+       py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(priv_notif_iter),
+               SWIGTYPE_p_bt_private_notification_iterator, 0);
+       if (!py_iter_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       /*
+        * Create object with borrowed native notification iterator
+        * reference:
+        *
+        *     py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr)
+        */
+       py_iter = PyObject_CallMethod(py_iter_cls, "__new__",
+               "(OO)", py_iter_cls, py_iter_ptr);
+       if (!py_iter) {
+               BT_LOGE("Failed to call Python class's __new__() method: "
+                       "py-cls-addr=%p", py_iter_cls);
+               goto error;
+       }
+
+       /*
+        * Initialize object:
+        *
+        *     py_iter.__init__()
+        *
+        * At this point, py_iter._ptr is set, so this initialization
+        * function has access to self._component (which gives it the
+        * user Python component object from which the iterator was
+        * created).
+        */
+       py_init_method_result = PyObject_CallMethod(py_iter, "__init__", NULL);
+       if (!py_init_method_result) {
+               BT_LOGE_STR("User's __init__() method failed.");
+               goto error;
+       }
+
+       /*
+        * Since the Python code can never instantiate a user-defined
+        * notification iterator class, the native notification iterator
+        * object does NOT belong to a user Python notification iterator
+        * object (borrowed reference). However this Python object is
+        * owned by this native notification iterator object.
+        *
+        * In the Python world, the lifetime of the native notification
+        * iterator is managed by a _GenericNotificationIterator
+        * instance:
+        *
+        *     _GenericNotificationIterator instance:
+        *         owns a native bt_notification_iterator object (iter)
+        *             owns a _UserNotificationIterator instance (py_iter)
+        *                 self._ptr is a borrowed reference to the
+        *                 native bt_private_notification_iterator
+        *                 object (iter)
+        */
+       bt_private_notification_iterator_set_user_data(priv_notif_iter,
+               py_iter);
+       py_iter = NULL;
+       goto end;
+
+error:
+       status = bt_py3_exc_to_notif_iter_status();
+       if (status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
+               /*
+                * Looks like there wasn't any exception from the Python
+                * side, but we're still in an error state here.
+                */
+               status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
+       }
+
+       /*
+        * Clear any exception: we're returning a bad status anyway. If
+        * this call originated from Python, then the user gets an
+        * appropriate creation error.
+        */
+       PyErr_Clear();
+
+end:
+       bt_put(priv_comp);
+       Py_XDECREF(py_comp_cls);
+       Py_XDECREF(py_iter_cls);
+       Py_XDECREF(py_iter_ptr);
+       Py_XDECREF(py_init_method_result);
+       Py_XDECREF(py_iter);
+       return status;
+}
+
+static void bt_py3_cc_notification_iterator_finalize(
+               struct bt_private_notification_iterator *priv_notif_iter)
+{
+       PyObject *py_notif_iter =
+               bt_private_notification_iterator_get_user_data(priv_notif_iter);
+       PyObject *py_method_result = NULL;
+
+       assert(py_notif_iter);
+
+       /* Call user's _finalize() method */
+       py_method_result = PyObject_CallMethod(py_notif_iter,
+               "_finalize", NULL);
+
+       if (PyErr_Occurred()) {
+               BT_LOGW("User's _finalize() method raised an exception: ignoring.");
+       }
+
+       /*
+        * Ignore any exception raised by the _finalize() method because
+        * it won't change anything at this point: the component is
+        * being destroyed anyway.
+        */
+       PyErr_Clear();
+       Py_XDECREF(py_method_result);
+       Py_DECREF(py_notif_iter);
+}
+
+static struct bt_notification_iterator_next_return
+bt_py3_cc_notification_iterator_next(
+                       struct bt_private_notification_iterator *priv_notif_iter)
+{
+       struct bt_notification_iterator_next_return next_ret = {
+               .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
+               .notification = NULL,
+       };
+       PyObject *py_notif_iter =
+               bt_private_notification_iterator_get_user_data(priv_notif_iter);
+       PyObject *py_method_result = NULL;
+
+       assert(py_notif_iter);
+       py_method_result = PyObject_CallMethod(py_notif_iter,
+               "_next_from_native", NULL);
+       if (!py_method_result) {
+               next_ret.status = bt_py3_exc_to_notif_iter_status();
+               assert(next_ret.status != BT_NOTIFICATION_ITERATOR_STATUS_OK);
+               goto end;
+       }
+
+       /*
+        * The returned object, on success, is an integer object
+        * (PyLong) containing the address of a native notification
+        * object (which is now ours).
+        */
+       next_ret.notification =
+               (struct bt_notification *) PyLong_AsUnsignedLongLong(
+                       py_method_result);
+
+       /* Clear potential overflow error; should never happen */
+       assert(!PyErr_Occurred());
+       assert(next_ret.notification);
+       goto end;
+
+end:
+       Py_XDECREF(py_method_result);
+       return next_ret;
+}
+
+static enum bt_component_status bt_py3_cc_sink_consume(
+               struct bt_private_component *priv_comp)
+{
+       PyObject *py_comp = bt_private_component_get_user_data(priv_comp);
+       PyObject *py_method_result = NULL;
+       enum bt_component_status status;
+
+       assert(py_comp);
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_consume", NULL);
+       status = bt_py3_exc_to_component_status();
+       if (!py_method_result && status == BT_COMPONENT_STATUS_OK) {
+               /* Pretty sure this should never happen, but just in case */
+               BT_LOGE("User's _consume() method failed without raising an exception: "
+                       "status=%d", status);
+               status = BT_COMPONENT_STATUS_ERROR;
+       }
+
+       Py_XDECREF(py_method_result);
+       return status;
+}
+
+
+/* Component class creation functions (called from Python module) */
+
+static int bt_py3_cc_set_optional_attrs_methods(struct bt_component_class *cc,
+               const char *description, const char *help)
+{
+       int ret = 0;
+
+       if (description) {
+               ret = bt_component_class_set_description(cc, description);
+               if (ret) {
+                       BT_LOGE("Cannot set component class's description: "
+                               "comp-cls-addr=%p", cc);
+                       goto end;
+               }
+       }
+
+       if (help) {
+               ret = bt_component_class_set_help(cc, help);
+               if (ret) {
+                       BT_LOGE("Cannot set component class's help text: "
+                               "comp-cls-addr=%p", cc);
+                       goto end;
+               }
+       }
+
+       ret = bt_component_class_set_init_method(cc, bt_py3_cc_init);
+       assert(ret == 0);
+       ret = bt_component_class_set_finalize_method(cc, bt_py3_cc_finalize);
+       assert(ret == 0);
+       ret = bt_component_class_set_accept_port_connection_method(cc,
+               bt_py3_cc_accept_port_connection);
+       assert(ret == 0);
+       ret = bt_component_class_set_port_connected_method(cc,
+               bt_py3_cc_port_connected);
+       assert(ret == 0);
+       ret = bt_component_class_set_port_disconnected_method(cc,
+               bt_py3_cc_port_disconnected);
+       assert(ret == 0);
+       ret = bt_component_class_set_query_method(cc, bt_py3_cc_query);
+       assert(ret == 0);
+
+end:
+       return ret;
+}
+
+static void bt_py3_cc_set_optional_iter_methods(struct bt_component_class *cc,
+               int (*set_notif_iter_init_method)(struct bt_component_class *, bt_component_class_notification_iterator_init_method),
+               int (*set_notif_iter_finalize_method)(struct bt_component_class *, bt_component_class_notification_iterator_finalize_method))
+{
+       int ret;
+
+       ret = set_notif_iter_init_method(
+               cc, bt_py3_cc_notification_iterator_init);
+       assert(ret == 0);
+       ret = set_notif_iter_finalize_method(
+               cc, bt_py3_cc_notification_iterator_finalize);
+       assert(ret == 0);
+}
+
+static struct bt_component_class *bt_py3_component_class_source_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help)
+{
+       struct bt_component_class *cc;
+       int ret;
+
+       assert(py_cls);
+       cc = bt_component_class_source_create(name,
+               bt_py3_cc_notification_iterator_next);
+       if (!cc) {
+               BT_LOGE_STR("Cannot create source component class.");
+               goto end;
+       }
+
+       ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
+       if (ret) {
+               BT_LOGE_STR("Cannot set source component class's optional attributes and methods.");
+               BT_PUT(cc);
+               goto end;
+       }
+
+       bt_py3_cc_set_optional_iter_methods(cc,
+               bt_component_class_source_set_notification_iterator_init_method,
+               bt_component_class_source_set_notification_iterator_finalize_method);
+       register_cc_ptr_to_py_cls(cc, py_cls);
+       bt_component_class_freeze(cc);
+
+end:
+       return cc;
+}
+
+static struct bt_component_class *bt_py3_component_class_filter_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help)
+{
+       struct bt_component_class *cc;
+       int ret;
+
+       assert(py_cls);
+       cc = bt_component_class_filter_create(name,
+               bt_py3_cc_notification_iterator_next);
+       if (!cc) {
+               BT_LOGE_STR("Cannot create filter component class.");
+               goto end;
+       }
+
+       ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
+       if (ret) {
+               BT_LOGE_STR("Cannot set filter component class's optional attributes and methods.");
+               BT_PUT(cc);
+               goto end;
+       }
+
+       bt_py3_cc_set_optional_iter_methods(cc,
+               bt_component_class_filter_set_notification_iterator_init_method,
+               bt_component_class_filter_set_notification_iterator_finalize_method);
+       register_cc_ptr_to_py_cls(cc, py_cls);
+       bt_component_class_freeze(cc);
+
+end:
+       return cc;
+}
+
+static struct bt_component_class *bt_py3_component_class_sink_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help)
+{
+       struct bt_component_class *cc;
+       int ret;
+
+       assert(py_cls);
+       cc = bt_component_class_sink_create(name, bt_py3_cc_sink_consume);
+       if (!cc) {
+               BT_LOGE_STR("Cannot create sink component class.");
+               goto end;
+       }
+
+       ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
+       if (ret) {
+               BT_LOGE_STR("Cannot set sink component class's optional attributes and methods.");
+               BT_PUT(cc);
+               goto end;
+       }
+
+       register_cc_ptr_to_py_cls(cc, py_cls);
+       bt_component_class_freeze(cc);
+
+end:
+       return cc;
+}
+%}
+
+struct bt_component_class *bt_py3_component_class_source_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help);
+struct bt_component_class *bt_py3_component_class_filter_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help);
+struct bt_component_class *bt_py3_component_class_sink_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help);
+void bt_py3_cc_init_from_bt2(void);
+void bt_py3_cc_exit_handler(void);
diff --git a/bindings/python/bt2/bt2/native_btconnection.i b/bindings/python/bt2/bt2/native_btconnection.i
new file mode 100644 (file)
index 0000000..e9c1ab9
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_connection;
+struct bt_private_connection;
+
+/* Status */
+enum bt_connection_status {
+       BT_CONNECTION_STATUS_GRAPH_IS_CANCELED = 125,
+       BT_CONNECTION_STATUS_OK = 0,
+       BT_CONNECTION_STATUS_INVALID = -22,
+       BT_CONNECTION_STATUS_ERROR = -1,
+       BT_CONNECTION_STATUS_NOMEM = -12,
+       BT_CONNECTION_STATUS_IS_ENDED = 104,
+};
+
+/* Functions (public) */
+struct bt_port *bt_connection_get_downstream_port(
+               struct bt_connection *connection);
+struct bt_port *bt_connection_get_upstream_port(
+               struct bt_connection *connection);
+int bt_connection_is_ended(struct bt_connection *connection);
+
+/* Functions (private) */
+struct bt_connection *bt_connection_from_private_connection(
+               struct bt_private_connection *private_connection);
+
+/* Helper functions for Python */
+%typemap(out) struct bt_py3_create_notif_iter_ret {
+       $result = PyTuple_New(2);
+       PyObject *py_notif_iter_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr($1.notif_iter),
+               SWIGTYPE_p_bt_notification_iterator, 0);
+       PyObject *py_status = SWIG_From_long_SS_long($1.status);
+       PyTuple_SET_ITEM($result, 0, py_status);
+       PyTuple_SET_ITEM($result, 1, py_notif_iter_ptr);
+}
+
+%{
+struct bt_py3_create_notif_iter_ret {
+       enum bt_connection_status status;
+       struct bt_notification_iterator *notif_iter;
+};
+
+static struct bt_py3_create_notif_iter_ret bt_py3_create_notif_iter(
+               unsigned long long priv_conn_addr, PyObject *py_notif_types)
+{
+       struct bt_private_connection *priv_conn;
+       enum bt_notification_type *notification_types = NULL;
+       struct bt_py3_create_notif_iter_ret ret;
+
+       priv_conn = (void *) priv_conn_addr;
+       assert(!PyErr_Occurred());
+       assert(priv_conn);
+
+       if (py_notif_types != Py_None) {
+               size_t i;
+
+               assert(PyList_Check(py_notif_types));
+               notification_types = g_new0(enum bt_notification_type,
+                       PyList_Size(py_notif_types) + 1);
+               assert(notification_types);
+               notification_types[PyList_Size(py_notif_types)] =
+                       BT_NOTIFICATION_TYPE_SENTINEL;
+
+               for (i = 0; i < PyList_Size(py_notif_types); i++) {
+                       PyObject *item = PyList_GetItem(py_notif_types, i);
+                       long value;
+                       int overflow;
+
+                       assert(item);
+                       assert(PyLong_Check(item));
+                       value = PyLong_AsLongAndOverflow(item, &overflow);
+                       assert(overflow == 0);
+                       notification_types[i] = value;
+               }
+       }
+
+       ret.status = bt_private_connection_create_notification_iterator(
+               priv_conn, notification_types, &ret.notif_iter);
+
+       if (notification_types) {
+               g_free(notification_types);
+       }
+
+       return ret;
+}
+%}
+
+struct bt_py3_create_notif_iter_ret bt_py3_create_notif_iter(
+               unsigned long long priv_conn_addr, PyObject *notif_types);
diff --git a/bindings/python/bt2/bt2/native_btctfwriter.i b/bindings/python/bt2/bt2/native_btctfwriter.i
new file mode 100644 (file)
index 0000000..293ed25
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Types */
+struct bt_ctf_clock;
+struct bt_ctf_writer;
+
+/* Clock functions */
+struct bt_ctf_clock *bt_ctf_clock_create(const char *name);
+const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock);
+const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock);
+int bt_ctf_clock_set_description(struct bt_ctf_clock *clock,
+               const char *desc);
+uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock);
+int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock,
+               uint64_t freq);
+uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock);
+int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock,
+               uint64_t precision);
+int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock,
+               int64_t *OUTPUT);
+int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock,
+               int64_t offset_s);
+int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock,
+               int64_t *OUTPUT);
+int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock,
+               int64_t offset);
+int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock);
+int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock,
+               int is_absolute);
+BTUUID bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock);
+int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock,
+               BTUUID uuid);
+int bt_ctf_clock_set_time(struct bt_ctf_clock *clock,
+               int64_t time);
+
+/* Stream functions */
+int bt_ctf_stream_get_discarded_events_count(
+               struct bt_ctf_stream *stream, uint64_t *OUTPUT);
+void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
+               uint64_t event_count);
+int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
+               struct bt_ctf_event *event);
+struct bt_ctf_field *bt_ctf_stream_get_packet_header(
+               struct bt_ctf_stream *stream);
+int bt_ctf_stream_set_packet_header(
+               struct bt_ctf_stream *stream,
+               struct bt_ctf_field *packet_header);
+struct bt_ctf_field *bt_ctf_stream_get_packet_context(
+               struct bt_ctf_stream *stream);
+int bt_ctf_stream_set_packet_context(
+               struct bt_ctf_stream *stream,
+               struct bt_ctf_field *packet_context);
+int bt_ctf_stream_flush(struct bt_ctf_stream *stream);
+int bt_ctf_stream_is_writer(struct bt_ctf_stream *stream);
+
+/* Stream class functions */
+int bt_ctf_stream_class_set_clock(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_clock *clock);
+struct bt_ctf_clock *bt_ctf_stream_class_get_clock(
+               struct bt_ctf_stream_class *stream_class);
+
+/* Writer functions */
+struct bt_ctf_writer *bt_ctf_writer_create(const char *path);
+struct bt_ctf_trace *bt_ctf_writer_get_trace(
+               struct bt_ctf_writer *writer);
+int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer,
+               struct bt_ctf_clock *clock);
+char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer);
+void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer);
diff --git a/bindings/python/bt2/bt2/native_btevent.i b/bindings/python/bt2/bt2/native_btevent.i
new file mode 100644 (file)
index 0000000..f6e6494
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_ctf_event;
+
+/* Functions */
+struct bt_ctf_event *bt_ctf_event_create(
+               struct bt_ctf_event_class *event_class);
+struct bt_ctf_event_class *bt_ctf_event_get_class(
+               struct bt_ctf_event *event);
+struct bt_ctf_packet *bt_ctf_event_get_packet(
+               struct bt_ctf_event *event);
+int bt_ctf_event_set_packet(struct bt_ctf_event *event,
+               struct bt_ctf_packet *packet);
+struct bt_ctf_stream *bt_ctf_event_get_stream(
+               struct bt_ctf_event *event);
+struct bt_ctf_field *bt_ctf_event_get_header(
+               struct bt_ctf_event *event);
+int bt_ctf_event_set_header(struct bt_ctf_event *event,
+               struct bt_ctf_field *header);
+struct bt_ctf_field *bt_ctf_event_get_stream_event_context(
+               struct bt_ctf_event *event);
+int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
+               struct bt_ctf_field *context);
+struct bt_ctf_field *bt_ctf_event_get_event_context(
+               struct bt_ctf_event *event);
+int bt_ctf_event_set_event_context(struct bt_ctf_event *event,
+               struct bt_ctf_field *context);
+struct bt_ctf_field *bt_ctf_event_get_event_payload(
+               struct bt_ctf_event *event);
+int bt_ctf_event_set_event_payload(struct bt_ctf_event *event,
+               struct bt_ctf_field *payload);
+struct bt_ctf_clock_value *bt_ctf_event_get_clock_value(
+               struct bt_ctf_event *event,
+               struct bt_ctf_clock_class *clock_class);
+int bt_ctf_event_set_clock_value(
+               struct bt_ctf_event *event,
+               struct bt_ctf_clock_value *clock_value);
diff --git a/bindings/python/bt2/bt2/native_bteventclass.i b/bindings/python/bt2/bt2/native_bteventclass.i
new file mode 100644 (file)
index 0000000..c4b8c8d
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_ctf_event_class;
+
+/* Log levels */
+enum bt_ctf_event_class_log_level {
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_UNKNOWN = -1,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED = 255,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_EMERGENCY = 0,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_ALERT = 1,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_CRITICAL = 2,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_ERROR = 3,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_WARNING = 4,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_NOTICE = 5,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_INFO = 6,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM = 7,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM = 8,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS = 9,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE = 10,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT = 11,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION = 12,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE = 13,
+       BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG = 14,
+};
+
+/* Functions */
+struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name);
+struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class(
+               struct bt_ctf_event_class *event_class);
+const char *bt_ctf_event_class_get_name(
+               struct bt_ctf_event_class *event_class);
+int64_t bt_ctf_event_class_get_id(
+               struct bt_ctf_event_class *event_class);
+int bt_ctf_event_class_set_id(
+               struct bt_ctf_event_class *event_class, uint64_t id);
+enum bt_ctf_event_class_log_level bt_ctf_event_class_get_log_level(
+               struct bt_ctf_event_class *event_class);
+int bt_ctf_event_class_set_log_level(
+               struct bt_ctf_event_class *event_class,
+               enum bt_ctf_event_class_log_level log_level);
+const char *bt_ctf_event_class_get_emf_uri(
+               struct bt_ctf_event_class *event_class);
+int bt_ctf_event_class_set_emf_uri(
+               struct bt_ctf_event_class *event_class,
+               const char *emf_uri);
+struct bt_ctf_field_type *bt_ctf_event_class_get_context_type(
+               struct bt_ctf_event_class *event_class);
+int bt_ctf_event_class_set_context_type(
+               struct bt_ctf_event_class *event_class,
+               struct bt_ctf_field_type *context_type);
+struct bt_ctf_field_type *bt_ctf_event_class_get_payload_type(
+               struct bt_ctf_event_class *event_class);
+int bt_ctf_event_class_set_payload_type(
+               struct bt_ctf_event_class *event_class,
+               struct bt_ctf_field_type *payload_type);
diff --git a/bindings/python/bt2/bt2/native_btfields.i b/bindings/python/bt2/bt2/native_btfields.i
new file mode 100644 (file)
index 0000000..883bec3
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_ctf_field;
+
+/* Common functions */
+struct bt_ctf_field *bt_ctf_field_create(
+               struct bt_ctf_field_type *type);
+struct bt_ctf_field_type *bt_ctf_field_get_type(
+               struct bt_ctf_field *field);
+struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field);
+
+/* Integer field functions */
+int bt_ctf_field_signed_integer_get_value(struct bt_ctf_field *integer,
+               int64_t *OUTPUT);
+int bt_ctf_field_signed_integer_set_value(struct bt_ctf_field *integer,
+               int64_t value);
+int bt_ctf_field_unsigned_integer_get_value(struct bt_ctf_field *integer,
+               uint64_t *OUTPUT);
+int bt_ctf_field_unsigned_integer_set_value(struct bt_ctf_field *integer,
+               uint64_t value);
+
+/* Floating point number field functions */
+int bt_ctf_field_floating_point_get_value(
+               struct bt_ctf_field *floating_point, double *OUTPUT);
+int bt_ctf_field_floating_point_set_value(
+               struct bt_ctf_field *floating_point,
+               double value);
+
+/* Enumeration field functions */
+struct bt_ctf_field *bt_ctf_field_enumeration_get_container(
+               struct bt_ctf_field *enumeration);
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_enumeration_get_mappings(struct bt_ctf_field *enum_field);
+
+/* String field functions */
+const char *bt_ctf_field_string_get_value(
+               struct bt_ctf_field *string_field);
+int bt_ctf_field_string_set_value(struct bt_ctf_field *string_field,
+               const char *value);
+int bt_ctf_field_string_append(struct bt_ctf_field *string_field,
+               const char *value);
+int bt_ctf_field_string_append_len(
+               struct bt_ctf_field *string_field, const char *value,
+               unsigned int length);
+
+/* Structure field functions */
+struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index(
+               struct bt_ctf_field *structure, int index);
+struct bt_ctf_field *bt_ctf_field_structure_get_field_by_name(
+               struct bt_ctf_field *struct_field, const char *name);
+int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *struct_field,
+               const char *name, struct bt_ctf_field *field);
+
+/* Array field functions */
+struct bt_ctf_field *bt_ctf_field_array_get_field(
+               struct bt_ctf_field *array, uint64_t index);
+
+/* Sequence field functions */
+struct bt_ctf_field *bt_ctf_field_sequence_get_length(
+               struct bt_ctf_field *sequence);
+int bt_ctf_field_sequence_set_length(struct bt_ctf_field *sequence,
+               struct bt_ctf_field *length_field);
+struct bt_ctf_field *bt_ctf_field_sequence_get_field(
+               struct bt_ctf_field *sequence, uint64_t index);
+
+/* Variant field functions */
+struct bt_ctf_field *bt_ctf_field_variant_get_field(
+               struct bt_ctf_field *variant, struct bt_ctf_field *tag);
+struct bt_ctf_field *bt_ctf_field_variant_get_current_field(
+               struct bt_ctf_field *variant);
+struct bt_ctf_field *bt_ctf_field_variant_get_tag(
+               struct bt_ctf_field *variant);
diff --git a/bindings/python/bt2/bt2/native_btft.i b/bindings/python/bt2/bt2/native_btft.i
new file mode 100644 (file)
index 0000000..c24a863
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_ctf_field_type;
+
+/* Common enumerations */
+enum bt_ctf_scope {
+       BT_CTF_SCOPE_UNKNOWN = -1,
+       BT_CTF_SCOPE_TRACE_PACKET_HEADER = 1,
+       BT_CTF_SCOPE_STREAM_PACKET_CONTEXT = 2,
+       BT_CTF_SCOPE_STREAM_EVENT_HEADER = 3,
+       BT_CTF_SCOPE_STREAM_EVENT_CONTEXT = 4,
+       BT_CTF_SCOPE_EVENT_CONTEXT = 5,
+       BT_CTF_SCOPE_EVENT_PAYLOAD = 6,
+       BT_CTF_SCOPE_ENV = 0,
+       BT_CTF_SCOPE_EVENT_FIELDS = 6,
+};
+
+enum bt_ctf_field_type_id {
+       BT_CTF_FIELD_TYPE_ID_UNKNOWN = CTF_TYPE_UNKNOWN,
+       BT_CTF_FIELD_TYPE_ID_INTEGER = CTF_TYPE_INTEGER,
+       BT_CTF_FIELD_TYPE_ID_FLOAT = CTF_TYPE_FLOAT,
+       BT_CTF_FIELD_TYPE_ID_ENUM = CTF_TYPE_ENUM,
+       BT_CTF_FIELD_TYPE_ID_STRING = CTF_TYPE_STRING,
+       BT_CTF_FIELD_TYPE_ID_STRUCT = CTF_TYPE_STRUCT,
+       BT_CTF_FIELD_TYPE_ID_ARRAY = CTF_TYPE_ARRAY,
+       BT_CTF_FIELD_TYPE_ID_SEQUENCE = CTF_TYPE_SEQUENCE,
+       BT_CTF_FIELD_TYPE_ID_VARIANT = CTF_TYPE_VARIANT,
+       BT_CTF_NR_TYPE_IDS = NR_CTF_TYPES,
+};
+
+enum bt_ctf_byte_order {
+       BT_CTF_BYTE_ORDER_UNKNOWN = -1,
+       BT_CTF_BYTE_ORDER_NATIVE = 0,
+       BT_CTF_BYTE_ORDER_UNSPECIFIED,
+       BT_CTF_BYTE_ORDER_LITTLE_ENDIAN,
+       BT_CTF_BYTE_ORDER_BIG_ENDIAN,
+       BT_CTF_BYTE_ORDER_NETWORK,
+};
+
+enum bt_ctf_string_encoding {
+       BT_CTF_STRING_ENCODING_UNKNOWN = CTF_STRING_UNKNOWN,
+       BT_CTF_STRING_ENCODING_NONE = CTF_STRING_NONE,
+       BT_CTF_STRING_ENCODING_UTF8 = CTF_STRING_UTF8,
+       BT_CTF_STRING_ENCODING_ASCII = CTF_STRING_ASCII,
+};
+
+/* Common functions */
+enum bt_ctf_field_type_id bt_ctf_field_type_get_type_id(
+               struct bt_ctf_field_type *field_type);
+int bt_ctf_field_type_get_alignment(
+               struct bt_ctf_field_type *field_type);
+int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *field_type,
+               unsigned int alignment);
+enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order(
+               struct bt_ctf_field_type *field_type);
+int bt_ctf_field_type_set_byte_order(
+               struct bt_ctf_field_type *field_type,
+               enum bt_ctf_byte_order byte_order);
+int bt_ctf_field_type_compare(struct bt_ctf_field_type *field_type_a,
+               struct bt_ctf_field_type *field_type_b);
+struct bt_ctf_field_type *bt_ctf_field_type_copy(
+               struct bt_ctf_field_type *field_type);
+
+/* Integer field type base enumeration */
+enum bt_ctf_integer_base {
+       BT_CTF_INTEGER_BASE_UNKNOWN = -1,
+       BT_CTF_INTEGER_BASE_BINARY = 2,
+       BT_CTF_INTEGER_BASE_OCTAL = 8,
+       BT_CTF_INTEGER_BASE_DECIMAL = 10,
+       BT_CTF_INTEGER_BASE_HEXADECIMAL = 16,
+};
+
+/* Integer field type functions */
+struct bt_ctf_field_type *bt_ctf_field_type_integer_create(
+               unsigned int size);
+int bt_ctf_field_type_integer_get_size(
+               struct bt_ctf_field_type *int_field_type);
+int bt_ctf_field_type_integer_set_size(
+               struct bt_ctf_field_type *int_field_type, unsigned int size);
+int bt_ctf_field_type_integer_is_signed(
+               struct bt_ctf_field_type *int_field_type);
+int bt_ctf_field_type_integer_set_is_signed(
+               struct bt_ctf_field_type *int_field_type, int is_signed);
+enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base(
+               struct bt_ctf_field_type *int_field_type);
+int bt_ctf_field_type_integer_set_base(
+               struct bt_ctf_field_type *int_field_type,
+               enum bt_ctf_integer_base base);
+enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding(
+               struct bt_ctf_field_type *int_field_type);
+int bt_ctf_field_type_integer_set_encoding(
+               struct bt_ctf_field_type *int_field_type,
+               enum bt_ctf_string_encoding encoding);
+struct bt_ctf_clock_class *bt_ctf_field_type_integer_get_mapped_clock_class(
+               struct bt_ctf_field_type *int_field_type);
+int bt_ctf_field_type_integer_set_mapped_clock_class(
+               struct bt_ctf_field_type *int_field_type,
+               struct bt_ctf_clock_class *clock_class);
+
+/* Floating point number field type functions */
+struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void);
+int bt_ctf_field_type_floating_point_get_exponent_digits(
+               struct bt_ctf_field_type *float_field_type);
+int bt_ctf_field_type_floating_point_set_exponent_digits(
+               struct bt_ctf_field_type *float_field_type,
+               unsigned int exponent_size);
+int bt_ctf_field_type_floating_point_get_mantissa_digits(
+               struct bt_ctf_field_type *float_field_type);
+int bt_ctf_field_type_floating_point_set_mantissa_digits(
+               struct bt_ctf_field_type *float_field_type,
+               unsigned int mantissa_sign_size);
+
+/* Enumeration field type functions */
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create(
+               struct bt_ctf_field_type *int_field_type);
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_type(
+               struct bt_ctf_field_type *enum_field_type);
+int64_t bt_ctf_field_type_enumeration_get_mapping_count(
+               struct bt_ctf_field_type *enum_field_type);
+int bt_ctf_field_type_enumeration_get_mapping_signed(
+               struct bt_ctf_field_type *enum_field_type, int index,
+               const char **BTOUTSTR, int64_t *OUTPUT, int64_t *OUTPUT);
+int bt_ctf_field_type_enumeration_get_mapping_unsigned(
+               struct bt_ctf_field_type *enum_field_type, int index,
+               const char **BTOUTSTR, uint64_t *OUTPUT,
+               uint64_t *OUTPUT);
+int bt_ctf_field_type_enumeration_add_mapping_signed(
+               struct bt_ctf_field_type *enum_field_type, const char *name,
+               int64_t range_begin, int64_t range_end);
+int bt_ctf_field_type_enumeration_add_mapping_unsigned(
+               struct bt_ctf_field_type *enum_field_type, const char *name,
+               uint64_t range_begin, uint64_t range_end);
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_enumeration_find_mappings_by_name(
+               struct bt_ctf_field_type *enum_field_type,
+               const char *name);
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_enumeration_find_mappings_by_signed_value(
+               struct bt_ctf_field_type *enum_field_type,
+               int64_t value);
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_enumeration_find_mappings_by_unsigned_value(
+               struct bt_ctf_field_type *enum_field_type,
+               uint64_t value);
+
+/* Enumeration field type mapping iterator functions */
+int bt_ctf_field_type_enumeration_mapping_iterator_get_signed(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter,
+               const char **BTOUTSTR, int64_t *OUTPUT, int64_t *OUTPUT);
+int bt_ctf_field_type_enumeration_mapping_iterator_get_unsigned(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter,
+               const char **BTOUTSTR, uint64_t *OUTPUT, uint64_t *OUTPUT);
+int bt_ctf_field_type_enumeration_mapping_iterator_next(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter);
+
+/* String field type functions */
+struct bt_ctf_field_type *bt_ctf_field_type_string_create(void);
+enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding(
+               struct bt_ctf_field_type *string_field_type);
+int bt_ctf_field_type_string_set_encoding(
+               struct bt_ctf_field_type *string_field_type,
+               enum bt_ctf_string_encoding encoding);
+
+/* Structure field type functions */
+struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void);
+int64_t bt_ctf_field_type_structure_get_field_count(
+               struct bt_ctf_field_type *struct_field_type);
+int bt_ctf_field_type_structure_get_field_by_index(
+               struct bt_ctf_field_type *struct_field_type,
+               const char **BTOUTSTR, struct bt_ctf_field_type **BTOUTFT,
+               uint64_t index);
+struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name(
+               struct bt_ctf_field_type *struct_field_type,
+               const char *field_name);
+int bt_ctf_field_type_structure_add_field(
+               struct bt_ctf_field_type *struct_field_type,
+               struct bt_ctf_field_type *field_type,
+               const char *field_name);
+
+/* Array field type functions */
+struct bt_ctf_field_type *bt_ctf_field_type_array_create(
+               struct bt_ctf_field_type *element_field_type,
+               unsigned int length);
+struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type(
+               struct bt_ctf_field_type *array_field_type);
+int64_t bt_ctf_field_type_array_get_length(
+               struct bt_ctf_field_type *array_field_type);
+
+/* Sequence field type functions */
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_create(
+               struct bt_ctf_field_type *element_field_type,
+               const char *length_name);
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type(
+               struct bt_ctf_field_type *sequence_field_type);
+const char *bt_ctf_field_type_sequence_get_length_field_name(
+               struct bt_ctf_field_type *sequence_field_type);
+struct bt_ctf_field_path *bt_ctf_field_type_sequence_get_length_field_path(
+               struct bt_ctf_field_type *sequence_field_type);
+
+/* Variant field type functions */
+struct bt_ctf_field_type *bt_ctf_field_type_variant_create(
+               struct bt_ctf_field_type *tag_field_type,
+               const char *tag_name);
+struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_type(
+               struct bt_ctf_field_type *variant_field_type);
+const char *bt_ctf_field_type_variant_get_tag_name(
+               struct bt_ctf_field_type *variant_field_type);
+int bt_ctf_field_type_variant_set_tag_name(
+               struct bt_ctf_field_type *variant_field_type,
+               const char *tag_name);
+struct bt_ctf_field_path *bt_ctf_field_type_variant_get_tag_field_path(
+               struct bt_ctf_field_type *variant_field_type);
+int64_t bt_ctf_field_type_variant_get_field_count(
+               struct bt_ctf_field_type *variant_field_type);
+int bt_ctf_field_type_variant_get_field_by_index(
+               struct bt_ctf_field_type *variant_field_type,
+               const char **BTOUTSTR,
+               struct bt_ctf_field_type **BTOUTFT, uint64_t index);
+struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name(
+               struct bt_ctf_field_type *variant_field_type,
+               const char *field_name);
+int bt_ctf_field_type_variant_add_field(
+               struct bt_ctf_field_type *variant_field_type,
+               struct bt_ctf_field_type *field_type,
+               const char *field_name);
diff --git a/bindings/python/bt2/bt2/native_btgraph.i b/bindings/python/bt2/bt2/native_btgraph.i
new file mode 100644 (file)
index 0000000..f8ee71d
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Types */
+struct bt_graph;
+
+/* Status */
+enum bt_graph_status {
+       BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION = 111,
+       BT_GRAPH_STATUS_CANCELED = 125,
+       BT_GRAPH_STATUS_AGAIN = 11,
+       BT_GRAPH_STATUS_END = 1,
+       BT_GRAPH_STATUS_OK = 0,
+       BT_GRAPH_STATUS_INVALID = -22,
+       BT_GRAPH_STATUS_NO_SINK = -6,
+       BT_GRAPH_STATUS_ERROR = -1,
+       BT_GRAPH_STATUS_NOMEM = -12,
+};
+
+/* Functions */
+struct bt_graph *bt_graph_create(void);
+enum bt_graph_status bt_graph_add_component(
+               struct bt_graph *graph,
+               struct bt_component_class *component_class,
+               const char *name, struct bt_value *params,
+               struct bt_component **BTOUTCOMP);
+enum bt_graph_status bt_graph_add_component_with_init_method_data(
+               struct bt_graph *graph,
+               struct bt_component_class *component_class,
+               const char *name, struct bt_value *params,
+               void *init_method_data,
+               struct bt_component **BTOUTCOMP);
+enum bt_graph_status bt_graph_connect_ports(struct bt_graph *graph,
+               struct bt_port *upstream, struct bt_port *downstream,
+               struct bt_connection **BTOUTCONN);
+enum bt_graph_status bt_graph_run(struct bt_graph *graph);
+enum bt_graph_status bt_graph_consume(struct bt_graph *graph);
+enum bt_graph_status bt_graph_cancel(struct bt_graph *graph);
+int bt_graph_is_canceled(struct bt_graph *graph);
+
+/* Helper functions for Python */
+%{
+static void port_added_listener(struct bt_port *port, void *py_callable)
+{
+       PyObject *py_port_ptr = NULL;
+       PyObject *py_res = NULL;
+
+       py_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(port),
+               SWIGTYPE_p_bt_port, 0);
+       if (!py_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(O)", py_port_ptr);
+       assert(py_res == Py_None);
+       Py_DECREF(py_port_ptr);
+       Py_DECREF(py_res);
+}
+
+static void port_removed_listener(struct bt_component *component,
+               struct bt_port *port, void *py_callable)
+{
+       PyObject *py_port_ptr = NULL;
+       PyObject *py_res = NULL;
+
+       py_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(port),
+               SWIGTYPE_p_bt_port, 0);
+       if (!py_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(O)", py_port_ptr);
+       assert(py_res == Py_None);
+       Py_DECREF(py_port_ptr);
+       Py_DECREF(py_res);
+}
+
+static void ports_connected_listener(struct bt_port *upstream_port,
+               struct bt_port *downstream_port, void *py_callable)
+{
+       PyObject *py_upstream_port_ptr = NULL;
+       PyObject *py_downstream_port_ptr = NULL;
+       PyObject *py_res = NULL;
+
+       py_upstream_port_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr(upstream_port), SWIGTYPE_p_bt_port, 0);
+       if (!py_upstream_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_downstream_port_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr(downstream_port), SWIGTYPE_p_bt_port, 0);
+       if (!py_downstream_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(OO)",
+               py_upstream_port_ptr, py_downstream_port_ptr);
+       assert(py_res == Py_None);
+       Py_DECREF(py_upstream_port_ptr);
+       Py_DECREF(py_downstream_port_ptr);
+       Py_DECREF(py_res);
+}
+
+static void ports_disconnected_listener(
+               struct bt_component *upstream_component,
+               struct bt_component *downstream_component,
+               struct bt_port *upstream_port, struct bt_port *downstream_port,
+               void *py_callable)
+{
+       PyObject *py_upstream_comp_ptr = NULL;
+       PyObject *py_downstream_comp_ptr = NULL;
+       PyObject *py_upstream_port_ptr = NULL;
+       PyObject *py_downstream_port_ptr = NULL;
+       PyObject *py_res = NULL;
+
+       py_upstream_comp_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr(upstream_component),
+               SWIGTYPE_p_bt_component, 0);
+       if (!py_upstream_comp_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_downstream_comp_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr(downstream_component),
+               SWIGTYPE_p_bt_component, 0);
+       if (!py_downstream_comp_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_upstream_port_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr(upstream_port), SWIGTYPE_p_bt_port, 0);
+       if (!py_upstream_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_downstream_port_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr(downstream_port), SWIGTYPE_p_bt_port, 0);
+       if (!py_downstream_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(OOOO)",
+               py_upstream_comp_ptr, py_downstream_comp_ptr,
+               py_upstream_port_ptr, py_downstream_port_ptr);
+       assert(py_res == Py_None);
+       Py_DECREF(py_upstream_comp_ptr);
+       Py_DECREF(py_downstream_comp_ptr);
+       Py_DECREF(py_upstream_port_ptr);
+       Py_DECREF(py_downstream_port_ptr);
+       Py_DECREF(py_res);
+}
+
+static void graph_listener_removed(void *py_callable)
+{
+       assert(py_callable);
+       Py_DECREF(py_callable);
+}
+
+static int bt_py3_graph_add_port_added_listener(struct bt_graph *graph,
+               PyObject *py_callable)
+{
+       int ret = 0;
+
+       assert(graph);
+       assert(py_callable);
+       ret = bt_graph_add_port_added_listener(graph, port_added_listener,
+               graph_listener_removed, py_callable);
+       if (ret >= 0) {
+               Py_INCREF(py_callable);
+       }
+
+       return ret;
+}
+
+static int bt_py3_graph_add_port_removed_listener(struct bt_graph *graph,
+               PyObject *py_callable)
+{
+       int ret = 0;
+
+       assert(graph);
+       assert(py_callable);
+       ret = bt_graph_add_port_removed_listener(graph, port_removed_listener,
+               graph_listener_removed, py_callable);
+       if (ret >= 0) {
+               Py_INCREF(py_callable);
+       }
+
+       return ret;
+}
+
+static int bt_py3_graph_add_ports_connected_listener(struct bt_graph *graph,
+               PyObject *py_callable)
+{
+       int ret = 0;
+
+       assert(graph);
+       assert(py_callable);
+       ret = bt_graph_add_ports_connected_listener(graph,
+               ports_connected_listener, graph_listener_removed, py_callable);
+       if (ret >= 0) {
+               Py_INCREF(py_callable);
+       }
+
+       return ret;
+}
+
+static int bt_py3_graph_add_ports_disconnected_listener(struct bt_graph *graph,
+               PyObject *py_callable)
+{
+       int ret = 0;
+
+       assert(graph);
+       assert(py_callable);
+       ret = bt_graph_add_ports_disconnected_listener(graph,
+               ports_disconnected_listener, graph_listener_removed,
+               py_callable);
+       if (ret >= 0) {
+               Py_INCREF(py_callable);
+       }
+
+       return ret;
+}
+%}
+
+int bt_py3_graph_add_port_added_listener(struct bt_graph *graph,
+               PyObject *py_callable);
+int bt_py3_graph_add_port_removed_listener(struct bt_graph *graph,
+               PyObject *py_callable);
+int bt_py3_graph_add_ports_connected_listener(struct bt_graph *graph,
+               PyObject *py_callable);
+int bt_py3_graph_add_ports_disconnected_listener(struct bt_graph *graph,
+               PyObject *py_callable);
diff --git a/bindings/python/bt2/bt2/native_btlogging.i b/bindings/python/bt2/bt2/native_btlogging.i
new file mode 100644 (file)
index 0000000..0406a2a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+%{
+#include <babeltrace/logging.h>
+%}
+
+/* Log levels */
+enum bt_logging_level {
+       BT_LOGGING_LEVEL_VERBOSE = 1,
+       BT_LOGGING_LEVEL_DEBUG = 2,
+       BT_LOGGING_LEVEL_INFO = 3,
+       BT_LOGGING_LEVEL_WARN = 4,
+       BT_LOGGING_LEVEL_ERROR = 5,
+       BT_LOGGING_LEVEL_FATAL = 6,
+       BT_LOGGING_LEVEL_NONE = 0xff,
+};
+
+/* Logging functions */
+enum bt_logging_level bt_logging_get_minimal_level(void);
+enum bt_logging_level bt_logging_get_global_level(void);
+void bt_logging_set_global_level(enum bt_logging_level log_level);
diff --git a/bindings/python/bt2/bt2/native_btnotification.i b/bindings/python/bt2/bt2/native_btnotification.i
new file mode 100644 (file)
index 0000000..4192278
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_notification;
+
+/* Notification type */
+enum bt_notification_type {
+       BT_NOTIFICATION_TYPE_SENTINEL = -1000,
+       BT_NOTIFICATION_TYPE_UNKNOWN = -1,
+       BT_NOTIFICATION_TYPE_ALL = -2,
+       BT_NOTIFICATION_TYPE_EVENT = 0,
+       BT_NOTIFICATION_TYPE_INACTIVITY = 1,
+       BT_NOTIFICATION_TYPE_STREAM_BEGIN = 2,
+       BT_NOTIFICATION_TYPE_STREAM_END = 3,
+       BT_NOTIFICATION_TYPE_PACKET_BEGIN = 4,
+       BT_NOTIFICATION_TYPE_PACKET_END = 5,
+       BT_NOTIFICATION_TYPE_DISCARDED_EVENTS = 6,
+       BT_NOTIFICATION_TYPE_DISCARDED_PACKETS = 7,
+};
+
+/* General functions */
+enum bt_notification_type bt_notification_get_type(
+               struct bt_notification *notification);
+
+/* Event notification functions */
+struct bt_notification *bt_notification_event_create(
+               struct bt_ctf_event *event,
+               struct bt_clock_class_priority_map *clock_class_priority_map);
+struct bt_ctf_event *bt_notification_event_get_event(
+               struct bt_notification *notification);
+struct bt_clock_class_priority_map *
+bt_notification_event_get_clock_class_priority_map(
+               struct bt_notification *notification);
+
+/* Inactivity notification functions */
+struct bt_notification *bt_notification_inactivity_create(
+               struct bt_clock_class_priority_map *clock_class_priority_map);
+struct bt_clock_class_priority_map *
+bt_notification_inactivity_get_clock_class_priority_map(
+               struct bt_notification *notification);
+struct bt_ctf_clock_value *bt_notification_inactivity_get_clock_value(
+               struct bt_notification *notification,
+               struct bt_ctf_clock_class *clock_class);
+int bt_notification_inactivity_set_clock_value(
+               struct bt_notification *notification,
+               struct bt_ctf_clock_value *clock_value);
+
+/* Packet notification functions */
+struct bt_notification *bt_notification_packet_begin_create(
+               struct bt_ctf_packet *packet);
+struct bt_notification *bt_notification_packet_end_create(
+               struct bt_ctf_packet *packet);
+struct bt_ctf_packet *bt_notification_packet_begin_get_packet(
+               struct bt_notification *notification);
+struct bt_ctf_packet *bt_notification_packet_end_get_packet(
+               struct bt_notification *notification);
+
+/* Stream notification functions */
+struct bt_notification *bt_notification_stream_begin_create(
+               struct bt_ctf_stream *stream);
+struct bt_notification *bt_notification_stream_end_create(
+               struct bt_ctf_stream *stream);
+struct bt_ctf_stream *bt_notification_stream_begin_get_stream(
+               struct bt_notification *notification);
+struct bt_ctf_stream *bt_notification_stream_end_get_stream(
+               struct bt_notification *notification);
+
+/* Discarded packets notification functions */
+struct bt_ctf_clock_value *
+bt_notification_discarded_packets_get_begin_clock_value(
+               struct bt_notification *notification);
+struct bt_ctf_clock_value *
+bt_notification_discarded_packets_get_end_clock_value(
+               struct bt_notification *notification);
+int64_t bt_notification_discarded_packets_get_count(
+               struct bt_notification *notification);
+struct bt_ctf_stream *bt_notification_discarded_packets_get_stream(
+               struct bt_notification *notification);
+
+/* Discarded events notification functions */
+struct bt_ctf_clock_value *
+bt_notification_discarded_events_get_begin_clock_value(
+               struct bt_notification *notification);
+struct bt_ctf_clock_value *
+bt_notification_discarded_events_get_end_clock_value(
+               struct bt_notification *notification);
+int64_t bt_notification_discarded_events_get_count(
+               struct bt_notification *notification);
+struct bt_ctf_stream *bt_notification_discarded_events_get_stream(
+               struct bt_notification *notification);
diff --git a/bindings/python/bt2/bt2/native_btnotifiter.i b/bindings/python/bt2/bt2/native_btnotifiter.i
new file mode 100644 (file)
index 0000000..bdc7e73
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_notification_iterator;
+
+/* Status */
+enum bt_notification_iterator_status {
+       BT_NOTIFICATION_ITERATOR_STATUS_CANCELED = 125,
+       BT_NOTIFICATION_ITERATOR_STATUS_AGAIN = 11,
+       BT_NOTIFICATION_ITERATOR_STATUS_END = 1,
+       BT_NOTIFICATION_ITERATOR_STATUS_OK = 0,
+       BT_NOTIFICATION_ITERATOR_STATUS_INVALID = -22,
+       BT_NOTIFICATION_ITERATOR_STATUS_ERROR = -1,
+       BT_NOTIFICATION_ITERATOR_STATUS_NOMEM = -12,
+       BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED = -2,
+};
+
+/* Functions */
+struct bt_notification *bt_notification_iterator_get_notification(
+               struct bt_notification_iterator *iterator);
+enum bt_notification_iterator_status bt_notification_iterator_next(
+               struct bt_notification_iterator *iterator);
+struct bt_component *bt_notification_iterator_get_component(
+               struct bt_notification_iterator *iterator);
+
+/* Helper functions for Python */
+%{
+static PyObject *bt_py3_get_user_component_from_user_notif_iter(
+               struct bt_private_notification_iterator *priv_notif_iter)
+{
+       struct bt_private_component *priv_comp =
+               bt_private_notification_iterator_get_private_component(
+                       priv_notif_iter);
+       PyObject *py_comp;
+
+       assert(priv_comp);
+       py_comp = bt_private_component_get_user_data(priv_comp);
+       bt_put(priv_comp);
+       assert(py_comp);
+
+       /* Return new reference */
+       Py_INCREF(py_comp);
+       return py_comp;
+}
+%}
+
+PyObject *bt_py3_get_user_component_from_user_notif_iter(
+               struct bt_private_notification_iterator *priv_notif_iter);
diff --git a/bindings/python/bt2/bt2/native_btpacket.i b/bindings/python/bt2/bt2/native_btpacket.i
new file mode 100644 (file)
index 0000000..6887711
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_ctf_packet;
+
+/* Functions */
+struct bt_ctf_packet *bt_ctf_packet_create(
+               struct bt_ctf_stream *stream);
+struct bt_ctf_stream *bt_ctf_packet_get_stream(
+               struct bt_ctf_packet *packet);
+struct bt_ctf_field *bt_ctf_packet_get_header(
+               struct bt_ctf_packet *packet);
+int bt_ctf_packet_set_header(
+               struct bt_ctf_packet *packet, struct bt_ctf_field *header);
+struct bt_ctf_field *bt_ctf_packet_get_context(
+               struct bt_ctf_packet *packet);
+int bt_ctf_packet_set_context(
+               struct bt_ctf_packet *packet, struct bt_ctf_field *context);
diff --git a/bindings/python/bt2/bt2/native_btplugin.i b/bindings/python/bt2/bt2/native_btplugin.i
new file mode 100644 (file)
index 0000000..5df3fcf
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Types */
+struct bt_plugin;
+struct bt_plugin_set;
+
+/* Status */
+enum bt_plugin_status {
+       BT_PLUGIN_STATUS_OK = 0,
+       BT_PLUGIN_STATUS_ERROR = -1,
+       BT_PLUGIN_STATUS_NOMEM = -4,
+};
+
+/* Plugin functions */
+struct bt_plugin *bt_plugin_find(const char *plugin_name);
+struct bt_component_class *bt_plugin_find_component_class(
+               const char *plugin_name, const char *component_class_name,
+               enum bt_component_class_type component_class_type);
+struct bt_plugin_set *bt_plugin_create_all_from_file(const char *path);
+struct bt_plugin_set *bt_plugin_create_all_from_dir(const char *path,
+               int recurse);
+struct bt_plugin_set *bt_plugin_create_all_from_static(void);
+const char *bt_plugin_get_name(struct bt_plugin *plugin);
+const char *bt_plugin_get_author(struct bt_plugin *plugin);
+const char *bt_plugin_get_license(struct bt_plugin *plugin);
+const char *bt_plugin_get_description(struct bt_plugin *plugin);
+const char *bt_plugin_get_path(struct bt_plugin *plugin);
+enum bt_plugin_status bt_plugin_get_version(struct bt_plugin *plugin,
+               unsigned int *OUTPUTINIT, unsigned int *OUTPUTINIT,
+               unsigned int *OUTPUTINIT, const char **BTOUTSTR);
+int64_t bt_plugin_get_component_class_count(struct bt_plugin *plugin);
+struct bt_component_class *bt_plugin_get_component_class_by_index(
+               struct bt_plugin *plugin, uint64_t index);
+struct bt_component_class *bt_plugin_get_component_class_by_name_and_type(
+               struct bt_plugin *plugin, const char *name,
+               enum bt_component_class_type type);
+
+/* Plugin set functions */
+int64_t bt_plugin_set_get_plugin_count(struct bt_plugin_set *plugin_set);
+struct bt_plugin *bt_plugin_set_get_plugin(struct bt_plugin_set *plugin_set,
+               uint64_t index);
diff --git a/bindings/python/bt2/bt2/native_btport.i b/bindings/python/bt2/bt2/native_btport.i
new file mode 100644 (file)
index 0000000..e88de58
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_port;
+struct bt_private_port;
+
+/* Status */
+enum bt_port_status {
+       BT_PORT_STATUS_OK = 0,
+       BT_PORT_STATUS_ERROR = -1,
+       BT_PORT_STATUS_INVALID = -2,
+};
+
+/* Port type */
+enum bt_port_type {
+       BT_PORT_TYPE_INPUT = 0,
+       BT_PORT_TYPE_OUTPUT = 1,
+       BT_PORT_TYPE_UNKOWN = -1,
+};
+
+/* Functions (public) */
+const char *bt_port_get_name(struct bt_port *port);
+enum bt_port_type bt_port_get_type(struct bt_port *port);
+struct bt_connection *bt_port_get_connection(struct bt_port *port);
+struct bt_component *bt_port_get_component(struct bt_port *port);
+enum bt_port_status bt_port_disconnect(struct bt_port *port);
+int bt_port_is_connected(struct bt_port *port);
+
+/* Functions (private) */
+struct bt_port *bt_port_from_private_port(struct bt_private_port *private_port);
+struct bt_private_connection *bt_private_port_get_private_connection(
+               struct bt_private_port *private_port);
+struct bt_private_component *bt_private_port_get_private_component(
+               struct bt_private_port *private_port);
+enum bt_port_status bt_private_port_remove_from_component(
+               struct bt_private_port *private_port);
+void *bt_private_port_get_user_data(
+               struct bt_private_port *private_port);
diff --git a/bindings/python/bt2/bt2/native_btref.i b/bindings/python/bt2/bt2/native_btref.i
new file mode 100644 (file)
index 0000000..dacf916
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Functions */
+void *bt_get(void *obj);
+void bt_put(void *obj);
diff --git a/bindings/python/bt2/bt2/native_btstream.i b/bindings/python/bt2/bt2/native_btstream.i
new file mode 100644 (file)
index 0000000..39747bc
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2017 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_ctf_stream;
+
+/* Functions */
+struct bt_ctf_stream *bt_ctf_stream_create(
+               struct bt_ctf_stream_class *stream_class,
+               const char *name);
+struct bt_ctf_stream *bt_ctf_stream_create_with_id(
+               struct bt_ctf_stream_class *stream_class,
+               const char *name, uint64_t id);
+const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream);
+int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream);
+struct bt_ctf_stream_class *bt_ctf_stream_get_class(
+               struct bt_ctf_stream *stream);
diff --git a/bindings/python/bt2/bt2/native_btstreamclass.i b/bindings/python/bt2/bt2/native_btstreamclass.i
new file mode 100644 (file)
index 0000000..8244057
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_ctf_stream_class;
+
+/* Functions */
+struct bt_ctf_stream_class *bt_ctf_stream_class_create_empty(
+               const char *name);
+struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name);
+struct bt_ctf_trace *bt_ctf_stream_class_get_trace(
+               struct bt_ctf_stream_class *stream_class);
+const char *bt_ctf_stream_class_get_name(
+               struct bt_ctf_stream_class *stream_class);
+int bt_ctf_stream_class_set_name(
+               struct bt_ctf_stream_class *stream_class, const char *name);
+int64_t bt_ctf_stream_class_get_id(
+               struct bt_ctf_stream_class *stream_class);
+int bt_ctf_stream_class_set_id(
+               struct bt_ctf_stream_class *stream_class, uint64_t id);
+struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
+               struct bt_ctf_stream_class *stream_class);
+int bt_ctf_stream_class_set_packet_context_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *packet_context_type);
+struct bt_ctf_field_type *
+bt_ctf_stream_class_get_event_header_type(
+               struct bt_ctf_stream_class *stream_class);
+int bt_ctf_stream_class_set_event_header_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *event_header_type);
+struct bt_ctf_field_type *
+bt_ctf_stream_class_get_event_context_type(
+               struct bt_ctf_stream_class *stream_class);
+int bt_ctf_stream_class_set_event_context_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *event_context_type);
+int64_t bt_ctf_stream_class_get_event_class_count(
+               struct bt_ctf_stream_class *stream_class);
+struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
+               struct bt_ctf_stream_class *stream_class, uint64_t index);
+struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
+               struct bt_ctf_stream_class *stream_class, uint64_t id);
+int bt_ctf_stream_class_add_event_class(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_event_class *event_class);
diff --git a/bindings/python/bt2/bt2/native_bttrace.i b/bindings/python/bt2/bt2/native_bttrace.i
new file mode 100644 (file)
index 0000000..8947ae0
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Type */
+struct bt_ctf_trace;
+
+/* Functions */
+struct bt_ctf_trace *bt_ctf_trace_create(void);
+const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace_class);
+int bt_ctf_trace_set_name(struct bt_ctf_trace *trace_class,
+               const char *name);
+enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
+               struct bt_ctf_trace *trace_class);
+int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace_class,
+               enum bt_ctf_byte_order native_byte_order);
+BTUUID bt_ctf_trace_get_uuid(
+               struct bt_ctf_trace *trace_class);
+int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace_class,
+               BTUUID uuid);
+int64_t bt_ctf_trace_get_environment_field_count(
+               struct bt_ctf_trace *trace_class);
+const char *
+bt_ctf_trace_get_environment_field_name_by_index(
+               struct bt_ctf_trace *trace_class, uint64_t index);
+struct bt_value *
+bt_ctf_trace_get_environment_field_value_by_index(struct bt_ctf_trace *trace_class,
+               uint64_t index);
+struct bt_value *
+bt_ctf_trace_get_environment_field_value_by_name(
+               struct bt_ctf_trace *trace_class, const char *name);
+int bt_ctf_trace_set_environment_field(
+               struct bt_ctf_trace *trace_class, const char *name,
+               struct bt_value *value);
+struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type(
+               struct bt_ctf_trace *trace_class);
+int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace_class,
+               struct bt_ctf_field_type *packet_header_type);
+int64_t bt_ctf_trace_get_clock_class_count(
+               struct bt_ctf_trace *trace_class);
+struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
+               struct bt_ctf_trace *trace_class, uint64_t index);
+struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
+               struct bt_ctf_trace *trace_class, const char *name);
+int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace_class,
+               struct bt_ctf_clock_class *clock_class);
+int64_t bt_ctf_trace_get_stream_class_count(
+               struct bt_ctf_trace *trace_class);
+struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
+               struct bt_ctf_trace *trace_class, uint64_t index);
+struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
+               struct bt_ctf_trace *trace_class, uint64_t id);
+int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace_class,
+               struct bt_ctf_stream_class *stream_class);
+int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace_class);
+struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
+               struct bt_ctf_trace *trace_class, uint64_t index);
+int bt_ctf_trace_is_static(struct bt_ctf_trace *trace_class);
+int bt_ctf_trace_set_is_static(struct bt_ctf_trace *trace_class);
+
+/* Helper functions for Python */
+%{
+void trace_is_static_listener(struct bt_ctf_trace *trace, void *py_callable)
+{
+       PyObject *py_trace_ptr = NULL;
+       PyObject *py_res = NULL;
+
+       py_trace_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace),
+               SWIGTYPE_p_bt_ctf_trace, 0);
+       if (!py_trace_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_ptr);
+       assert(py_res == Py_None);
+       Py_DECREF(py_trace_ptr);
+       Py_DECREF(py_res);
+}
+
+void trace_listener_removed(struct bt_ctf_trace *trace, void *py_callable)
+{
+       assert(py_callable);
+       Py_DECREF(py_callable);
+}
+
+static int bt_py3_trace_add_is_staitc_listener(unsigned long long trace_addr,
+               PyObject *py_callable)
+{
+       struct bt_ctf_trace *trace = (void *) trace_addr;
+       int ret = 0;
+
+       assert(trace);
+       assert(py_callable);
+       ret = bt_ctf_trace_add_is_static_listener(trace,
+               trace_is_static_listener, trace_listener_removed, py_callable);
+       if (ret >= 0) {
+               Py_INCREF(py_callable);
+       }
+
+       return ret;
+}
+%}
+
+int bt_py3_trace_add_is_staitc_listener(unsigned long long trace_addr,
+               PyObject *py_callable);
diff --git a/bindings/python/bt2/bt2/native_btvalues.i b/bindings/python/bt2/bt2/native_btvalues.i
new file mode 100644 (file)
index 0000000..6563bce
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@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.
+ */
+
+/* Remove prefix from `bt_value_null` */
+%rename(value_null) bt_value_null;
+
+/* Type and status */
+struct bt_value;
+
+enum bt_value_type {
+       BT_VALUE_TYPE_UNKNOWN =         -1,
+       BT_VALUE_TYPE_NULL =            0,
+       BT_VALUE_TYPE_BOOL =            1,
+       BT_VALUE_TYPE_INTEGER =         2,
+       BT_VALUE_TYPE_FLOAT =           3,
+       BT_VALUE_TYPE_STRING =          4,
+       BT_VALUE_TYPE_ARRAY =           5,
+       BT_VALUE_TYPE_MAP =             6,
+};
+
+enum bt_value_type bt_value_get_type(const struct bt_value *object);
+
+enum bt_value_status {
+       BT_VALUE_STATUS_FROZEN =        -4,
+       BT_VALUE_STATUS_CANCELLED =     -3,
+       BT_VALUE_STATUS_INVAL =         -22,
+       BT_VALUE_STATUS_ERROR =         -1,
+       BT_VALUE_STATUS_OK =            0,
+};
+
+/* Null value object singleton */
+struct bt_value * const bt_value_null;
+
+/* Common functions */
+enum bt_value_status bt_value_freeze(struct bt_value *object);
+int bt_value_is_frozen(const struct bt_value *object);
+struct bt_value *bt_value_copy(const struct bt_value *object);
+int bt_value_compare(const struct bt_value *object_a,
+               const struct bt_value *object_b);
+
+/* Boolean value object functions */
+struct bt_value *bt_value_bool_create(void);
+struct bt_value *bt_value_bool_create_init(int val);
+enum bt_value_status bt_value_bool_get(
+               const struct bt_value *bool_obj, int *OUTPUT);
+enum bt_value_status bt_value_bool_set(struct bt_value *bool_obj,
+               int val);
+
+/* Integer value object functions */
+struct bt_value *bt_value_integer_create(void);
+struct bt_value *bt_value_integer_create_init(int64_t val);
+enum bt_value_status bt_value_integer_get(
+               const struct bt_value *integer_obj, int64_t *OUTPUT);
+enum bt_value_status bt_value_integer_set(
+               struct bt_value *integer_obj, int64_t val);
+
+/* Floating point number value object functions */
+struct bt_value *bt_value_float_create(void);
+struct bt_value *bt_value_float_create_init(double val);
+enum bt_value_status bt_value_float_get(
+               const struct bt_value *float_obj, double *OUTPUT);
+enum bt_value_status bt_value_float_set(
+               struct bt_value *float_obj, double val);
+
+/* String value object functions */
+struct bt_value *bt_value_string_create(void);
+struct bt_value *bt_value_string_create_init(const char *val);
+enum bt_value_status bt_value_string_set(struct bt_value *string_obj,
+               const char *val);
+enum bt_value_status bt_value_string_get(
+               const struct bt_value *string_obj, const char **BTOUTSTR);
+
+/* Array value object functions */
+struct bt_value *bt_value_array_create(void);
+int bt_value_array_size(const struct bt_value *array_obj);
+struct bt_value *bt_value_array_get(const struct bt_value *array_obj,
+               size_t index);
+enum bt_value_status bt_value_array_append(struct bt_value *array_obj,
+               struct bt_value *element_obj);
+enum bt_value_status bt_value_array_set(struct bt_value *array_obj,
+               size_t index, struct bt_value *element_obj);
+
+/* Map value object functions */
+struct bt_value *bt_value_map_create(void);
+int bt_value_map_size(const struct bt_value *map_obj);
+struct bt_value *bt_value_map_get(const struct bt_value *map_obj,
+               const char *key);
+int bt_value_map_has_key(const struct bt_value *map_obj,
+               const char *key);
+enum bt_value_status bt_value_map_insert(
+               struct bt_value *map_obj, const char *key,
+               struct bt_value *element_obj);
+struct bt_value *bt_value_map_extend(struct bt_value *base_map_obj,
+               struct bt_value *extension_map_obj);
+
+%{
+struct bt_value_map_get_keys_private_data {
+       struct bt_value *keys;
+};
+
+static int bt_value_map_get_keys_private_cb(const char *key,
+               struct bt_value *object, void *data)
+{
+       enum bt_value_status status;
+       struct bt_value_map_get_keys_private_data *priv_data = data;
+
+       status = bt_value_array_append_string(priv_data->keys, key);
+       if (status != BT_VALUE_STATUS_OK) {
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static struct bt_value *bt_value_map_get_keys_private(
+               const struct bt_value *map_obj)
+{
+       enum bt_value_status status;
+       struct bt_value_map_get_keys_private_data data;
+
+       data.keys = bt_value_array_create();
+       if (!data.keys) {
+               return NULL;
+       }
+
+       status = bt_value_map_foreach(map_obj, bt_value_map_get_keys_private_cb,
+               &data);
+       if (status != BT_VALUE_STATUS_OK) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (data.keys) {
+               BT_PUT(data.keys);
+       }
+
+end:
+       return data.keys;
+}
+%}
+
+struct bt_value *bt_value_map_get_keys_private(const struct bt_value *map_obj);
diff --git a/bindings/python/bt2/bt2/native_btversion.i b/bindings/python/bt2/bt2/native_btversion.i
new file mode 100644 (file)
index 0000000..e368b9b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@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.
+ */
+
+%{
+#include <babeltrace/version.h>
+%}
+
+/* Version functions */
+int bt_version_get_major(void);
+int bt_version_get_minor(void);
+int bt_version_get_patch(void);
+const char *bt_version_get_extra(void);
diff --git a/bindings/python/bt2/bt2/notification.py b/bindings/python/bt2/bt2/notification.py
new file mode 100644 (file)
index 0000000..2ad8487
--- /dev/null
@@ -0,0 +1,465 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.clock_class_priority_map
+import bt2.packet
+import bt2.stream
+import bt2.event
+import copy
+import bt2
+
+
+def _create_from_ptr(ptr):
+    notif_type = native_bt.notification_get_type(ptr)
+    cls = None
+
+    if notif_type not in _NOTIF_TYPE_TO_CLS:
+        raise bt2.Error('unknown notification type: {}'.format(notif_type))
+
+    return _NOTIF_TYPE_TO_CLS[notif_type]._create_from_ptr(ptr)
+
+
+class _Notification(object._Object):
+    pass
+
+
+class _CopyableNotification(_Notification):
+    def __copy__(self):
+        return self._copy(lambda obj: obj)
+
+    def __deepcopy__(self, memo):
+        cpy = self._copy(copy.deepcopy)
+        memo[id(self)] = cpy
+        return cpy
+
+
+class EventNotification(_CopyableNotification):
+    _TYPE = native_bt.NOTIFICATION_TYPE_EVENT
+
+    def __init__(self, event, cc_prio_map=None):
+        utils._check_type(event, bt2.event._Event)
+
+        if cc_prio_map is not None:
+            utils._check_type(cc_prio_map, bt2.clock_class_priority_map.ClockClassPriorityMap)
+            cc_prio_map_ptr = cc_prio_map._ptr
+        else:
+            cc_prio_map_ptr = None
+
+        ptr = native_bt.notification_event_create(event._ptr, cc_prio_map_ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create event notification object')
+
+        super().__init__(ptr)
+
+    @property
+    def event(self):
+        event_ptr = native_bt.notification_event_get_event(self._ptr)
+        assert(event_ptr)
+        return bt2.event._create_from_ptr(event_ptr)
+
+    @property
+    def clock_class_priority_map(self):
+        cc_prio_map_ptr = native_bt.notification_event_get_clock_class_priority_map(self._ptr)
+        assert(cc_prio_map_ptr)
+        return bt2.clock_class_priority_map.ClockClassPriorityMap._create_from_ptr(cc_prio_map_ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        self_props = (
+            self.event,
+            self.clock_class_priority_map,
+        )
+        other_props = (
+            other.event,
+            other.clock_class_priority_map,
+        )
+        return self_props == other_props
+
+    def _copy(self, copy_func):
+        # We can always use references here because those properties are
+        # frozen anyway if they are part of a notification. Since the
+        # user cannot modify them after copying the notification, it's
+        # useless to copy/deep-copy them.
+        return EventNotification(self.event, self.clock_class_priority_map)
+
+
+class PacketBeginningNotification(_CopyableNotification):
+    _TYPE = native_bt.NOTIFICATION_TYPE_PACKET_BEGIN
+
+    def __init__(self, packet):
+        utils._check_type(packet, bt2.packet._Packet)
+        ptr = native_bt.notification_packet_begin_create(packet._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create packet beginning notification object')
+
+        super().__init__(ptr)
+
+    @property
+    def packet(self):
+        packet_ptr = native_bt.notification_packet_begin_get_packet(self._ptr)
+        assert(packet_ptr)
+        return bt2.packet._Packet._create_from_ptr(packet_ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        return self.packet == other.packet
+
+    def _copy(self, copy_func):
+        # We can always use references here because those properties are
+        # frozen anyway if they are part of a notification. Since the
+        # user cannot modify them after copying the notification, it's
+        # useless to copy/deep-copy them.
+        return PacketBeginningNotification(self.packet)
+
+
+class PacketEndNotification(_CopyableNotification):
+    _TYPE = native_bt.NOTIFICATION_TYPE_PACKET_END
+
+    def __init__(self, packet):
+        utils._check_type(packet, bt2.packet._Packet)
+        ptr = native_bt.notification_packet_end_create(packet._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create packet end notification object')
+
+        super().__init__(ptr)
+
+    @property
+    def packet(self):
+        packet_ptr = native_bt.notification_packet_end_get_packet(self._ptr)
+        assert(packet_ptr)
+        return bt2.packet._Packet._create_from_ptr(packet_ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        return self.packet == other.packet
+
+    def _copy(self, copy_func):
+        # We can always use references here because those properties are
+        # frozen anyway if they are part of a notification. Since the
+        # user cannot modify them after copying the notification, it's
+        # useless to copy/deep-copy them.
+        return PacketEndNotification(self.packet)
+
+
+class StreamBeginningNotification(_CopyableNotification):
+    _TYPE = native_bt.NOTIFICATION_TYPE_STREAM_BEGIN
+
+    def __init__(self, stream):
+        utils._check_type(stream, bt2.stream._Stream)
+        ptr = native_bt.notification_stream_begin_create(stream._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create stream beginning notification object')
+
+        super().__init__(ptr)
+
+    @property
+    def stream(self):
+        stream_ptr = native_bt.notification_stream_begin_get_stream(self._ptr)
+        assert(stream_ptr)
+        return bt2.stream._create_from_ptr(stream_ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        return self.stream == other.stream
+
+    def _copy(self, copy_func):
+        # We can always use references here because those properties are
+        # frozen anyway if they are part of a notification. Since the
+        # user cannot modify them after copying the notification, it's
+        # useless to copy/deep-copy them.
+        return StreamBeginningNotification(self.stream)
+
+
+class StreamEndNotification(_CopyableNotification):
+    _TYPE = native_bt.NOTIFICATION_TYPE_STREAM_END
+
+    def __init__(self, stream):
+        utils._check_type(stream, bt2.stream._Stream)
+        ptr = native_bt.notification_stream_end_create(stream._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create stream end notification object')
+
+        super().__init__(ptr)
+
+    @property
+    def stream(self):
+        stream_ptr = native_bt.notification_stream_end_get_stream(self._ptr)
+        assert(stream_ptr)
+        return bt2.stream._create_from_ptr(stream_ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        return self.stream == other.stream
+
+    def _copy(self, copy_func):
+        # We can always use references here because those properties are
+        # frozen anyway if they are part of a notification. Since the
+        # user cannot modify them after copying the notification, it's
+        # useless to copy/deep-copy them.
+        return StreamEndNotification(self.stream)
+
+
+class InactivityNotification(_CopyableNotification):
+    _TYPE = native_bt.NOTIFICATION_TYPE_INACTIVITY
+
+    def __init__(self, cc_prio_map=None):
+        if cc_prio_map is not None:
+            utils._check_type(cc_prio_map, bt2.clock_class_priority_map.ClockClassPriorityMap)
+            cc_prio_map_ptr = cc_prio_map._ptr
+        else:
+            cc_prio_map_ptr = None
+
+        ptr = native_bt.notification_inactivity_create(cc_prio_map_ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create inactivity notification object')
+
+        super().__init__(ptr)
+
+    @property
+    def clock_class_priority_map(self):
+        cc_prio_map_ptr = native_bt.notification_inactivity_get_clock_class_priority_map(self._ptr)
+        assert(cc_prio_map_ptr)
+        return bt2.clock_class_priority_map.ClockClassPriorityMap._create_from_ptr(cc_prio_map_ptr)
+
+    def clock_value(self, clock_class):
+        utils._check_type(clock_class, bt2.ClockClass)
+        clock_value_ptr = native_bt.notification_inactivity_get_clock_value(self._ptr,
+                                                                            clock_class._ptr)
+
+        if clock_value_ptr is None:
+            return
+
+        clock_value = bt2.clock_class._create_clock_value_from_ptr(clock_value_ptr)
+        return clock_value
+
+    def add_clock_value(self, clock_value):
+        utils._check_type(clock_value, bt2.clock_class._ClockValue)
+        ret = native_bt.notification_inactivity_set_clock_value(self._ptr,
+                                                                clock_value._ptr)
+        utils._handle_ret(ret, "cannot set inactivity notification object's clock value")
+
+    def _get_clock_values(self):
+        clock_values = {}
+
+        for clock_class in self.clock_class_priority_map:
+            clock_value = self.clock_value(clock_class)
+
+            if clock_value is None:
+                continue
+
+            clock_values[clock_class] = clock_value
+
+        return clock_values
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        self_props = (
+            self.clock_class_priority_map,
+            self._get_clock_values(),
+        )
+        other_props = (
+            other.clock_class_priority_map,
+            other._get_clock_values(),
+        )
+        return self_props == other_props
+
+    def __copy__(self):
+        cpy = InactivityNotification(self.clock_class_priority_map)
+
+        for clock_class in self.clock_class_priority_map:
+            clock_value = self.clock_value(clock_class)
+
+            if clock_value is None:
+                continue
+
+            cpy.add_clock_value(clock_value)
+
+        return cpy
+
+    def __deepcopy__(self, memo):
+        cc_prio_map_cpy = copy.deepcopy(self.clock_class_priority_map)
+        cpy = InactivityNotification(cc_prio_map_cpy)
+
+        # copy clock values
+        for orig_clock_class in self.clock_class_priority_map:
+            orig_clock_value = self.clock_value(orig_clock_class)
+
+            if orig_clock_value is None:
+                continue
+
+            # find equivalent, copied clock class in CC priority map copy
+            for cpy_clock_class in cc_prio_map_cpy:
+                if cpy_clock_class == orig_clock_class:
+                    break
+
+            # create copy of clock value from copied clock class
+            clock_value_cpy = cpy_clock_class(orig_clock_value.cycles)
+
+            # set copied clock value in notification copy
+            cpy.add_clock_value(clock_value_cpy)
+
+        memo[id(self)] = cpy
+        return cpy
+
+
+class _DiscardedElementsNotification(_Notification):
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        self_props = (
+            self.count,
+            self.stream,
+            self.beginning_clock_value,
+            self.end_clock_value,
+        )
+        other_props = (
+            other.count,
+            other.stream,
+            other.beginning_clock_value,
+            other.end_clock_value,
+        )
+        return self_props == other_props
+
+
+class _DiscardedPacketsNotification(_DiscardedElementsNotification):
+    _TYPE = native_bt.NOTIFICATION_TYPE_DISCARDED_PACKETS
+
+    @property
+    def count(self):
+        count = native_bt.notification_discarded_packets_get_count(self._ptr)
+        assert(count >= 0)
+        return count
+
+    @property
+    def stream(self):
+        stream_ptr = native_bt.notification_discarded_packets_get_stream(self._ptr)
+        assert(stream_ptr)
+        return bt2.stream._create_from_ptr(stream_ptr)
+
+    @property
+    def beginning_clock_value(self):
+        clock_value_ptr = native_bt.notification_discarded_packets_get_begin_clock_value(self._ptr)
+
+        if clock_value_ptr is None:
+            return
+
+        clock_value = bt2.clock_class._create_clock_value_from_ptr(clock_value_ptr)
+        return clock_value
+
+    @property
+    def end_clock_value(self):
+        clock_value_ptr = native_bt.notification_discarded_packets_get_end_clock_value(self._ptr)
+
+        if clock_value_ptr is None:
+            return
+
+        clock_value = bt2.clock_class._create_clock_value_from_ptr(clock_value_ptr)
+        return clock_value
+
+
+class _DiscardedEventsNotification(_DiscardedElementsNotification):
+    _TYPE = native_bt.NOTIFICATION_TYPE_DISCARDED_EVENTS
+
+    @property
+    def count(self):
+        count = native_bt.notification_discarded_events_get_count(self._ptr)
+        assert(count >= 0)
+        return count
+
+    @property
+    def stream(self):
+        stream_ptr = native_bt.notification_discarded_events_get_stream(self._ptr)
+        assert(stream_ptr)
+        return bt2.stream._create_from_ptr(stream_ptr)
+
+    @property
+    def beginning_clock_value(self):
+        clock_value_ptr = native_bt.notification_discarded_events_get_begin_clock_value(self._ptr)
+
+        if clock_value_ptr is None:
+            return
+
+        clock_value = bt2.clock_class._create_clock_value_from_ptr(clock_value_ptr)
+        return clock_value
+
+    @property
+    def end_clock_value(self):
+        clock_value_ptr = native_bt.notification_discarded_events_get_end_clock_value(self._ptr)
+
+        if clock_value_ptr is None:
+            return
+
+        clock_value = bt2.clock_class._create_clock_value_from_ptr(clock_value_ptr)
+        return clock_value
+
+
+_NOTIF_TYPE_TO_CLS = {
+    native_bt.NOTIFICATION_TYPE_EVENT: EventNotification,
+    native_bt.NOTIFICATION_TYPE_PACKET_BEGIN: PacketBeginningNotification,
+    native_bt.NOTIFICATION_TYPE_PACKET_END: PacketEndNotification,
+    native_bt.NOTIFICATION_TYPE_STREAM_BEGIN: StreamBeginningNotification,
+    native_bt.NOTIFICATION_TYPE_STREAM_END: StreamEndNotification,
+    native_bt.NOTIFICATION_TYPE_INACTIVITY: InactivityNotification,
+    native_bt.NOTIFICATION_TYPE_DISCARDED_PACKETS: _DiscardedPacketsNotification,
+    native_bt.NOTIFICATION_TYPE_DISCARDED_EVENTS: _DiscardedEventsNotification,
+}
diff --git a/bindings/python/bt2/bt2/notification_iterator.py b/bindings/python/bt2/bt2/notification_iterator.py
new file mode 100644 (file)
index 0000000..39b6bf0
--- /dev/null
@@ -0,0 +1,115 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.notification
+import collections.abc
+import bt2.component
+import bt2
+
+
+class _NotificationIterator(collections.abc.Iterator):
+    def _handle_status(self, status, gen_error_msg):
+        if status == native_bt.NOTIFICATION_ITERATOR_STATUS_CANCELED:
+            raise bt2.NotificationIteratorCanceled
+        elif status == native_bt.NOTIFICATION_ITERATOR_STATUS_AGAIN:
+            raise bt2.TryAgain
+        elif status == native_bt.NOTIFICATION_ITERATOR_STATUS_END:
+            raise bt2.Stop
+        elif status == native_bt.NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED:
+            raise bt2.UnsupportedFeature
+        elif status < 0:
+            raise bt2.Error(gen_error_msg)
+
+    def __next__(self):
+        raise NotImplementedError
+
+
+class _GenericNotificationIterator(object._Object, _NotificationIterator):
+    @property
+    def component(self):
+        comp_ptr = native_bt.notification_iterator_get_component(self._ptr)
+        assert(comp_ptr)
+        return bt2.component._create_generic_component_from_ptr(comp_ptr)
+
+    def _get_notif(self):
+        notif_ptr = native_bt.notification_iterator_get_notification(self._ptr)
+        utils._handle_ptr(notif_ptr, "cannot get notification iterator object's current notification object")
+        return bt2.notification._create_from_ptr(notif_ptr)
+
+    def _next(self):
+        status = native_bt.notification_iterator_next(self._ptr)
+        self._handle_status(status,
+                            'unexpected error: cannot advance the notification iterator')
+
+    def __next__(self):
+        self._next()
+        return self._get_notif()
+
+
+class _UserNotificationIterator(_NotificationIterator):
+    def __new__(cls, ptr):
+        # User iterator objects are always created by the native side,
+        # that is, never instantiated directly by Python code.
+        #
+        # The native code calls this, then manually calls
+        # self.__init__() without the `ptr` argument. The user has
+        # access to self.component during this call, thanks to this
+        # self._ptr argument being set.
+        #
+        # self._ptr is NOT owned by this object here, so there's nothing
+        # to do in __del__().
+        self = super().__new__(cls)
+        self._ptr = ptr
+        return self
+
+    def __init__(self):
+        pass
+
+    @property
+    def _component(self):
+        return native_bt.py3_get_user_component_from_user_notif_iter(self._ptr)
+
+    @property
+    def addr(self):
+        return int(self._ptr)
+
+    def _finalize(self):
+        pass
+
+    def __next__(self):
+        raise bt2.Stop
+
+    def _next_from_native(self):
+        # this can raise anything: it's catched by the native part
+        try:
+            notif = next(self)
+        except StopIteration:
+            raise bt2.Stop
+        except:
+            raise
+
+        utils._check_type(notif, bt2.notification._Notification)
+
+        # take a new reference for the native part
+        notif._get()
+        return int(notif._ptr)
diff --git a/bindings/python/bt2/bt2/object.py b/bindings/python/bt2/bt2/object.py
new file mode 100644 (file)
index 0000000..774027c
--- /dev/null
@@ -0,0 +1,81 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt
+import abc
+
+
+class _Object:
+    def __init__(self, ptr):
+        self._ptr = ptr
+
+    @property
+    def addr(self):
+        return int(self._ptr)
+
+    @classmethod
+    def _create_from_ptr(cls, ptr):
+        obj = cls.__new__(cls)
+        obj._ptr = ptr
+        return obj
+
+    def _get(self):
+        native_bt.get(self._ptr)
+
+    def __del__(self):
+        ptr = getattr(self, '_ptr', None)
+        native_bt.put(ptr)
+        self._ptr = None
+
+    def __repr__(self):
+        return '<{}.{} object @ {}>'.format(self.__class__.__module__,
+                                            self.__class__.__name__,
+                                            hex(self.addr))
+
+
+class _PrivateObject:
+    def __del__(self):
+        pub_ptr = getattr(self, '_pub_ptr', None)
+        native_bt.put(pub_ptr)
+        self._pub_ptr = None
+        super().__del__()
+
+
+class _Freezable(metaclass=abc.ABCMeta):
+    @property
+    def is_frozen(self):
+        return self._is_frozen()
+
+    @property
+    def frozen(self):
+        return self.is_frozen
+
+    def freeze(self):
+        self._freeze()
+
+    @abc.abstractmethod
+    def _is_frozen(self):
+        pass
+
+    @abc.abstractmethod
+    def _freeze(self):
+        pass
diff --git a/bindings/python/bt2/bt2/packet.py b/bindings/python/bt2/bt2/packet.py
new file mode 100644 (file)
index 0000000..1fba03c
--- /dev/null
@@ -0,0 +1,107 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2016-2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import bt2.fields
+import bt2.stream
+import copy
+import abc
+import bt2
+
+
+class _Packet(object._Object):
+    @property
+    def stream(self):
+        stream_ptr = native_bt.ctf_packet_get_stream(self._ptr)
+        assert(stream_ptr)
+        return bt2.stream._Stream._create_from_ptr(stream_ptr)
+
+    @property
+    def header_field(self):
+        field_ptr = native_bt.ctf_packet_get_header(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.fields._create_from_ptr(field_ptr)
+
+    @header_field.setter
+    def header_field(self, header_field):
+        header_field_ptr = None
+
+        if header_field is not None:
+            utils._check_type(header_field, bt2.fields._Field)
+            header_field_ptr = header_field._ptr
+
+        ret = native_bt.ctf_packet_set_header(self._ptr, header_field_ptr)
+        utils._handle_ret(ret, "cannot set packet object's header field")
+
+    @property
+    def context_field(self):
+        field_ptr = native_bt.ctf_packet_get_context(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.fields._create_from_ptr(field_ptr)
+
+    @context_field.setter
+    def context_field(self, context_field):
+        context_field_ptr = None
+
+        if context_field is not None:
+            utils._check_type(context_field, bt2.fields._Field)
+            context_field_ptr = context_field._ptr
+
+        ret = native_bt.ctf_packet_set_context(self._ptr, context_field_ptr)
+        utils._handle_ret(ret, "cannot set packet object's context field")
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        if self.addr == other.addr:
+            return True
+
+        self_props = (
+            self.header_field,
+            self.context_field,
+        )
+        other_props = (
+            other.header_field,
+            other.context_field,
+        )
+        return self_props == other_props
+
+    def _copy(self, copy_func):
+        cpy = self.stream.create_packet()
+        cpy.header_field = copy_func(self.header_field)
+        cpy.context_field = copy_func(self.context_field)
+        return cpy
+
+    def __copy__(self):
+        return self._copy(copy.copy)
+
+    def __deepcopy__(self, memo):
+        cpy = self._copy(copy.deepcopy)
+        memo[id(self)] = cpy
+        return cpy
diff --git a/bindings/python/bt2/bt2/plugin.py b/bindings/python/bt2/bt2/plugin.py
new file mode 100644 (file)
index 0000000..a37e763
--- /dev/null
@@ -0,0 +1,215 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import collections.abc
+import bt2.component
+import os.path
+import bt2
+
+
+def find_plugins(path, recurse=True):
+    utils._check_str(path)
+    utils._check_bool(recurse)
+    plugin_set_ptr = None
+
+    if os.path.isfile(path):
+        plugin_set_ptr = native_bt.plugin_create_all_from_file(path)
+    elif os.path.isdir(path):
+        plugin_set_ptr = native_bt.plugin_create_all_from_dir(path, int(recurse))
+
+    if plugin_set_ptr is None:
+        return
+
+    return _PluginSet._create_from_ptr(plugin_set_ptr)
+
+
+def find_plugin(name):
+    utils._check_str(name)
+    ptr = native_bt.plugin_find(name)
+
+    if ptr is None:
+        return
+
+    return _Plugin._create_from_ptr(ptr)
+
+
+class _PluginSet(object._Object, collections.abc.Sequence):
+    def __len__(self):
+        count = native_bt.plugin_set_get_plugin_count(self._ptr)
+        assert(count >= 0)
+        return count
+
+    def __getitem__(self, index):
+        utils._check_uint64(index)
+
+        if index >= len(self):
+            raise IndexError
+
+        plugin_ptr = native_bt.plugin_set_get_plugin(self._ptr, index)
+        assert(plugin_ptr)
+        return _Plugin._create_from_ptr(plugin_ptr)
+
+
+class _PluginVersion:
+    def __init__(self, major, minor, patch, extra):
+        self._major = major
+        self._minor = minor
+        self._patch = patch
+        self._extra = extra
+
+    @property
+    def major(self):
+        return self._major
+
+    @property
+    def minor(self):
+        return self._minor
+
+    @property
+    def patch(self):
+        return self._patch
+
+    @property
+    def extra(self):
+        return self._extra
+
+    def __str__(self):
+        extra = ''
+
+        if self._extra is not None:
+            extra = self._extra
+
+        return '{}.{}.{}{}'.format(self._major, self._minor, self._patch, extra)
+
+
+class _PluginComponentClassesIterator(collections.abc.Iterator):
+    def __init__(self, plugin_comp_cls):
+        self._plugin_comp_cls = plugin_comp_cls
+        self._at = 0
+
+    def __next__(self):
+        plugin_ptr = self._plugin_comp_cls._plugin._ptr
+        comp_cls_type = self._plugin_comp_cls._comp_cls_type
+        total = native_bt.plugin_get_component_class_count(plugin_ptr)
+
+        while True:
+            if self._at == total:
+                raise StopIteration
+
+            comp_cls_ptr = native_bt.plugin_get_component_class_by_index(plugin_ptr,
+                                                                         self._at)
+            assert(comp_cls_ptr)
+            cc_type = native_bt.component_class_get_type(comp_cls_ptr)
+            self._at += 1
+
+            if cc_type == comp_cls_type:
+                break
+
+            native_bt.put(comp_cls_ptr)
+
+        name = native_bt.component_class_get_name(comp_cls_ptr)
+        native_bt.put(comp_cls_ptr)
+        assert(name is not None)
+        return name
+
+
+class _PluginComponentClasses(collections.abc.Mapping):
+    def __init__(self, plugin, comp_cls_type):
+        self._plugin = plugin
+        self._comp_cls_type = comp_cls_type
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        cc_ptr = native_bt.plugin_get_component_class_by_name_and_type(self._plugin._ptr,
+                                                                       key,
+                                                                       self._comp_cls_type)
+
+        if cc_ptr is None:
+            raise KeyError(key)
+
+        return bt2.component._create_generic_component_class_from_ptr(cc_ptr)
+
+    def __len__(self):
+        count = 0
+        total = native_bt.plugin_get_component_class_count(self._plugin._ptr)
+
+        for at in range(total):
+            comp_cls_ptr = native_bt.plugin_get_component_class_by_index(self._plugin._ptr,
+                                                                         at)
+            assert(comp_cls_ptr)
+            cc_type = native_bt.component_class_get_type(comp_cls_ptr)
+
+            if cc_type == self._comp_cls_type:
+                count += 1
+
+            native_bt.put(comp_cls_ptr)
+
+        return count
+
+    def __iter__(self):
+        return _PluginComponentClassesIterator(self)
+
+
+class _Plugin(object._Object):
+    @property
+    def name(self):
+        name = native_bt.plugin_get_name(self._ptr)
+        assert(name is not None)
+        return name
+
+    @property
+    def author(self):
+        return native_bt.plugin_get_author(self._ptr)
+
+    @property
+    def license(self):
+        return native_bt.plugin_get_license(self._ptr)
+
+    @property
+    def description(self):
+        return native_bt.plugin_get_description(self._ptr)
+
+    @property
+    def path(self):
+        return native_bt.plugin_get_path(self._ptr)
+
+    @property
+    def version(self):
+        status, major, minor, patch, extra = native_bt.plugin_get_version(self._ptr)
+
+        if status < 0:
+            return
+
+        return _PluginVersion(major, minor, patch, extra)
+
+    @property
+    def source_component_classes(self):
+        return _PluginComponentClasses(self, native_bt.COMPONENT_CLASS_TYPE_SOURCE)
+
+    @property
+    def filter_component_classes(self):
+        return _PluginComponentClasses(self, native_bt.COMPONENT_CLASS_TYPE_FILTER)
+
+    @property
+    def sink_component_classes(self):
+        return _PluginComponentClasses(self, native_bt.COMPONENT_CLASS_TYPE_SINK)
diff --git a/bindings/python/bt2/bt2/port.py b/bindings/python/bt2/bt2/port.py
new file mode 100644 (file)
index 0000000..ed168c4
--- /dev/null
@@ -0,0 +1,160 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import native_bt, object, utils
+import collections.abc
+import bt2.component
+import bt2.connection
+import copy
+import bt2
+
+
+def _create_from_ptr(ptr):
+    port_type = native_bt.port_get_type(ptr)
+
+    if port_type == native_bt.PORT_TYPE_INPUT:
+        cls = _InputPort
+    elif port_type == native_bt.PORT_TYPE_OUTPUT:
+        cls = _OutputPort
+    else:
+        raise bt2.Error('unknown port type: {}'.format(port_type))
+
+    return cls._create_from_ptr(ptr)
+
+
+def _create_private_from_ptr(ptr):
+    pub_ptr = native_bt.port_from_private_port(ptr)
+    utils._handle_ptr(pub_ptr, 'cannot get port object from private port object')
+    port_type = native_bt.port_get_type(pub_ptr)
+    assert(port_type == native_bt.PORT_TYPE_INPUT or port_type == native_bt.PORT_TYPE_OUTPUT)
+
+    if port_type == native_bt.PORT_TYPE_INPUT:
+        cls = _PrivateInputPort
+    elif port_type == native_bt.PORT_TYPE_OUTPUT:
+        cls = _PrivateOutputPort
+
+    obj = cls._create_from_ptr(ptr)
+    obj._pub_ptr = pub_ptr
+    return obj
+
+
+class _Port(object._Object):
+    @staticmethod
+    def _name(ptr):
+        name = native_bt.port_get_name(ptr)
+        assert(name is not None)
+        return name
+
+    @staticmethod
+    def _disconnect(ptr):
+        status = native_bt.port_disconnect(ptr)
+
+        if status < 0:
+            raise bt2.Error('cannot disconnect port')
+
+    @property
+    def name(self):
+        return self._name(self._ptr)
+
+    @property
+    def component(self):
+        comp_ptr = native_bt.port_get_component(self._ptr)
+
+        if comp_ptr is None:
+            return
+
+        return bt2.component._create_generic_component_from_ptr(comp_ptr)
+
+    @property
+    def connection(self):
+        conn_ptr = native_bt.port_get_connection(self._ptr)
+
+        if conn_ptr is None:
+            return
+
+        return bt2.connection._Connection._create_from_ptr(conn_ptr)
+
+    @property
+    def is_connected(self):
+        return self.connection is not None
+
+    def disconnect(self):
+        self._disconnect(self._ptr)
+
+    def __eq__(self, other):
+        if type(other) is not type(self):
+            return False
+
+        return self.addr == other.addr
+
+
+class _InputPort(_Port):
+    pass
+
+
+class _OutputPort(_Port):
+    pass
+
+
+class _PrivatePort(object._PrivateObject, _Port):
+    @property
+    def name(self):
+        return self._name(self._pub_ptr)
+
+    @property
+    def component(self):
+        comp_ptr = native_bt.private_port_get_private_component(self._ptr)
+
+        if comp_ptr is None:
+            return
+
+        pub_comp_ptr = native_bt.component_from_private_component(comp_ptr)
+        assert(pub_comp_ptr)
+        comp = bt2.component._create_generic_component_from_ptr(pub_comp_ptr)
+        native_bt.put(comp_ptr)
+        return comp
+
+    @property
+    def connection(self):
+        conn_ptr = native_bt.private_port_get_private_connection(self._ptr)
+
+        if conn_ptr is None:
+            return
+
+        return bt2.connection._create_private_from_ptr(conn_ptr)
+
+    def remove_from_component(self):
+        status = native_bt.private_port_remove_from_component(self._ptr)
+
+        if status < 0:
+            raise bt2.Error("cannot remove port from component")
+
+    def disconnect(self):
+        self._disconnect(self._pub_ptr)
+
+
+class _PrivateInputPort(_PrivatePort, _InputPort):
+    pass
+
+
+class _PrivateOutputPort(_PrivatePort, _OutputPort):
+    pass
diff --git a/bindings/python/bt2/bt2/py_plugin.py b/bindings/python/bt2/bt2/py_plugin.py
new file mode 100644 (file)
index 0000000..b845030
--- /dev/null
@@ -0,0 +1,135 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@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.
+
+from bt2 import utils
+import bt2.component
+
+
+def plugin_component_class(component_class):
+    if not issubclass(component_class, bt2.component._UserComponent):
+        raise TypeError('component class is not a subclass of a user component class')
+
+    component_class._bt_plugin_component_class = None
+    return component_class
+
+
+def register_plugin(module_name, name, description=None, author=None,
+                    license=None, version=None):
+    import sys
+
+    if module_name not in sys.modules:
+        raise RuntimeError("cannot find module '{}' in loaded modules".format(module_name))
+
+    utils._check_str(name)
+
+    if description is not None:
+        utils._check_str(description)
+
+    if author is not None:
+        utils._check_str(author)
+
+    if license is not None:
+        utils._check_str(license)
+
+    if version is not None:
+        if not _validate_version(version):
+            raise ValueError('wrong version: expecting a tuple: (major, minor, patch) or (major, minor, patch, extra)')
+
+    sys.modules[module_name]._bt_plugin_info = _PluginInfo(name, description,
+                                                           author, license,
+                                                           version)
+
+
+def _validate_version(version):
+    if version is None:
+        return True
+
+    if not isinstance(version, tuple):
+        return False
+
+    if len(version) < 3 or len(version) > 4:
+        return False
+
+    if not isinstance(version[0], int):
+        return False
+
+    if not isinstance(version[1], int):
+        return False
+
+    if not isinstance(version[2], int):
+        return False
+
+    if len(version) == 4:
+        if not isinstance(version[3], str):
+            return False
+
+    return True
+
+
+class _PluginInfo:
+    def __init__(self, name, description, author, license, version):
+        self.name = name
+        self.description = description
+        self.author = author
+        self.license = license
+        self.version = version
+        self.comp_class_addrs = None
+
+
+# called by the BT plugin system
+def _try_load_plugin_module(path):
+    import importlib.machinery
+    import inspect
+    import hashlib
+
+    if path is None:
+        raise TypeError('missing path')
+
+    # In order to load the module uniquely from its path, even from
+    # different files which have the same basename, we hash the path
+    # and prefix with `bt_plugin_`. This is its key in sys.modules.
+    h = hashlib.sha256()
+    h.update(path.encode())
+    module_name = 'bt_plugin_{}'.format(h.hexdigest())
+
+    # try loading the module: any raised exception is catched by the caller
+    mod = importlib.machinery.SourceFileLoader(module_name, path).load_module()
+
+    # we have the module: look for its plugin info first
+    if not hasattr(mod, '_bt_plugin_info'):
+        raise RuntimeError("missing '_bt_plugin_info' module attribute")
+
+    plugin_info = mod._bt_plugin_info
+
+    # search for user component classes
+    def is_user_comp_class(obj):
+        if not inspect.isclass(obj):
+            return False
+
+        if not hasattr(obj, '_bt_plugin_component_class'):
+            return False
+
+        return True
+
+    comp_class_entries = inspect.getmembers(mod, is_user_comp_class)
+    plugin_info.comp_class_addrs = [entry[1].addr for entry in comp_class_entries]
+    return plugin_info
diff --git a/bindings/python/bt2/bt2/stream.py b/bindings/python/bt2/bt2/stream.py
new file mode 100644 (file)
index 0000000..