Update Python bindings and tests to match the latest API
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 15 Jun 2017 18:46:40 +0000 (14:46 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 15 Aug 2017 16:03:57 +0000 (12:03 -0400)
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
77 files changed:
bindings/Makefile.am
bindings/python/bt2/Makefile.am
bindings/python/bt2/__init__.py.in
bindings/python/bt2/clock_class.py
bindings/python/bt2/clock_class_priority_map.py [new file with mode: 0644]
bindings/python/bt2/component.py
bindings/python/bt2/connection.py [new file with mode: 0644]
bindings/python/bt2/ctf_writer.py
bindings/python/bt2/event.py
bindings/python/bt2/event_class.py
bindings/python/bt2/field_types.py
bindings/python/bt2/fields.py
bindings/python/bt2/graph.py [new file with mode: 0644]
bindings/python/bt2/logging.c [new file with mode: 0644]
bindings/python/bt2/logging.h [new file with mode: 0644]
bindings/python/bt2/logging.py [new file with mode: 0644]
bindings/python/bt2/native_bt.i
bindings/python/bt2/native_btccpriomap.i [new file with mode: 0644]
bindings/python/bt2/native_btclockclass.i
bindings/python/bt2/native_btcomponent.i
bindings/python/bt2/native_btcomponentclass.i
bindings/python/bt2/native_btconnection.i [new file with mode: 0644]
bindings/python/bt2/native_btctfwriter.i
bindings/python/bt2/native_btevent.i
bindings/python/bt2/native_bteventclass.i
bindings/python/bt2/native_btfields.i
bindings/python/bt2/native_btft.i
bindings/python/bt2/native_btgraph.i [new file with mode: 0644]
bindings/python/bt2/native_btlogging.i [new file with mode: 0644]
bindings/python/bt2/native_btnotification.i
bindings/python/bt2/native_btnotifiter.i
bindings/python/bt2/native_btpacket.i
bindings/python/bt2/native_btplugin.i
bindings/python/bt2/native_btport.i [new file with mode: 0644]
bindings/python/bt2/native_btref.i
bindings/python/bt2/native_btstream.i
bindings/python/bt2/native_btstreamclass.i
bindings/python/bt2/native_bttrace.i
bindings/python/bt2/native_btvalues.i
bindings/python/bt2/native_btversion.i [new file with mode: 0644]
bindings/python/bt2/notification.py
bindings/python/bt2/notification_iterator.py
bindings/python/bt2/object.py
bindings/python/bt2/packet.py
bindings/python/bt2/plugin.py
bindings/python/bt2/port.py [new file with mode: 0644]
bindings/python/bt2/stream.py
bindings/python/bt2/stream_class.py
bindings/python/bt2/trace.py
bindings/python/bt2/utils.py
bindings/python/bt2/values.py
configure.ac
tests/bindings/python/bt2/.coveragerc
tests/bindings/python/bt2/Makefile.am
tests/bindings/python/bt2/test_clock_class.py
tests/bindings/python/bt2/test_clock_class_priority_map.py [new file with mode: 0644]
tests/bindings/python/bt2/test_comp_notif_iter.py [deleted file]
tests/bindings/python/bt2/test_component.py [new file with mode: 0644]
tests/bindings/python/bt2/test_component_class.py [new file with mode: 0644]
tests/bindings/python/bt2/test_connection.py [new file with mode: 0644]
tests/bindings/python/bt2/test_ctf_writer_clock.py
tests/bindings/python/bt2/test_event.py
tests/bindings/python/bt2/test_event_class.py
tests/bindings/python/bt2/test_field_types.py
tests/bindings/python/bt2/test_fields.py
tests/bindings/python/bt2/test_graph.py [new file with mode: 0644]
tests/bindings/python/bt2/test_notification.py [new file with mode: 0644]
tests/bindings/python/bt2/test_notification_iterator.py [new file with mode: 0644]
tests/bindings/python/bt2/test_packet.py
tests/bindings/python/bt2/test_plugin.py [new file with mode: 0644]
tests/bindings/python/bt2/test_port.py [new file with mode: 0644]
tests/bindings/python/bt2/test_stream.py
tests/bindings/python/bt2/test_stream_class.py
tests/bindings/python/bt2/test_trace.py
tests/bindings/python/bt2/test_values.py
tests/bindings/python/bt2/testall.sh.in
tests/utils/Makefile.am

index 6341f126ccc08fe4890cb854a7cb354a09f0bea2..773e43adb0f20a6fdbd1ba9b71d09324f22794ff 100644 (file)
@@ -1,4 +1,3 @@
 if ENABLE_PYTHON_BINDINGS
-#Disabled temporarily (work in progress)
-#SUBDIRS = python
+SUBDIRS = python
 endif
index 4a96fdb35b8b4735a01a4c89a1dafd98a4bca3fe..7b20517f7c231e2b4b1aadea39c0af7d15d12279 100644 (file)
@@ -3,44 +3,55 @@ NATIVE_MODULE = native_bt
 
 # interface dependencies (without `native_bt` prefix and `.i` extension)
 NATIVE_MODULE_DEPS =   \
+       ccpriomap       \
        clockclass      \
-       eventclass      \
+       component       \
+       componentclass  \
+       connection      \
+       ctfwriter       \
        event           \
+       eventclass      \
        fields          \
        ft              \
+       graph           \
+       logging         \
+       notification    \
+       notifiter       \
        packet          \
+       plugin          \
+       port            \
        ref             \
-       streamclass     \
        stream          \
+       streamclass     \
        trace           \
        values          \
-       ctfwriter       \
-       componentclass  \
-       component       \
-       notification    \
-       notifiter       \
-       plugin
+       version
 
 # Python modules (without `.py` extension)
-EXTRA_MODULES =                \
-       clock_class             \
-       event_class             \
-       event                   \
-       fields                  \
-       field_types             \
-       object                  \
-       packet                  \
-       stream_class            \
-       stream                  \
-       trace                   \
-       utils                   \
-       values                  \
-       ctf_writer              \
-       component               \
-       notification            \
-       notification_iterator   \
-       plugin                  \
-       py_plugin
+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
 
 # automatically generated file lists
 EXTRA_MODULES_PY = $(addprefix $(srcdir)/,$(addsuffix .py,$(EXTRA_MODULES)))
@@ -64,19 +75,20 @@ $(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)
 
 # native_bt module
-_native_bt_la_SOURCES = native_bt_wrap.c
+_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 = $(GLIB_CFLAGS) $(PYTHON_INCLUDE) -I$(srcdir) $(AM_CFLAGS)
-_native_bt_la_LIBS = $(GLIB_LIBS)
+_native_bt_la_CFLAGS = $(PYTHON_INCLUDE) -I$(srcdir) $(AM_CFLAGS)
 _native_bt_la_LIBADD = \
        $(top_builddir)/lib/libbabeltrace.la \
-       $(top_builddir)/formats/ctf/libbabeltrace-ctf.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);     \
+                       cp -f "$(srcdir)/$$file" "$(builddir)"; \
                done;                                           \
        fi
 
@@ -84,7 +96,7 @@ all-local:
 clean-local:
        @if [ x"$(srcdir)" != x"$(builddir)" ]; then            \
                for file in $(EXTRA_MODULES_PY); do             \
-                       rm -f $(srcdir)/$$file $(builddir);     \
+                       rm -f "$(srcdir)/$$file" "$(builddir)"; \
                done;                                           \
        fi
 
index ba196289f28258dce0ccd23c320bbb48d8bdbb1d..ebab24ab780ace043984a0603686f4d3b53a1425 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -24,18 +24,59 @@ __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):
@@ -46,11 +87,11 @@ class CreationError(Error):
     pass
 
 
-class FrozenError(Error):
+class Frozen(Error):
     pass
 
 
-class NoSuchPluginError(Error):
+class NoSuchPlugin(Error):
     pass
 
 
@@ -58,6 +99,10 @@ class UnsupportedFeature(Exception):
     pass
 
 
+class NoSinkComponent(Exception):
+    pass
+
+
 class TryAgain(Exception):
     pass
 
@@ -66,12 +111,42 @@ class Stop(StopIteration):
     pass
 
 
-class IncompleteUserClassError(Error):
+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
index adfba44815051af552c054cbc8734a96ab35989f..24b1db680783341aca38b764f0dce08eb42aa80d 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -22,6 +22,7 @@
 
 from bt2 import native_bt, object, utils
 import uuid as uuidp
+import numbers
 import bt2
 
 
@@ -40,6 +41,9 @@ class ClockClassOffset:
     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
@@ -49,10 +53,11 @@ class ClockClassOffset:
 
 
 class ClockClass(object._Object):
-    def __init__(self, name, description=None, frequency=None, precision=None,
+    def __init__(self, name, frequency, description=None, precision=None,
                  offset=None, is_absolute=None, uuid=None):
         utils._check_str(name)
-        ptr = native_bt.ctf_clock_class_create(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')
@@ -113,10 +118,21 @@ class ClockClass(object._Object):
         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)
-        utils._handle_ptr(name, "cannot get clock class object's name")
+        assert(name is not None)
         return name
 
     @name.setter
@@ -127,8 +143,7 @@ class ClockClass(object._Object):
 
     @property
     def description(self):
-        description = native_bt.ctf_clock_class_get_description(self._ptr)
-        return description
+        return native_bt.ctf_clock_class_get_description(self._ptr)
 
     @description.setter
     def description(self, description):
@@ -139,10 +154,7 @@ class ClockClass(object._Object):
     @property
     def frequency(self):
         frequency = native_bt.ctf_clock_class_get_frequency(self._ptr)
-
-        if utils._is_m1ull(frequency):
-            raise bt2.Error("cannot get clock class object's frequency")
-
+        assert(frequency >= 1)
         return frequency
 
     @frequency.setter
@@ -154,10 +166,7 @@ class ClockClass(object._Object):
     @property
     def precision(self):
         precision = native_bt.ctf_clock_class_get_precision(self._ptr)
-
-        if utils._is_m1ull(precision):
-            raise bt2.Error("cannot get clock class object's precision")
-
+        assert(precision >= 0)
         return precision
 
     @precision.setter
@@ -169,9 +178,9 @@ class ClockClass(object._Object):
     @property
     def offset(self):
         ret, offset_s = native_bt.ctf_clock_class_get_offset_s(self._ptr)
-        utils._handle_ret(ret, "cannot get clock class object's offset (seconds)")
+        assert(ret == 0)
         ret, offset_cycles = native_bt.ctf_clock_class_get_offset_cycles(self._ptr)
-        utils._handle_ret(ret, "cannot get clock class object's offset (cycles)")
+        assert(ret == 0)
         return ClockClassOffset(offset_s, offset_cycles)
 
     @offset.setter
@@ -184,8 +193,8 @@ class ClockClass(object._Object):
 
     @property
     def is_absolute(self):
-        is_absolute = native_bt.ctf_clock_class_get_is_absolute(self._ptr)
-        utils._handle_ret(is_absolute, "cannot get clock class object's absoluteness")
+        is_absolute = native_bt.ctf_clock_class_is_absolute(self._ptr)
+        assert(is_absolute >= 0)
         return is_absolute > 0
 
     @is_absolute.setter
@@ -199,7 +208,7 @@ class ClockClass(object._Object):
         uuid_bytes = native_bt.ctf_clock_class_get_uuid(self._ptr)
 
         if uuid_bytes is None:
-            raise bt2.Error("cannot get clock class object's UUID")
+            return
 
         return uuidp.UUID(bytes=uuid_bytes)
 
@@ -209,7 +218,7 @@ class ClockClass(object._Object):
         ret = native_bt.ctf_clock_class_set_uuid(self._ptr, uuid.bytes)
         utils._handle_ret(ret, "cannot set clock class object's UUID")
 
-    def create_clock_value(self, cycles):
+    def __call__(self, cycles):
         return _ClockValue(self._ptr, cycles)
 
 
@@ -231,13 +240,13 @@ class _ClockValue(object._Object):
     @property
     def clock_class(self):
         ptr = native_bt.ctf_clock_value_get_class(self._ptr)
-        utils._handle_ptr(ptr, "cannot get clock value object's clock class object")
+        assert(ptr)
         return ClockClass._create_from_ptr(ptr)
 
     @property
     def cycles(self):
         ret, cycles = native_bt.ctf_clock_value_get_value(self._ptr)
-        utils._handle_ret(ret, "cannot get clock value object's cycles")
+        assert(ret == 0)
         return cycles
 
     @property
@@ -247,6 +256,9 @@ class _ClockValue(object._Object):
         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
@@ -254,12 +266,12 @@ class _ClockValue(object._Object):
         if self.addr == other.addr:
             return True
 
-        self_props = self.clock_class.addr, self.cycles
-        other_props = other.clock_class.addr, other.cycles
+        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.create_clock_value(self.cycles)
+        return self.clock_class(self.cycles)
 
     def __deepcopy__(self, memo):
         cpy = self.__copy__()
diff --git a/bindings/python/bt2/clock_class_priority_map.py b/bindings/python/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
index 6ee1a145a9bc708263352500f3ed50a31fdde819..927fd061b8aadaea05ce6366af1d3a03fe898a17 100644 (file)
@@ -24,8 +24,15 @@ 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
@@ -35,7 +42,9 @@ import bt2
 class _GenericComponentClass(object._Object):
     @property
     def name(self):
-        return native_bt.component_class_get_name(self._ptr)
+        name = native_bt.component_class_get_name(self._ptr)
+        assert(name is not None)
+        return name
 
     @property
     def description(self):
@@ -48,17 +57,15 @@ class _GenericComponentClass(object._Object):
     def query(self, obj, params=None):
         return _query(self._ptr, obj, params)
 
-    def __call__(self, params=None, name=None):
-        params = bt2.create_value(params)
-        comp_ptr = native_bt.component_create_with_init_method_data(self._ptr,
-                                                                    name,
-                                                                    params._ptr,
-                                                                    None)
-
-        if comp_ptr is None:
-            raise bt2.CreationError('cannot create component object')
+    def __eq__(self, other):
+        if not isinstance(other, _GenericComponentClass):
+            try:
+                if not issubclass(other, _UserComponent):
+                    return False
+            except TypeError:
+                return False
 
-        return _create_generic_component_from_ptr(comp_ptr)
+        return self.addr == other.addr
 
 
 class _GenericSourceComponentClass(_GenericComponentClass):
@@ -73,94 +80,175 @@ 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 _CommonComponentMethods:
+class _Component:
     @property
     def name(self):
-        return native_bt.component_get_name(self._ptr)
+        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)
-        utils._handle_ptr(cc_ptr, "cannot get component object's class object")
+        assert(cc_ptr)
         return _create_generic_component_class_from_ptr(cc_ptr)
 
-    def _handle_status(self, 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 < 0:
-            raise bt2.Error(gen_error_msg)
-
-
-class _CommonSourceComponentMethods(_CommonComponentMethods):
-    def create_notification_iterator(self):
-        iter_ptr = native_bt.component_source_create_notification_iterator_with_init_method_data(self._ptr, None)
-
-        if iter_ptr is None:
-            raise bt2.CreationError('cannot create notification iterator object')
-
-        return bt2.notification_iterator._GenericNotificationIterator._create_from_ptr(iter_ptr)
+    def __eq__(self, other):
+        if not hasattr(other, 'addr'):
+            return False
 
+        return self.addr == other.addr
 
-class _CommonFilterComponentMethods(_CommonComponentMethods):
-    def create_notification_iterator(self):
-        iter_ptr = native_bt.component_filter_create_notification_iterator_with_init_method_data(self._ptr, None)
 
-        if iter_ptr is None:
-            raise bt2.CreationError('cannot create notification iterator object')
-
-        return bt2.notification_iterator._GenericNotificationIterator._create_from_ptr(iter_ptr)
+class _SourceComponent(_Component):
+    pass
 
-    def add_notification_iterator(self, notif_iter):
-        utils._check_type(notif_iter, bt2.notification_iterator._GenericNotificationIteratorMethods)
-        status = native_bt.component_filter_add_iterator(self._ptr, notif_iter._ptr)
-        self._handle_status(status, 'unexpected error: cannot add notification iterator to filter component object')
 
+class _FilterComponent(_Component):
+    pass
 
-class _CommonSinkComponentMethods(_CommonComponentMethods):
-    def add_notification_iterator(self, notif_iter):
-        utils._check_type(notif_iter, bt2.notification_iterator._GenericNotificationIteratorMethods)
-        status = native_bt.component_sink_add_iterator(self._ptr, notif_iter._ptr)
-        self._handle_status(status, 'unexpected error: cannot add notification iterator to sink component object')
 
-    def consume(self):
-        status = native_bt.component_sink_consume(self._ptr)
-        self._handle_status(status, 'unexpected error: cannot consume sink component object')
+class _SinkComponent(_Component):
+    pass
 
 
 # This is analogous to _GenericSourceComponentClass, but for source
 # component objects.
-class _GenericSourceComponent(object._Object, _CommonSourceComponentMethods):
-    pass
+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, _CommonFilterComponentMethods):
-    pass
+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, _CommonSinkComponentMethods):
-    pass
+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_CLS = {
+_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_CLS = {
+_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,
@@ -169,12 +257,12 @@ _COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_CLS = {
 
 def _create_generic_component_from_ptr(ptr):
     comp_cls_type = native_bt.component_get_class_type(ptr)
-    return _COMP_CLS_TYPE_TO_GENERIC_COMP_CLS[comp_cls_type]._create_from_ptr(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_CLS[comp_cls_type]._create_from_ptr(ptr)
+    return _COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS[comp_cls_type]._create_from_ptr(ptr)
 
 
 def _trim_docstring(docstring):
@@ -212,22 +300,19 @@ def _query(comp_cls_ptr, obj, params):
         params_ptr = params._ptr
 
     results_ptr = native_bt.component_class_query(comp_cls_ptr, obj,
-                                                       params_ptr)
+                                                  params_ptr)
 
     if results_ptr is None:
         raise bt2.Error('cannot query info with object "{}"'.format(obj))
 
-    if results_ptr == native_bt.value_null:
-        return
-
     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
+# 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
@@ -260,29 +345,29 @@ def _query(comp_cls_ptr, obj, params):
 #     def __init__(self, params, name, something_else):
 #         ...
 #
-# The user-defined component class can also have a _destroy() method
+# The user-defined component class can also have a _finalize() method
 # (do NOT use __del__()) to be notified when the component object is
-# (really) destroyed.
+# 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 MyNotificationIterator(bt2._UserNotificationIterator):
 #         ...
 #
-#     class MySource(bt2.UserSourceComponent,
+#     class MySource(bt2._UserSourceComponent,
 #                    notification_iterator_class=MyNotificationIterator):
 #         ...
 #
 # This notification iterator class must inherit
-# bt2.UserNotificationIterator, and it must define the _get() and
+# 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 _destroy()
-# method (again, do NOT use __del__()): this is called when the
-# notification iterator is (really) destroyed.
+# 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
@@ -297,14 +382,24 @@ class _UserComponentType(type):
         super().__init__(class_name, bases, namespace)
 
         # skip our own bases; they are never directly instantiated by the user
-        if class_name in ('_UserComponent', 'UserSourceComponent', 'UserFilterComponent', 'UserSinkComponent'):
+        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()
 
@@ -316,101 +411,64 @@ class _UserComponentType(type):
 
         iter_cls = kwargs.get('notification_iterator_class')
 
-        if UserSourceComponent in bases:
+        if _UserSourceComponent in bases:
             _UserComponentType._set_iterator_class(cls, iter_cls)
-            has_seek_time = _UserComponentType._has_seek_to_time_method(cls._iter_cls)
             cc_ptr = native_bt.py3_component_class_source_create(cls,
                                                                  comp_cls_name,
                                                                  comp_cls_descr,
-                                                                 comp_cls_help,
-                                                                 has_seek_time)
-        elif UserFilterComponent in bases:
+                                                                 comp_cls_help)
+        elif _UserFilterComponent in bases:
             _UserComponentType._set_iterator_class(cls, iter_cls)
-            has_seek_time = _UserComponentType._has_seek_to_time_method(cls._iter_cls)
             cc_ptr = native_bt.py3_component_class_filter_create(cls,
                                                                  comp_cls_name,
                                                                  comp_cls_descr,
-                                                                 comp_cls_help,
-                                                                 has_seek_time)
-        elif UserSinkComponent in bases:
+                                                                 comp_cls_help)
+        elif _UserSinkComponent in bases:
             if not hasattr(cls, '_consume'):
-                raise bt2.IncompleteUserClassError("cannot create component class '{}': missing a _consume() method".format(class_name))
+                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.IncompleteUserClassError("cannot find a known component class base in the bases of '{}'".format(class_name))
+            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 __call__(cls, *args, **kwargs):
-        # create instance
+    def _init_from_native(cls, comp_ptr, params_ptr):
+        # create instance, not user-initialized yet
         self = cls.__new__(cls)
 
-        # assign native component pointer received from caller
-        self._ptr = kwargs.get('__comp_ptr')
-        name = kwargs.get('name')
-
-        if self._ptr is None:
-            # called from Python code
-            self._belongs_to_native_component = False
-
-            # py3_component_create() will call self.__init__() with the
-            # desired arguments and keyword arguments. This is needed
-            # because functions such as
-            # bt_component_sink_set_minimum_input_count() can only be
-            # called _during_ the bt_component_create() call (in
-            # Python words: during self.__init__()).
-            #
-            # The arguments and keyword arguments to use for
-            # self.__init__() are put in the object itself to find them
-            # from the bt_component_create() function.
-            self._init_args = args
-            self._init_kwargs = kwargs
-            native_bt.py3_component_create(cls._cc_ptr, self, name)
-
-            # At this point, self._ptr should be set to non-None. If
-            # it's not, an error occured during the
-            # native_bt.py3_component_create() call. We consider this a
-            # creation error.
-            if self._ptr is None:
-                raise bt2.CreationError("cannot create component object from component class '{}'".format(cls.__name__))
-        else:
-            # Called from non-Python code (within
-            # bt_component_create()): call __init__() here, after
-            # removing the __comp_ptr keyword argument which is just for
-            # this __call__() method.
-            self._belongs_to_native_component = True
-            del kwargs['__comp_ptr']
+        # pointer to native private component object (weak/borrowed)
+        self._ptr = comp_ptr
 
-            # inject `name` into the keyword arguments
-            kwargs['name'] = self.name
-            self.__init__(*args, **kwargs)
+        # 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
 
-    @staticmethod
-    def _has_seek_to_time_method(iter_cls):
-        return hasattr(iter_cls, '_seek_to_time')
+    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.IncompleteUserClassError("cannot create component class '{}': missing notification iterator class".format(cls.__name__))
+            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.IncompleteUserClassError("cannot create component class '{}': notification iterator class does not inherit bt2.UserNotificationIterator".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, '_get'):
-            raise bt2.IncompleteUserClassError("cannot create component class '{}': notification iterator class is missing a _get() method".format(cls.__name__))
-
-        if not hasattr(iter_cls, '_next'):
-            raise bt2.IncompleteUserClassError("cannot create component class '{}': notification iterator class is missing a _next() method".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
 
@@ -430,131 +488,206 @@ class _UserComponentType(type):
     def addr(cls):
         return int(cls._cc_ptr)
 
-    def query(cls, action, params=None):
-        return _query(cls._cc_ptr, action, params)
+    def query(cls, obj, params=None):
+        return _query(cls._cc_ptr, obj, params)
 
-    def _query_from_bt(cls, action, 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
-        results = cls._query(action, params)
-        results = bt2.create_value(results)
+        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:
-            # steal the underlying native value object for the caller
+            # return new reference
+            results._get()
             results_addr = int(results._ptr)
-            results._ptr = None
 
         return results_addr
 
-    @staticmethod
-    def _query(action, params):
+    @classmethod
+    def _query(cls, obj, params):
         # BT catches this and returns NULL to the user
-        raise NotImplementedError
+        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 _ComponentInputNotificationIterators(collections.abc.Sequence):
-    def __init__(self, comp, count_func, get_func):
-        self._comp = comp
-        self._count_func = count_func
-        self._get_func = get_func
-
-    def __len__(self):
-        status, count = self._count_func(self._comp._ptr)
-        utils._handle_ret(status, "cannot get component object's input notification iterator count")
-        return count
-
-    def __getitem__(self, index):
-        utils._check_uint64(index)
-
-        if index >= len(self):
-            raise IndexError
+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
 
-        notif_iter_ptr = self._get_func(self._comp._ptr, index)
-        utils._handle_ptr(notif_iter_ptr, "cannot get component object's input notification iterator")
-        return bt2.notification_iterator._GenericNotificationIterator._create_from_ptr(notif_iter_ptr)
+    @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)
 
-class _UserComponent(metaclass=_UserComponentType):
     @property
     def addr(self):
         return int(self._ptr)
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, params=None):
         pass
 
-    def _destroy(self):
+    def _finalize(self):
         pass
 
-    def __del__(self):
-        if not self._belongs_to_native_component:
-            self._belongs_to_native_component = True
-            native_bt.py3_component_on_del(self)
-            native_bt.put(self._ptr)
-
-
-class UserSourceComponent(_UserComponent, _CommonSourceComponentMethods):
-    pass
-
+    def _accept_port_connection(self, port, other_port):
+        return True
 
-class UserFilterComponent(_UserComponent, _CommonFilterComponentMethods):
-    def _set_minimum_input_notification_iterator_count(self, count):
-        utils._check_uint64(count)
-        status = native_bt.component_filter_set_minimum_input_count(self._ptr, count)
-        self._handle_status(status, "unexpected error: cannot set filter component object's minimum input notification iterator count")
+    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)
 
-    _minimum_input_notification_iterator_count = property(fset=_set_minimum_input_notification_iterator_count)
+        if type(res) is not bool:
+            raise TypeError("'{}' is not a 'bool' object")
 
-    def _set_maximum_input_notification_iterator_count(self, count):
-        utils._check_uint64(count)
-        status = native_bt.component_filter_set_maximum_input_count(self._ptr, count)
-        self._handle_status(status, "unexpected error: cannot set filter component object's maximum input notification iterator count")
+        return res
 
-    _maximum_input_notification_iterator_count = property(fset=_set_maximum_input_notification_iterator_count)
+    def _port_connected(self, port, other_port):
+        pass
 
-    @property
-    def _input_notification_iterators(self):
-        return _ComponentInputNotificationIterators(self,
-                                                    native_bt.component_filter_get_input_count,
-                                                    native_bt.component_filter_get_input_iterator_private)
+    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)
 
-    def _add_iterator_from_bt(self, notif_iter_ptr):
-        notif_iter = bt2.notification_iterator._GenericNotificationIterator._create_from_ptr(notif_iter_ptr)
-        self._add_notification_iterator(notif_iter)
+        try:
+            self._port_connected(port, other_port_ptr)
+        except:
+            if not _NO_PRINT_TRACEBACK:
+                traceback.print_exc()
 
-    def _add_notification_iterator(self, notif_iter):
+    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)
 
-class UserSinkComponent(_UserComponent, _CommonSinkComponentMethods):
-    def _set_minimum_input_notification_iterator_count(self, count):
-        utils._check_uint64(count)
-        status = native_bt.component_sink_set_minimum_input_count(self._ptr, count)
-        self._handle_status(status, "unexpected error: cannot set sink component object's minimum input notification iterator count")
-
-    _minimum_input_notification_iterator_count = property(fset=_set_minimum_input_notification_iterator_count)
-
-    def _set_maximum_input_notification_iterator_count(self, count):
-        utils._check_uint64(count)
-        status = native_bt.component_sink_set_maximum_input_count(self._ptr, count)
-        self._handle_status(status, "unexpected error: cannot set sink component object's maximum input notification iterator count")
+        try:
+            self._port_disconnected(port)
+        except:
+            if not _NO_PRINT_TRACEBACK:
+                traceback.print_exc()
 
-    _maximum_input_notification_iterator_count = property(fset=_set_maximum_input_notification_iterator_count)
 
+class _UserSourceComponent(_UserComponent, _SourceComponent):
     @property
-    def _input_notification_iterators(self):
-        return _ComponentInputNotificationIterators(self,
-                                                    native_bt.component_sink_get_input_count,
-                                                    native_bt.component_sink_get_input_iterator_private)
-
-    def _add_iterator_from_bt(self, notif_iter_ptr):
-        notif_iter = bt2.notification_iterator._GenericNotificationIterator._create_from_ptr(notif_iter_ptr)
-        self._add_notification_iterator(notif_iter)
+    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)
 
-    def _add_notification_iterator(self, notif_iter):
-        pass
+    @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/connection.py b/bindings/python/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)
index 5a167cb2d33b6b27d3913d5703aee76f852dd0dc..0bbabaf4ce0cef2ae7f9b8b83f4cc692d0deb634 100644 (file)
@@ -98,7 +98,7 @@ class CtfWriterClock(object._Object):
     @property
     def name(self):
         name = native_bt.ctf_clock_get_name(self._ptr)
-        utils._handle_ptr(name, "cannot get CTF writer clock object's name")
+        assert(name is not None)
         return name
 
     @property
@@ -115,10 +115,7 @@ class CtfWriterClock(object._Object):
     @property
     def frequency(self):
         frequency = native_bt.ctf_clock_get_frequency(self._ptr)
-
-        if utils._is_m1ull(frequency):
-            raise bt2.Error("cannot get CTF writer clock object's frequency")
-
+        assert(frequency >= 1)
         return frequency
 
     @frequency.setter
@@ -130,10 +127,7 @@ class CtfWriterClock(object._Object):
     @property
     def precision(self):
         precision = native_bt.ctf_clock_get_precision(self._ptr)
-
-        if utils._is_m1ull(precision):
-            raise bt2.Error("cannot get CTF writer clock object's precision")
-
+        assert(precision >= 0)
         return precision
 
     @precision.setter
@@ -145,9 +139,9 @@ class CtfWriterClock(object._Object):
     @property
     def offset(self):
         ret, offset_s = native_bt.ctf_clock_get_offset_s(self._ptr)
-        utils._handle_ret(ret, "cannot get CTF writer clock object's offset (seconds)")
+        assert(ret == 0)
         ret, offset_cycles = native_bt.ctf_clock_get_offset(self._ptr)
-        utils._handle_ret(ret, "cannot get CTF writer clock object's offset (cycles)")
+        assert(ret == 0)
         return bt2.ClockClassOffset(offset_s, offset_cycles)
 
     @offset.setter
@@ -161,7 +155,7 @@ class CtfWriterClock(object._Object):
     @property
     def is_absolute(self):
         is_absolute = native_bt.ctf_clock_get_is_absolute(self._ptr)
-        utils._handle_ret(is_absolute, "cannot get CTF writer clock object's absoluteness")
+        assert(is_absolute >= 0)
         return is_absolute > 0
 
     @is_absolute.setter
@@ -173,10 +167,7 @@ class CtfWriterClock(object._Object):
     @property
     def uuid(self):
         uuid_bytes = native_bt.ctf_clock_get_uuid(self._ptr)
-
-        if uuid_bytes is None:
-            raise bt2.Error("cannot get CTF writer clock object's UUID")
-
+        assert(uuid_bytes is not None)
         return uuidp.UUID(bytes=uuid_bytes)
 
     @uuid.setter
@@ -305,13 +296,13 @@ class CtfWriter(object._Object):
     @property
     def trace(self):
         trace_ptr = native_bt.ctf_writer_get_trace(self._ptr)
-        utils._handle_ptr(name, "cannot get CTF writer object's trace class")
+        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)
-        utils._handle_ptr(metadata_string, "cannot get CTF writer object's metadata string")
+        assert(metadata_string is not None)
         return metadata_string
 
     def flush_metadata(self):
index 1ca642c40ea2641489067656e85ba42ea55eda91..2e11de087380c6f7fe46436bd2f2c81395cd0e3b 100644 (file)
@@ -143,7 +143,7 @@ class _Event(object._Object):
 
     @property
     def payload_field(self):
-        field_ptr = native_bt.ctf_event_get_payload_field(self._ptr)
+        field_ptr = native_bt.ctf_event_get_event_payload(self._ptr)
 
         if field_ptr is None:
             return
@@ -158,7 +158,7 @@ class _Event(object._Object):
             utils._check_type(payload, bt2.fields._Field)
             payload_ptr = payload._ptr
 
-        ret = native_bt.ctf_event_set_payload_field(self._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):
@@ -173,7 +173,7 @@ class _Event(object._Object):
         utils._handle_ret(ret, "cannot get clock value object's cycles")
         return cycles
 
-    def get_clock_value(self, clock_class):
+    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)
@@ -184,7 +184,7 @@ class _Event(object._Object):
         clock_value = bt2.clock_class._create_clock_value_from_ptr(clock_value_ptr)
         return clock_value
 
-    def set_clock_value(self, 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)
@@ -293,12 +293,16 @@ class _Event(object._Object):
         cpy.context_field = copy_func(self.context_field)
         cpy.payload_field = copy_func(self.payload_field)
 
-        # copy known clock values
+        # 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.get_clock_value(clock_class)
+            clock_value = self.clock_value(clock_class)
 
             if clock_value is not None:
-                cpy.set_clock_value(clock_value)
+                cpy.add_clock_value(clock_value)
 
         return cpy
 
index 6d82b64eabe6cf4ee1ade8698d6efffebf61d558..fb527ad7dce6bad27b039b4151901c36df537cc7 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -29,58 +29,29 @@ import copy
 import bt2
 
 
-class _EventClassAttributesIterator(collections.abc.Iterator):
-    def __init__(self, attributes):
-        self._attributes = attributes
-        self._at = 0
-
-    def __next__(self):
-        if self._at == len(self._attributes):
-            raise StopIteration
-
-        name = native_bt.ctf_event_class_get_attribute_name(self._attributes._event_class_ptr,
-                                                            self._at)
-        utils._handle_ptr("cannot get event class object's attribute name")
-        self._at += 1
-        return name
-
-
-class _EventClassAttributes(collections.abc.MutableMapping):
-    def __init__(self, event_class_ptr):
-        self._event_class_ptr = event_class_ptr
-
-    def __getitem__(self, key):
-        utils._check_str(key)
-        value_ptr = native_bt.ctf_event_class_get_attribute_value_by_name(self._event_class_ptr,
-                                                                          key)
-
-        if value_ptr is None:
-            raise KeyError(key)
-
-        return bt2.values._create_from_ptr(value_ptr)
-
-    def __setitem__(self, key, value):
-        utils._check_str(key)
-        value = bt2.create_value(value)
-        ret = native_bt.ctf_event_class_set_attribute(self._event_class_ptr, key,
-                                                      value._ptr)
-        utils._handle_ret(ret, "cannot set event class object's attribute")
-
-    def __delitem__(self, key):
-        raise NotImplementedError
-
-    def __len__(self):
-        count = native_bt.ctf_event_class_get_attribute_count(self._event_class_ptr)
-        utils._handle_ret(count, "cannot get event class object's attribute count")
-        return count
-
-    def __iter__(self):
-        return _EventClassAttributesIterator(self)
+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, context_field_type=None,
-                 payload_field_type=None, attributes=None):
+    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)
 
@@ -92,16 +63,18 @@ class EventClass(object._Object):
         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
 
-        if attributes is not None:
-            for name, value in attributes.items():
-                self.attributes[name] = value
-
     @property
     def stream_class(self):
         sc_ptr = native_bt.ctf_event_class_get_stream_class(self._ptr)
@@ -109,10 +82,6 @@ class EventClass(object._Object):
         if sc_ptr is not None:
             return bt2.StreamClass._create_from_ptr(sc_ptr)
 
-    @property
-    def attributes(self):
-        return _EventClassAttributes(self._ptr)
-
     @property
     def name(self):
         return native_bt.ctf_event_class_get_name(self._ptr)
@@ -120,11 +89,7 @@ class EventClass(object._Object):
     @property
     def id(self):
         id = native_bt.ctf_event_class_get_id(self._ptr)
-
-        if utils._is_m1ull(id):
-            raise bt2.Error("cannot get event class object's ID")
-
-        return id
+        return id if id >= 0 else None
 
     @id.setter
     def id(self, id):
@@ -132,6 +97,48 @@ class EventClass(object._Object):
         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)
@@ -187,19 +194,19 @@ class EventClass(object._Object):
         if self.addr == other.addr:
             return True
 
-        self_attributes = {name: val for name, val in self.attributes.items()}
-        other_attributes = {name: val for name, val in other.attributes.items()}
         self_props = (
-            self_attributes,
             self.name,
             self.id,
+            self.log_level,
+            self.emf_uri,
             self.context_field_type,
             self.payload_field_type
         )
         other_props = (
-            other_attributes,
             other.name,
             other.id,
+            other.log_level,
+            other.emf_uri,
             other.context_field_type,
             other.payload_field_type
         )
@@ -209,8 +216,11 @@ class EventClass(object._Object):
         cpy = EventClass(self.name)
         cpy.id = self.id
 
-        for name, value in self.attributes.items():
-            cpy.attributes[name] = value
+        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)
index 5268836c48236ad8e499b54f1a59c1e861b34bcc..3a4e820f8ec1a0c05f3d792529859f2e2307ab19 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -103,7 +103,7 @@ class _AlignmentProp:
     @property
     def alignment(self):
         alignment = native_bt.ctf_field_type_get_alignment(self._ptr)
-        utils._handle_ret(alignment, "cannot get field type object's alignment")
+        assert(alignment >= 0)
         return alignment
 
     @alignment.setter
@@ -117,7 +117,7 @@ class _ByteOrderProp:
     @property
     def byte_order(self):
         bo = native_bt.ctf_field_type_get_byte_order(self._ptr)
-        utils._handle_ret(bo, "cannot get field type object's byte order")
+        assert(bo >= 0)
         return bo
 
     @byte_order.setter
@@ -162,26 +162,25 @@ class IntegerFieldType(_FieldType, _AlignmentProp, _ByteOrderProp):
     @property
     def size(self):
         size = native_bt.ctf_field_type_integer_get_size(self._ptr)
-        utils._handle_ret(size, "cannot get integer field type object's size")
+        assert(size >= 1)
         return size
 
     @property
     def is_signed(self):
-        is_signed = native_bt.ctf_field_type_integer_get_signed(self._ptr)
-        utils._handle_ret(is_signed,
-                    "cannot get integer field type object's signedness")
+        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_signed(self._ptr, int(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)
-        utils._handle_ret(base, "cannot get integer field type object's base")
+        assert(base >= 0)
         return base
 
     @base.setter
@@ -193,7 +192,7 @@ class IntegerFieldType(_FieldType, _AlignmentProp, _ByteOrderProp):
     @property
     def encoding(self):
         encoding = native_bt.ctf_field_type_integer_get_encoding(self._ptr)
-        utils._handle_ret(encoding, "cannot get integer field type object's encoding")
+        assert(encoding >= 0)
         return encoding
 
     @encoding.setter
@@ -205,7 +204,10 @@ class IntegerFieldType(_FieldType, _AlignmentProp, _ByteOrderProp):
     @property
     def mapped_clock_class(self):
         ptr = native_bt.ctf_field_type_integer_get_mapped_clock_class(self._ptr)
-        utils._handle_ptr(ptr, "cannot get integer field type object's mapped clock class")
+
+        if ptr is None:
+            return
+
         return bt2.ClockClass._create_from_ptr(ptr)
 
     @mapped_clock_class.setter
@@ -239,7 +241,7 @@ class FloatingPointNumberFieldType(_FieldType, _AlignmentProp, _ByteOrderProp):
     @property
     def exponent_size(self):
         exp_size = native_bt.ctf_field_type_floating_point_get_exponent_digits(self._ptr)
-        utils._handle_ret(exp_size, "cannot get floating point number field type object's exponent size")
+        assert(exp_size >= 0)
         return exp_size
 
     @exponent_size.setter
@@ -250,9 +252,9 @@ class FloatingPointNumberFieldType(_FieldType, _AlignmentProp, _ByteOrderProp):
 
     @property
     def mantissa_size(self):
-        exp_size = native_bt.ctf_field_type_floating_point_get_mantissa_digits(self._ptr)
-        utils._handle_ret(exp_size, "cannot get floating point number field type object's mantissa size")
-        return exp_size
+        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):
@@ -302,7 +304,7 @@ class _EnumerationFieldTypeMappingIterator(object._Object,
         else:
             ret, name, lower, upper = native_bt.ctf_field_type_enumeration_mapping_iterator_get_unsigned(self._ptr)
 
-        utils._handle_ret(ret, "cannot get enumeration field type mapping iterator object's current mapping")
+        assert(ret == 0)
         mapping = _EnumerationFieldTypeMapping(name, lower, upper)
         ret = native_bt.ctf_field_type_enumeration_mapping_iterator_next(self._ptr)
 
@@ -333,7 +335,7 @@ class EnumerationFieldType(IntegerFieldType, collections.abc.Sequence):
     @property
     def integer_field_type(self):
         ptr = native_bt.ctf_field_type_enumeration_get_container_type(self._ptr)
-        utils._handle_ptr(ptr, "cannot get enumeration field type object's integer field type")
+        assert(ptr)
         return _create_from_ptr(ptr)
 
     @property
@@ -390,7 +392,7 @@ class EnumerationFieldType(IntegerFieldType, collections.abc.Sequence):
 
     def __len__(self):
         count = native_bt.ctf_field_type_enumeration_get_mapping_count(self._ptr)
-        utils._handle_ret(count, "cannot get enumeration field type object's mapping count")
+        assert(count >= 0)
         return count
 
     def __getitem__(self, index):
@@ -405,7 +407,7 @@ class EnumerationFieldType(IntegerFieldType, collections.abc.Sequence):
             get_fn = native_bt.ctf_field_type_enumeration_get_mapping_unsigned
 
         ret, name, lower, upper = get_fn(self._ptr, index)
-        utils._handle_ret(ret, "cannot get enumeration field type object's mapping")
+        assert(ret == 0)
         return _EnumerationFieldTypeMapping(name, lower, upper)
 
     def _get_mapping_iter(self, iter_ptr):
@@ -433,7 +435,7 @@ class EnumerationFieldType(IntegerFieldType, collections.abc.Sequence):
             upper = lower
 
         if self.is_signed:
-            add_fn = native_bt.ctf_field_type_enumeration_add_mapping
+            add_fn = native_bt.ctf_field_type_enumeration_add_mapping_signed
             utils._check_int64(lower)
             utils._check_int64(upper)
         else:
@@ -465,7 +467,7 @@ class StringFieldType(_FieldType):
     @property
     def encoding(self):
         encoding = native_bt.ctf_field_type_string_get_encoding(self._ptr)
-        utils._handle_ret(encoding, "cannot get string field type object's encoding")
+        assert(encoding >= 0)
         return encoding
 
     @encoding.setter
@@ -478,7 +480,7 @@ class StringFieldType(_FieldType):
 class _FieldContainer(collections.abc.Mapping):
     def __len__(self):
         count = self._count()
-        utils._handle_ret(count, "cannot get {} field type object's field count".format(self._NAME.lower()))
+        assert(count >= 0)
         return count
 
     def __getitem__(self, key):
@@ -521,8 +523,10 @@ class _StructureFieldTypeFieldIterator(collections.abc.Iterator):
         if self._at == len(self._struct_field_type):
             raise StopIteration
 
-        ret, name, field_type_ptr = native_bt.ctf_field_type_structure_get_field(self._struct_field_type._ptr, self._at)
-        utils._handle_ret(ret, "cannot get structure field type object's field")
+        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
@@ -551,8 +555,11 @@ class StructureFieldType(_FieldType, _FieldContainer, _AlignmentProp):
                                                             name)
 
     def _at(self, index):
-        ret, name, field_type_ptr = native_bt.ctf_field_type_structure_get_field(self._ptr, index)
-        utils._handle_ret(ret, "cannot get structure field type object's field")
+        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)
 
 
@@ -569,8 +576,9 @@ class _VariantFieldTypeFieldIterator(collections.abc.Iterator):
         if self._at == len(self._variant_field_type):
             raise StopIteration
 
-        ret, name, field_type_ptr = native_bt.ctf_field_type_variant_get_field(self._variant_field_type._ptr, self._at)
-        utils._handle_ret(ret, "cannot get variant field type object's field")
+        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
@@ -580,16 +588,24 @@ class VariantFieldType(_FieldType, _FieldContainer, _AlignmentProp):
     _NAME = 'Variant'
     _ITER_CLS = _VariantFieldTypeFieldIterator
 
-    def __init__(self, tag_name):
+    def __init__(self, tag_name, tag_field_type=None):
         utils._check_str(tag_name)
-        ptr = native_bt.ctf_field_type_variant_create(None, 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)
-        utils._handle_ptr(tag_name, "cannot get variant field type object's tag name")
+        assert(tag_name is not None)
         return tag_name
 
     @tag_name.setter
@@ -598,6 +614,15 @@ class VariantFieldType(_FieldType, _FieldContainer, _AlignmentProp):
         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)
 
@@ -608,8 +633,11 @@ class VariantFieldType(_FieldType, _FieldContainer, _AlignmentProp):
         return native_bt.ctf_field_type_variant_add_field(self._ptr, ptr, name)
 
     def _at(self, index):
-        ret, name, field_type_ptr = native_bt.ctf_field_type_variant_get_field(self._ptr, index)
-        utils._handle_ret(ret, "cannot get variant field type object's field")
+        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)
 
 
@@ -626,13 +654,13 @@ class ArrayFieldType(_FieldType):
     @property
     def length(self):
         length = native_bt.ctf_field_type_array_get_length(self._ptr)
-        utils._handle_ret(length, "cannot get array field type object's length")
+        assert(length >= 0)
         return length
 
     @property
     def element_field_type(self):
         ptr = native_bt.ctf_field_type_array_get_element_type(self._ptr)
-        utils._handle_ptr(ptr, "cannot get array field type object's element field type")
+        assert(ptr)
         return _create_from_ptr(ptr)
 
 
@@ -650,24 +678,23 @@ class SequenceFieldType(_FieldType):
     @property
     def length_name(self):
         length_name = native_bt.ctf_field_type_sequence_get_length_field_name(self._ptr)
-        utils._handle_ptr(length_name, "cannot get sequence field type object's length name")
+        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)
-        utils._handle_ptr(ptr, "cannot get sequence field type object's element field type")
+        assert(ptr)
         return _create_from_ptr(ptr)
 
 
 _TYPE_ID_TO_OBJ = {
-    native_bt.CTF_TYPE_ID_INTEGER: IntegerFieldType,
-    native_bt.CTF_TYPE_ID_FLOAT: FloatingPointNumberFieldType,
-    native_bt.CTF_TYPE_ID_ENUM: EnumerationFieldType,
-    native_bt.CTF_TYPE_ID_STRING: StringFieldType,
-    native_bt.CTF_TYPE_ID_STRUCT: StructureFieldType,
-    native_bt.CTF_TYPE_ID_ARRAY: ArrayFieldType,
-    native_bt.CTF_TYPE_ID_SEQUENCE: SequenceFieldType,
-    native_bt.CTF_TYPE_ID_VARIANT: VariantFieldType,
-    native_bt.CTF_TYPE_ID_UNTAGGED_VARIANT: VariantFieldType,
+    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,
 }
index c63cf35729a15a6d502ad57370de3baa50f9ff2d..44d6a386ad847a1f6ad62745e134e0ab414406ad 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -277,7 +277,10 @@ class _IntegerField(_IntegralField):
         else:
             ret, value = native_bt.ctf_field_unsigned_integer_get_value(self._ptr)
 
-        utils._handle_ret(ret, "cannot get integer field object's value")
+        if ret < 0:
+            # field is not set
+            return
+
         return value
 
     @value.setter
@@ -304,7 +307,11 @@ class _FloatingPointNumberField(_RealField):
     @property
     def value(self):
         ret, value = native_bt.ctf_field_floating_point_get_value(self._ptr)
-        utils._handle_ret(ret, "cannot get floating point number field object's value")
+
+        if ret < 0:
+            # field is not set
+            return
+
         return value
 
     @value.setter
@@ -320,8 +327,7 @@ class _EnumerationField(_IntegerField):
     @property
     def integer_field(self):
         int_field_ptr = native_bt.ctf_field_enumeration_get_container(self._ptr)
-        utils._handle_ptr(int_field_ptr,
-                          "cannot get enumeration field object's underlying integer field")
+        assert(int_field_ptr)
         return _create_from_ptr(int_field_ptr)
 
     @property
@@ -334,8 +340,10 @@ class _EnumerationField(_IntegerField):
 
     @property
     def mappings(self):
-        iter_ptr = bt_ctf_field_enumeration_get_mappings(self._ptr)
-        return self.field_type._get_mapping_iter(iter_ptr)
+        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
@@ -354,7 +362,11 @@ class _StringField(_Field, collections.abc.Sequence):
     @property
     def value(self):
         value = native_bt.ctf_field_string_get_value(self._ptr)
-        utils._handle_ptr(value, "cannot get string field object's value")
+
+        if value is None:
+            # field is not set
+            return
+
         return value
 
     @value.setter
@@ -402,7 +414,7 @@ class _ContainerField(_Field):
 
     def __len__(self):
         count = self._count()
-        utils._handle_ret(count, "cannot get {} field object's field count".format(self._NAME.lower()))
+        assert(count >= 0)
         return count
 
     def __delitem__(self, index):
@@ -417,7 +429,7 @@ class _StructureField(_ContainerField, collections.abc.MutableMapping):
 
     def __getitem__(self, key):
         utils._check_str(key)
-        ptr = native_bt.ctf_field_structure_get_field(self._ptr, key)
+        ptr = native_bt.ctf_field_structure_get_field_by_name(self._ptr, key)
 
         if ptr is None:
             raise KeyError(key)
@@ -441,8 +453,12 @@ class _StructureField(_ContainerField, collections.abc.MutableMapping):
 
     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)
-        utils._handle_ptr(field_ptr, "cannot get structure field object's field")
+        assert(field_ptr)
         return _create_from_ptr(field_ptr)
 
     def __iter__(self):
@@ -474,7 +490,10 @@ class _VariantField(_Field):
     @property
     def tag_field(self):
         field_ptr = native_bt.ctf_field_variant_get_tag(self._ptr)
-        utils._handle_ptr(field_ptr, "cannot get variant field object's tag field")
+
+        if field_ptr is None:
+            return
+
         return _create_from_ptr(field_ptr)
 
     @property
@@ -484,7 +503,9 @@ class _VariantField(_Field):
     def field(self, tag_field=None):
         if tag_field is None:
             field_ptr = native_bt.ctf_field_variant_get_current_field(self._ptr)
-            utils._handle_ptr(field_ptr, "cannot get variant field object's selected field")
+
+            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)
@@ -493,7 +514,16 @@ class _VariantField(_Field):
         return _create_from_ptr(field_ptr)
 
     def __eq__(self, other):
-        return self.field == 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):
@@ -507,7 +537,7 @@ class _ArraySequenceField(_ContainerField, collections.abc.MutableSequence):
             raise IndexError('{} field object index is out of range'.format(self._NAME))
 
         field_ptr = self._get_field_ptr_at_index(index)
-        utils._handle_ptr(field_ptr, "cannot get {} field object's field".format(self._NAME))
+        assert(field_ptr)
         return _create_from_ptr(field_ptr)
 
     def __setitem__(self, index, value):
@@ -575,13 +605,12 @@ class _SequenceField(_ArraySequenceField):
 
 
 _TYPE_ID_TO_OBJ = {
-    native_bt.CTF_TYPE_ID_INTEGER: _IntegerField,
-    native_bt.CTF_TYPE_ID_FLOAT: _FloatingPointNumberField,
-    native_bt.CTF_TYPE_ID_ENUM: _EnumerationField,
-    native_bt.CTF_TYPE_ID_STRING: _StringField,
-    native_bt.CTF_TYPE_ID_STRUCT: _StructureField,
-    native_bt.CTF_TYPE_ID_ARRAY: _ArrayField,
-    native_bt.CTF_TYPE_ID_SEQUENCE: _SequenceField,
-    native_bt.CTF_TYPE_ID_VARIANT: _VariantField,
-    native_bt.CTF_TYPE_ID_UNTAGGED_VARIANT: _VariantField,
+    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/graph.py b/bindings/python/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/logging.c b/bindings/python/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/logging.h b/bindings/python/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/logging.py b/bindings/python/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)
index 88953af55feb99b06645ea5b3801ebbe7d5eaced..0852b74376585ca17d17349e8ac030fcb9c30e42 100644 (file)
  * THE SOFTWARE.
  */
 
+#ifndef SWIGPYTHON
+# error Unsupported output language
+#endif
+
 %{
+#define BT_LOG_TAG "PY-NATIVE"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+
 typedef const unsigned char *BTUUID;
 %}
 
-#ifndef SWIGPYTHON
-# error Unsupported output language
-#endif
+typedef int bt_bool;
 
 /* For uint*_t/int*_t */
 %include "stdint.i"
@@ -69,6 +76,72 @@ typedef const unsigned char *BTUUID;
        }
 }
 
+/* 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);
@@ -102,20 +175,26 @@ typedef const unsigned char *BTUUID;
 }
 
 /* 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_btctfwriter.i"
-%include "native_btcomponentclass.i"
-%include "native_btcomponent.i"
-%include "native_btnotifiter.i"
-%include "native_btnotification.i"
-%include "native_btplugin.i"
+%include "native_btversion.i"
diff --git a/bindings/python/bt2/native_btccpriomap.i b/bindings/python/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);
index e79a7b4d267bbfa99828ba39e3bf9a700be8e447..5a09e894543a7bfb0c0afcb10464110e080b060c 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/clock-class.h>
-%}
-
 /* 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);
+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);
index 6394efd226a315e782eb6197003ea5d98e6b75af..ea3e0f8a869c326accda4306e541b6942bc29dd8 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/component/component.h>
-#include <babeltrace/component/component-source.h>
-#include <babeltrace/component/component-sink.h>
-#include <babeltrace/component/component-filter.h>
-%}
-
 /* Types */
 struct bt_component;
 
 /* Status */
 enum bt_component_status {
-       BT_COMPONENT_STATUS_OK =                0,
-       BT_COMPONENT_STATUS_END =               1,
-       BT_COMPONENT_STATUS_AGAIN =             2,
-       BT_COMPONENT_STATUS_ERROR =             -1,
-       BT_COMPONENT_STATUS_UNSUPPORTED =       -2,
-       BT_COMPONENT_STATUS_INVALID =           -3,
-       BT_COMPONENT_STATUS_NOMEM =             -4,
+       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 */
-struct bt_component *bt_component_create_with_init_method_data(
-               struct bt_component_class *component_class, const char *name,
-               struct bt_value *params, void *init_method_data);
 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 */
-struct bt_notification_iterator *bt_component_source_create_notification_iterator_with_init_method_data(
-        struct bt_component *component, void *init_method_data);
-
-/* Filter component functions */
-%{
-static struct bt_notification_iterator *bt_component_filter_get_input_iterator_private(
-               struct bt_component *filter, unsigned int index)
-{
-       struct bt_notification_iterator *iterator = NULL;
+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);
 
-       if (bt_component_filter_get_input_iterator(filter, index, &iterator)) {
-               iterator = NULL;
-               goto end;
-       }
+/* 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);
 
-end:
-       return iterator;
-}
-%}
+/* 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);
 
-struct bt_notification_iterator *bt_component_filter_create_notification_iterator_with_init_method_data(
-               struct bt_component *component, void *init_method_data);
-enum bt_component_status bt_component_filter_add_iterator(
-               struct bt_component *component,
-               struct bt_notification_iterator *iterator);
-enum bt_component_status bt_component_filter_set_minimum_input_count(
-               struct bt_component *filter, unsigned int minimum);
-enum bt_component_status bt_component_filter_set_maximum_input_count(
-               struct bt_component *filter, unsigned int maximum);
-enum bt_component_status bt_component_filter_get_input_count(
-               struct bt_component *filter, unsigned int *OUTPUT);
-struct bt_notification_iterator *bt_component_filter_get_input_iterator_private(
-               struct bt_component *filter, unsigned int 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 */
-%{
-static struct bt_notification_iterator *bt_component_sink_get_input_iterator_private(
-               struct bt_component *sink, unsigned int index)
-{
-       struct bt_notification_iterator *iterator = NULL;
-
-       if (bt_component_sink_get_input_iterator(sink, index, &iterator)) {
-               iterator = NULL;
-               goto end;
-       }
-
-end:
-       return iterator;
-}
-%}
-
-enum bt_component_status bt_component_sink_add_iterator(
-               struct bt_component *component,
-               struct bt_notification_iterator *iterator);
-enum bt_component_status bt_component_sink_consume(
+int64_t bt_component_sink_get_input_port_count(
                struct bt_component *component);
-enum bt_component_status bt_component_sink_set_minimum_input_count(
-               struct bt_component *sink, unsigned int minimum);
-enum bt_component_status bt_component_sink_set_maximum_input_count(
-               struct bt_component *sink, unsigned int maximum);
-enum bt_component_status bt_component_sink_get_input_count(
-               struct bt_component *sink, unsigned int *OUTPUT);
-struct bt_notification_iterator *bt_component_sink_get_input_iterator_private(
-               struct bt_component *sink, unsigned int index);
+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);
index 4fe24886126c4fd5e5a21bd885af35b9ce903c01..195ca3819c3a7865cf1b2a55360ab712c6568b1c 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/component/component-class.h>
-#include <babeltrace/component/component-class-source.h>
-#include <babeltrace/component/component-class-sink.h>
-#include <babeltrace/component/component-class-filter.h>
-#include <babeltrace/component/notification/iterator.h>
-#include <babeltrace/component/notification/notification.h>
-#include <assert.h>
-#include <glib.h>
-%}
-
 /* 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,
+       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 */
@@ -53,7 +42,7 @@ 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 *action, struct bt_value *params);
+               const char *object, struct bt_value *params);
 enum bt_component_class_type bt_component_class_get_type(
                struct bt_component_class *component_class);
 
@@ -81,12 +70,29 @@ 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);
 }
@@ -101,8 +107,10 @@ 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_values = NULL;
-static PyObject *py_mod_bt2_values_create_from_ptr_func = 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)
 {
@@ -116,12 +124,6 @@ static void bt_py3_cc_init_from_bt2(void)
         */
        py_mod_bt2 = PyImport_ImportModule("bt2");
        assert(py_mod_bt2);
-       py_mod_bt2_values = PyImport_ImportModule("bt2.values");
-       assert(py_mod_bt2_values);
-       py_mod_bt2_values_create_from_ptr_func =
-               PyObject_GetAttrString(py_mod_bt2_values,
-                       "_create_from_ptr");
-       assert(py_mod_bt2_values_create_from_ptr_func);
        py_mod_bt2_exc_error_type =
                PyObject_GetAttrString(py_mod_bt2, "Error");
        assert(py_mod_bt2_exc_error_type);
@@ -131,6 +133,12 @@ static void bt_py3_cc_init_from_bt2(void)
                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);
 }
 
@@ -143,476 +151,399 @@ static void bt_py3_cc_exit_handler(void)
         * 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
-        * to modules are still loaded, so it should be safe to use them
-        * even without a strong reference.
+        * 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_values_create_from_ptr_func);
-       Py_XDECREF(py_mod_bt2_values);
        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 constructor and destructor */
-
-__attribute__((constructor))
-static void bt_py3_native_comp_class_ctor(void) {
-       /* Initialize component class association 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);
-}
+/* 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);
        }
 }
 
 
-/* Converts a BT value object to a bt2.values object */
+/* Component class proxy methods (delegate to the attached Python object) */
 
-static PyObject *bt_py3_bt_value_from_ptr(struct bt_value *value)
+static enum bt_notification_iterator_status bt_py3_exc_to_notif_iter_status(void)
 {
-       PyObject *py_create_from_ptr_func = NULL;
-       PyObject *py_value = NULL;
-       PyObject *py_ptr = NULL;
+       enum bt_notification_iterator_status status =
+               BT_NOTIFICATION_ITERATOR_STATUS_OK;
+       PyObject *exc = PyErr_Occurred();
 
-       py_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(value),
-               SWIGTYPE_p_bt_value, 0);
-       py_value = PyObject_CallFunctionObjArgs(
-               py_mod_bt2_values_create_from_ptr_func, py_ptr, NULL);
-       if (!py_value) {
+       if (!exc) {
                goto end;
        }
 
-       /*
-        * _create_from_ptr() only wraps an existing reference. `value`
-        * is a borrowed reference here, so increment its reference
-        * count for this new owner.
-        */
-       bt_get(value);
+       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:
-       Py_XDECREF(py_ptr);
        PyErr_Clear();
-       return py_value;
+       return status;
 }
 
-
-/* self.__init__(*args, **kwargs) */
-
-static int bt_py3_call_self_init(PyObject *py_self, PyObject *py_args,
-               PyObject *py_kwargs)
+static enum bt_component_status bt_py3_exc_to_component_status(void)
 {
-       int ret = 0;
-       size_t i;
-       PyObject *py_init_method_result = NULL;
-       PyObject *py_init_method = NULL;
-       PyObject *py_init_method_args = NULL;
-       PyObject *py_class = NULL;
+       enum bt_component_status status = BT_COMPONENT_STATUS_OK;
+       PyObject *exc = PyErr_Occurred();
 
-       py_class = PyObject_GetAttrString(py_self, "__class__");
-       if (!py_class) {
-               goto error;
+       if (!exc) {
+               goto end;
        }
 
-       py_init_method = PyObject_GetAttrString(py_class, "__init__");
-       if (!py_init_method) {
-               goto error;
+       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;
        }
 
-       /* Prepend py_self to the arguments (copy them to new tuple) */
-       py_init_method_args = PyTuple_New(PyTuple_Size(py_args) + 1);
-       if (!py_init_method_args) {
+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;
        }
 
-       Py_INCREF(py_self);
-       ret = PyTuple_SetItem(py_init_method_args, 0, py_self);
-       if (ret < 0) {
-               Py_DECREF(py_self);
+       /* 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;
        }
 
-       for (i = 0; i < PyTuple_Size(py_args); i++) {
-               PyObject *obj = PyTuple_GetItem(py_args, i);
-               if (!obj) {
-                       goto error;
-               }
-
-               Py_INCREF(obj);
-               ret = PyTuple_SetItem(py_init_method_args, i + 1, obj);
-               if (ret < 0) {
-                       Py_DECREF(obj);
-                       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;
        }
 
-       py_init_method_result = PyObject_Call(py_init_method,
-               py_init_method_args, py_kwargs);
-       if (!py_init_method_result) {
+       /*
+        * 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:
-       ret = -1;
-
-end:
-       Py_XDECREF(py_init_method_args);
-       Py_XDECREF(py_init_method_result);
-       Py_XDECREF(py_init_method);
-       Py_XDECREF(py_class);
-       return ret;
-}
-
-
-/* Component class proxy methods (delegate to the attached Python object) */
-
-static enum bt_component_status bt_py3_cc_init(
-               struct bt_component *component, struct bt_value *params,
-               void *init_method_data)
-{
-       enum bt_component_status status = BT_COMPONENT_STATUS_OK;
-       int ret;
+       status = BT_COMPONENT_STATUS_ERROR;
 
        /*
-        * This function is either called from
-        * _UserComponentType.__call__() (when init_method_data contains
-        * the PyObject * currently creating this component) or from
-        * other code (init_method_data is NULL).
+        * 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.
         */
-       if (init_method_data) {
-               /*
-                * Called from _UserComponentType.__call__().
-                *
-                * The `params` argument is completely ignored here,
-                * because if the user creating the component object
-                * from the component class object wants parameters,
-                * they'll be in the keyword arguments anyway.
-                */
-               PyObject *py_comp = init_method_data;
-               PyObject *py_comp_ptr = NULL;
-               PyObject *py_init_args = NULL;
-               PyObject *py_init_kwargs = NULL;
+       PyErr_Clear();
 
-               /*
-                * No need to take a Python reference on py_comp here:
-                * we store it as a _borrowed_ reference. When all the
-                * Python references are dropped, the object's __del__()
-                * method is called. This method calls this side
-                * (bt_py3_component_on_del()) to swap the ownership:
-                * this BT component becomes the only owner of the
-                * Python object.
-                */
-               bt_component_set_private_data(component, py_comp);
+end:
+       bt_put(comp_cls);
+       bt_put(comp);
+       Py_XDECREF(py_comp);
+       Py_XDECREF(py_params_ptr);
+       Py_XDECREF(py_comp_ptr);
+       return status;
+}
 
-               /*
-                * Set this BT component pointer as py_comp._ptr, and
-                * take a reference on it (on success, at the end).
-                *
-                * This reference is put in the Python component
-                * object's __del__() method.
-                */
-               py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component),
-                       SWIGTYPE_p_bt_component, 0);
-               if (!py_comp_ptr) {
-                       PyErr_Clear();
-                       goto with_init_method_data_error;
-               }
+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;
 
-               ret = PyObject_SetAttrString(py_comp, "_ptr", py_comp_ptr);
-               if (ret < 0) {
-                       PyErr_Clear();
-                       goto with_init_method_data_error;
-               }
+       assert(py_comp);
 
-               /*
-                * _UserComponentType.__call__() puts the arguments and
-                * keyword arguments to use for the py_comp.__init__()
-                * call in py_comp._init_args and py_comp._init_kwargs.
-                *
-                * We need to get them and remove them from py_comp before
-                * calling py_comp.__init__().
-                */
-               py_init_args = PyObject_GetAttrString(py_comp, "_init_args");
-               if (!py_init_args) {
-                       PyErr_Clear();
-                       goto with_init_method_data_error;
-               }
+       /* Call user's _finalize() method */
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_finalize", NULL);
 
-               py_init_kwargs = PyObject_GetAttrString(py_comp, "_init_kwargs");
-               if (!py_init_kwargs) {
-                       PyErr_Clear();
-                       goto with_init_method_data_error;
-               }
+       if (PyErr_Occurred()) {
+               BT_LOGW("User's _finalize() method raised an exception: ignoring.");
+       }
 
-               ret = PyObject_DelAttrString(py_comp, "_init_args");
-               if (ret < 0) {
-                       PyErr_Clear();
-                       goto with_init_method_data_error;
-               }
+       /*
+        * 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);
+}
 
-               ret = PyObject_DelAttrString(py_comp, "_init_kwargs");
-               if (ret < 0) {
-                       PyErr_Clear();
-                       goto with_init_method_data_error;
-               }
+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;
 
-               /* Ready to call py_comp.__init__() */
-               ret = bt_py3_call_self_init(py_comp, py_init_args,
-                       py_init_kwargs);
-               if (ret) {
-                       /*
-                        * We do not clear any raised exception here
-                        * so that the Python caller (the one who is
-                        * instantiating the class) gets the exception
-                        * from the __init__() method.
-                        */
-                       goto with_init_method_data_error;
-               }
+       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_comp.__init__() went well: get the native BT
-                * component object reference for the Python object.
-                */
-               bt_get(component);
-               goto with_init_method_data_end;
+       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;
+       }
 
-with_init_method_data_error:
-               status = BT_COMPONENT_STATUS_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) {
                /*
-                * Reset py_comp._ptr to None to signal the error to
-                * _UserComponentType.__call__(). For exceptions raised
-                * from py_comp.__init__(), this is not important,
-                * because __call__() will also raise before even
-                * checking py_comp._ptr.
+                * Looks like the user method raised
+                * PortConnectionRefused: accept this like if it
+                * returned False.
                 */
-               if (PyObject_HasAttrString(py_comp, "_ptr")) {
-                       PyObject *py_err_type, *py_err_value, *py_err_traceback;
-                       PyErr_Fetch(&py_err_type, &py_err_value,
-                               &py_err_traceback);
-                       Py_INCREF(Py_None);
-                       PyObject_SetAttrString(py_comp, "_ptr", Py_None);
-                       PyErr_Restore(py_err_type, py_err_value,
-                               py_err_traceback);
-               }
+               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;
+       }
 
-               /*
-                * Important: remove py_comp from our the BT component's
-                * private data. Since we're failing,
-                * bt_py3_cc_destroy() is about to be called: it must
-                * not consider py_comp. py_comp's __del__() method
-                * will be called (because the instance exists), but
-                * since py_comp._ptr is None, it won't do anything.
-                */
-               bt_component_set_private_data(component, NULL);
+       assert(PyBool_Check(py_method_result));
 
-with_init_method_data_end:
-               Py_XDECREF(py_comp_ptr);
-               Py_XDECREF(py_init_args);
-               Py_XDECREF(py_init_kwargs);
+       if (py_method_result == Py_True) {
+               status = BT_COMPONENT_STATUS_OK;
        } else {
-               /*
-                * Not called from _UserComponentType.__call__().
-                *
-                * In this case we need to instantiate the user-defined
-                * Python class. To do this we call the user-defined
-                * class manually with this already-created BT component
-                * object pointer as the __comp_ptr keyword argument.
-                *
-                * We keep a reference, the only existing one, to the
-                * created Python object. bt_py3_component_on_del() will
-                * never be called by the object's __del__() method
-                * because _UserComponentType.__call__() marks the
-                * object as owned by the native BT component object.
-                */
-               PyObject *py_cls = NULL;
-               PyObject *py_comp = NULL;
-               PyObject *py_params = NULL;
-               PyObject *py_comp_ptr = NULL;
-               PyObject *py_cls_ctor_args = NULL;
-               PyObject *py_cls_ctor_kwargs = NULL;
-
-               /*
-                * 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(bt_component_get_class(component));
-               if (!py_cls) {
-                       goto without_init_method_data_error;
-               }
-
-               /* BT value object -> Python bt2.values object */
-               py_params = bt_py3_bt_value_from_ptr(params);
-               if (!py_params) {
-                       goto without_init_method_data_error;
-               }
-
-               /* Component pointer -> SWIG pointer Python object */
-               py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component),
-                       SWIGTYPE_p_bt_component, 0);
-               if (!py_comp_ptr) {
-                       goto without_init_method_data_error;
-               }
-
-               /*
-                * Do the equivalent of this:
-                *
-                *     py_comp = py_cls(__comp_ptr=py_comp_ptr, params=py_params)
-                *
-                * _UserComponentType.__call__() calls the Python
-                * component object's __init__() function itself in this
-                * case.
-                */
-               py_cls_ctor_args = PyTuple_New(0);
-               if (!py_cls_ctor_args) {
-                       goto without_init_method_data_error;
-               }
-
-               py_cls_ctor_kwargs = PyDict_New();
-               if (!py_cls_ctor_kwargs) {
-                       goto without_init_method_data_error;
-               }
-
-               ret = PyDict_SetItemString(py_cls_ctor_kwargs, "__comp_ptr",
-                       py_comp_ptr);
-               if (ret < 0) {
-                       goto without_init_method_data_error;
-               }
-
-               ret = PyDict_SetItemString(py_cls_ctor_kwargs, "params",
-                       py_params);
-               if (ret < 0) {
-                       goto without_init_method_data_error;
-               }
-
-               py_comp = PyObject_Call(py_cls, py_cls_ctor_args,
-                       py_cls_ctor_kwargs);
-               if (!py_comp) {
-                       goto without_init_method_data_error;
-               }
+               status = BT_COMPONENT_STATUS_REFUSE_PORT_CONNECTION;
+       }
 
-               /*
-                * Our user Python component object is now fully created
-                * and initialized by the user. Since we just created
-                * it, this BT component is its only (persistent) owner.
-                */
-               bt_component_set_private_data(component, py_comp);
-               py_comp = NULL;
-               goto without_init_method_data_end;
+       goto end;
 
-without_init_method_data_error:
-               status = BT_COMPONENT_STATUS_ERROR;
+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();
-
-without_init_method_data_end:
-               Py_XDECREF(py_comp);
-               Py_XDECREF(py_params);
-               Py_XDECREF(py_comp_ptr);
-               Py_XDECREF(py_cls_ctor_args);
-               Py_XDECREF(py_cls_ctor_kwargs);
-       }
+       /*
+        * 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_destroy(struct bt_component *component)
+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 = bt_component_get_private_data(component);
-       PyObject *py_destroy_method_result = NULL;
+       PyObject *py_comp = NULL;
+       PyObject *py_self_port_ptr = NULL;
+       PyObject *py_other_port_ptr = NULL;
+       PyObject *py_method_result = NULL;
 
-       if (py_comp) {
-               /*
-                * If we're here, this BT component is the only owner of
-                * its private user Python object. It is safe to
-                * decrement its reference count, and thus destroy it.
-                *
-                * We call its _destroy() method before doing so to notify
-                * the Python user.
-                */
-               py_destroy_method_result = PyObject_CallMethod(py_comp,
-                       "_destroy", 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);
+}
 
-               /*
-                * Ignore any exception raised by the _destroy() method
-                * because it won't change anything at this point: the
-                * component is being destroyed anyway.
-                */
-               PyErr_Clear();
-               Py_XDECREF(py_destroy_method_result);
-               Py_DECREF(py_comp);
-       }
+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 *component_class,
+               struct bt_component_class *comp_cls,
                const char *object, struct bt_value *params)
 {
        PyObject *py_cls = NULL;
-       PyObject *py_params = 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(component_class);
+       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 = bt_py3_bt_value_from_ptr(params);
-       if (!py_params) {
+       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_bt", "(OO)", py_object, py_params);
-       if (!py_results_addr) {
+               "_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;
        }
 
-       /*
-        * The returned object, on success, is an integer object
-        * (PyLong) containing the address of a BT value object
-        * (which is now ours).
-        */
-       results = (struct bt_value *) PyLong_AsUnsignedLongLong(
-               py_results_addr);
-
-       /* Clear potential overflow error; should never happen */
-       if (PyErr_Occurred()) {
-               results = NULL;
-               goto error;
-       }
-
-       if (!results) {
+       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:
@@ -620,41 +551,16 @@ error:
        PyErr_Clear();
 
 end:
-       Py_XDECREF(py_params);
+       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_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 {
-               status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-       }
-
-end:
-       PyErr_Clear();
-       return status;
-}
-
 static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_init(
-               struct bt_component *component,
-               struct bt_notification_iterator *iter, void *init_method_data)
+               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;
@@ -663,34 +569,45 @@ static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_init
        PyObject *py_iter_ptr = NULL;
        PyObject *py_init_method_result = NULL;
        PyObject *py_iter = NULL;
-       PyObject *py_comp = bt_component_get_private_data(component);
+       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 BT notification iterator
+        * Create object with borrowed native notification iterator
         * reference:
         *
         *     py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr)
         */
-       py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(iter),
-               SWIGTYPE_p_bt_notification_iterator, 0);
-       if (!py_iter_ptr) {
-               goto error;
-       }
-
        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;
        }
 
@@ -700,33 +617,36 @@ static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_init
         *     py_iter.__init__()
         *
         * At this point, py_iter._ptr is set, so this initialization
-        * function has access to the py_iter.component property (which
-        * gives it the user Python component object from which the
-        * iterator was created).
+        * 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 BT notification iterator
+        * 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 BT notification iterator object.
+        * owned by this native notification iterator object.
         *
-        * In the Python world, the lifetime of the BT notification
+        * 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)
+        *             owns a _UserNotificationIterator instance (py_iter)
         *                 self._ptr is a borrowed reference to the
-        *                 native bt_notification_iterator object (iter)
+        *                 native bt_private_notification_iterator
+        *                 object (iter)
         */
-       bt_notification_iterator_set_private_data(iter, py_iter);
+       bt_private_notification_iterator_set_user_data(priv_notif_iter,
+               py_iter);
        py_iter = NULL;
        goto end;
 
@@ -748,6 +668,7 @@ error:
        PyErr_Clear();
 
 end:
+       bt_put(priv_comp);
        Py_XDECREF(py_comp_cls);
        Py_XDECREF(py_iter_cls);
        Py_XDECREF(py_iter_ptr);
@@ -756,197 +677,92 @@ end:
        return status;
 }
 
-static void bt_py3_cc_notification_iterator_destroy(
-               struct bt_notification_iterator *iter)
+static void bt_py3_cc_notification_iterator_finalize(
+               struct bt_private_notification_iterator *priv_notif_iter)
 {
        PyObject *py_notif_iter =
-               bt_notification_iterator_get_private_data(iter);
-       PyObject *py_destroy_method_result = NULL;
+               bt_private_notification_iterator_get_user_data(priv_notif_iter);
+       PyObject *py_method_result = NULL;
 
        assert(py_notif_iter);
-       py_destroy_method_result = PyObject_CallMethod(py_notif_iter,
-               "_destroy", NULL);
+
+       /* 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 _destroy() method because
-        * it won't change anything at this point. The notification
-        * iterator is being destroyed anyway.
+        * 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_destroy_method_result);
+       Py_XDECREF(py_method_result);
        Py_DECREF(py_notif_iter);
 }
 
-static struct bt_notification *bt_py3_cc_notification_iterator_get(
-               struct bt_notification_iterator *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_notification_iterator_get_private_data(iter);
-       PyObject *py_get_method_result = NULL;
-       struct bt_notification *notif = NULL;
+               bt_private_notification_iterator_get_user_data(priv_notif_iter);
+       PyObject *py_method_result = NULL;
 
        assert(py_notif_iter);
-       py_get_method_result = PyObject_CallMethod(py_notif_iter,
-               "_get_from_bt", NULL);
-       if (!py_get_method_result) {
-               goto error;
+       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 BT notification
+        * (PyLong) containing the address of a native notification
         * object (which is now ours).
         */
-       notif = (struct bt_notification *) PyLong_AsUnsignedLongLong(
-               py_get_method_result);
+       next_ret.notification =
+               (struct bt_notification *) PyLong_AsUnsignedLongLong(
+                       py_method_result);
 
        /* Clear potential overflow error; should never happen */
-       if (PyErr_Occurred()) {
-               notif = NULL;
-               goto error;
-       }
-
-       if (!notif) {
-               goto error;
-       }
-
+       assert(!PyErr_Occurred());
+       assert(next_ret.notification);
        goto end;
 
-error:
-       BT_PUT(notif);
-
-       /*
-        * Clear any exception: we're returning NULL anyway. If this
-        * call originated from Python, then the user gets an
-        * appropriate error.
-        */
-       PyErr_Clear();
-
 end:
-       Py_XDECREF(py_get_method_result);
-       return notif;
-}
-
-static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_next(
-               struct bt_notification_iterator *iter)
-{
-       enum bt_notification_iterator_status status;
-       PyObject *py_notif_iter =
-               bt_notification_iterator_get_private_data(iter);
-       PyObject *py_next_method_result = NULL;
-
-       assert(py_notif_iter);
-       py_next_method_result = PyObject_CallMethod(py_notif_iter,
-               "_next", NULL);
-       status = bt_py3_exc_to_notif_iter_status();
-       if (!py_next_method_result
-                       && status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
-               /* Pretty sure this should never happen, but just in case */
-               status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-       }
-
-       Py_XDECREF(py_next_method_result);
-       return status;
-}
-
-static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_seek_time(
-               struct bt_notification_iterator *iter, int64_t time)
-{
-       enum bt_notification_iterator_status status;
-       PyObject *py_notif_iter =
-               bt_notification_iterator_get_private_data(iter);
-       PyObject *py_seek_to_time_method_result = NULL;
-
-       assert(py_notif_iter);
-       py_seek_to_time_method_result = PyObject_CallMethod(py_notif_iter,
-               "_seek_to_time", "(L)", time);
-       status = bt_py3_exc_to_notif_iter_status();
-       if (!py_seek_to_time_method_result
-                       && status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
-               /* Pretty sure this should never happen, but just in case */
-               status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-       }
-
-       Py_XDECREF(py_seek_to_time_method_result);
-       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 {
-               status = BT_COMPONENT_STATUS_ERROR;
-       }
-
-end:
-       PyErr_Clear();
-       return status;
+       Py_XDECREF(py_method_result);
+       return next_ret;
 }
 
 static enum bt_component_status bt_py3_cc_sink_consume(
-               struct bt_component *component)
+               struct bt_private_component *priv_comp)
 {
-       PyObject *py_comp = bt_component_get_private_data(component);
-       PyObject *py_consume_method_result = NULL;
+       PyObject *py_comp = bt_private_component_get_user_data(priv_comp);
+       PyObject *py_method_result = NULL;
        enum bt_component_status status;
 
-       py_consume_method_result = PyObject_CallMethod(py_comp,
+       assert(py_comp);
+       py_method_result = PyObject_CallMethod(py_comp,
                "_consume", NULL);
        status = bt_py3_exc_to_component_status();
-       if (!py_consume_method_result && status == BT_COMPONENT_STATUS_OK) {
-               /* Pretty sure this should never happen, but just in case */
-               status = BT_COMPONENT_STATUS_ERROR;
-       }
-
-       Py_XDECREF(py_consume_method_result);
-       return status;
-}
-
-static enum bt_component_status bt_py3_cc_sink_filter_add_iterator(
-               struct bt_component *component,
-               struct bt_notification_iterator *iter)
-{
-       PyObject *py_comp = bt_component_get_private_data(component);
-       PyObject *py_add_iterator_method_result = NULL;
-       PyObject *py_notif_iter_ptr = NULL;
-       enum bt_component_status status;
-
-       py_notif_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(iter),
-               SWIGTYPE_p_bt_notification_iterator, 0);
-       if (!py_notif_iter_ptr) {
-               PyErr_Clear();
-               status = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       bt_get(iter);
-       py_add_iterator_method_result = PyObject_CallMethod(py_comp,
-               "_add_iterator_from_bt", "(O)", py_notif_iter_ptr);
-       status = bt_py3_exc_to_component_status();
-       if (!py_add_iterator_method_result
-                       && status == BT_COMPONENT_STATUS_OK) {
+       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;
        }
 
-end:
-       Py_XDECREF(py_notif_iter_ptr);
-       Py_XDECREF(py_add_iterator_method_result);
+       Py_XDECREF(py_method_result);
        return status;
 }
 
@@ -961,6 +777,8 @@ static int bt_py3_cc_set_optional_attrs_methods(struct bt_component_class *cc,
        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;
                }
        }
@@ -968,91 +786,71 @@ static int bt_py3_cc_set_optional_attrs_methods(struct bt_component_class *cc,
        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);
-       if (ret) {
-               goto end;
-       }
-
-       ret = bt_component_class_set_destroy_method(cc, bt_py3_cc_destroy);
-       if (ret) {
-               goto end;
-       }
-
+       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);
-       if (ret) {
-               goto end;
-       }
+       assert(ret == 0);
 
 end:
        return ret;
 }
 
-static int bt_py3_cc_set_optional_iter_methods(struct bt_component_class *cc,
-               bool has_seek_time,
+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_destroy_method)(struct bt_component_class *, bt_component_class_notification_iterator_destroy_method),
-               int (*set_notif_iter_seek_time_method)(struct bt_component_class *, bt_component_class_notification_iterator_seek_time_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);
-       if (ret) {
-               goto end;
-       }
-
-       ret = set_notif_iter_destroy_method(
-               cc, bt_py3_cc_notification_iterator_destroy);
-       if (ret) {
-               goto end;
-       }
-
-       if (has_seek_time) {
-               ret = set_notif_iter_seek_time_method(
-                       cc, bt_py3_cc_notification_iterator_seek_time);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
+       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, bool has_seek_time)
+               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_get,
                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;
        }
 
-       ret = bt_py3_cc_set_optional_iter_methods(cc, has_seek_time,
+       bt_py3_cc_set_optional_iter_methods(cc,
                bt_component_class_source_set_notification_iterator_init_method,
-               bt_component_class_source_set_notification_iterator_destroy_method,
-               bt_component_class_source_set_notification_iterator_seek_time_method);
-       if (ret) {
-               BT_PUT(cc);
-               goto end;
-       }
-
+               bt_component_class_source_set_notification_iterator_finalize_method);
        register_cc_ptr_to_py_cls(cc, py_cls);
        bt_component_class_freeze(cc);
 
@@ -1062,41 +860,29 @@ end:
 
 static struct bt_component_class *bt_py3_component_class_filter_create(
                PyObject *py_cls, const char *name, const char *description,
-               const char *help, bool has_seek_time)
+               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_get,
                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;
        }
 
-       ret = bt_py3_cc_set_optional_iter_methods(cc, has_seek_time,
+       bt_py3_cc_set_optional_iter_methods(cc,
                bt_component_class_filter_set_notification_iterator_init_method,
-               bt_component_class_filter_set_notification_iterator_destroy_method,
-               bt_component_class_filter_set_notification_iterator_seek_time_method);
-       if (ret) {
-               BT_PUT(cc);
-               goto end;
-       }
-
-       ret = bt_component_class_filter_set_add_iterator_method(cc,
-               bt_py3_cc_sink_filter_add_iterator);
-       if (ret) {
-               BT_PUT(cc);
-               goto end;
-       }
-
+               bt_component_class_filter_set_notification_iterator_finalize_method);
        register_cc_ptr_to_py_cls(cc, py_cls);
        bt_component_class_freeze(cc);
 
@@ -1114,18 +900,13 @@ static struct bt_component_class *bt_py3_component_class_sink_create(
        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_PUT(cc);
-               goto end;
-       }
-
-       ret = bt_component_class_sink_set_add_iterator_method(cc,
-               bt_py3_cc_sink_filter_add_iterator);
-       if (ret) {
+               BT_LOGE_STR("Cannot set sink component class's optional attributes and methods.");
                BT_PUT(cc);
                goto end;
        }
@@ -1136,70 +917,16 @@ static struct bt_component_class *bt_py3_component_class_sink_create(
 end:
        return cc;
 }
-
-
-/* Component creation function (called from Python module) */
-
-static void bt_py3_component_create(
-               struct bt_component_class *comp_class, PyObject *py_self,
-               const char *name)
-{
-       struct bt_component *component =
-               bt_component_create_with_init_method_data(comp_class,
-                       name, NULL, py_self);
-
-       /*
-        * Our component initialization function, bt_py3_cc_init(), sets
-        * a new reference to the created component in the user's Python
-        * object (py_self._ptr). This is where the reference is kept.
-        * We don't need the returned component in this case (if any,
-        * because it might be NULL if the creation failed, most
-        * probably because py_self.__init__() raised something).
-        */
-       bt_put(component);
-}
-
-
-/* Component delete notification */
-
-static void bt_py3_component_on_del(PyObject *py_comp)
-{
-       /*
-        * The Python component's __del__() function calls this to
-        * indicate that there's no more reference on it from the
-        * Python world.
-        *
-        * Since the BT component can continue to live once the Python
-        * component object is deleted, we increment the Python
-        * component's reference count so that it now only belong to the
-        * BT component. We will decrement this reference count once
-        * the BT component is destroyed in bt_py3_cc_destroy().
-        */
-       assert(py_comp);
-       Py_INCREF(py_comp);
-}
 %}
 
-%exception bt_py3_component_create {
-       $action
-       if (PyErr_Occurred()) {
-               /* Exception is already set by bt_py3_component_create() */
-               SWIG_fail;
-       }
-}
-
 struct bt_component_class *bt_py3_component_class_source_create(
                PyObject *py_cls, const char *name, const char *description,
-               const char *help, bool has_seek_time);
+               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, bool has_seek_time);
+               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_component_create(
-               struct bt_component_class *comp_class, PyObject *py_self,
-               const char *name);
-void bt_py3_component_on_del(PyObject *py_comp);
 void bt_py3_cc_init_from_bt2(void);
 void bt_py3_cc_exit_handler(void);
diff --git a/bindings/python/bt2/native_btconnection.i b/bindings/python/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);
index 479e1e330ca9a932cfbe04440087405901153a3f..293ed2548a11bb52006dd75f88887419575c8cff 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-writer/clock.h>
-#include <babeltrace/ctf-writer/stream.h>
-#include <babeltrace/ctf-writer/stream-class.h>
-#include <babeltrace/ctf-writer/writer.h>
-%}
-
 /* Types */
 struct bt_ctf_clock;
 struct bt_ctf_writer;
index 3d73b2f3ac13a5c80247d7fa87eff7a92325396f..f6e649456a11a3dcf802a3042d9cfc0e98b40ec7 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/event.h>
-%}
-
 /* Type */
 struct bt_ctf_event;
 
@@ -52,9 +48,9 @@ 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_payload_field(
+struct bt_ctf_field *bt_ctf_event_get_event_payload(
                struct bt_ctf_event *event);
-int bt_ctf_event_set_payload_field(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,
index 66a59830996ee7f449470cb8ed703a9d80609346..c4b8c8d773776f52c9445dd81cb856c13976a6dc 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/event-class.h>
-%}
-
 /* 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(
@@ -38,17 +55,17 @@ const char *bt_ctf_event_class_get_name(
 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, uint32_t id);
-int bt_ctf_event_class_get_attribute_count(
+               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);
-const char *bt_ctf_event_class_get_attribute_name(
-               struct bt_ctf_event_class *event_class, int index);
-struct bt_value *
-bt_ctf_event_class_get_attribute_value_by_name(
-               struct bt_ctf_event_class *event_class, const char *name);
-int bt_ctf_event_class_set_attribute(
-               struct bt_ctf_event_class *event_class, const char *name,
-               struct bt_value *value);
+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(
index e3753fddd5ca14b30dc12d61c8a46ea1b6819382..883bec3b0271d1383b7cef4556163aac5ccc723a 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/fields.h>
-%}
-
 /* Type */
 struct bt_ctf_field;
 
@@ -73,8 +69,10 @@ int bt_ctf_field_string_append_len(
 /* 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(
-               struct bt_ctf_field *structure, const char *name);
+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(
index 1636e83d616c8bff6e2cab25e04b355c8cf53e06..c24a863087e89fc1f39fd0353e4933b5fd5305fb 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/field-types.h>
-%}
-
 /* Type */
 struct bt_ctf_field_type;
 
@@ -42,23 +38,23 @@ enum bt_ctf_scope {
        BT_CTF_SCOPE_EVENT_FIELDS = 6,
 };
 
-enum bt_ctf_type_id {
-       BT_CTF_TYPE_ID_UNKNOWN = CTF_TYPE_UNKNOWN,
-       BT_CTF_TYPE_ID_INTEGER = CTF_TYPE_INTEGER,
-       BT_CTF_TYPE_ID_FLOAT = CTF_TYPE_FLOAT,
-       BT_CTF_TYPE_ID_ENUM = CTF_TYPE_ENUM,
-       BT_CTF_TYPE_ID_STRING = CTF_TYPE_STRING,
-       BT_CTF_TYPE_ID_STRUCT = CTF_TYPE_STRUCT,
-       BT_CTF_TYPE_ID_UNTAGGED_VARIANT = CTF_TYPE_UNTAGGED_VARIANT,
-       BT_CTF_TYPE_ID_ARRAY = CTF_TYPE_ARRAY,
-       BT_CTF_TYPE_ID_SEQUENCE = CTF_TYPE_SEQUENCE,
-       BT_CTF_TYPE_ID_VARIANT = CTF_TYPE_VARIANT,
+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,
@@ -72,7 +68,7 @@ enum bt_ctf_string_encoding {
 };
 
 /* Common functions */
-enum bt_ctf_type_id bt_ctf_field_type_get_type_id(
+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);
@@ -102,9 +98,11 @@ 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_get_signed(
+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_signed(
+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);
@@ -140,7 +138,7 @@ 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);
-int bt_ctf_field_type_enumeration_get_mapping_count(
+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,
@@ -149,7 +147,7 @@ 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(
+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(
@@ -174,7 +172,7 @@ int bt_ctf_field_type_enumeration_mapping_iterator_get_signed(
                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, int64_t *OUTPUT, int64_t *OUTPUT);
+               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);
 
@@ -188,12 +186,12 @@ int bt_ctf_field_type_string_set_encoding(
 
 /* Structure field type functions */
 struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void);
-int bt_ctf_field_type_structure_get_field_count(
+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(
+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,
-               int index);
+               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);
@@ -212,14 +210,14 @@ int64_t bt_ctf_field_type_array_get_length(
                struct bt_ctf_field_type *array_field_type);
 
 /* Sequence field type functions */
-extern struct bt_ctf_field_type *bt_ctf_field_type_sequence_create(
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_create(
                struct bt_ctf_field_type *element_field_type,
                const char *length_name);
-extern struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type(
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type(
                struct bt_ctf_field_type *sequence_field_type);
-extern const char *bt_ctf_field_type_sequence_get_length_field_name(
+const char *bt_ctf_field_type_sequence_get_length_field_name(
                struct bt_ctf_field_type *sequence_field_type);
-extern struct bt_ctf_field_path *bt_ctf_field_type_sequence_get_length_field_path(
+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 */
@@ -235,12 +233,12 @@ int bt_ctf_field_type_variant_set_tag_name(
                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);
-int bt_ctf_field_type_variant_get_field_count(
+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(
+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, int index);
+               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);
diff --git a/bindings/python/bt2/native_btgraph.i b/bindings/python/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/native_btlogging.i b/bindings/python/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);
index 294110e06300c233d4efb87c2fb63c566141b439..4192278575aa53617fb2256bc911555a0c369826 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/component/notification/event.h>
-#include <babeltrace/component/notification/packet.h>
-#include <babeltrace/component/notification/schema.h>
-#include <babeltrace/component/notification/stream.h>
-%}
-
 /* Type */
-struct bt_notification;;
+struct bt_notification;
 
 /* Notification type */
 enum bt_notification_type {
+       BT_NOTIFICATION_TYPE_SENTINEL = -1000,
        BT_NOTIFICATION_TYPE_UNKNOWN = -1,
-       BT_NOTIFICATION_TYPE_ALL = 0,
-       BT_NOTIFICATION_TYPE_EVENT = 1,
-       BT_NOTIFICATION_TYPE_PACKET_BEGIN = 2,
-       BT_NOTIFICATION_TYPE_PACKET_END = 3,
-       BT_NOTIFICATION_TYPE_STREAM_END = 4,
-       BT_NOTIFICATION_TYPE_NEW_TRACE = 5,
-       BT_NOTIFICATION_TYPE_NEW_STREAM_CLASS = 6,
-       BT_NOTIFICATION_TYPE_NEW_EVENT_CLASS = 7,
-       BT_NOTIFICATION_TYPE_END_OF_TRACE = 8,
-       BT_NOTIFICATION_TYPE_NR,
+       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 */
@@ -53,34 +46,67 @@ enum bt_notification_type bt_notification_get_type(
 
 /* Event notification functions */
 struct bt_notification *bt_notification_event_create(
-               struct bt_ctf_event *event);
+               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_ctf_packet *bt_notification_packet_begin_get_packet(
-               struct bt_notification *notification);
 struct bt_notification *bt_notification_packet_end_create(
                struct bt_ctf_packet *packet);
-struct bt_ctf_packet *bt_notification_packet_end_get_packet(
-               struct bt_notification *notification);
-
-/* Schema notification functions */
-/*
-struct bt_notification *bt_notification_new_trace_create(
-               struct bt_ctf_trace *trace);
-struct bt_ctf_trace *bt_notification_new_trace_get_trace(
+struct bt_ctf_packet *bt_notification_packet_begin_get_packet(
                struct bt_notification *notification);
-struct bt_notification *bt_notification_new_stream_class_create(
-               struct bt_ctf_stream_class *stream_class);
-struct bt_ctf_trace *bt_notification_new_stream_class_get_stream_class(
+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);
index d1deb487d25ad780150a1efb0269e7804602a63e..bdc7e73de7c7c1bfa6888ddb02d53788ec10807f 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/component/notification/iterator.h>
-%}
-
 /* 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_INVAL = -1,
-       BT_NOTIFICATION_ITERATOR_STATUS_ERROR = -2,
-       BT_NOTIFICATION_ITERATOR_STATUS_NOMEM = -3,
-       BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED = -4,
-};
-
-/* Seek reference */
-enum bt_notification_iterator_seek_origin {
-       BT_NOTIFICATION_ITERATOR_SEEK_ORIGIN_BEGIN = 0,
-       BT_NOTIFICATION_ITERATOR_SEEK_ORIGIN_CURRENT = 1,
-       BT_NOTIFICATION_ITERATOR_SEEK_ORIGIN_END = 2,
-       BT_NOTIFICATION_ITERATOR_SEEK_ORIGIN_EPOCH = 3,
+       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 */
@@ -52,28 +42,22 @@ 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);
-enum bt_notification_iterator_status bt_notification_iterator_seek_time(
-               struct bt_notification_iterator *iterator,
-               enum bt_notification_iterator_seek_origin seek_origin,
-               int64_t time);
 struct bt_component *bt_notification_iterator_get_component(
                struct bt_notification_iterator *iterator);
-enum bt_notification_iterator_status bt_notification_iterator_set_private_data(
-               struct bt_notification_iterator *iterator, void *data);
-void *bt_notification_iterator_get_private_data(
-               struct bt_notification_iterator *iterator);
 
 /* Helper functions for Python */
 %{
-static PyObject *bt_py3_get_component_from_notif_iter(
-               struct bt_notification_iterator *iter)
+static PyObject *bt_py3_get_user_component_from_user_notif_iter(
+               struct bt_private_notification_iterator *priv_notif_iter)
 {
-       struct bt_component *component = bt_notification_iterator_get_component(iter);
+       struct bt_private_component *priv_comp =
+               bt_private_notification_iterator_get_private_component(
+                       priv_notif_iter);
        PyObject *py_comp;
 
-       assert(component);
-       py_comp = bt_component_get_private_data(component);
-       BT_PUT(component);
+       assert(priv_comp);
+       py_comp = bt_private_component_get_user_data(priv_comp);
+       bt_put(priv_comp);
        assert(py_comp);
 
        /* Return new reference */
@@ -82,5 +66,5 @@ static PyObject *bt_py3_get_component_from_notif_iter(
 }
 %}
 
-PyObject *bt_py3_get_component_from_notif_iter(
-               struct bt_notification_iterator *iter);
+PyObject *bt_py3_get_user_component_from_user_notif_iter(
+               struct bt_private_notification_iterator *priv_notif_iter);
index e9181e416cba97218b57914607357dd5d890f0c9..6887711088b0001080036dd04408a1a4c28a2a49 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/packet.h>
-%}
-
 /* Type */
 struct bt_ctf_packet;
 
index 95164f1bc800192ddfa299d2a6346d8a93e71a0b..5df3fcf9f1a23f90fff13869993f7459330c24e0 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/plugin/plugin.h>
-#include <assert.h>
-%}
-
 /* 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,
+       BT_PLUGIN_STATUS_OK = 0,
+       BT_PLUGIN_STATUS_ERROR = -1,
+       BT_PLUGIN_STATUS_NOMEM = -4,
 };
 
-/* Functions */
+/* 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 *OUTPUT, unsigned int *OUTPUT, unsigned int *OUTPUT,
-               const char **BTOUTSTR);
-int bt_plugin_get_component_class_count(struct bt_plugin *plugin);
-struct bt_component_class *bt_plugin_get_component_class(
-               struct bt_plugin *plugin, size_t index);
+               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);
-struct bt_plugin *bt_plugin_create_from_name(const char *plugin_name);
-
-%{
-static PyObject *bt_py3_plugin_ptrs_list_from_bt_plugins(struct bt_plugin **plugins)
-{
-       PyObject *py_plugin_ptrs = NULL;
-       struct bt_plugin **plugin_at;
-
-       if (!plugins) {
-               goto error;
-       }
-
-       py_plugin_ptrs = PyList_New(0);
-       if (!py_plugin_ptrs) {
-               goto error;
-       }
-
-       plugin_at = plugins;
-
-       while (*plugin_at) {
-               struct bt_plugin *plugin = *plugin_at;
-               PyObject *py_plugin_ptr;
-               int ret;
-
-               py_plugin_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(plugin),
-                       SWIGTYPE_p_bt_plugin, 0);
-               if (!py_plugin_ptr) {
-                       goto error;
-               }
-
-               ret = PyList_Append(py_plugin_ptrs, py_plugin_ptr);
-               Py_DECREF(py_plugin_ptr);
-               if (ret < 0) {
-                       goto error;
-               }
-
-               plugin_at++;
-       }
-
-       goto end;
-
-error:
-       Py_XDECREF(py_plugin_ptrs);
-       py_plugin_ptrs = Py_None;
-       Py_INCREF(py_plugin_ptrs);
-
-       if (plugins) {
-               /*
-                * Put existing plugin references since they are not
-                * moved to the caller.
-                */
-               plugin_at = plugins;
-
-               while (*plugin_at) {
-                       bt_put(*plugin_at);
-                       plugin_at++;
-               }
-       }
-
-end:
-       PyErr_Clear();
-       free(plugins);
-       return py_plugin_ptrs;
-}
-
-static PyObject *bt_py3_plugin_create_all_from_file(const char *path)
-{
-       return bt_py3_plugin_ptrs_list_from_bt_plugins(
-               bt_plugin_create_all_from_file(path));
-}
-
-static PyObject *bt_py3_plugin_create_all_from_dir(const char *path,
-               bool recurse)
-{
-       return bt_py3_plugin_ptrs_list_from_bt_plugins(
-               bt_plugin_create_all_from_dir(path, recurse));
-}
-%}
 
-PyObject *bt_py3_plugin_create_all_from_file(const char *path);
-PyObject *bt_py3_plugin_create_all_from_dir(const char *path,
-               bool recurse);
+/* 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/native_btport.i b/bindings/python/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);
index 1d7a2d31385a4727a77656f9c670b2940a679626..dacf916a94320782aaa66f2a2d9b92d00ff7c19c 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ref.h>
-%}
-
 /* Functions */
 void *bt_get(void *obj);
 void bt_put(void *obj);
index 91d4dd8222137ae7d526f2293371accd4d17426f..39747bc7c92a474faff5e0fe23ee4c00a491a6ce 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/stream.h>
-%}
-
 /* Type */
 struct bt_ctf_stream;
 
@@ -33,6 +29,10 @@ struct bt_ctf_stream;
 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);
index 2ba6024c473a8780c61d0fd37819d90b868309a4..824405712d1de85fccb79bf5bf6136bb913e6e19 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/stream-class.h>
-%}
-
 /* 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);
@@ -40,7 +38,7 @@ int bt_ctf_stream_class_set_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, uint32_t 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(
@@ -58,14 +56,12 @@ bt_ctf_stream_class_get_event_context_type(
 int bt_ctf_stream_class_set_event_context_type(
                struct bt_ctf_stream_class *stream_class,
                struct bt_ctf_field_type *event_context_type);
-int bt_ctf_stream_class_get_event_class_count(
+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(
-               struct bt_ctf_stream_class *stream_class, int index);
-struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_name(
-               struct bt_ctf_stream_class *stream_class, const char *name);
+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, uint32_t 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);
index 523acf7adf7c12fdb282aeac9fda195751af05be..8947ae07ac6b46fb98b9c70685df5d7400d35f32 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/ctf-ir/trace.h>
-%}
-
 /* 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);
-int bt_ctf_trace_set_name(struct bt_ctf_trace *trace,
+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_byte_order(
-               struct bt_ctf_trace *trace);
-int bt_ctf_trace_set_byte_order(struct bt_ctf_trace *trace,
-               enum bt_ctf_byte_order byte_order);
-int bt_ctf_trace_get_environment_field_count(
-               struct bt_ctf_trace *trace);
+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(struct bt_ctf_trace *trace,
-               int index);
+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(struct bt_ctf_trace *trace,
-               int index);
+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, const char *name);
+               struct bt_ctf_trace *trace_class, const char *name);
 int bt_ctf_trace_set_environment_field(
-               struct bt_ctf_trace *trace, const char *name,
+               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);
-int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace,
+               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);
-int bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace);
-struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class(
-               struct bt_ctf_trace *trace, int index);
+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, const char *name);
-int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
+               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);
-int bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace);
-struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class(
-               struct bt_ctf_trace *trace, int index);
+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, uint32_t id);
-int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
+               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);
index 57fdae7d367c9887ff58fa224b3641293e57050a..6563bced267e35d904f29a921d49268e4b18f863 100644 (file)
  * THE SOFTWARE.
  */
 
-%{
-#include <babeltrace/values.h>
-%}
-
-/* For uint*_t/int*_t */
-%include "stdint.i"
-
 /* Remove prefix from `bt_value_null` */
 %rename(value_null) bt_value_null;
 
@@ -61,18 +54,18 @@ struct bt_value * const bt_value_null;
 
 /* Common functions */
 enum bt_value_status bt_value_freeze(struct bt_value *object);
-bool bt_value_is_frozen(const 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);
-bool bt_value_compare(const struct bt_value *object_a,
+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(bool val);
+struct bt_value *bt_value_bool_create_init(int val);
 enum bt_value_status bt_value_bool_get(
-               const struct bt_value *bool_obj, bool *OUTPUT);
+               const struct bt_value *bool_obj, int *OUTPUT);
 enum bt_value_status bt_value_bool_set(struct bt_value *bool_obj,
-               bool val);
+               int val);
 
 /* Integer value object functions */
 struct bt_value *bt_value_integer_create(void);
@@ -113,18 +106,20 @@ 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);
-bool bt_value_map_has_key(const struct bt_value *map_obj,
+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 bool bt_value_map_get_keys_private_cb(const char *key,
+static int bt_value_map_get_keys_private_cb(const char *key,
                struct bt_value *object, void *data)
 {
        enum bt_value_status status;
@@ -132,10 +127,10 @@ static bool bt_value_map_get_keys_private_cb(const char *key,
 
        status = bt_value_array_append_string(priv_data->keys, key);
        if (status != BT_VALUE_STATUS_OK) {
-               return false;
+               return BT_FALSE;
        }
 
-       return true;
+       return BT_TRUE;
 }
 
 static struct bt_value *bt_value_map_get_keys_private(
diff --git a/bindings/python/bt2/native_btversion.i b/bindings/python/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);
index 66ed4cd063f6fc11a56ac38b306d225d88685ea3..2ad8487893dd8a141c3c3610c6cff44bd66f88e7 100644 (file)
 # 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
 
 
@@ -41,113 +43,423 @@ class _Notification(object._Object):
     pass
 
 
-class TraceEventNotification(_Notification):
-    def __init__(self, event):
+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)
-        ptr = native_bt.notification_event_create(event._ptr)
+
+        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 trace event notification object')
+            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)
-        utils._handle_ptr(event_ptr, "cannot get trace event notification object's event object")
+        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
 
-class BeginningOfPacketNotification(_Notification):
     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 beginning of packet notification object')
+            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)
-        utils._handle_ptr(packet_ptr, "cannot get beginning of packet notification object's packet object")
+        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
 
-class EndOfPacketNotification(_Notification):
     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 end of packet notification object')
+            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)
-        utils._handle_ptr(packet_ptr, "cannot get end of packet notification object's packet object")
+        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
 
-class EndOfStreamNotification(_Notification):
     def __init__(self, stream):
         utils._check_type(stream, bt2.stream._Stream)
-        ptr = native_bt.notification_stream_end_create(stream._ptr)
+        ptr = native_bt.notification_stream_begin_create(stream._ptr)
 
         if ptr is None:
-            raise bt2.CreationError('cannot create end of stream notification object')
+            raise bt2.CreationError('cannot create stream beginning notification object')
 
         super().__init__(ptr)
 
     @property
     def stream(self):
-        stream_ptr = native_bt.notification_stream_end_get_stream(self._ptr)
-        utils._handle_ptr(stream_ptr, "cannot get end of stream notification object's stream object")
+        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
 
-class NewTraceNotification(_Notification):
-    def __init__(self, trace):
-        utils._check_type(trace, bt2.Trace)
-        ptr = native_bt.notification_new_trace_create(trace._ptr)
+    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 new trace notification object')
+            raise bt2.CreationError('cannot create stream end notification object')
 
         super().__init__(ptr)
 
     @property
-    def trace(self):
-        trace_ptr = native_bt.notification_new_trace_get_trace(self._ptr)
-        utils._handle_ptr(trace_ptr, "cannot get new trace notification object's trace object")
-        return bt2.trace._create_from_ptr(trace_ptr)
+    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
 
-class NewStreamClassNotification(_Notification):
-    def __init__(self, stream_class):
-        utils._check_type(stream_class, bt2.StreamClass)
-        ptr = native_bt.notification_new_stream_class_create(stream_class._ptr)
+        ptr = native_bt.notification_inactivity_create(cc_prio_map_ptr)
 
         if ptr is None:
-            raise bt2.CreationError('cannot create new stream class notification object')
+            raise bt2.CreationError('cannot create inactivity notification object')
 
         super().__init__(ptr)
 
     @property
-    def stream_class(self):
-        stream_class_ptr = native_bt.notification_new_stream_class_get_stream_class(self._ptr)
-        utils._handle_ptr(stream_class_ptr, "cannot get new stream class notification object's stream class object")
-        return bt2.stream_class.StreamClass._create_from_ptr(stream_class_ptr)
+    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: TraceEventNotification,
-    native_bt.NOTIFICATION_TYPE_PACKET_BEGIN: BeginningOfPacketNotification,
-    native_bt.NOTIFICATION_TYPE_PACKET_END: EndOfPacketNotification,
-    native_bt.NOTIFICATION_TYPE_STREAM_END: EndOfStreamNotification,
-    native_bt.NOTIFICATION_TYPE_NEW_TRACE: NewTraceNotification,
-    native_bt.NOTIFICATION_TYPE_NEW_STREAM_CLASS: NewStreamClassNotification,
+    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,
 }
index e0d0b0c79f3e1ce520a42e61c207a3eadbec231a..39b6bf0e3b776dd8160342c2d49250141e25a2ec 100644 (file)
@@ -27,62 +27,54 @@ import bt2.component
 import bt2
 
 
-class NotificationIteratorSeekOrigin:
-    BEGIN = native_bt.NOTIFICATION_ITERATOR_SEEK_ORIGIN_BEGIN
-    CURRENT = native_bt.NOTIFICATION_ITERATOR_SEEK_ORIGIN_CURRENT
-    END = native_bt.NOTIFICATION_ITERATOR_SEEK_ORIGIN_END
-
-
-class _GenericNotificationIteratorMethods(collections.abc.Iterator):
-    @property
-    def notification(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)
-
+class _NotificationIterator(collections.abc.Iterator):
     def _handle_status(self, status, gen_error_msg):
-        if status == native_bt.NOTIFICATION_ITERATOR_STATUS_END:
+        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):
-        status = native_bt.notification_iterator_next(self._ptr)
-        self._handle_status(status,
-                            'unexpected error: cannot go to the next notification')
-
     def __next__(self):
-        self.next()
-        return self.notification
-
-    def seek_to_time(self, origin, time):
-        utils._check_int64(origin)
-        utils._check_int64(time)
-        status = native_bt.notification_iterator_seek_time(self._ptr, origin,
-                                                           time)
-        self._handle_status(status,
-                            'unexpected error: cannot seek notification iterator to time')
+        raise NotImplementedError
 
 
-class _GenericNotificationIterator(object._Object, _GenericNotificationIteratorMethods):
+class _GenericNotificationIterator(object._Object, _NotificationIterator):
     @property
     def component(self):
         comp_ptr = native_bt.notification_iterator_get_component(self._ptr)
-        utils._handle_ptr(comp_ptr, "cannot get notification iterator object's component object")
+        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(_GenericNotificationIteratorMethods):
+
+class _UserNotificationIterator(_NotificationIterator):
     def __new__(cls, ptr):
-        # User iterator objects are always created by the BT system,
+        # User iterator objects are always created by the native side,
         # that is, never instantiated directly by Python code.
         #
-        # The system 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.
+        # 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__().
@@ -94,22 +86,30 @@ class UserNotificationIterator(_GenericNotificationIteratorMethods):
         pass
 
     @property
-    def component(self):
-        return native_bt.py3_get_component_from_notif_iter(self._ptr)
+    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 _destroy(self):
+    def _finalize(self):
         pass
 
-    def _get_from_bt(self):
-        # this can raise anything: it's catched by the system
-        notif = self._get()
+    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)
 
-        # steal the underlying native notification object for the caller
-        notif_ptr = notif._ptr
-        notif._ptr = None
-        return int(notif_ptr)
+        # take a new reference for the native part
+        notif._get()
+        return int(notif._ptr)
index ef574e1220778660db39401521f07b3bf4b80cfb..774027cbdc6685105b72bb1154d3992eb385fe5d 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -44,6 +44,7 @@ class _Object:
     def __del__(self):
         ptr = getattr(self, '_ptr', None)
         native_bt.put(ptr)
+        self._ptr = None
 
     def __repr__(self):
         return '<{}.{} object @ {}>'.format(self.__class__.__module__,
@@ -51,6 +52,14 @@ class _Object:
                                             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):
index 9a9d79b7870d9057eb023a13ba88e86a4ba82c89..1fba03cac77645ea4baf183887c3b9850552be1a 100644 (file)
@@ -32,7 +32,7 @@ class _Packet(object._Object):
     @property
     def stream(self):
         stream_ptr = native_bt.ctf_packet_get_stream(self._ptr)
-        utils._handle_ptr(stream_ptr, "cannot get packet object's stream object")
+        assert(stream_ptr)
         return bt2.stream._Stream._create_from_ptr(stream_ptr)
 
     @property
index 920eb63642d71502868c3cc3becbe69e3c41e3af..a37e7631340d206f0b6988af8777f0f058730e14 100644 (file)
 from bt2 import native_bt, object, utils
 import collections.abc
 import bt2.component
+import os.path
 import bt2
 
 
-def _plugin_ptrs_to_plugins(plugin_ptrs):
-    plugins = []
-
-    for plugin_ptr in plugin_ptrs:
-        plugin = _Plugin._create_from_ptr(plugin_ptr)
-        plugins.append(plugin)
+def find_plugins(path, recurse=True):
+    utils._check_str(path)
+    utils._check_bool(recurse)
+    plugin_set_ptr = None
 
-    return plugins
+    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
 
-def create_plugins_from_file(path):
-    utils._check_str(path)
-    plugin_ptrs = native_bt.py3_plugin_create_all_from_file(path)
+    return _PluginSet._create_from_ptr(plugin_set_ptr)
 
-    if plugin_ptrs is None:
-        raise bt2.Error('cannot get plugin objects from file')
 
-    return _plugin_ptrs_to_plugins(plugin_ptrs)
+def find_plugin(name):
+    utils._check_str(name)
+    ptr = native_bt.plugin_find(name)
 
+    if ptr is None:
+        return
 
-def create_plugins_from_dir(path, recurse=True):
-    utils._check_str(path)
-    plugin_ptrs = native_bt.py3_plugin_create_all_from_dir(path, recurse)
+    return _Plugin._create_from_ptr(ptr)
 
-    if plugin_ptrs is None:
-        raise bt2.Error('cannot get plugin objects from directory')
-
-    return _plugin_ptrs_to_plugins(plugin_ptrs)
 
+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 create_plugin_from_name(name):
-    utils._check_str(name)
-    plugin_ptr = native_bt.plugin_create_from_name(name)
+    def __getitem__(self, index):
+        utils._check_uint64(index)
 
-    if plugin_ptr is None:
-        raise bt2.NoSuchPluginError(name)
+        if index >= len(self):
+            raise IndexError
 
-    return _Plugin._create_from_ptr(plugin_ptr)
+        plugin_ptr = native_bt.plugin_set_get_plugin(self._ptr, index)
+        assert(plugin_ptr)
+        return _Plugin._create_from_ptr(plugin_ptr)
 
 
 class _PluginVersion:
@@ -98,11 +102,79 @@ class _PluginVersion:
         return '{}.{}.{}{}'.format(self._major, self._minor, self._patch, extra)
 
 
-class _Plugin(object._Object, collections.abc.Sequence):
+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)
-        utils._handle_ptr(name, "cannot get plugin object's name")
+        assert(name is not None)
         return name
 
     @property
@@ -130,50 +202,14 @@ class _Plugin(object._Object, collections.abc.Sequence):
 
         return _PluginVersion(major, minor, patch, extra)
 
-    def source_component_class(self, name):
-        utils._check_str(name)
-        cc_ptr = native_bt.plugin_get_component_class_by_name_and_type(self._ptr,
-                                                                       name,
-                                                                       native_bt.COMPONENT_CLASS_TYPE_SOURCE)
-
-        if cc_ptr is None:
-            return
-
-        return bt2.component._create_generic_component_class_from_ptr(cc_ptr)
-
-    def filter_component_class(self, name):
-        utils._check_str(name)
-        cc_ptr = native_bt.plugin_get_component_class_by_name_and_type(self._ptr,
-                                                                       name,
-                                                                       native_bt.COMPONENT_CLASS_TYPE_FILTER)
-
-        if cc_ptr is None:
-            return
-
-        return bt2.component._create_generic_component_class_from_ptr(cc_ptr)
-
-    def sink_component_class(self, name):
-        utils._check_str(name)
-        cc_ptr = native_bt.plugin_get_component_class_by_name_and_type(self._ptr,
-                                                                       name,
-                                                                       native_bt.COMPONENT_CLASS_TYPE_SINK)
-
-        if cc_ptr is None:
-            return
-
-        return bt2.component._create_generic_component_class_from_ptr(cc_ptr)
-
-    def __len__(self):
-        count = native_bt.plugin_get_component_class_count(self._ptr)
-        utils._handle_ret(count, "cannot get plugin object's component class count")
-        return count
-
-    def __getitem__(self, index):
-        utils._check_uint64(index)
+    @property
+    def source_component_classes(self):
+        return _PluginComponentClasses(self, native_bt.COMPONENT_CLASS_TYPE_SOURCE)
 
-        if index >= len(self):
-            raise IndexError
+    @property
+    def filter_component_classes(self):
+        return _PluginComponentClasses(self, native_bt.COMPONENT_CLASS_TYPE_FILTER)
 
-        cc_ptr = native_bt.plugin_get_component_class(self._ptr, index)
-        utils._handle_ptr(cc_ptr, "cannot get plugin object's component class object")
-        return bt2.component._create_generic_component_class_from_ptr(cc_ptr)
+    @property
+    def sink_component_classes(self):
+        return _PluginComponentClasses(self, native_bt.COMPONENT_CLASS_TYPE_SINK)
diff --git a/bindings/python/bt2/port.py b/bindings/python/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
index 56bd5100e397b0ab9b49f25d81e4cec20615eaa6..32fb9a5fb0de8c44e9daa5e1d8e05593d72f48a8 100644 (file)
@@ -42,18 +42,23 @@ class _StreamBase(object._Object):
     @property
     def stream_class(self):
         stream_class_ptr = native_bt.ctf_stream_get_class(self._ptr)
-        utils._handle_ptr(stream_class_ptr, "cannot get stream object's stream class object")
+        assert(stream_class_ptr)
         return bt2.StreamClass._create_from_ptr(stream_class_ptr)
 
     @property
     def name(self):
         return native_bt.ctf_stream_get_name(self._ptr)
 
+    @property
+    def id(self):
+        id = native_bt.ctf_stream_get_id(self._ptr)
+        return id if id >= 0 else None
+
     def __eq__(self, other):
         if self.addr == other.addr:
             return True
 
-        return self.name == other.name
+        return (self.name, self.id) == (other.name, other.id)
 
 
 class _Stream(_StreamBase):
@@ -72,7 +77,7 @@ class _Stream(_StreamBase):
         return _StreamBase.__eq__(self, other)
 
     def _copy(self):
-        return self.stream_class(self.name)
+        return self.stream_class(self.name, self.id)
 
     def __copy__(self):
         return self._copy()
index ce03edfeb995a72fbb9849ddbd952026dfa14ab5..17c6de0f975bff9e6866683f9d2f637025ab46fa 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -38,21 +38,21 @@ class _EventClassIterator(collections.abc.Iterator):
         if self._at == len(self._stream_class):
             raise StopIteration
 
-        ec_ptr = native_bt.ctf_stream_class_get_event_class(self._stream_class._ptr,
-                                                            self._at)
-        utils._handle_ptr(ec_ptr, "cannot get stream class object's event class object")
-        name = native_bt.ctf_event_class_get_name(ec_ptr)
+        ec_ptr = native_bt.ctf_stream_class_get_event_class_by_index(self._stream_class._ptr,
+                                                                     self._at)
+        assert(ec_ptr)
+        ev_id = native_bt.ctf_event_class_get_id(ec_ptr)
         native_bt.put(ec_ptr)
-        utils._handle_ptr(name, "cannot get event class object's name")
+        utils._handle_ret(ev_id, "cannot get event class object's ID")
         self._at += 1
-        return name
+        return ev_id
 
 
 class StreamClass(object._Object, collections.abc.Mapping):
     def __init__(self, name=None, id=None, packet_context_field_type=None,
                  event_header_field_type=None, event_context_field_type=None,
                  event_classes=None):
-        ptr = native_bt.ctf_stream_class_create(None)
+        ptr = native_bt.ctf_stream_class_create_empty(None)
 
         if ptr is None:
             raise bt2.CreationError('cannot create stream class object')
@@ -79,9 +79,9 @@ class StreamClass(object._Object, collections.abc.Mapping):
                 self.add_event_class(event_class)
 
     def __getitem__(self, key):
-        utils._check_str(key)
-        ec_ptr = native_bt.ctf_stream_class_get_event_class_by_name(self._ptr,
-                                                                    key)
+        utils._check_int64(key)
+        ec_ptr = native_bt.ctf_stream_class_get_event_class_by_id(self._ptr,
+                                                                  key)
 
         if ec_ptr is None:
             raise KeyError(key)
@@ -90,18 +90,12 @@ class StreamClass(object._Object, collections.abc.Mapping):
 
     def __len__(self):
         count = native_bt.ctf_stream_class_get_event_class_count(self._ptr)
-        utils._handle_ret(count, "cannot get stream class object's event class count")
+        assert(count >= 0)
         return count
 
     def __iter__(self):
         return _EventClassIterator(self)
 
-    def event_class_with_id(self, id):
-        utils._check_int64(id)
-        ec_ptr = native_bt.ctf_stream_class_get_event_class_by_id(self._ptr, id)
-        utils._handle_ptr(ec_ptr, "cannot get stream class object's event class object")
-        return bt2.EventClass._create_from_ptr(ec_ptr)
-
     def add_event_class(self, event_class):
         utils._check_type(event_class, bt2.EventClass)
         ret = native_bt.ctf_stream_class_add_event_class(self._ptr, event_class._ptr)
@@ -128,8 +122,8 @@ class StreamClass(object._Object, collections.abc.Mapping):
     def id(self):
         id = native_bt.ctf_stream_class_get_id(self._ptr)
 
-        if utils._is_m1ull(id):
-            raise bt2.Error("cannot get stream class object's ID")
+        if id < 0:
+            return
 
         return id
 
@@ -217,11 +211,14 @@ class StreamClass(object._Object, collections.abc.Mapping):
                                                                event_context_field_type_ptr)
         utils._handle_ret(ret, "cannot set stream class object's event context field type")
 
-    def __call__(self, name=None):
+    def __call__(self, name=None, id=None):
         if name is not None:
             utils._check_str(name)
 
-        stream_ptr = native_bt.ctf_stream_create(self._ptr, name)
+        if id is None:
+            stream_ptr = native_bt.ctf_stream_create(self._ptr, name)
+        else:
+            stream_ptr = native_bt.ctf_stream_create_with_id(self._ptr, name, id)
 
         if stream_ptr is None:
             raise bt2.CreationError('cannot create stream object')
@@ -241,26 +238,35 @@ class StreamClass(object._Object, collections.abc.Mapping):
             self_event_classes,
             self.name,
             self.id,
-            self.clock,
             self.packet_context_field_type,
             self.event_header_field_type,
             self.event_context_field_type,
+            self.clock,
         )
         other_props = (
             other_event_classes,
             other.name,
             other.id,
-            other.clock,
             other.packet_context_field_type,
             other.event_header_field_type,
             other.event_context_field_type,
+            other.clock,
         )
+
         return self_props == other_props
 
     def _copy(self, ft_copy_func, ev_copy_func):
         cpy = StreamClass()
-        cpy.id = self.id
-        cpy.name = self.name
+
+        if self.id is not None:
+            cpy.id = self.id
+
+        if self.name is not None:
+            cpy.name = self.name
+
+        if self.clock is not None:
+            cpy.clock = self.clock
+
         cpy.packet_context_field_type = ft_copy_func(self.packet_context_field_type)
         cpy.event_header_field_type = ft_copy_func(self.event_header_field_type)
         cpy.event_context_field_type = ft_copy_func(self.event_context_field_type)
index 8ecbb386284e6ab190476938d842877d32245f47..3d5c4e3f292491e6db65e846e67a25deaa517311 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -24,6 +24,7 @@ from bt2 import native_bt, object, utils
 import bt2.field_types
 import collections.abc
 import bt2.values
+import bt2.stream
 import copy
 import bt2
 
@@ -37,19 +38,37 @@ class _StreamClassIterator(collections.abc.Iterator):
         if self._at == len(self._trace):
             raise StopIteration
 
-        sc_ptr = native_bt.ctf_trace_get_stream_class(self._trace._ptr,
-                                                      self._at)
-        utils._handle_ptr(sc_ptr, "cannot get trace class object's stream class object")
+        sc_ptr = native_bt.ctf_trace_get_stream_class_by_index(self._trace._ptr,
+                                                               self._at)
+        assert(sc_ptr)
         id = native_bt.ctf_stream_class_get_id(sc_ptr)
         native_bt.put(sc_ptr)
-
-        if utils._is_m1ull(id):
-            raise bt2.Error("cannot get stream class object's ID")
-
+        assert(id >= 0)
         self._at += 1
         return id
 
 
+class _TraceStreams(collections.abc.Sequence):
+    def __init__(self, trace):
+        self._trace = trace
+
+    def __len__(self):
+        count = native_bt.ctf_trace_get_stream_count(self._trace._ptr)
+        assert(count >= 0)
+        return count
+
+    def __getitem__(self, index):
+        utils._check_uint64(index)
+
+        if index >= len(self):
+            raise IndexError
+
+        stream_ptr = native_bt.ctf_trace_get_stream_by_index(self._trace._ptr,
+                                                             index)
+        assert(stream_ptr)
+        return bt2.stream._create_from_ptr(stream_ptr)
+
+
 class _TraceClockClassesIterator(collections.abc.Iterator):
     def __init__(self, trace_clock_classes):
         self._trace_clock_classes = trace_clock_classes
@@ -60,11 +79,11 @@ class _TraceClockClassesIterator(collections.abc.Iterator):
             raise StopIteration
 
         trace_ptr = self._trace_clock_classes._trace._ptr
-        cc_ptr = native_bt.ctf_trace_get_clock_class(trace_ptr, self._at)
-        utils._handle_ptr(cc_ptr, "cannot get trace class object's clock class")
+        cc_ptr = native_bt.ctf_trace_get_clock_class_by_index(trace_ptr, self._at)
+        assert(cc_ptr)
         name = native_bt.ctf_clock_class_get_name(cc_ptr)
         native_bt.put(cc_ptr)
-        utils._handle_ptr(name, "cannot get clock class object's name")
+        assert(name is not None)
         self._at += 1
         return name
 
@@ -85,7 +104,7 @@ class _TraceClockClasses(collections.abc.Mapping):
 
     def __len__(self):
         count = native_bt.ctf_trace_get_clock_class_count(self._trace._ptr)
-        utils._handle_ret(count, "cannot get trace class object's clock class count")
+        assert(count >= 0)
         return count
 
     def __iter__(self):
@@ -102,9 +121,9 @@ class _TraceEnvIterator(collections.abc.Iterator):
             raise StopIteration
 
         trace_ptr = self._trace_env._trace._ptr
-        entry_name = native_bt.ctf_trace_get_environment_field_name(trace_ptr,
-                                                                    self._at)
-        utils._handle_ptr(entry_name, "cannot get trace class object's environment entry name")
+        entry_name = native_bt.ctf_trace_get_environment_field_name_by_index(trace_ptr,
+                                                                             self._at)
+        assert(entry_name is not None)
         self._at += 1
         return entry_name
 
@@ -135,7 +154,7 @@ class _TraceEnv(collections.abc.MutableMapping):
 
     def __len__(self):
         count = native_bt.ctf_trace_get_environment_field_count(self._trace._ptr)
-        utils._handle_ret(count, "cannot get trace class object's environment entry count")
+        assert(count >= 0)
         return count
 
     def __iter__(self):
@@ -185,7 +204,7 @@ class Trace(object._Object, collections.abc.Mapping):
 
     def __len__(self):
         count = native_bt.ctf_trace_get_stream_class_count(self._ptr)
-        utils._handle_ret(count, "cannot get trace class object's stream class count")
+        assert(count >= 0)
         return count
 
     def __iter__(self):
@@ -208,16 +227,25 @@ class Trace(object._Object, collections.abc.Mapping):
 
     @property
     def native_byte_order(self):
-        bo = native_bt.ctf_trace_get_byte_order(self._ptr)
-        utils._handle_ret(bo, "cannot get trace class object's native byte order")
+        bo = native_bt.ctf_trace_get_native_byte_order(self._ptr)
+        assert(bo >= 0)
         return bo
 
     @native_byte_order.setter
     def native_byte_order(self, native_byte_order):
         utils._check_int(native_byte_order)
-        ret = native_bt.ctf_trace_set_byte_order(self._ptr, native_byte_order)
+        ret = native_bt.ctf_trace_set_native_byte_order(self._ptr, native_byte_order)
         utils._handle_ret(ret, "cannot set trace class object's native byte order")
 
+    @property
+    def is_static(self):
+        is_static = native_bt.ctf_trace_is_static(self._ptr)
+        return is_static > 0
+
+    def set_is_static(self):
+        ret = native_bt.ctf_trace_set_is_static(self._ptr)
+        utils._handle_ret(ret, "cannot set trace object as static")
+
     @property
     def env(self):
         return _TraceEnv(self)
@@ -231,6 +259,10 @@ class Trace(object._Object, collections.abc.Mapping):
         ret = native_bt.ctf_trace_add_clock_class(self._ptr, clock_class._ptr)
         utils._handle_ret(ret, "cannot add clock class object to trace class object")
 
+    @property
+    def streams(self):
+        return _TraceStreams(self)
+
     @property
     def packet_header_field_type(self):
         ft_ptr = native_bt.ctf_trace_get_packet_header_type(self._ptr)
index 52133a58f7a70318119975db2050e6d5524ebd85..294fadb6edc91a4bc1952dab96f8f08545ed50ed 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -88,7 +88,6 @@ def _is_pow2(v):
 def _check_alignment(a):
     _check_uint64(a)
 
-
     if not _is_pow2(a):
         raise ValueError('{} is not a power of two'.format(a))
 
index 6af3d7a01a93691bc437250dbf62b6325603e2d0..26444e1aad025cbe3da3fb38614f7b35a1739c69 100644 (file)
@@ -1,6 +1,6 @@
 # The MIT License (MIT)
 #
-# Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+# 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
@@ -34,7 +34,7 @@ def _handle_status(status, obj_name):
         return
 
     if status == native_bt.VALUE_STATUS_FROZEN:
-        raise bt2.FrozenError('{} value object is frozen'.format(obj_name))
+        raise bt2.Frozen('{} value object is frozen'.format(obj_name))
     elif status == native_bt.VALUE_STATUS_INVAL:
         # In practice, this should never happen, because arguments
         # should always be validated in this Python module before
@@ -89,9 +89,6 @@ def create_value(value):
 
 
 class _Value(object._Object, object._Freezable, metaclass=abc.ABCMeta):
-    def __init__(self, ptr):
-        super().__init__(ptr)
-
     def __eq__(self, other):
         if other is None:
             # self is never the null value object
@@ -187,7 +184,7 @@ class _NumericValue(_Value, _BasicCopy):
         return self.value <= float(other)
 
     def _spec_eq(self, other):
-        return
+        pass
 
     def __eq__(self, other):
         if not isinstance(other, numbers.Number):
@@ -372,13 +369,13 @@ class BoolValue(_Value, _BasicCopy):
         if not isinstance(value, bool):
             raise TypeError("'{}' object is not a 'bool' or 'BoolValue' object".format(value.__class__))
 
-        return value
+        return int(value)
 
     @property
     def value(self):
         status, value = native_bt.value_bool_get(self._ptr)
-        self._handle_status(status)
-        return value
+        assert(status == native_bt.VALUE_STATUS_OK)
+        return value > 0
 
     @value.setter
     def value(self, value):
@@ -409,7 +406,7 @@ class IntegerValue(_IntegralValue):
     @property
     def value(self):
         status, value = native_bt.value_integer_get(self._ptr)
-        self._handle_status(status)
+        assert(status == native_bt.VALUE_STATUS_OK)
         return value
 
     @value.setter
@@ -440,7 +437,7 @@ class FloatValue(_RealValue):
     @property
     def value(self):
         status, value = native_bt.value_float_get(self._ptr)
-        self._handle_status(status)
+        assert(status == native_bt.VALUE_STATUS_OK)
         return value
 
     @value.setter
@@ -473,7 +470,7 @@ class StringValue(_BasicCopy, collections.abc.Sequence, _Value):
     @property
     def value(self):
         status, value = native_bt.value_string_get(self._ptr)
-        self._handle_status(status)
+        assert(status == native_bt.VALUE_STATUS_OK)
         return value
 
     @value.setter
@@ -523,8 +520,7 @@ class _Container:
         ptr = native_bt.value_copy(self._ptr)
 
         if ptr is None:
-            fmt = 'unexpected error: cannot deep-copy {} value object'
-            raise RuntimeError(fmt.format(self._NAME))
+            raise RuntimeError('unexpected error: cannot deep-copy {} value object'.format(self._NAME))
 
         copy = self.__class__._create_from_ptr(ptr)
         memo[id(self)] = copy
@@ -564,7 +560,7 @@ class ArrayValue(_Container, collections.abc.MutableSequence, _Value):
 
     def __len__(self):
         size = native_bt.value_array_size(self._ptr)
-        self._handle_status(size)
+        assert(size >= 0)
         return size
 
     def _check_index(self, index):
@@ -580,10 +576,7 @@ class ArrayValue(_Container, collections.abc.MutableSequence, _Value):
     def __getitem__(self, index):
         self._check_index(index)
         ptr = native_bt.value_array_get(self._ptr, index)
-
-        if ptr is None:
-            raise RuntimeError('unexpected error: cannot get array value object element')
-
+        assert(ptr)
         return _create_from_ptr(ptr)
 
     def __setitem__(self, index, value):
@@ -694,7 +687,7 @@ class MapValue(_Container, collections.abc.MutableMapping, _Value):
 
     def __len__(self):
         size = native_bt.value_map_size(self._ptr)
-        self._handle_status(size)
+        assert(size >= 0)
         return size
 
     def __contains__(self, key):
@@ -711,10 +704,7 @@ class MapValue(_Container, collections.abc.MutableMapping, _Value):
     def __getitem__(self, key):
         self._check_key(key)
         ptr = native_bt.value_map_get(self._ptr, key)
-
-        if ptr is None:
-            raise RuntimeError('unexpected error: cannot get map value object element')
-
+        assert(ptr)
         return _create_from_ptr(ptr)
 
     def __iter__(self):
index cd24ae4263f585b901c85c27ce5522fc778e02b1..ad89358d3f8f21f477038f73e750025e414815e6 100644 (file)
@@ -497,7 +497,7 @@ AS_IF([test "x$enable_built_in_python_plugin_support" = xyes],
 )
 
 
-# Check for conflicting optionnal features user choices
+# Check for conflicting optional features user choices
 
 AS_IF([test "x$enable_python_bindings" = xno],
   [
@@ -655,14 +655,11 @@ CFLAGS=${save_CFLAGS}
 program_transform_name="s&babeltrace\.bin&babeltrace&;s&babeltrace-log\.bin&babeltrace-log&;$program_transform_name"
 AC_SUBST(program_transform_name)
 
-
-       #TODO: removed, work in progress
-       #bindings/python/Makefile
-       #bindings/python/babeltrace/Makefile
-       #bindings/python/bt2/Makefile
-       #bindings/python/bt2/__init__.py
 AC_CONFIG_FILES([
        Makefile
+       bindings/python/Makefile
+       bindings/python/bt2/Makefile
+       bindings/python/bt2/__init__.py
        common/Makefile
        compat/Makefile
        cli/Makefile
@@ -737,7 +734,7 @@ AC_CONFIG_FILES([tests/plugins/test-utils-muxer-complete], [chmod +x tests/plugi
 AC_CONFIG_FILES([tests/plugins/test_dwarf_complete], [chmod +x tests/plugins/test_dwarf_complete])
 AC_CONFIG_FILES([tests/plugins/test_bin_info_complete], [chmod +x tests/plugins/test_bin_info_complete])
 
-AS_IF([test "x$enable_python" = xyes],
+AS_IF([test "x$enable_python_bindings_tests" = xyes],
   [AC_CONFIG_FILES([tests/bindings/python/bt2/testall.sh], [chmod +x tests/bindings/python/bt2/testall.sh])]
 )
 
index 869bc00562e4b4ee9f33dc360f40378e600acf9b..1a31f26eb6fb8c3ed1ded3f8224df02a613409a6 100644 (file)
@@ -5,10 +5,17 @@ omit =
     *native_*.py
     */object.py
     */utils.py
+    */logging.py
+    */py_plugin.py
 
 [report]
 exclude_lines =
     def __repr__
     raise bt2\.CreationError
     raise NotImplementedError
+    return NotImplemented
     pass
+    raise \w+Error\(['"][Uu]nexpected
+    if (self|other)\.addr == (self|other)\.addr
+    if not _NO_PRINT_TRACEBACK
+    class _PluginVersion:
index 31dfbe4dc6cddc4889703d729734c07baa9cc8be..a31d9be8b459cb903a1681bbc752e0c162f280d6 100644 (file)
@@ -1,17 +1,26 @@
 check_SCRIPTS = testall.sh
-EXTRA_DIST = \
-       $(check_SCRIPTS) \
-       test_clock_class.py \
-       test_ctf_writer_clock.py \
-       test_event_class.py \
-       test_event.py \
-       test_fields.py \
-       test_field_types.py \
-       test_packet.py \
-       test_stream_class.py \
-       test_stream.py \
-       test_trace.py \
-       test_values.py \
+EXTRA_DIST =                                   \
+       $(check_SCRIPTS)                        \
+       test_clock_class.py                     \
+       test_clock_class_priority_map.py        \
+       test_component.py                       \
+       test_component_class.py                 \
+       test_connection.py                      \
+       test_ctf_writer_clock.py                \
+       test_event.py                           \
+       test_event_class.py                     \
+       test_field_types.py                     \
+       test_fields.py                          \
+       test_graph.py                           \
+       test_notification.py                    \
+       test_notification_iterator.py           \
+       test_packet.py                          \
+       test_plugin.py                          \
+       test_port.py                            \
+       test_stream.py                          \
+       test_stream_class.py                    \
+       test_trace.py                           \
+       test_values.py                          \
        .coveragerc
 
 LOG_DRIVER_FLAGS='--merge'
index 436b2b9ec7c0c03d936356404a238f1588edf46c..c667e4ffab8420fa36b6426188f0656f1038b641 100644 (file)
@@ -49,7 +49,10 @@ class ClockClassOffsetTestCase(unittest.TestCase):
 
 class ClockClassTestCase(unittest.TestCase):
     def setUp(self):
-        self._cc = bt2.ClockClass('salut')
+        self._cc = bt2.ClockClass('salut', 1000000)
+
+    def tearDown(self):
+        del self._cc
 
     def test_create_default(self):
         self.assertEqual(self._cc.name, 'salut')
@@ -130,7 +133,7 @@ class ClockClassTestCase(unittest.TestCase):
             self._cc.uuid = object()
 
     def test_create_clock_value(self):
-        cv = self._cc.create_clock_value(756)
+        cv = self._cc(756)
         self.assertEqual(cv.clock_class.addr, self._cc.addr)
 
     def _test_copy(self, cpy):
@@ -245,10 +248,15 @@ class ClockClassTestCase(unittest.TestCase):
         self.assertFalse(self._cc == 23)
 
 
-class ClockClassValueTestCase(unittest.TestCase):
+class ClockValueTestCase(unittest.TestCase):
     def setUp(self):
-        self._cc = bt2.ClockClass('salut')
-        self._cv = self._cc.create_clock_value(123)
+        self._cc = bt2.ClockClass('salut', 1000,
+                                  offset=bt2.ClockClassOffset(45, 354))
+        self._cv = self._cc(123)
+
+    def tearDown(self):
+        del self._cc
+        del self._cv
 
     def test_create_default(self):
         self.assertEqual(self._cv.clock_class.addr, self._cc.addr)
@@ -256,30 +264,32 @@ class ClockClassValueTestCase(unittest.TestCase):
 
     def test_create_invalid_cycles_type(self):
         with self.assertRaises(TypeError):
-            self._cc.create_clock_value('yes')
+            self._cc('yes')
 
     def test_ns_from_epoch(self):
-        self._cv.clock_class.frequency = 1000
-        self._cv.clock_class.offset = bt2.ClockClassOffset(45, 354)
         s_from_epoch = 45 + ((354 + 123) / 1000)
         ns_from_epoch = int(s_from_epoch * 1e9)
         self.assertEqual(self._cv.ns_from_epoch, ns_from_epoch)
 
     def test_eq(self):
-        cv1 = self._cc.create_clock_value(123)
-        cv2 = self._cc.create_clock_value(123)
+        cv1 = self._cc(123)
+        cv2 = self._cc(123)
         self.assertEqual(cv1, cv2)
 
+    def test_eq_int(self):
+        cv1 = self._cc(123)
+        self.assertEqual(cv1, 123)
+
     def test_ne_clock_class(self):
-        cc1 = bt2.ClockClass('yes')
-        cc2 = bt2.ClockClass('yes')
-        cv1 = cc1.create_clock_value(123)
-        cv2 = cc2.create_clock_value(123)
+        cc1 = bt2.ClockClass('yes', 1500)
+        cc2 = bt2.ClockClass('yes', 1501)
+        cv1 = cc1(123)
+        cv2 = cc2(123)
         self.assertNotEqual(cv1, cv2)
 
     def test_ne_cycles(self):
-        cv1 = self._cc.create_clock_value(123)
-        cv2 = self._cc.create_clock_value(125)
+        cv1 = self._cc(123)
+        cv2 = self._cc(125)
         self.assertNotEqual(cv1, cv2)
 
     def test_eq_invalid(self):
diff --git a/tests/bindings/python/bt2/test_clock_class_priority_map.py b/tests/bindings/python/bt2/test_clock_class_priority_map.py
new file mode 100644 (file)
index 0000000..989927e
--- /dev/null
@@ -0,0 +1,139 @@
+import unittest
+import uuid
+import copy
+import bt2
+
+
+class ClockClassPriorityMapTestCase(unittest.TestCase):
+    def test_create_empty(self):
+        cc_prio_map = bt2.ClockClassPriorityMap()
+        self.assertEqual(len(cc_prio_map), 0)
+        self.assertIsNone(cc_prio_map.highest_priority_clock_class)
+
+    def test_create_full(self):
+        cc1 = bt2.ClockClass('meow', 1234)
+        cc2 = bt2.ClockClass('mix', 5678)
+        cc_prio_map = bt2.ClockClassPriorityMap({cc1: 17, cc2: 2})
+        self.assertEqual(len(cc_prio_map), 2)
+        self.assertEqual(cc_prio_map[cc1], 17)
+        self.assertEqual(cc_prio_map[cc2], 2)
+        self.assertEqual(cc_prio_map.highest_priority_clock_class, cc2)
+
+    def test_setitem(self):
+        cc_prio_map = bt2.ClockClassPriorityMap()
+        cc1 = bt2.ClockClass('mix', 5678)
+        cc_prio_map[cc1] = 184
+        self.assertEqual(len(cc_prio_map), 1)
+        self.assertEqual(cc_prio_map[cc1], 184)
+        self.assertEqual(cc_prio_map.highest_priority_clock_class, cc1)
+
+    def test_setitem_wrong_key_type(self):
+        cc_prio_map = bt2.ClockClassPriorityMap()
+
+        with self.assertRaises(TypeError):
+            cc_prio_map['the clock'] = 184
+
+    def test_setitem_wrong_value_type(self):
+        cc_prio_map = bt2.ClockClassPriorityMap()
+        cc1 = bt2.ClockClass('mix', 5678)
+
+        with self.assertRaises(TypeError):
+            cc_prio_map[cc1] = 'priority'
+
+    def test_getitem_wrong_key(self):
+        cc_prio_map = bt2.ClockClassPriorityMap()
+        cc1 = bt2.ClockClass('mix', 5678)
+        cc2 = bt2.ClockClass('mix', 5678)
+        cc_prio_map[cc1] = 2
+
+        with self.assertRaises(KeyError):
+            cc_prio_map[cc2]
+
+    def test_getitem_wrong_key_type(self):
+        cc_prio_map = bt2.ClockClassPriorityMap()
+
+        with self.assertRaises(TypeError):
+            cc_prio_map[23]
+
+    def test_iter(self):
+        cc1 = bt2.ClockClass('meow', 1234)
+        cc2 = bt2.ClockClass('mix', 5678)
+        cc3 = bt2.ClockClass('lel', 1548)
+        cc_prio_map = bt2.ClockClassPriorityMap({cc1: 17, cc2: 2, cc3: 25})
+        cc_prios = {}
+
+        for cc, prio in cc_prio_map.items():
+            cc_prios[cc] = prio
+
+        self.assertEqual(len(cc_prios), 3)
+        self.assertEqual(cc_prios[cc1], 17)
+        self.assertEqual(cc_prios[cc2], 2)
+        self.assertEqual(cc_prios[cc3], 25)
+
+    def test_eq(self):
+        cc1 = bt2.ClockClass('meow', 1234)
+        cc2 = bt2.ClockClass('mix', 5678)
+        cc3 = bt2.ClockClass('lel', 1548)
+        cc_prio_map = bt2.ClockClassPriorityMap({cc1: 17, cc2: 2, cc3: 25})
+        other_cc1 = bt2.ClockClass('meow', 1234)
+        other_cc2 = bt2.ClockClass('mix', 5678)
+        other_cc3 = bt2.ClockClass('lel', 1548)
+        other_cc_prio_map = bt2.ClockClassPriorityMap({other_cc1: 17, other_cc2: 2, other_cc3: 25})
+        self.assertEqual(cc_prio_map, other_cc_prio_map)
+
+    def test_ne_clock_class(self):
+        cc1 = bt2.ClockClass('meow', 1234)
+        cc2 = bt2.ClockClass('mix', 5678)
+        cc3 = bt2.ClockClass('lel', 1548)
+        cc_prio_map = bt2.ClockClassPriorityMap({cc1: 17, cc2: 2, cc3: 25})
+        other_cc1 = bt2.ClockClass('meow', 1234)
+        other_cc2 = bt2.ClockClass('coucou', 5678)
+        other_cc3 = bt2.ClockClass('lel', 1548)
+        other_cc_prio_map = bt2.ClockClassPriorityMap({other_cc1: 17, other_cc2: 2, other_cc3: 25})
+        self.assertNotEqual(cc_prio_map, other_cc_prio_map)
+
+    def test_ne_prio(self):
+        cc1 = bt2.ClockClass('meow', 1234)
+        cc2 = bt2.ClockClass('mix', 5678)
+        cc3 = bt2.ClockClass('lel', 1548)
+        cc_prio_map = bt2.ClockClassPriorityMap({cc1: 17, cc2: 2, cc3: 25})
+        other_cc1 = bt2.ClockClass('meow', 1234)
+        other_cc2 = bt2.ClockClass('mix', 5678)
+        other_cc3 = bt2.ClockClass('lel', 1548)
+        other_cc_prio_map = bt2.ClockClassPriorityMap({other_cc1: 17, other_cc2: 3, other_cc3: 25})
+        self.assertNotEqual(cc_prio_map, other_cc_prio_map)
+
+    def test_eq_invalid(self):
+        self.assertFalse(bt2.ClockClassPriorityMap() == 23)
+
+    def test_copy(self):
+        cc1 = bt2.ClockClass('meow', 1234)
+        cc2 = bt2.ClockClass('mix', 5678)
+        cc3 = bt2.ClockClass('lel', 1548)
+        cc_prio_map = bt2.ClockClassPriorityMap({cc1: 17, cc2: 2, cc3: 25})
+        cc_prio_map_cpy = copy.copy(cc_prio_map)
+        self.assertEqual(cc_prio_map, cc_prio_map_cpy)
+        self.assertEqual(list(cc_prio_map.keys())[0].addr, list(cc_prio_map_cpy.keys())[0].addr)
+        self.assertEqual(list(cc_prio_map.keys())[1].addr, list(cc_prio_map_cpy.keys())[1].addr)
+        self.assertEqual(list(cc_prio_map.keys())[2].addr, list(cc_prio_map_cpy.keys())[2].addr)
+        self.assertEqual(list(cc_prio_map.values())[0], list(cc_prio_map_cpy.values())[0])
+        self.assertEqual(list(cc_prio_map.values())[1], list(cc_prio_map_cpy.values())[1])
+        self.assertEqual(list(cc_prio_map.values())[2], list(cc_prio_map_cpy.values())[2])
+        self.assertEqual(cc_prio_map.highest_priority_clock_class.addr,
+                         cc_prio_map_cpy.highest_priority_clock_class.addr)
+
+    def test_deep_copy(self):
+        cc1 = bt2.ClockClass('meow', 1234)
+        cc2 = bt2.ClockClass('mix', 5678)
+        cc3 = bt2.ClockClass('lel', 1548)
+        cc_prio_map = bt2.ClockClassPriorityMap({cc1: 17, cc2: 2, cc3: 25})
+        cc_prio_map_cpy = copy.deepcopy(cc_prio_map)
+        self.assertEqual(cc_prio_map, cc_prio_map_cpy)
+        self.assertNotEqual(list(cc_prio_map.keys())[0].addr, list(cc_prio_map_cpy.keys())[0].addr)
+        self.assertNotEqual(list(cc_prio_map.keys())[1].addr, list(cc_prio_map_cpy.keys())[1].addr)
+        self.assertNotEqual(list(cc_prio_map.keys())[2].addr, list(cc_prio_map_cpy.keys())[2].addr)
+        self.assertEqual(list(cc_prio_map.values())[0], list(cc_prio_map_cpy.values())[0])
+        self.assertEqual(list(cc_prio_map.values())[1], list(cc_prio_map_cpy.values())[1])
+        self.assertEqual(list(cc_prio_map.values())[2], list(cc_prio_map_cpy.values())[2])
+        self.assertNotEqual(cc_prio_map.highest_priority_clock_class.addr,
+                            cc_prio_map_cpy.highest_priority_clock_class.addr)
diff --git a/tests/bindings/python/bt2/test_comp_notif_iter.py b/tests/bindings/python/bt2/test_comp_notif_iter.py
deleted file mode 100644 (file)
index 70afebe..0000000
+++ /dev/null
@@ -1,861 +0,0 @@
-from collections import OrderedDict
-import unittest
-import copy
-import bt2.notification_iterator
-import bt2
-
-
-def _create_ec():
-    # clock class
-    cc = bt2.ClockClass('salut_clock')
-
-    # event header
-    eh = bt2.StructureFieldType()
-    eh += OrderedDict((
-        ('id', bt2.IntegerFieldType(8)),
-        ('ts', bt2.IntegerFieldType(32, mapped_clock_class=cc)),
-    ))
-
-    # packet context
-    pc = bt2.StructureFieldType()
-    pc += OrderedDict((
-        ('something', bt2.IntegerFieldType(8)),
-    ))
-
-    # stream class
-    sc = bt2.StreamClass()
-    sc.packet_context_field_type = pc
-    sc.event_header_field_type = eh
-    sc.event_context_field_type = None
-
-    # event payload
-    ep = bt2.StructureFieldType()
-    ep += OrderedDict((
-        ('mosquito', bt2.StringFieldType()),
-    ))
-
-    # event class
-    event_class = bt2.EventClass('ec', id=0)
-    event_class.context_field_type = None
-    event_class.payload_field_type = ep
-    sc.add_event_class(event_class)
-
-    # packet header
-    ph = bt2.StructureFieldType()
-    ph += OrderedDict((
-        ('magic', bt2.IntegerFieldType(32)),
-        ('stream_id', bt2.IntegerFieldType(16)),
-    ))
-
-    # trace
-    trace = bt2.Trace()
-    trace.packet_header_field_type = ph
-    trace.add_clock_class(cc)
-    trace.add_stream_class(sc)
-    return event_class
-
-
-def _create_event(event_class, msg):
-    ev = event_class()
-    ev.header_field['id'] = 0
-    ev.header_field['ts'] = 19487
-    ev.payload_field['mosquito'] = msg
-    return ev
-
-
-def _create_packet(stream):
-    packet = stream.create_packet()
-    packet.header_field['magic'] = 0xc1fc1fc1
-    packet.header_field['stream_id'] = 0
-    packet.context_field['something'] = 194
-    return packet
-
-
-def _create_source():
-    class MyIter(bt2.UserNotificationIterator):
-        def __init__(self):
-            self._event_class = self.component._event_class
-            self._stream = self.component._stream
-            self._packet = _create_packet(self._stream)
-            self._at = 0
-            self._cur_notif = None
-
-        def _get(self):
-            if self._cur_notif is None:
-                raise bt2.Error('nothing here!')
-
-            return self._cur_notif
-
-        def _next(self):
-            if self._at == 0:
-                notif = bt2.BeginningOfPacketNotification(self._packet)
-            elif self._at < 5:
-                ev = _create_event(self._event_class, 'at {}'.format(self._at))
-                ev.packet = self._packet
-                notif = bt2.TraceEventNotification(ev)
-            elif self._at == 5:
-                notif = bt2.EndOfPacketNotification(self._packet)
-            elif self._at == 6:
-                notif = bt2.EndOfStreamNotification(self._stream)
-            else:
-                raise bt2.Stop
-
-            self._at += 1
-            self._cur_notif = notif
-
-    class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-        def __init__(self):
-            self._event_class = _create_ec()
-            self._stream = self._event_class.stream_class(name='abcdef')
-
-    return MySource()
-
-
-class GenCompClassTestCase(unittest.TestCase):
-    def test_attr_name(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-        sink = MySink()
-        self.assertEqual(sink.component_class.name, 'MySink')
-
-    def test_attr_description(self):
-        class MySink(bt2.UserSinkComponent):
-            '''This is the description.
-
-            This is the help.
-
-            This too:
-
-                * And this.
-                * And also that.
-
-            Voilà.
-            '''
-
-            def _consume(self):
-                pass
-
-        sink = MySink()
-        self.assertEqual(sink.component_class.description,
-                         'This is the description.')
-
-    def test_attr_help(self):
-        class MySink(bt2.UserSinkComponent):
-            '''This is the description.
-
-            This is the help.
-
-            This too:
-
-                * And this.
-                * And also that.
-
-            Voilà.
-            '''
-
-            def _consume(self):
-                pass
-
-        sink = MySink()
-        expected_help = '''This is the help.
-
-This too:
-
-    * And this.
-    * And also that.
-
-Voilà.'''
-        self.assertEqual(sink.component_class.help, expected_help)
-
-    def test_instantiate(self):
-        class MySink(bt2.UserSinkComponent):
-            'hello'
-
-            def __init__(self, params=None, name=None):
-                if params is None or name is None:
-                    return
-
-                nonlocal nl_params_a, nl_name
-                nl_params_a = params['a']
-                nl_name = name
-
-            def _consume(self):
-                pass
-
-        nl_params_a = None
-        nl_name = None
-        sink = MySink()
-        self.assertIsNone(nl_params_a)
-        self.assertIsNone(nl_name)
-        gen_comp_class = sink.component_class
-        sink2 = gen_comp_class(params={'a': 23}, name='salut')
-        self.assertEqual(nl_params_a, 23)
-        self.assertEqual(nl_name, 'salut')
-
-
-class UserCompClassTestCase(unittest.TestCase):
-    def test_attr_name(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-        self.assertEqual(MySink.name, 'MySink')
-
-    def test_attr_name_param(self):
-        class MySink(bt2.UserSinkComponent, name='my custom name'):
-            def _consume(self):
-                pass
-
-        self.assertEqual(MySink.name, 'my custom name')
-
-    def test_attr_description(self):
-        class MySink(bt2.UserSinkComponent):
-            '''This is the description.
-
-            This is the help.
-
-            This too:
-
-                * And this.
-                * And also that.
-
-            Voilà.
-            '''
-
-            def _consume(self):
-                pass
-
-        self.assertEqual(MySink.description, 'This is the description.')
-
-    def test_attr_help(self):
-        class MySink(bt2.UserSinkComponent):
-            '''This is the description.
-
-            This is the help.
-
-            This too:
-
-                * And this.
-                * And also that.
-
-            Voilà.
-            '''
-
-            def _consume(self):
-                pass
-
-        expected_help = '''This is the help.
-
-This too:
-
-    * And this.
-    * And also that.
-
-Voilà.'''
-        self.assertEqual(MySink.help, expected_help)
-
-    def test_query_missing(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-        with self.assertRaises(bt2.Error):
-            MySink.query('salut')
-
-    def test_query_raises(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-            @staticmethod
-            def _query(obj, params):
-                raise ValueError
-
-        with self.assertRaises(bt2.Error):
-            MySink.query('salut')
-
-    def test_query_gets_none_params(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-            @staticmethod
-            def _query(obj, params):
-                nonlocal recv_params
-                recv_params = params
-
-        recv_params = NotImplemented
-        MySink.query('allo', None)
-        self.assertIsNone(recv_params)
-
-    def test_query_gets_same_params(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-            @staticmethod
-            def _query(obj, params):
-                nonlocal recv_params
-                recv_params = params
-
-        recv_params = NotImplemented
-        params = bt2.create_value(23)
-        MySink.query('allo', params)
-        self.assertEqual(recv_params.addr, params.addr)
-
-    def test_query_obj(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-            @staticmethod
-            def _query(obj, params):
-                nonlocal recv_obj
-                recv_obj = obj
-
-        recv_obj = None
-        MySink.query('salut')
-        self.assertEqual(recv_obj, 'salut')
-
-    def test_query_returns_none(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-            @staticmethod
-            def _query(obj, params):
-                pass
-
-        self.assertIsNone(MySink.query('allo', 177))
-
-    def test_query_returns_params(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-            @staticmethod
-            def _query(obj, params):
-                return {'obj': obj, 'params': params}
-
-        results = MySink.query('hello', (45, 'lol'))
-        self.assertEqual(results['obj'], 'hello')
-        self.assertEqual(results['params'], (45, 'lol'))
-
-    def test_init(self):
-        class MySink(bt2.UserSinkComponent):
-            def __init__(self):
-                nonlocal inited
-                inited = True
-
-            def _consume(self):
-                pass
-
-        inited = False
-        sink = MySink()
-        self.assertTrue(inited)
-
-    def test_init_raises(self):
-        class MySink(bt2.UserSinkComponent):
-            def __init__(self):
-                raise RuntimeError('oops')
-
-            def _consume(self):
-                pass
-
-        with self.assertRaises(RuntimeError):
-            sink = MySink()
-
-    def test_destroy(self):
-        class MySink(bt2.UserSinkComponent):
-            def _destroy(self):
-                nonlocal destroyed
-                destroyed = True
-
-            def _consume(self):
-                pass
-
-        destroyed = False
-        sink = MySink()
-        del sink
-        self.assertTrue(destroyed)
-
-    def test_destroy_raises(self):
-        class MySink(bt2.UserSinkComponent):
-            def _destroy(self):
-                raise RuntimeError('oh oh')
-                nonlocal destroyed
-                destroyed = True
-
-            def _consume(self):
-                pass
-
-        destroyed = False
-        sink = MySink()
-        del sink
-        self.assertFalse(destroyed)
-
-    def test_comp_attr_name(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-        sink = MySink(name='salut')
-        self.assertEqual(sink.name, 'salut')
-
-    def test_comp_attr_no_name(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-        sink = MySink()
-        self.assertIsNone(sink.name)
-
-    def test_comp_attr_class(self):
-        class MySink(bt2.UserSinkComponent):
-            def _consume(self):
-                pass
-
-        sink = MySink()
-        self.assertEqual(sink.component_class.name, 'MySink')
-
-
-class UserSinkCompClassTestCase(unittest.TestCase):
-    def test_missing_consume(self):
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MySink(bt2.UserSinkComponent):
-                pass
-
-    def test_set_min_input(self):
-        class MySink(bt2.UserSinkComponent):
-            def __init__(self):
-                self._maximum_input_notification_iterator_count = 10
-                self._minimum_input_notification_iterator_count = 5
-
-            def _consume(self):
-                pass
-
-        sink = MySink()
-
-    def test_set_max_input(self):
-        class MySink(bt2.UserSinkComponent):
-            def __init__(self):
-                self._maximum_input_notification_iterator_count = 5
-
-            def _consume(self):
-                pass
-
-        sink = MySink()
-
-    def test_consume(self):
-        class MySink(bt2.UserSinkComponent):
-            def __init__(self):
-                pass
-
-            def _consume(self):
-                nonlocal consumed
-                consumed = True
-
-        sink = MySink()
-        consumed = False
-        source = _create_source()
-        notif_iter = source.create_notification_iterator()
-        sink.add_notification_iterator(notif_iter)
-        sink.consume()
-        self.assertTrue(consumed)
-
-    def test_consume_raises(self):
-        class MySink(bt2.UserSinkComponent):
-            def __init__(self):
-                pass
-
-            def _consume(self):
-                raise RuntimeError('hello')
-
-        sink = MySink()
-        source = _create_source()
-        notif_iter = source.create_notification_iterator()
-        sink.add_notification_iterator(notif_iter)
-
-        with self.assertRaises(bt2.Error):
-            sink.consume()
-
-    def test_add_notification_iterator(self):
-        class MySink(bt2.UserSinkComponent):
-            def __init__(self):
-                pass
-
-            def _consume(self):
-                pass
-
-            def _add_notification_iterator(self, notif_iter):
-                nonlocal added
-                added = True
-
-        sink = MySink()
-        added = False
-        source = _create_source()
-        notif_iter = source.create_notification_iterator()
-        sink.add_notification_iterator(notif_iter)
-        self.assertTrue(added)
-
-    def test_input_notif_iterators(self):
-        class MySink(bt2.UserSinkComponent):
-            def __init__(self):
-                self._maximum_input_notification_iterator_count = 5
-
-            def _consume(self):
-                nonlocal count
-                count = 0
-
-                for notif_iter in self._input_notification_iterators:
-                    count += 1
-
-        sink = MySink()
-        count = 0
-        source = _create_source()
-        notif_iter1 = source.create_notification_iterator()
-        notif_iter2 = source.create_notification_iterator()
-        sink.add_notification_iterator(notif_iter1)
-        sink.add_notification_iterator(notif_iter2)
-        sink.consume()
-        self.assertEqual(count, 2)
-
-
-class UserSourceCompClassTestCase(unittest.TestCase):
-    def test_missing_notif_iterator_class(self):
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MySource(bt2.UserSourceComponent):
-                pass
-
-    def test_invalid_notif_iterator_class(self):
-        class Lel:
-            pass
-
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MySource(bt2.UserSourceComponent, notification_iterator_class=Lel):
-                pass
-
-    def test_notif_iterator_class_missing_get(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                pass
-
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-                pass
-
-    def test_notif_iterator_class_missing_next(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _get(self):
-                pass
-
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-                pass
-
-    def test_create_notification_iterator(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def __init__(self):
-                nonlocal created
-                created = True
-
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-        class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-            pass
-
-        created = False
-        source = MySource()
-        notif_iter = source.create_notification_iterator()
-        self.assertTrue(created)
-
-
-class UserSourceCompClassTestCase(unittest.TestCase):
-    def test_missing_notif_iterator_class(self):
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MyFilter(bt2.UserFilterComponent):
-                pass
-
-    def test_invalid_notif_iterator_class(self):
-        class Lel:
-            pass
-
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MyFilter(bt2.UserFilterComponent, notification_iterator_class=Lel):
-                pass
-
-    def test_notif_iterator_class_missing_get(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                pass
-
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MyFilter(bt2.UserFilterComponent, notification_iterator_class=MyIter):
-                pass
-
-    def test_notif_iterator_class_missing_next(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _get(self):
-                pass
-
-        with self.assertRaises(bt2.IncompleteUserClassError):
-            class MyFilter(bt2.UserFilterComponent, notification_iterator_class=MyIter):
-                pass
-
-    def test_create_notification_iterator(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def __init__(self):
-                nonlocal created
-                created = True
-
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-        class MyFilter(bt2.UserFilterComponent, notification_iterator_class=MyIter):
-            pass
-
-        created = False
-        filter = MyFilter()
-        notif_iter = filter.create_notification_iterator()
-        self.assertTrue(created)
-
-    def test_set_min_input(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-        class MyFilter(bt2.UserFilterComponent, notification_iterator_class=MyIter):
-            def __init__(self):
-                self._maximum_input_notification_iterator_count = 10
-                self._minimum_input_notification_iterator_count = 5
-
-        filter = MyFilter()
-
-    def test_set_max_input(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-        class MyFilter(bt2.UserFilterComponent, notification_iterator_class=MyIter):
-            def __init__(self):
-                self._maximum_input_notification_iterator_count = 5
-
-        filter = MyFilter()
-
-    def test_add_notification_iterator(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-        class MyFilter(bt2.UserFilterComponent, notification_iterator_class=MyIter):
-            def __init__(self):
-                pass
-
-            def _add_notification_iterator(self, notif_iter):
-                nonlocal added
-                added = True
-
-        filter = MyFilter()
-        added = False
-        source = _create_source()
-        notif_iter = source.create_notification_iterator()
-        filter.add_notification_iterator(notif_iter)
-        self.assertTrue(added)
-
-    def test_input_notif_iterators(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-        class MyFilter(bt2.UserFilterComponent, notification_iterator_class=MyIter):
-            def __init__(self):
-                self._maximum_input_notification_iterator_count = 5
-
-            def _test(self):
-                nonlocal count
-                count = 0
-
-                for notif_iter in self._input_notification_iterators:
-                    count += 1
-
-        filter = MyFilter()
-        count = 0
-        source = _create_source()
-        notif_iter1 = source.create_notification_iterator()
-        notif_iter2 = source.create_notification_iterator()
-        filter.add_notification_iterator(notif_iter1)
-        filter.add_notification_iterator(notif_iter2)
-        filter._test()
-        self.assertEqual(count, 2)
-
-
-class UserNotificationIteratorTestCase(unittest.TestCase):
-    def test_init(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def __init__(self):
-                nonlocal inited
-                inited = True
-
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-        class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-            pass
-
-        inited = False
-        source = MySource()
-        notif_iter = source.create_notification_iterator()
-        self.assertTrue(inited)
-
-    def test_destroy(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-            def _destroy(self):
-                nonlocal destroyed
-                destroyed = True
-
-        class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-            pass
-
-        source = MySource()
-        notif_iter = source.create_notification_iterator()
-        destroyed = False
-        del notif_iter
-        self.assertTrue(destroyed)
-
-    def test_attr_component(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def __init__(self):
-                nonlocal source, is_same
-                is_same = self.component is source
-
-            def _next(self):
-                pass
-
-            def _get(self):
-                pass
-
-        class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-            pass
-
-        source = MySource()
-        is_same = False
-        notif_iter = source.create_notification_iterator()
-        self.assertTrue(is_same)
-
-    def test_next_raises_stop(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                raise bt2.Stop
-
-            def _get(self):
-                pass
-
-        class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-            pass
-
-        source = MySource()
-        is_same = False
-        notif_iter = source.create_notification_iterator()
-
-        with self.assertRaises(bt2.Stop):
-            notif_iter.next()
-
-    def test_next_raises_unsupported_feature(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                raise bt2.UnsupportedFeature
-
-            def _get(self):
-                pass
-
-        class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-            pass
-
-        source = MySource()
-        is_same = False
-        notif_iter = source.create_notification_iterator()
-
-        with self.assertRaises(bt2.UnsupportedFeature):
-            notif_iter.next()
-
-    def test_next_raises_unknown(self):
-        class MyIter(bt2.UserNotificationIterator):
-            def _next(self):
-                raise TypeError('lel')
-
-            def _get(self):
-                pass
-
-        class MySource(bt2.UserSourceComponent, notification_iterator_class=MyIter):
-            pass
-
-        source = MySource()
-        is_same = False
-        notif_iter = source.create_notification_iterator()
-
-        with self.assertRaises(bt2.Error):
-            notif_iter.next()
-
-    def test_iteration(self):
-        source = _create_source()
-        notif_iter = source.create_notification_iterator()
-        pkt_addr = None
-
-        for index, notif in enumerate(notif_iter):
-            if index == 0:
-                self.assertIsInstance(notif, bt2.BeginningOfPacketNotification)
-                self.assertEqual(notif.packet.header_field['magic'], 0xc1fc1fc1)
-                self.assertEqual(notif.packet.context_field['something'], 194)
-                pkt_addr = notif.packet.addr
-            elif index < 5:
-                self.assertIsInstance(notif, bt2.TraceEventNotification)
-                self.assertEqual(notif.event.header_field['ts'], 19487)
-                self.assertEqual(notif.event.payload_field['mosquito'], 'at {}'.format(index))
-            elif index == 5:
-                self.assertIsInstance(notif, bt2.EndOfPacketNotification)
-                self.assertEqual(notif.packet.header_field['magic'], 0xc1fc1fc1)
-                self.assertEqual(notif.packet.context_field['something'], 194)
-                self.assertEqual(notif.packet.addr, pkt_addr)
-            elif index == 6:
-                self.assertIsInstance(notif, bt2.EndOfStreamNotification)
-                self.assertEqual(notif.stream.name, 'abcdef')
-            else:
-                raise RuntimeError('FAIL')
-
-
-class GenNotificationIteratorTestCase(unittest.TestCase):
-    def test_attr_component(self):
-        source = _create_source()
-        notif_iter = source.create_notification_iterator()
-        self.assertIsInstance(notif_iter, bt2.notification_iterator._GenericNotificationIterator)
-        self.assertEqual(notif_iter.component.addr, source.addr)
diff --git a/tests/bindings/python/bt2/test_component.py b/tests/bindings/python/bt2/test_component.py
new file mode 100644 (file)
index 0000000..99438dc
--- /dev/null
@@ -0,0 +1,121 @@
+from bt2 import values
+import unittest
+import copy
+import bt2
+
+
+class UserComponentTestCase(unittest.TestCase):
+    @staticmethod
+    def _create_comp(comp_cls, name=None):
+        graph = bt2.Graph()
+
+        if name is None:
+            name = 'comp'
+
+        return graph.add_component(comp_cls, name)
+
+    def test_name(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                self.assertEqual(comp_self.name, 'yaes')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink, 'yaes')
+
+    def test_graph(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                nonlocal graph
+                self.assertEqual(comp_self.graph, graph)
+
+            def _consume(self):
+                pass
+
+        graph = bt2.Graph()
+        comp = graph.add_component(MySink, 'lel')
+        del graph
+
+    def test_class(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                self.assertEqual(comp_self.component_class, MySink)
+
+            def _consume(self):
+                pass
+
+        self._create_comp(MySink)
+
+    def test_addr(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                self.assertIsInstance(comp_self.addr, int)
+                self.assertNotEqual(comp_self.addr, 0)
+
+            def _consume(self):
+                pass
+
+        self._create_comp(MySink)
+
+    def test_finalize(self):
+        finalized = False
+
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            def _finalize(comp_self):
+                nonlocal finalized
+                finalized = True
+
+        graph = bt2.Graph()
+        comp = graph.add_component(MySink, 'lel')
+        del graph
+        del comp
+        self.assertTrue(finalized)
+
+
+class GenericComponentTestCase(unittest.TestCase):
+    @staticmethod
+    def _create_comp(comp_cls, name=None):
+        graph = bt2.Graph()
+
+        if name is None:
+            name = 'comp'
+
+        return graph.add_component(comp_cls, name)
+
+    def test_name(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink, 'yaes')
+        self.assertEqual(comp.name, 'yaes')
+
+    def test_graph(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        graph = bt2.Graph()
+        comp = graph.add_component(MySink, 'lel')
+        self.assertEqual(comp.graph, graph)
+
+    def test_class(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertEqual(comp.component_class, MySink)
+
+    def test_addr(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertIsInstance(comp.addr, int)
+        self.assertNotEqual(comp.addr, 0)
diff --git a/tests/bindings/python/bt2/test_component_class.py b/tests/bindings/python/bt2/test_component_class.py
new file mode 100644 (file)
index 0000000..a8160c3
--- /dev/null
@@ -0,0 +1,323 @@
+from bt2 import values
+import unittest
+import copy
+import bt2
+
+
+class UserComponentClassTestCase(unittest.TestCase):
+    def _test_no_init(self, cls):
+        with self.assertRaises(bt2.Error):
+            cls()
+
+    def test_no_init_source(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            pass
+
+        self._test_no_init(MySource)
+
+    def test_no_init_filter(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            pass
+
+        self._test_no_init(MyFilter)
+
+    def test_no_init_sink(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        self._test_no_init(MySink)
+
+    def test_incomplete_source_no_notif_iter_cls(self):
+        class MyIter(bt2._UserNotificationIterator):
+            pass
+
+        with self.assertRaises(bt2.IncompleteUserClass):
+            class MySource(bt2._UserSourceComponent):
+                pass
+
+    def test_incomplete_source_wrong_notif_iter_cls_type(self):
+        class MyIter(bt2._UserNotificationIterator):
+            pass
+
+        with self.assertRaises(bt2.IncompleteUserClass):
+            class MySource(bt2._UserSourceComponent,
+                           notification_iterator_class=int):
+                pass
+
+    def test_incomplete_filter_no_notif_iter_cls(self):
+        class MyIter(bt2._UserNotificationIterator):
+            pass
+
+        with self.assertRaises(bt2.IncompleteUserClass):
+            class MyFilter(bt2._UserFilterComponent):
+                pass
+
+    def test_incomplete_sink_no_consume_method(self):
+        class MyIter(bt2._UserNotificationIterator):
+            pass
+
+        with self.assertRaises(bt2.IncompleteUserClass):
+            class MySink(bt2._UserSinkComponent):
+                pass
+
+    def test_minimal_source(self):
+        class MyIter(bt2._UserNotificationIterator):
+            pass
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            pass
+
+    def test_minimal_filter(self):
+        class MyIter(bt2._UserNotificationIterator):
+            pass
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            pass
+
+    def test_minimal_sink(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+    def test_default_name(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        self.assertEqual(MySink.name, 'MySink')
+
+    def test_custom_name(self):
+        class MySink(bt2._UserSinkComponent, name='salut'):
+            def _consume(self):
+                pass
+
+        self.assertEqual(MySink.name, 'salut')
+
+    def test_invalid_custom_name(self):
+        with self.assertRaises(TypeError):
+            class MySink(bt2._UserSinkComponent, name=23):
+                def _consume(self):
+                    pass
+
+    def test_description(self):
+        class MySink(bt2._UserSinkComponent):
+            """
+            The description.
+
+            Bacon ipsum dolor amet ribeye t-bone corned beef, beef jerky
+            porchetta burgdoggen prosciutto chicken frankfurter boudin
+            hamburger doner bacon turducken. Sirloin shank sausage,
+            boudin meatloaf alcatra meatball t-bone tongue pastrami
+            cupim flank tenderloin.
+            """
+
+            def _consume(self):
+                pass
+
+        self.assertEqual(MySink.description, 'The description.')
+
+    def test_empty_description(self):
+        class MySink(bt2._UserSinkComponent):
+            """
+            """
+
+            def _consume(self):
+                pass
+
+        self.assertIsNone(MySink.description)
+
+    def test_help(self):
+        class MySink(bt2._UserSinkComponent):
+            """
+            The description.
+
+            The help
+            text is
+            here.
+            """
+
+            def _consume(self):
+                pass
+
+        self.assertEqual(MySink.help, 'The help\ntext is\nhere.')
+
+    def test_addr(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        self.assertIsInstance(MySink.addr, int)
+        self.assertNotEqual(MySink.addr, 0)
+
+    def test_query_not_implemented(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        with self.assertRaises(bt2.Error):
+            MySink.query('obj', 23)
+
+    def test_query_raises(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, obj, params):
+                raise ValueError
+
+        with self.assertRaises(bt2.Error):
+            MySink.query('obj', 23)
+
+    def test_query_wrong_return_type(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, obj, params):
+                return ...
+
+        with self.assertRaises(bt2.Error):
+            MySink.query('obj', 23)
+
+    def test_query_params_none(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, obj, params):
+                nonlocal query_params
+                query_params = params
+                return None
+
+        query_params = None
+        params = None
+        res = MySink.query('obj', params)
+        self.assertEqual(query_params, params)
+        self.assertIsNone(res)
+        del query_params
+
+    def test_query_simple(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, obj, params):
+                nonlocal query_params
+                query_params = params
+                return 17.5
+
+        query_params = None
+        params = ['coucou', 23, None]
+        res = MySink.query('obj', params)
+        self.assertEqual(query_params, params)
+        self.assertEqual(res, 17.5)
+        del query_params
+
+    def test_query_complex(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, obj, params):
+                nonlocal query_params
+                query_params = params
+                return {
+                    'null': None,
+                    'bt2': 'BT2',
+                }
+
+        query_params = None
+        params = {
+            'array': ['coucou', 23, None],
+            'other_map': {
+                'yes': 'yeah',
+                '19': 19,
+                'minus 1.5': -1.5,
+            },
+            'null': None,
+        }
+
+        res = MySink.query('obj', params)
+        self.assertEqual(query_params, params)
+        self.assertEqual(res, {
+            'null': None,
+            'bt2': 'BT2',
+        })
+        del query_params
+
+    def test_eq(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        self.assertEqual(MySink, MySink)
+
+
+class GenericComponentClassTestCase(unittest.TestCase):
+    def setUp(self):
+        class MySink(bt2._UserSinkComponent):
+            '''
+            The description.
+
+            The help.
+            '''
+            def _consume(self):
+                pass
+
+            @classmethod
+            def _query(cls, obj, params):
+                return [obj, params, 23]
+
+        self._py_comp_cls = MySink
+        graph = bt2.Graph()
+        comp = graph.add_component(MySink, 'salut')
+        self._comp_cls = comp.component_class
+        self.assertTrue(issubclass(type(self._comp_cls),
+                                   bt2.component._GenericComponentClass))
+
+    def tearDown(self):
+        del self._py_comp_cls
+        del self._comp_cls
+
+    def test_description(self):
+        self.assertEqual(self._comp_cls.description, 'The description.')
+
+    def test_help(self):
+        self.assertEqual(self._comp_cls.help, 'The help.')
+
+    def test_name(self):
+        self.assertEqual(self._comp_cls.name, 'MySink')
+
+    def test_addr(self):
+        self.assertIsInstance(self._comp_cls.addr, int)
+        self.assertNotEqual(self._comp_cls.addr, 0)
+
+    def test_eq_invalid(self):
+        self.assertFalse(self._comp_cls == 23)
+
+    def test_eq(self):
+        self.assertEqual(self._comp_cls, self._comp_cls)
+        self.assertEqual(self._py_comp_cls, self._comp_cls)
+
+    def test_query(self):
+        res = self._comp_cls.query('an object', {'yes': 'no', 'book': -17})
+        expected = ['an object', {'yes': 'no', 'book': -17}, 23]
+        self.assertEqual(res, expected)
diff --git a/tests/bindings/python/bt2/test_connection.py b/tests/bindings/python/bt2/test_connection.py
new file mode 100644 (file)
index 0000000..0481413
--- /dev/null
@@ -0,0 +1,392 @@
+from bt2 import values
+import unittest
+import copy
+import bt2
+
+
+class ConnectionTestCase(unittest.TestCase):
+    def test_create(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertIsInstance(conn, bt2._Connection)
+        self.assertNotIsInstance(conn, bt2._PrivateConnection)
+
+    def test_is_ended_false(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertFalse(conn.is_ended)
+
+    def test_is_ended_true(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        src.output_ports['out'].disconnect()
+        self.assertTrue(conn.is_ended)
+
+    def test_downstream_port(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertEqual(conn.downstream_port.addr, sink.input_ports['in'].addr)
+
+    def test_upstream_port(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertEqual(conn.upstream_port.addr, src.output_ports['out'].addr)
+
+    def test_eq(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertEqual(conn, conn)
+
+    def test_eq_invalid(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertNotEqual(conn, 23)
+
+
+class PrivateConnectionTestCase(unittest.TestCase):
+    def test_create(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                nonlocal priv_conn
+                priv_conn = port.connection
+
+        priv_conn = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertIsInstance(priv_conn, bt2._PrivateConnection)
+        self.assertEqual(conn, priv_conn)
+        del priv_conn
+
+    def test_is_ended_false(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                nonlocal priv_conn
+                priv_conn = port.connection
+
+        priv_conn = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertFalse(priv_conn.is_ended)
+        del priv_conn
+
+    def test_is_ended_true(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                nonlocal priv_conn
+                priv_conn = port.connection
+
+        priv_conn = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        sink.input_ports['in'].disconnect()
+        self.assertTrue(priv_conn.is_ended)
+        del priv_conn
+
+    def test_downstream_port(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                nonlocal priv_port
+                priv_conn = port.connection
+                priv_port = priv_conn.downstream_port
+
+        priv_port = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertEqual(priv_port.addr, sink.input_ports['in'].addr)
+        del priv_port
+
+    def test_upstream_port(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                nonlocal priv_port
+                priv_conn = port.connection
+                priv_port = priv_conn.upstream_port
+
+        priv_port = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertEqual(priv_port.addr, src.output_ports['out'].addr)
+        del priv_port
+
+    def test_eq(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                nonlocal priv_conn
+                priv_conn = port.connection
+
+        priv_conn = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertEqual(priv_conn, conn)
+        del priv_conn
+
+    def test_eq_invalid(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                nonlocal priv_conn
+                priv_conn = port.connection
+
+        priv_conn = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        self.assertNotEqual(priv_conn, 23)
+        del priv_conn
index 147914674554cfe1d41aec7068c819104ddd496e..02e9609b2bcd076a43a65c85fec6a08e8e951781 100644 (file)
@@ -8,6 +8,9 @@ class CtfWriterClockTestCase(unittest.TestCase):
     def setUp(self):
         self._clock = bt2.CtfWriterClock('salut')
 
+    def tearDown(self):
+        del self._clock
+
     def test_create_default(self):
         self.assertEqual(self._clock.name, 'salut')
 
index 6e7bdc679e906b334789bd9e6e2c08ec779f7f20..ed6a107e029a4ec1badcd79d7966005713b5b289 100644 (file)
@@ -9,6 +9,9 @@ class EventTestCase(unittest.TestCase):
     def setUp(self):
         self._ec = self._create_ec()
 
+    def tearDown(self):
+        del self._ec
+
     def _create_ec(self, with_eh=True, with_sec=True, with_ec=True, with_ep=True):
         # event header
         if with_eh:
@@ -164,19 +167,19 @@ class EventTestCase(unittest.TestCase):
     def test_clock_value(self):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev = self._ec()
-        ev.set_clock_value(cc.create_clock_value(177))
-        self.assertEqual(ev.get_clock_value(cc).cycles, 177)
+        ev.add_clock_value(cc(177))
+        self.assertEqual(ev.clock_value(cc).cycles, 177)
 
     def test_no_clock_value(self):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev = self._ec()
-        self.assertIsNone(ev.get_clock_value(cc))
+        self.assertIsNone(ev.clock_value(cc))
 
     def test_no_packet(self):
         ev = self._ec()
@@ -234,7 +237,7 @@ class EventTestCase(unittest.TestCase):
     def _get_full_ev(self):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev = self._ec()
         self._fill_ev(ev)
@@ -280,70 +283,70 @@ class EventTestCase(unittest.TestCase):
     def test_eq(self):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev1 = self._ec()
         self._fill_ev(ev1)
-        ev1.set_clock_value(cc.create_clock_value(234))
+        ev1.add_clock_value(cc(234))
         ev2 = self._ec()
         self._fill_ev(ev2)
-        ev2.set_clock_value(cc.create_clock_value(234))
+        ev2.add_clock_value(cc(234))
         self.assertEqual(ev1, ev2)
 
     def test_ne_header_field(self):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev1 = self._ec()
         self._fill_ev(ev1)
         ev1.header_field['id'] = 19
-        ev1.set_clock_value(cc.create_clock_value(234))
+        ev1.add_clock_value(cc(234))
         ev2 = self._ec()
         self._fill_ev(ev2)
-        ev2.set_clock_value(cc.create_clock_value(234))
+        ev2.add_clock_value(cc(234))
         self.assertNotEqual(ev1, ev2)
 
     def test_ne_stream_event_context_field(self):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev1 = self._ec()
         self._fill_ev(ev1)
         ev1.stream_event_context_field['cpu_id'] = 3
-        ev1.set_clock_value(cc.create_clock_value(234))
+        ev1.add_clock_value(cc(234))
         ev2 = self._ec()
         self._fill_ev(ev2)
-        ev2.set_clock_value(cc.create_clock_value(234))
+        ev2.add_clock_value(cc(234))
         self.assertNotEqual(ev1, ev2)
 
     def test_ne_context_field(self):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev1 = self._ec()
         self._fill_ev(ev1)
         ev1.context_field['ant'] = -3
-        ev1.set_clock_value(cc.create_clock_value(234))
+        ev1.add_clock_value(cc(234))
         ev2 = self._ec()
         self._fill_ev(ev2)
-        ev2.set_clock_value(cc.create_clock_value(234))
+        ev2.add_clock_value(cc(234))
         self.assertNotEqual(ev1, ev2)
 
     def test_ne_payload_field(self):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev1 = self._ec()
         self._fill_ev(ev1)
         ev1.payload_field['mosquito'] = 98
-        ev1.set_clock_value(cc.create_clock_value(234))
+        ev1.add_clock_value(cc(234))
         ev2 = self._ec()
         self._fill_ev(ev2)
-        ev2.set_clock_value(cc.create_clock_value(234))
+        ev2.add_clock_value(cc(234))
         self.assertNotEqual(ev1, ev2)
 
     def test_eq_invalid(self):
@@ -353,11 +356,11 @@ class EventTestCase(unittest.TestCase):
     def _test_copy(self, func):
         tc = bt2.Trace()
         tc.add_stream_class(self._ec.stream_class)
-        cc = bt2.ClockClass('hi')
+        cc = bt2.ClockClass('hi', 1000)
         tc.add_clock_class(cc)
         ev = self._ec()
         self._fill_ev(ev)
-        ev.set_clock_value(cc.create_clock_value(234))
+        ev.add_clock_value(cc(234))
         cpy = func(ev)
         self.assertIsNot(ev, cpy)
         self.assertNotEqual(ev.addr, cpy.addr)
index 8d21b844cbe278136d159a920e45cb84ca1737ac..d1f6d8e72af34c9eede812ee59fd271cf4022d5b 100644 (file)
@@ -13,14 +13,23 @@ class EventClassTestCase(unittest.TestCase):
         self._payload_ft.append_field('zoom', bt2.StringFieldType())
         self._ec = bt2.EventClass('my_event')
         self._ec.id = 18
+        self._ec.emf_uri = 'yes'
+        self._ec.log_level = bt2.EventClassLogLevel.INFO
         self._ec.context_field_type = self._context_ft
         self._ec.payload_field_type = self._payload_ft
 
+    def tearDown(self):
+        del self._context_ft
+        del self._payload_ft
+        del self._ec
+
     def test_create(self):
         self.assertEqual(self._ec.name, 'my_event')
         self.assertEqual(self._ec.id, 18)
         self.assertEqual(self._ec.context_field_type, self._context_ft)
         self.assertEqual(self._ec.payload_field_type, self._payload_ft)
+        self.assertEqual(self._ec.emf_uri, 'yes')
+        self.assertEqual(self._ec.log_level, bt2.EventClassLogLevel.INFO)
 
     def test_create_invalid_no_name(self):
         with self.assertRaises(TypeError):
@@ -30,12 +39,14 @@ class EventClassTestCase(unittest.TestCase):
         ec = bt2.EventClass(name='name', id=23,
                             context_field_type=self._context_ft,
                             payload_field_type=self._payload_ft,
-                            attributes={'model.emf.uri': 'my URI'})
+                            emf_uri='my URI',
+                            log_level=bt2.EventClassLogLevel.WARNING)
         self.assertEqual(ec.name, 'name')
         self.assertEqual(ec.id, 23)
         self.assertEqual(ec.context_field_type, self._context_ft)
         self.assertEqual(ec.payload_field_type, self._payload_ft)
-        self.assertEqual(ec.attributes['model.emf.uri'], 'my URI')
+        self.assertEqual(ec.emf_uri, 'my URI')
+        self.assertEqual(ec.log_level, bt2.EventClassLogLevel.WARNING)
 
     def test_assign_id(self):
         self._ec.id = 1717
@@ -94,90 +105,111 @@ class EventClassTestCase(unittest.TestCase):
         self.assertNotEqual(self._ec.context_field_type.addr, cpy.context_field_type.addr)
         self.assertNotEqual(self._ec.payload_field_type.addr, cpy.payload_field_type.addr)
 
-    def test_attr_getitem(self):
-        self.assertEqual(self._ec.attributes['id'], 18)
-        self.assertEqual(self._ec.attributes['name'], 'my_event')
-
-    def test_attr_setitem(self):
-        self._ec.attributes['model.emf.uri'] = 'my url'
-        self.assertEqual(self._ec.attributes['model.emf.uri'], 'my url')
+    def test_assign_emf_uri(self):
+        self._ec.emf_uri = 'salut'
+        self.assertEqual(self._ec.emf_uri, 'salut')
 
-    def test_attr_len(self):
-        self.assertTrue(len(self._ec.attributes) != 0)
+    def test_assign_invalid_emf_uri(self):
+        with self.assertRaises(TypeError):
+            self._ec.emf_uri = 23
 
-    def test_attr_iter(self):
-        for name, value in self._ec.attributes.items():
-            self.assertIsInstance(value, values._Value)
+    def test_assign_log_level(self):
+        self._ec.log_level = bt2.EventClassLogLevel.EMERGENCY
+        self.assertEqual(self._ec.log_level, bt2.EventClassLogLevel.EMERGENCY)
 
-            if name == 'name':
-                self.assertEqual(value, 'my_event')
-            elif name == 'id':
-                self.assertEqual(value, 18)
+    def test_assign_invalid_log_level(self):
+        with self.assertRaises(ValueError):
+            self._ec.log_level = 'zoom'
 
     def test_eq(self):
         ec1 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         ec2 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         self.assertEqual(ec1, ec2)
 
     def test_ne_name(self):
         ec1 = bt2.EventClass(name='name1', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         ec2 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         self.assertNotEqual(ec1, ec2)
 
     def test_ne_id(self):
         ec1 = bt2.EventClass(name='name', id=24,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         ec2 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         self.assertNotEqual(ec1, ec2)
 
     def test_ne_context_field_type(self):
         ec1 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._payload_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         ec2 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         self.assertNotEqual(ec1, ec2)
 
     def test_ne_payload_field_type(self):
         ec1 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._context_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
+        ec2 = bt2.EventClass(name='name', id=23,
+                             context_field_type=self._context_ft,
+                             payload_field_type=self._payload_ft,
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
+        self.assertNotEqual(ec1, ec2)
+
+    def test_ne_emf_uri(self):
+        ec1 = bt2.EventClass(name='name', id=23,
+                             context_field_type=self._context_ft,
+                             payload_field_type=self._payload_ft,
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         ec2 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my UR',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         self.assertNotEqual(ec1, ec2)
 
-    def test_ne_attribute(self):
+    def test_ne_log_level(self):
         ec1 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my URI'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.WARNING)
         ec2 = bt2.EventClass(name='name', id=23,
                              context_field_type=self._context_ft,
                              payload_field_type=self._payload_ft,
-                             attributes={'model.emf.uri': 'my UR'})
+                             emf_uri='my URI',
+                             log_level=bt2.EventClassLogLevel.ERROR)
         self.assertNotEqual(ec1, ec2)
 
     def test_eq_invalid(self):
index b265402d5571ee132d16df9ab81d0a5cf3f8be7f..763e30e6f3718854ae7f120758637e64fdb1874c 100644 (file)
@@ -73,7 +73,7 @@ class _TestIntegerFieldTypeProps:
             self._ft.encoding = 'hey'
 
     def test_assign_mapped_clock_class(self):
-        cc = bt2.ClockClass('name')
+        cc = bt2.ClockClass('name', 1000)
         self._ft.mapped_clock_class = cc
         self.assertEqual(self._ft.mapped_clock_class, cc)
 
@@ -88,8 +88,12 @@ class IntegerFieldTypeTestCase(_TestIntegerFieldTypeProps, _TestCopySimple,
     def setUp(self):
         self._ft = bt2.IntegerFieldType(35)
 
+    def tearDown(self):
+        del self._ft
+
     def test_create_default(self):
         self.assertEqual(self._ft.size, 35)
+        self.assertIsNone(self._ft.mapped_clock_class)
 
     def test_create_invalid_size(self):
         with self.assertRaises(TypeError):
@@ -104,7 +108,7 @@ class IntegerFieldTypeTestCase(_TestIntegerFieldTypeProps, _TestCopySimple,
             ft = bt2.IntegerFieldType(0)
 
     def test_create_full(self):
-        cc = bt2.ClockClass('name')
+        cc = bt2.ClockClass('name', 1000)
         ft = bt2.IntegerFieldType(24, alignment=16,
                                   byte_order=bt2.ByteOrder.BIG_ENDIAN,
                                   is_signed=True, base=bt2.Base.OCTAL,
@@ -133,6 +137,9 @@ class FloatingPointNumberFieldTypeTestCase(_TestCopySimple, _TestAlignmentProp,
     def setUp(self):
         self._ft = bt2.FloatingPointNumberFieldType()
 
+    def tearDown(self):
+        del self._ft
+
     def test_create_default(self):
         pass
 
@@ -177,6 +184,9 @@ class EnumerationFieldTypeTestCase(_TestIntegerFieldTypeProps, _TestInvalidEq,
     def setUp(self):
         self._ft = bt2.EnumerationFieldType(size=35)
 
+    def tearDown(self):
+        del self._ft
+
     def test_create_from_int_ft(self):
         int_ft = bt2.IntegerFieldType(23)
         self._ft = bt2.EnumerationFieldType(int_ft)
@@ -421,6 +431,9 @@ class StringFieldTypeTestCase(_TestCopySimple, _TestInvalidEq,
     def setUp(self):
         self._ft = bt2.StringFieldType()
 
+    def tearDown(self):
+        del self._ft
+
     def test_create_default(self):
         pass
 
@@ -551,11 +564,20 @@ class _TestFieldContainer(_TestInvalidEq, _TestCopySimple):
         with self.assertRaises(TypeError):
             self._ft.at_index('yes')
 
+    def test_at_index_out_of_bounds_after(self):
+        self._ft.append_field('c', bt2.IntegerFieldType(32))
+
+        with self.assertRaises(IndexError):
+            self._ft.at_index(len(self._ft))
+
 
 class StructureFieldTypeTestCase(_TestFieldContainer, unittest.TestCase):
     def setUp(self):
         self._ft = bt2.StructureFieldType()
 
+    def tearDown(self):
+        del self._ft
+
     def test_create_default(self):
         self.assertEqual(self._ft.alignment, 1)
 
@@ -592,6 +614,9 @@ class VariantFieldTypeTestCase(_TestFieldContainer, unittest.TestCase):
     def setUp(self):
         self._ft = bt2.VariantFieldType('path.to.tag')
 
+    def tearDown(self):
+        del self._ft
+
     def test_create_default(self):
         self.assertEqual(self._ft.tag_name, 'path.to.tag')
 
@@ -614,6 +639,10 @@ class ArrayFieldTypeTestCase(_TestInvalidEq, _TestCopySimple,
         self._elem_ft = bt2.IntegerFieldType(23)
         self._ft = bt2.ArrayFieldType(self._elem_ft, 45)
 
+    def tearDown(self):
+        del self._ft
+        del self._elem_ft
+
     def test_create_default(self):
         self.assertEqual(self._ft.element_field_type, self._elem_ft)
         self.assertEqual(self._ft.length, 45)
@@ -645,6 +674,10 @@ class SequenceFieldTypeTestCase(_TestInvalidEq, _TestCopySimple,
         self._elem_ft = bt2.IntegerFieldType(23)
         self._ft = bt2.SequenceFieldType(self._elem_ft, 'the.length')
 
+    def tearDown(self):
+        del self._ft
+        del self._elem_ft
+
     def test_create_default(self):
         self.assertEqual(self._ft.element_field_type, self._elem_ft)
         self.assertEqual(self._ft.length_name, 'the.length')
index c14e0dea3b92c2ec27d5c2556d4df4c6b97aa94d..f8fbd4a53b6f20d7c293e4421af6daa1b5c4b3a0 100644 (file)
@@ -595,7 +595,6 @@ def _inject_numeric_testing_methods(cls):
 
     # inject testing methods for each binary operation
     for name, binop in _BINOPS:
-
         setattr(cls, test_binop_name('invalid_unknown'), partialmethod(_TestNumericField._test_binop_invalid_unknown, op=binop))
         setattr(cls, test_binop_name('invalid_none'), partialmethod(_TestNumericField._test_binop_invalid_none, op=binop))
         setattr(cls, test_binop_name('type_true'), partialmethod(_TestNumericField._test_binop_type_true, op=binop))
@@ -767,16 +766,48 @@ class IntegerFieldTestCase(_TestIntegerFieldCommon, unittest.TestCase):
         self._def_value = 17
         self._def_new_value = -101
 
+    def tearDown(self):
+        del self._ft
+        del self._field
+        del self._def
+
 
 class EnumerationFieldTestCase(_TestIntegerFieldCommon, unittest.TestCase):
     def setUp(self):
         self._ft = bt2.EnumerationFieldType(size=32, is_signed=True)
         self._ft.append_mapping('whole range', -(2 ** 31), (2 ** 31) - 1)
+        self._ft.append_mapping('something', 17)
+        self._ft.append_mapping('speaker', 12, 16)
+        self._ft.append_mapping('can', 18, 2540)
+        self._ft.append_mapping('zip', -45, 1001)
         self._def = self._ft()
         self._def.value = 17
         self._def_value = 17
         self._def_new_value = -101
 
+    def tearDown(self):
+        del self._ft
+        del self._def
+
+    def test_mappings(self):
+        mappings = (
+            ('whole range', -(2 ** 31), (2 ** 31) - 1),
+            ('something', 17, 17),
+            ('zip', -45, 1001),
+        )
+
+        total = 0
+        index_set = set()
+
+        for fm in self._def.mappings:
+            total += 1
+            for index, mapping in enumerate(mappings):
+                if fm.name == mapping[0] and fm.lower == mapping[1] and fm.upper == mapping[2]:
+                    index_set.add(index)
+
+        self.assertEqual(total, 3)
+        self.assertTrue(0 in index_set and 1 in index_set and 2 in index_set)
+
 
 class FloatingPointNumberFieldTestCase(_TestNumericField, unittest.TestCase):
     def setUp(self):
@@ -787,6 +818,11 @@ class FloatingPointNumberFieldTestCase(_TestNumericField, unittest.TestCase):
         self._def_value = 52.7
         self._def_new_value = -17.164857
 
+    def tearDown(self):
+        del self._ft
+        del self._field
+        del self._def
+
     def _test_invalid_op(self, cb):
         with self.assertRaises(TypeError):
             cb()
@@ -871,6 +907,10 @@ class StringFieldTestCase(_TestCopySimple, unittest.TestCase):
         self._def.value = self._def_value
         self._def_new_value = 'Yes!'
 
+    def tearDown(self):
+        del self._ft
+        del self._def
+
     def test_assign_int(self):
         with self.assertRaises(TypeError):
             self._def.value = 283
@@ -1059,6 +1099,11 @@ class ArrayFieldTestCase(_TestArraySequenceFieldCommon, unittest.TestCase):
         self._def[1] = 1847
         self._def[2] = 1948754
 
+    def tearDown(self):
+        del self._elem_ft
+        del self._ft
+        del self._def
+
 
 class SequenceFieldTestCase(_TestArraySequenceFieldCommon, unittest.TestCase):
     def setUp(self):
@@ -1071,6 +1116,12 @@ class SequenceFieldTestCase(_TestArraySequenceFieldCommon, unittest.TestCase):
         self._def[1] = 1847
         self._def[2] = 1948754
 
+    def tearDown(self):
+        del self._elem_ft
+        del self._ft
+        del self._def
+        del self._length_field
+
 
 class StructureFieldTestCase(_TestCopySimple, unittest.TestCase):
     def setUp(self):
@@ -1089,6 +1140,14 @@ class StructureFieldTestCase(_TestCopySimple, unittest.TestCase):
         self._def['C'] = 17.5
         self._def['D'] = 16497
 
+    def tearDown(self):
+        del self._ft0
+        del self._ft1
+        del self._ft2
+        del self._ft3
+        del self._ft
+        del self._def
+
     def _modify_def(self):
         self._def['B'] = 'hola'
 
@@ -1108,6 +1167,10 @@ class StructureFieldTestCase(_TestCopySimple, unittest.TestCase):
         self.assertIs(type(field), bt2.fields._IntegerField)
         self.assertEqual(field, -1872)
 
+    def test_at_index_out_of_bounds_after(self):
+        with self.assertRaises(IndexError):
+            self._def.at_index(len(self._ft))
+
     def test_eq(self):
         ft = bt2.StructureFieldType()
         ft.append_field('A', self._ft0)
@@ -1208,3 +1271,88 @@ class StructureFieldTestCase(_TestCopySimple, unittest.TestCase):
         for vkey, vval in self._def.items():
             val = orig_values[vkey]
             self.assertEqual(vval, val)
+
+
+class VariantFieldTestCase(_TestCopySimple, unittest.TestCase):
+    def setUp(self):
+        self._tag_ft = bt2.EnumerationFieldType(size=32)
+        self._tag_ft.append_mapping('corner', 23)
+        self._tag_ft.append_mapping('zoom', 17, 20)
+        self._tag_ft.append_mapping('mellotron', 1001)
+        self._tag_ft.append_mapping('giorgio', 2000, 3000)
+        self._ft0 = bt2.IntegerFieldType(32, is_signed=True)
+        self._ft1 = bt2.StringFieldType()
+        self._ft2 = bt2.FloatingPointNumberFieldType()
+        self._ft3 = bt2.IntegerFieldType(17)
+        self._ft = bt2.VariantFieldType('salut', self._tag_ft)
+        self._ft.append_field('corner', self._ft0)
+        self._ft.append_field('zoom', self._ft1)
+        self._ft.append_field('mellotron', self._ft2)
+        self._ft.append_field('giorgio', self._ft3)
+        self._def = self._ft()
+
+    def tearDown(self):
+        del self._tag_ft
+        del self._ft0
+        del self._ft1
+        del self._ft2
+        del self._ft3
+        del self._ft
+        del self._def
+
+    def test_bool_op_true(self):
+        tag_field = self._tag_ft(1001)
+        self._def.field(tag_field).value = -17.34
+        self.assertTrue(self._def)
+
+    def test_bool_op_false(self):
+        self.assertFalse(self._def)
+
+    def test_tag_field_none(self):
+        self.assertIsNone(self._def.tag_field)
+
+    def test_tag_field(self):
+        tag_field = self._tag_ft(2800)
+        self._def.field(tag_field).value = 1847
+        self.assertEqual(self._def.tag_field, tag_field)
+        self.assertEqual(self._def.tag_field.addr, tag_field.addr)
+
+    def test_selected_field_none(self):
+        self.assertIsNone(self._def.selected_field)
+
+    def test_selected_field(self):
+        var_field1 = self._ft()
+        tag_field1 = self._tag_ft(1001)
+        var_field1.field(tag_field1).value = -17.34
+        self.assertEqual(var_field1.field(), -17.34)
+        self.assertEqual(var_field1.selected_field, -17.34)
+        var_field2 = self._ft()
+        tag_field2 = self._tag_ft(2500)
+        var_field2.field(tag_field2).value = 1921
+        self.assertEqual(var_field2.field(), 1921)
+        self.assertEqual(var_field2.selected_field, 1921)
+
+    def test_eq(self):
+        tag_ft = bt2.EnumerationFieldType(size=32)
+        tag_ft.append_mapping('corner', 23)
+        tag_ft.append_mapping('zoom', 17, 20)
+        tag_ft.append_mapping('mellotron', 1001)
+        tag_ft.append_mapping('giorgio', 2000, 3000)
+        ft0 = bt2.IntegerFieldType(32, is_signed=True)
+        ft1 = bt2.StringFieldType()
+        ft2 = bt2.FloatingPointNumberFieldType()
+        ft3 = bt2.IntegerFieldType(17)
+        ft = bt2.VariantFieldType('salut', tag_ft)
+        ft.append_field('corner', ft0)
+        ft.append_field('zoom', ft1)
+        ft.append_field('mellotron', ft2)
+        ft.append_field('giorgio', ft3)
+        field = ft()
+        field_tag = tag_ft(23)
+        def_tag = self._tag_ft(23)
+        field.field(field_tag).value = 1774
+        self._def.field(def_tag).value = 1774
+        self.assertEqual(self._def, field)
+
+    def test_eq_invalid_type(self):
+        self.assertNotEqual(self._def, 23)
diff --git a/tests/bindings/python/bt2/test_graph.py b/tests/bindings/python/bt2/test_graph.py
new file mode 100644 (file)
index 0000000..7ce3ed8
--- /dev/null
@@ -0,0 +1,471 @@
+from bt2 import values
+import collections
+import unittest
+import copy
+import bt2
+
+
+class GraphTestCase(unittest.TestCase):
+    def setUp(self):
+        self._graph = bt2.Graph()
+
+    def tearDown(self):
+        del self._graph
+
+    def test_create_empty(self):
+        graph = bt2.Graph()
+
+    def test_add_component_user_cls(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        comp = self._graph.add_component(MySink, 'salut')
+        self.assertEqual(comp.name, 'salut')
+
+    def test_add_component_gen_cls(self):
+        class MySink(bt2._UserSinkComponent):
+            def _consume(self):
+                pass
+
+        comp = self._graph.add_component(MySink, 'salut')
+        assert(comp)
+        comp2 = self._graph.add_component(comp.component_class, 'salut2')
+        self.assertEqual(comp2.name, 'salut2')
+
+    def test_add_component_params(self):
+        comp_params = None
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                nonlocal comp_params
+                comp_params = params
+
+            def _consume(self):
+                pass
+
+        params = {'hello': 23, 'path': '/path/to/stuff'}
+        comp = self._graph.add_component(MySink, 'salut', params)
+        self.assertEqual(params, comp_params)
+        del comp_params
+
+    def test_add_component_invalid_cls_type(self):
+        with self.assertRaises(TypeError):
+            self._graph.add_component(int, 'salut')
+
+    def test_connect_ports(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        src = self._graph.add_component(MySource, 'src')
+        sink = self._graph.add_component(MySink, 'sink')
+        conn = self._graph.connect_ports(src.output_ports['out'],
+                                         sink.input_ports['in'])
+        self.assertTrue(src.output_ports['out'].is_connected)
+        self.assertTrue(sink.input_ports['in'].is_connected)
+        self.assertEqual(src.output_ports['out'].connection, conn)
+        self.assertEqual(sink.input_ports['in'].connection, conn)
+
+    def test_connect_ports_invalid_direction(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        src = self._graph.add_component(MySource, 'src')
+        sink = self._graph.add_component(MySink, 'sink')
+
+        with self.assertRaises(TypeError):
+            conn = self._graph.connect_ports(sink.input_ports['in'],
+                                             src.output_ports['out'])
+
+    def test_connect_ports_refused(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _accept_port_connection(self, port, other_port):
+                return False
+
+        src = self._graph.add_component(MySource, 'src')
+        sink = self._graph.add_component(MySink, 'sink')
+
+        with self.assertRaises(bt2.PortConnectionRefused):
+            conn = self._graph.connect_ports(src.output_ports['out'],
+                                             sink.input_ports['in'])
+
+    def test_connect_ports_canceled(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+        src = self._graph.add_component(MySource, 'src')
+        sink = self._graph.add_component(MySink, 'sink')
+        self._graph.cancel()
+
+        with self.assertRaises(bt2.GraphCanceled):
+            conn = self._graph.connect_ports(src.output_ports['out'],
+                                             sink.input_ports['in'])
+
+    def test_cancel(self):
+        self.assertFalse(self._graph.is_canceled)
+        self._graph.cancel()
+        self.assertTrue(self._graph.is_canceled)
+
+    def test_run(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __init__(self):
+                self._build_meta()
+                self._at = 0
+
+            def _build_meta(self):
+                self._trace = bt2.Trace()
+                self._sc = bt2.StreamClass()
+                self._ec = bt2.EventClass('salut')
+                self._my_int_ft = bt2.IntegerFieldType(32)
+                self._ec.payload_field_type = bt2.StructureFieldType()
+                self._ec.payload_field_type += collections.OrderedDict([
+                    ('my_int', self._my_int_ft),
+                ])
+                self._sc.add_event_class(self._ec)
+                self._trace.add_stream_class(self._sc)
+                self._stream = self._sc()
+                self._packet = self._stream.create_packet()
+
+            def _create_event(self, value):
+                ev = self._ec()
+                ev.payload_field['my_int'] = value
+                ev.packet = self._packet
+                return ev
+
+            def __next__(self):
+                if self._at == 5:
+                    raise bt2.Stop
+
+                notif = bt2.EventNotification(self._create_event(self._at * 3))
+                self._at += 1
+                return notif
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+                self._at = 0
+
+            def _consume(comp_self):
+                notif = next(comp_self._notif_iter)
+
+                if comp_self._at == 0:
+                    self.assertIsInstance(notif, bt2.StreamBeginningNotification)
+                elif comp_self._at == 1:
+                    self.assertIsInstance(notif, bt2.PacketBeginningNotification)
+                elif comp_self._at >= 2 and comp_self._at <= 6:
+                    self.assertIsInstance(notif, bt2.EventNotification)
+                    self.assertEqual(notif.event.event_class.name, 'salut')
+                    field = notif.event.payload_field['my_int']
+                    self.assertEqual(field, (comp_self._at - 2) * 3)
+                elif comp_self._at == 7:
+                    self.assertIsInstance(notif, bt2.PacketEndNotification)
+                elif comp_self._at == 8:
+                    self.assertIsInstance(notif, bt2.StreamEndNotification)
+
+                comp_self._at += 1
+
+            def _port_connected(self, port, other_port):
+                self._notif_iter = port.connection.create_notification_iterator()
+
+        src = self._graph.add_component(MySource, 'src')
+        sink = self._graph.add_component(MySink, 'sink')
+        conn = self._graph.connect_ports(src.output_ports['out'],
+                                         sink.input_ports['in'])
+        self._graph.run()
+
+    def test_run_again(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __init__(self):
+                self._build_meta()
+                self._at = 0
+
+            def _build_meta(self):
+                self._trace = bt2.Trace()
+                self._sc = bt2.StreamClass()
+                self._ec = bt2.EventClass('salut')
+                self._my_int_ft = bt2.IntegerFieldType(32)
+                self._ec.payload_field_type = bt2.StructureFieldType()
+                self._ec.payload_field_type += collections.OrderedDict([
+                    ('my_int', self._my_int_ft),
+                ])
+                self._sc.add_event_class(self._ec)
+                self._trace.add_stream_class(self._sc)
+                self._stream = self._sc()
+                self._packet = self._stream.create_packet()
+
+            def _create_event(self, value):
+                ev = self._ec()
+                ev.payload_field['my_int'] = value
+                ev.packet = self._packet
+                return ev
+
+            def __next__(self):
+                if self._at == 1:
+                    raise bt2.TryAgain
+
+                notif = bt2.EventNotification(self._create_event(self._at * 3))
+                self._at += 1
+                return notif
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+                self._at = 0
+
+            def _consume(comp_self):
+                if comp_self._at == 0:
+                    notif = next(comp_self._notif_iter)
+                    self.assertIsInstance(notif, bt2.EventNotification)
+                elif comp_self._at == 1:
+                    with self.assertRaises(bt2.TryAgain):
+                        notif = next(comp_self._notif_iter)
+
+                    raise bt2.TryAgain
+
+                comp_self._at += 1
+
+            def _port_connected(self, port, other_port):
+                types = [bt2.EventNotification]
+                self._notif_iter = port.connection.create_notification_iterator(types)
+
+        src = self._graph.add_component(MySource, 'src')
+        sink = self._graph.add_component(MySink, 'sink')
+        conn = self._graph.connect_ports(src.output_ports['out'],
+                                         sink.input_ports['in'])
+
+        with self.assertRaises(bt2.TryAgain):
+            self._graph.run()
+
+    def test_run_no_sink(self):
+        class MyIter(bt2._UserNotificationIterator):
+            pass
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+                self._add_input_port('in')
+
+        src = self._graph.add_component(MySource, 'src')
+        flt = self._graph.add_component(MyFilter, 'flt')
+        conn = self._graph.connect_ports(src.output_ports['out'],
+                                         flt.input_ports['in'])
+
+        with self.assertRaises(bt2.NoSinkComponent):
+            self._graph.run()
+
+    def test_run_error(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __init__(self):
+                self._build_meta()
+                self._at = 0
+
+            def _build_meta(self):
+                self._trace = bt2.Trace()
+                self._sc = bt2.StreamClass()
+                self._ec = bt2.EventClass('salut')
+                self._my_int_ft = bt2.IntegerFieldType(32)
+                self._ec.payload_field_type = bt2.StructureFieldType()
+                self._ec.payload_field_type += collections.OrderedDict([
+                    ('my_int', self._my_int_ft),
+                ])
+                self._sc.add_event_class(self._ec)
+                self._trace.add_stream_class(self._sc)
+                self._stream = self._sc()
+                self._packet = self._stream.create_packet()
+
+            def _create_event(self, value):
+                ev = self._ec()
+                ev.payload_field['my_int'] = value
+                ev.packet = self._packet
+                return ev
+
+            def __next__(self):
+                if self._at == 1:
+                    raise bt2.TryAgain
+
+                notif = bt2.EventNotification(self._create_event(self._at * 3))
+                self._at += 1
+                return notif
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+                self._at = 0
+
+            def _consume(comp_self):
+                if comp_self._at == 0:
+                    notif = next(comp_self._notif_iter)
+                    self.assertIsInstance(notif, bt2.EventNotification)
+                elif comp_self._at == 1:
+                    raise RuntimeError('error!')
+
+                comp_self._at += 1
+
+            def _port_connected(self, port, other_port):
+                types = [bt2.EventNotification]
+                self._notif_iter = port.connection.create_notification_iterator(types)
+
+        src = self._graph.add_component(MySource, 'src')
+        sink = self._graph.add_component(MySink, 'sink')
+        conn = self._graph.connect_ports(src.output_ports['out'],
+                                         sink.input_ports['in'])
+
+        with self.assertRaises(bt2.Error):
+            self._graph.run()
+
+    def test_listeners(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+                self._add_output_port('zero')
+
+            def _port_connected(self, port, other_port):
+                self._output_ports['zero'].remove_from_component()
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                self._add_input_port('taste')
+
+            def _port_disconnected(self, port):
+                port.remove_from_component()
+
+        def port_added_listener(port):
+            nonlocal calls
+            calls.append((port_added_listener, port))
+
+        def port_removed_listener(port):
+            nonlocal calls
+            calls.append((port_removed_listener, port))
+
+        def ports_connected_listener(upstream_port, downstream_port):
+            nonlocal calls
+            calls.append((ports_connected_listener, upstream_port,
+                          downstream_port))
+
+        def ports_disconnected_listener(upstream_comp, downstream_comp,
+                                        upstream_port, downstream_port):
+            nonlocal calls
+            calls.append((ports_disconnected_listener, upstream_comp,
+                          downstream_comp, upstream_port, downstream_port))
+
+        calls = []
+        self._graph.add_listener(bt2.GraphListenerType.PORT_ADDED,
+                                 port_added_listener)
+        self._graph.add_listener(bt2.GraphListenerType.PORT_REMOVED,
+                                 port_removed_listener)
+        self._graph.add_listener(bt2.GraphListenerType.PORTS_CONNECTED,
+                                 ports_connected_listener)
+        self._graph.add_listener(bt2.GraphListenerType.PORTS_DISCONNECTED,
+                                 ports_disconnected_listener)
+        src = self._graph.add_component(MySource, 'src')
+        sink = self._graph.add_component(MySink, 'sink')
+        self._graph.connect_ports(src.output_ports['out'],
+                                  sink.input_ports['in'])
+        sink.input_ports['in'].disconnect()
+        self.assertIs(calls[0][0], port_added_listener)
+        self.assertEqual(calls[0][1].name, 'out')
+        self.assertIs(calls[1][0], port_added_listener)
+        self.assertEqual(calls[1][1].name, 'zero')
+        self.assertIs(calls[2][0], port_added_listener)
+        self.assertEqual(calls[2][1].name, 'in')
+        self.assertIs(calls[3][0], port_removed_listener)
+        self.assertEqual(calls[3][1].name, 'zero')
+        self.assertIs(calls[4][0], port_added_listener)
+        self.assertEqual(calls[4][1].name, 'taste')
+        self.assertIs(calls[5][0], ports_connected_listener)
+        self.assertEqual(calls[5][1].name, 'out')
+        self.assertEqual(calls[5][2].name, 'in')
+        self.assertIs(calls[6][0], port_removed_listener)
+        self.assertEqual(calls[6][1].name, 'in')
+        self.assertIs(calls[7][0], ports_disconnected_listener)
+        self.assertEqual(calls[7][1].name, 'src')
+        self.assertEqual(calls[7][2].name, 'sink')
+        self.assertEqual(calls[7][3].name, 'out')
+        self.assertEqual(calls[7][4].name, 'in')
+        del calls
diff --git a/tests/bindings/python/bt2/test_notification.py b/tests/bindings/python/bt2/test_notification.py
new file mode 100644 (file)
index 0000000..62d48bd
--- /dev/null
@@ -0,0 +1,566 @@
+from bt2 import values
+import collections
+import unittest
+import copy
+import bt2
+
+
+class _NotificationTestCase(unittest.TestCase):
+    def setUp(self):
+        self._trace = bt2.Trace()
+        self._sc = bt2.StreamClass()
+        self._ec = bt2.EventClass('salut')
+        self._my_int_ft = bt2.IntegerFieldType(32)
+        self._ec.payload_field_type = bt2.StructureFieldType()
+        self._ec.payload_field_type += collections.OrderedDict([
+            ('my_int', self._my_int_ft),
+        ])
+        self._sc.add_event_class(self._ec)
+        self._clock_class = bt2.ClockClass('allo', 1000)
+        self._trace.add_clock_class(self._clock_class)
+        self._trace.packet_header_field_type = bt2.StructureFieldType()
+        self._trace.packet_header_field_type += collections.OrderedDict([
+            ('hello', self._my_int_ft),
+        ])
+        self._trace.add_stream_class(self._sc)
+        self._cc_prio_map = bt2.ClockClassPriorityMap()
+        self._cc_prio_map[self._clock_class] = 231
+        self._stream = self._sc()
+        self._packet = self._stream.create_packet()
+        self._packet.header_field['hello'] = 19487
+        self._event = self._ec()
+        self._event.add_clock_value(self._clock_class(1772))
+        self._event.payload_field['my_int'] = 23
+        self._event.packet = self._packet
+
+    def tearDown(self):
+        del self._trace
+        del self._sc
+        del self._ec
+        del self._my_int_ft
+        del self._clock_class
+        del self._cc_prio_map
+        del self._stream
+        del self._packet
+        del self._event
+
+
+class EventNotificationTestCase(_NotificationTestCase):
+    def test_create_no_cc_prio_map(self):
+        notif = bt2.EventNotification(self._event)
+        self.assertEqual(notif.event.addr, self._event.addr)
+        self.assertEqual(len(notif.clock_class_priority_map), 0)
+
+    def test_create_with_cc_prio_map(self):
+        notif = bt2.EventNotification(self._event, self._cc_prio_map)
+        self.assertEqual(notif.event.addr, self._event.addr)
+        self.assertEqual(len(notif.clock_class_priority_map), 1)
+        self.assertEqual(notif.clock_class_priority_map.highest_priority_clock_class.addr,
+                         self._clock_class.addr)
+        self.assertEqual(notif.clock_class_priority_map[self._clock_class], 231)
+
+    def test_eq(self):
+        notif = bt2.EventNotification(self._event, self._cc_prio_map)
+        event_copy = copy.copy(self._event)
+        event_copy.packet = self._packet
+        cc_prio_map_copy = copy.copy(self._cc_prio_map)
+        notif2 = bt2.EventNotification(event_copy, cc_prio_map_copy)
+        self.assertEqual(notif, notif2)
+
+    def test_ne_event(self):
+        notif = bt2.EventNotification(self._event, self._cc_prio_map)
+        event_copy = copy.copy(self._event)
+        event_copy.payload_field['my_int'] = 17
+        event_copy.packet = self._packet
+        cc_prio_map_copy = copy.copy(self._cc_prio_map)
+        notif2 = bt2.EventNotification(event_copy, cc_prio_map_copy)
+        self.assertNotEqual(notif, notif2)
+
+    def test_ne_cc_prio_map(self):
+        notif = bt2.EventNotification(self._event)
+        event_copy = copy.copy(self._event)
+        event_copy.packet = self._packet
+        cc_prio_map_copy = copy.copy(self._cc_prio_map)
+        notif2 = bt2.EventNotification(event_copy, cc_prio_map_copy)
+        self.assertNotEqual(notif, notif2)
+
+    def test_eq_invalid(self):
+        notif = bt2.EventNotification(self._event)
+        self.assertNotEqual(notif, 23)
+
+    def test_copy(self):
+        notif = bt2.EventNotification(self._event, self._cc_prio_map)
+        notif2 = copy.copy(notif)
+        self.assertEqual(notif, notif2)
+
+    def test_deepcopy(self):
+        notif = bt2.EventNotification(self._event, self._cc_prio_map)
+        notif2 = copy.deepcopy(notif)
+        self.assertEqual(notif, notif2)
+
+
+class PacketBeginningNotificationTestCase(_NotificationTestCase):
+    def test_create(self):
+        notif = bt2.PacketBeginningNotification(self._packet)
+        self.assertEqual(notif.packet.addr, self._packet.addr)
+
+    def test_eq(self):
+        notif = bt2.PacketBeginningNotification(self._packet)
+        packet_copy = copy.copy(self._packet)
+        notif2 = bt2.PacketBeginningNotification(packet_copy)
+        self.assertEqual(notif, notif2)
+
+    def test_ne_packet(self):
+        notif = bt2.PacketBeginningNotification(self._packet)
+        packet_copy = copy.copy(self._packet)
+        packet_copy.header_field['hello'] = 1847
+        notif2 = bt2.PacketBeginningNotification(packet_copy)
+        self.assertNotEqual(notif, notif2)
+
+    def test_eq_invalid(self):
+        notif = bt2.PacketBeginningNotification(self._packet)
+        self.assertNotEqual(notif, 23)
+
+    def test_copy(self):
+        notif = bt2.PacketBeginningNotification(self._packet)
+        notif2 = copy.copy(notif)
+        self.assertEqual(notif, notif2)
+
+    def test_deepcopy(self):
+        notif = bt2.PacketBeginningNotification(self._packet)
+        notif2 = copy.deepcopy(notif)
+        self.assertEqual(notif, notif2)
+
+
+class PacketEndNotificationTestCase(_NotificationTestCase):
+    def test_create(self):
+        notif = bt2.PacketEndNotification(self._packet)
+        self.assertEqual(notif.packet.addr, self._packet.addr)
+
+    def test_eq(self):
+        notif = bt2.PacketEndNotification(self._packet)
+        packet_copy = copy.copy(self._packet)
+        notif2 = bt2.PacketEndNotification(packet_copy)
+        self.assertEqual(notif, notif2)
+
+    def test_ne_packet(self):
+        notif = bt2.PacketEndNotification(self._packet)
+        packet_copy = copy.copy(self._packet)
+        packet_copy.header_field['hello'] = 1847
+        notif2 = bt2.PacketEndNotification(packet_copy)
+        self.assertNotEqual(notif, notif2)
+
+    def test_eq_invalid(self):
+        notif = bt2.PacketEndNotification(self._packet)
+        self.assertNotEqual(notif, 23)
+
+    def test_copy(self):
+        notif = bt2.PacketEndNotification(self._packet)
+        notif2 = copy.copy(notif)
+        self.assertEqual(notif, notif2)
+
+    def test_deepcopy(self):
+        notif = bt2.PacketEndNotification(self._packet)
+        notif2 = copy.deepcopy(notif)
+        self.assertEqual(notif, notif2)
+
+
+class StreamBeginningNotificationTestCase(_NotificationTestCase):
+    def test_create(self):
+        notif = bt2.StreamBeginningNotification(self._stream)
+        self.assertEqual(notif.stream.addr, self._stream.addr)
+
+    def test_eq(self):
+        notif = bt2.StreamBeginningNotification(self._stream)
+        stream_copy = copy.copy(self._stream)
+        notif2 = bt2.StreamBeginningNotification(stream_copy)
+        self.assertEqual(notif, notif2)
+
+    def test_ne_stream(self):
+        notif = bt2.StreamBeginningNotification(self._stream)
+        stream_copy = self._sc(name='salut')
+        notif2 = bt2.StreamBeginningNotification(stream_copy)
+        self.assertNotEqual(notif, notif2)
+
+    def test_eq_invalid(self):
+        notif = bt2.StreamBeginningNotification(self._stream)
+        self.assertNotEqual(notif, 23)
+
+    def test_copy(self):
+        notif = bt2.StreamBeginningNotification(self._stream)
+        notif2 = copy.copy(notif)
+        self.assertEqual(notif, notif2)
+
+    def test_deepcopy(self):
+        notif = bt2.StreamBeginningNotification(self._stream)
+        notif2 = copy.deepcopy(notif)
+        self.assertEqual(notif, notif2)
+
+
+class StreamEndNotificationTestCase(_NotificationTestCase):
+    def test_create(self):
+        notif = bt2.StreamEndNotification(self._stream)
+        self.assertEqual(notif.stream.addr, self._stream.addr)
+
+    def test_eq(self):
+        notif = bt2.StreamEndNotification(self._stream)
+        stream_copy = copy.copy(self._stream)
+        notif2 = bt2.StreamEndNotification(stream_copy)
+        self.assertEqual(notif, notif2)
+
+    def test_ne_stream(self):
+        notif = bt2.StreamEndNotification(self._stream)
+        stream_copy = self._sc(name='salut')
+        notif2 = bt2.StreamEndNotification(stream_copy)
+        self.assertNotEqual(notif, notif2)
+
+    def test_eq_invalid(self):
+        notif = bt2.StreamEndNotification(self._stream)
+        self.assertNotEqual(notif, 23)
+
+    def test_copy(self):
+        notif = bt2.StreamEndNotification(self._stream)
+        notif2 = copy.copy(notif)
+        self.assertEqual(notif, notif2)
+
+    def test_deepcopy(self):
+        notif = bt2.StreamEndNotification(self._stream)
+        notif2 = copy.deepcopy(notif)
+        self.assertEqual(notif, notif2)
+
+
+class InactivityNotificationTestCase(unittest.TestCase):
+    def setUp(self):
+        self._cc1 = bt2.ClockClass('cc1', 1000)
+        self._cc2 = bt2.ClockClass('cc2', 2000)
+        self._cc_prio_map = bt2.ClockClassPriorityMap()
+        self._cc_prio_map[self._cc1] = 25
+        self._cc_prio_map[self._cc2] = 50
+
+    def tearDown(self):
+        del self._cc1
+        del self._cc2
+        del self._cc_prio_map
+
+    def test_create_no_cc_prio_map(self):
+        notif = bt2.InactivityNotification()
+        self.assertEqual(len(notif.clock_class_priority_map), 0)
+
+    def test_create_with_cc_prio_map(self):
+        notif = bt2.InactivityNotification(self._cc_prio_map)
+        notif.add_clock_value(self._cc1(123))
+        notif.add_clock_value(self._cc2(19487))
+        self.assertEqual(len(notif.clock_class_priority_map), 2)
+        self.assertEqual(notif.clock_class_priority_map, self._cc_prio_map)
+        self.assertEqual(notif.clock_value(self._cc1), 123)
+        self.assertEqual(notif.clock_value(self._cc2), 19487)
+
+    def test_eq(self):
+        notif = bt2.InactivityNotification(self._cc_prio_map)
+        notif.add_clock_value(self._cc1(123))
+        notif.add_clock_value(self._cc2(19487))
+        cc_prio_map_copy = copy.copy(self._cc_prio_map)
+        notif2 = bt2.InactivityNotification(cc_prio_map_copy)
+        notif2.add_clock_value(self._cc1(123))
+        notif2.add_clock_value(self._cc2(19487))
+        self.assertEqual(notif, notif2)
+
+    def test_ne_cc_prio_map(self):
+        notif = bt2.InactivityNotification(self._cc_prio_map)
+        notif.add_clock_value(self._cc1(123))
+        notif.add_clock_value(self._cc2(19487))
+        cc_prio_map_copy = copy.copy(self._cc_prio_map)
+        cc_prio_map_copy[self._cc2] = 23
+        notif2 = bt2.InactivityNotification(cc_prio_map_copy)
+        self.assertNotEqual(notif, notif2)
+
+    def test_ne_clock_value(self):
+        notif = bt2.InactivityNotification(self._cc_prio_map)
+        notif.add_clock_value(self._cc1(123))
+        notif.add_clock_value(self._cc2(19487))
+        notif2 = bt2.InactivityNotification(self._cc_prio_map)
+        notif.add_clock_value(self._cc1(123))
+        notif.add_clock_value(self._cc2(1847))
+        self.assertNotEqual(notif, notif2)
+
+    def test_eq_invalid(self):
+        notif = bt2.InactivityNotification(self._cc_prio_map)
+        self.assertNotEqual(notif, 23)
+
+    def test_copy(self):
+        notif = bt2.InactivityNotification(self._cc_prio_map)
+        notif.add_clock_value(self._cc1(123))
+        notif.add_clock_value(self._cc2(19487))
+        notif_copy = copy.copy(notif)
+        self.assertEqual(notif, notif_copy)
+        self.assertNotEqual(notif.addr, notif_copy.addr)
+        self.assertEqual(notif.clock_class_priority_map.addr,
+                         notif_copy.clock_class_priority_map.addr)
+        self.assertEqual(notif_copy.clock_value(self._cc1), 123)
+        self.assertEqual(notif_copy.clock_value(self._cc2), 19487)
+
+    def test_deepcopy(self):
+        notif = bt2.InactivityNotification(self._cc_prio_map)
+        notif.add_clock_value(self._cc1(123))
+        notif.add_clock_value(self._cc2(19487))
+        notif_copy = copy.deepcopy(notif)
+        self.assertEqual(notif, notif_copy)
+        self.assertNotEqual(notif.addr, notif_copy.addr)
+        self.assertNotEqual(notif.clock_class_priority_map.addr,
+                            notif_copy.clock_class_priority_map.addr)
+        self.assertEqual(notif.clock_class_priority_map,
+                         notif_copy.clock_class_priority_map)
+        self.assertNotEqual(list(notif.clock_class_priority_map)[0].addr,
+                            list(notif_copy.clock_class_priority_map)[0].addr)
+        self.assertIsNone(notif_copy.clock_value(self._cc1))
+        self.assertIsNone(notif_copy.clock_value(self._cc2))
+        self.assertEqual(notif_copy.clock_value(list(notif_copy.clock_class_priority_map)[0]), 123)
+        self.assertEqual(notif_copy.clock_value(list(notif_copy.clock_class_priority_map)[1]), 19487)
+
+
+class DiscardedPacketsNotificationTestCase(unittest.TestCase):
+    def setUp(self):
+        self._trace = bt2.Trace()
+        self._sc = bt2.StreamClass()
+        self._ec = bt2.EventClass('salut')
+        self._clock_class = bt2.ClockClass('yo', 1000)
+        self._uint64_int_ft = bt2.IntegerFieldType(64, mapped_clock_class=self._clock_class)
+        self._my_int_ft = bt2.IntegerFieldType(32)
+        self._ec.payload_field_type = bt2.StructureFieldType()
+        self._ec.payload_field_type += collections.OrderedDict([
+            ('my_int', self._my_int_ft),
+        ])
+        self._sc.add_event_class(self._ec)
+        self._sc.packet_context_field_type = bt2.StructureFieldType()
+        self._sc.packet_context_field_type += collections.OrderedDict([
+            ('packet_seq_num', self._my_int_ft),
+            ('timestamp_begin', self._uint64_int_ft),
+            ('timestamp_end', self._uint64_int_ft),
+        ])
+        self._trace.add_clock_class(self._clock_class)
+        self._trace.add_stream_class(self._sc)
+        self._stream = self._sc()
+
+    def tearDown(self):
+        del self._trace
+        del self._sc
+        del self._ec
+        del self._clock_class
+        del self._uint64_int_ft
+        del self._my_int_ft
+        del self._stream
+
+    def _create_event(self, packet):
+        event = self._ec()
+        event.payload_field['my_int'] = 23
+        event.packet = packet
+        return event
+
+    def _get_notif(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __init__(iter_self):
+                packet1 = self._stream.create_packet()
+                packet1.context_field['packet_seq_num'] = 0
+                packet1.context_field['timestamp_begin'] = 3
+                packet1.context_field['timestamp_end'] = 6
+                packet2 = self._stream.create_packet()
+                packet2.context_field['packet_seq_num'] = 5
+                packet2.context_field['timestamp_begin'] = 7
+                packet2.context_field['timestamp_end'] = 10
+                iter_self._ev1 = self._create_event(packet1)
+                iter_self._ev2 = self._create_event(packet2)
+                iter_self._at = 0
+
+            def __next__(self):
+                if self._at == 0:
+                    notif = bt2.EventNotification(self._ev1)
+                elif self._at == 1:
+                    notif = bt2.EventNotification(self._ev2)
+                else:
+                    raise bt2.Stop
+
+                self._at += 1
+                return notif
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(comp_self):
+                nonlocal the_notif
+                notif = next(comp_self._notif_iter)
+
+                if type(notif) is bt2._DiscardedPacketsNotification:
+                    the_notif = notif
+                    raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                self._notif_iter = port.connection.create_notification_iterator()
+
+        the_notif = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        graph.run()
+        return the_notif
+
+    def test_create(self):
+        self.assertIsInstance(self._get_notif(), bt2._DiscardedPacketsNotification)
+
+    def test_count(self):
+        self.assertEqual(self._get_notif().count, 4)
+
+    def test_stream(self):
+        self.assertEqual(self._get_notif().stream.addr, self._stream.addr)
+
+    def test_beginning_clock_value(self):
+        notif = self._get_notif()
+        beginning_clock_value = notif.beginning_clock_value
+        self.assertEqual(beginning_clock_value.clock_class, self._clock_class)
+        self.assertEqual(beginning_clock_value, 6)
+
+    def test_end_clock_value(self):
+        notif = self._get_notif()
+        end_clock_value = notif.end_clock_value
+        self.assertEqual(end_clock_value.clock_class, self._clock_class)
+        self.assertEqual(end_clock_value, 7)
+
+    def test_eq(self):
+        notif1 = self._get_notif()
+        notif2 = self._get_notif()
+        self.assertEqual(notif1, notif2)
+
+    def test_eq_invalid(self):
+        notif1 = self._get_notif()
+        self.assertNotEqual(notif1, 23)
+
+
+class DiscardedEventsNotificationTestCase(unittest.TestCase):
+    def setUp(self):
+        self._trace = bt2.Trace()
+        self._sc = bt2.StreamClass()
+        self._ec = bt2.EventClass('salut')
+        self._clock_class = bt2.ClockClass('yo', 1000)
+        self._uint64_int_ft = bt2.IntegerFieldType(64, mapped_clock_class=self._clock_class)
+        self._my_int_ft = bt2.IntegerFieldType(32)
+        self._ec.payload_field_type = bt2.StructureFieldType()
+        self._ec.payload_field_type += collections.OrderedDict([
+            ('my_int', self._my_int_ft),
+        ])
+        self._sc.add_event_class(self._ec)
+        self._sc.packet_context_field_type = bt2.StructureFieldType()
+        self._sc.packet_context_field_type += collections.OrderedDict([
+            ('events_discarded', self._my_int_ft),
+            ('timestamp_begin', self._uint64_int_ft),
+            ('timestamp_end', self._uint64_int_ft),
+        ])
+        self._trace.add_clock_class(self._clock_class)
+        self._trace.add_stream_class(self._sc)
+        self._stream = self._sc()
+
+    def tearDown(self):
+        del self._trace
+        del self._sc
+        del self._ec
+        del self._clock_class
+        del self._uint64_int_ft
+        del self._my_int_ft
+        del self._stream
+
+    def _create_event(self, packet):
+        event = self._ec()
+        event.payload_field['my_int'] = 23
+        event.packet = packet
+        return event
+
+    def _get_notif(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __init__(iter_self):
+                packet1 = self._stream.create_packet()
+                packet1.context_field['events_discarded'] = 0
+                packet1.context_field['timestamp_begin'] = 3
+                packet1.context_field['timestamp_end'] = 6
+                packet2 = self._stream.create_packet()
+                packet2.context_field['events_discarded'] = 10
+                packet2.context_field['timestamp_begin'] = 7
+                packet2.context_field['timestamp_end'] = 10
+                iter_self._ev1 = self._create_event(packet1)
+                iter_self._ev2 = self._create_event(packet2)
+                iter_self._at = 0
+
+            def __next__(self):
+                if self._at == 0:
+                    notif = bt2.EventNotification(self._ev1)
+                elif self._at == 1:
+                    notif = bt2.EventNotification(self._ev2)
+                else:
+                    raise bt2.Stop
+
+                self._at += 1
+                return notif
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(comp_self):
+                nonlocal the_notif
+                notif = next(comp_self._notif_iter)
+
+                if type(notif) is bt2._DiscardedEventsNotification:
+                    the_notif = notif
+                    raise bt2.Stop
+
+            def _port_connected(self, port, other_port):
+                self._notif_iter = port.connection.create_notification_iterator()
+
+        the_notif = None
+        graph = bt2.Graph()
+        src = graph.add_component(MySource, 'src')
+        sink = graph.add_component(MySink, 'sink')
+        conn = graph.connect_ports(src.output_ports['out'],
+                                   sink.input_ports['in'])
+        graph.run()
+        return the_notif
+
+    def test_create(self):
+        self.assertIsInstance(self._get_notif(), bt2._DiscardedEventsNotification)
+
+    def test_count(self):
+        self.assertEqual(self._get_notif().count, 10)
+
+    def test_stream(self):
+        self.assertEqual(self._get_notif().stream.addr, self._stream.addr)
+
+    def test_beginning_clock_value(self):
+        notif = self._get_notif()
+        beginning_clock_value = notif.beginning_clock_value
+        self.assertEqual(beginning_clock_value.clock_class, self._clock_class)
+        self.assertEqual(beginning_clock_value, 6)
+
+    def test_end_clock_value(self):
+        notif = self._get_notif()
+        end_clock_value = notif.end_clock_value
+        self.assertEqual(end_clock_value.clock_class, self._clock_class)
+        self.assertEqual(end_clock_value, 10)
+
+    def test_eq(self):
+        notif1 = self._get_notif()
+        notif2 = self._get_notif()
+        self.assertEqual(notif1, notif2)
+
+    def test_eq_invalid(self):
+        notif1 = self._get_notif()
+        self.assertNotEqual(notif1, 23)
diff --git a/tests/bindings/python/bt2/test_notification_iterator.py b/tests/bindings/python/bt2/test_notification_iterator.py
new file mode 100644 (file)
index 0000000..04ed79d
--- /dev/null
@@ -0,0 +1,120 @@
+from bt2 import values
+import unittest
+import copy
+import bt2
+
+
+class UserNotificationIteratorTestCase(unittest.TestCase):
+    @staticmethod
+    def _create_graph(src_comp_cls):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                next(self._notif_iter)
+
+            def _port_connected(self, port, other_port):
+                self._notif_iter = port.connection.create_notification_iterator()
+
+        graph = bt2.Graph()
+        src_comp = graph.add_component(src_comp_cls, 'src')
+        sink_comp = graph.add_component(MySink, 'sink')
+        graph.connect_ports(src_comp.output_ports['out'],
+                            sink_comp.input_ports['in'])
+        return graph
+
+    def test_init(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __init__(self):
+                nonlocal initialized
+                initialized = True
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        initialized = False
+        graph = self._create_graph(MySource)
+        self.assertTrue(initialized)
+
+    def test_finalize(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def _finalize(self):
+                nonlocal finalized
+                finalized = True
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        finalized = False
+        graph = self._create_graph(MySource)
+        del graph
+        self.assertTrue(finalized)
+
+    def test_component(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __init__(self):
+                nonlocal salut
+                salut = self._component._salut
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+                self._salut = 23
+
+        salut = None
+        graph = self._create_graph(MySource)
+        self.assertEqual(salut, 23)
+
+    def test_addr(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __init__(self):
+                nonlocal addr
+                addr = self.addr
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        addr = None
+        graph = self._create_graph(MySource)
+        self.assertIsNotNone(addr)
+        self.assertNotEqual(addr, 0)
+
+
+class GenericNotificationIteratorTestCase(unittest.TestCase):
+    def test_component(self):
+        class MyIter(bt2._UserNotificationIterator):
+            pass
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(self, params):
+                self._add_output_port('out')
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(self, params):
+                self._add_input_port('in')
+
+            def _consume(self):
+                next(self._notif_iter)
+
+            def _port_connected(self, port, other_port):
+                nonlocal upstream_comp
+                self._notif_iter = port.connection.create_notification_iterator()
+                upstream_comp = self._notif_iter.component
+
+        upstream_comp = None
+        graph = bt2.Graph()
+        src_comp = graph.add_component(MySource, 'src')
+        sink_comp = graph.add_component(MySink, 'sink')
+        graph.connect_ports(src_comp.output_ports['out'],
+                            sink_comp.input_ports['in'])
+        self.assertEqual(src_comp, upstream_comp)
+        del upstream_comp
index 3ee58a15ac0d5ba9b0dddd665bc436fe8b48d695..51391cfb16ca0bda3e3986df2a5508b1f85c2070 100644 (file)
@@ -9,6 +9,9 @@ class PacketTestCase(unittest.TestCase):
     def setUp(self):
         self._packet = self._create_packet()
 
+    def tearDown(self):
+        del self._packet
+
     def _create_packet(self, with_ph=True, with_pc=True):
         # event header
         eh = bt2.StructureFieldType()
diff --git a/tests/bindings/python/bt2/test_plugin.py b/tests/bindings/python/bt2/test_plugin.py
new file mode 100644 (file)
index 0000000..6e461f3
--- /dev/null
@@ -0,0 +1,104 @@
+from bt2 import values
+import unittest
+import copy
+import bt2
+import bt2.plugin
+import os
+
+
+_TEST_PLUGIN_PLUGINS_PATH = os.environ['TEST_PLUGIN_PLUGINS_PATH']
+
+
+class PluginSetTestCase(unittest.TestCase):
+    def test_create(self):
+        pset = bt2.find_plugins(_TEST_PLUGIN_PLUGINS_PATH)
+        self.assertTrue(len(pset) >= 3)
+
+    def test_getitem(self):
+        pset = bt2.find_plugins(_TEST_PLUGIN_PLUGINS_PATH)
+        self.assertTrue(pset[0].path.startswith(_TEST_PLUGIN_PLUGINS_PATH))
+
+    def test_iter(self):
+        pset = bt2.find_plugins(_TEST_PLUGIN_PLUGINS_PATH)
+        names = set()
+
+        for plugin in pset:
+            names.add(plugin.name)
+
+        self.assertTrue('ctf' in names)
+        self.assertTrue('utils' in names)
+        self.assertTrue('text' in names)
+
+
+class FindPluginsTestCase(unittest.TestCase):
+    def test_find_none(self):
+        pset = bt2.find_plugins('/this/does/not/exist/246703df-cb85-46d5-8406-5e8dc4a88b41')
+        self.assertIsNone(pset)
+
+    def test_find_dir(self):
+        pset = bt2.find_plugins(_TEST_PLUGIN_PLUGINS_PATH)
+        self.assertTrue(len(pset) >= 3)
+
+
+class FindPluginTestCase(unittest.TestCase):
+    def test_find_none(self):
+        plugin = bt2.find_plugin('this-does-not-exist-246703df-cb85-46d5-8406-5e8dc4a88b41')
+        self.assertIsNone(plugin)
+
+    def test_find_existing(self):
+        plugin = bt2.find_plugin('ctf')
+        self.assertIsInstance(plugin, bt2.plugin._Plugin)
+
+
+class PluginTestCase(unittest.TestCase):
+    def setUp(self):
+        self._plugin = bt2.find_plugin('ctf')
+
+    def tearDown(self):
+        del self._plugin
+
+    def test_name(self):
+        self.assertEqual(self._plugin.name, 'ctf')
+
+    def test_path(self):
+        self.assertTrue(self._plugin.path.startswith(_TEST_PLUGIN_PLUGINS_PATH))
+
+    def test_author(self):
+        self.assertTrue('Philippe Proulx' in self._plugin.author)
+
+    def test_license(self):
+        self.assertTrue('MIT' in self._plugin.license)
+
+    def test_description(self):
+        self.assertTrue('CTF source and sink support' in self._plugin.description)
+
+    def test_version(self):
+        self.assertIsNone(self._plugin.version)
+
+    def test_source_comp_classes_len(self):
+        self.assertEqual(len(self._plugin.source_component_classes), 2)
+
+    def test_source_comp_classes_getitem(self):
+        self.assertEqual(self._plugin.source_component_classes['fs'].name, 'fs')
+
+    def test_source_comp_classes_getitem_invalid(self):
+        with self.assertRaises(KeyError):
+            self._plugin.source_component_classes['lol']
+
+    def test_source_comp_classes_iter(self):
+        plugins = {}
+
+        for cc_name, cc in self._plugin.source_component_classes.items():
+            plugins[cc_name] = cc
+
+        self.assertTrue('fs' in plugins)
+        self.assertTrue('lttng-live' in plugins)
+        self.assertEqual(plugins['fs'].name, 'fs')
+        self.assertEqual(plugins['lttng-live'].name, 'lttng-live')
+
+    def test_filter_comp_classes_len(self):
+        plugin = bt2.find_plugin('utils')
+        self.assertEqual(len(plugin.filter_component_classes), 2)
+
+    def test_sink_comp_classes_len(self):
+        self.assertEqual(len(self._plugin.sink_component_classes), 1)
diff --git a/tests/bindings/python/bt2/test_port.py b/tests/bindings/python/bt2/test_port.py
new file mode 100644 (file)
index 0000000..592a5b6
--- /dev/null
@@ -0,0 +1,888 @@
+from bt2 import values
+import unittest
+import copy
+import bt2
+
+
+class PortTestCase(unittest.TestCase):
+    @staticmethod
+    def _create_comp(comp_cls, name=None):
+        graph = bt2.Graph()
+
+        if name is None:
+            name = 'comp'
+
+        return graph.add_component(comp_cls, name)
+
+    def test_src_add_output_port(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port = comp_self._add_output_port('out')
+                self.assertEqual(port.name, 'out')
+
+        comp = self._create_comp(MySource)
+        self.assertEqual(len(comp.output_ports), 1)
+
+
+    def test_flt_add_output_port(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port = comp_self._add_output_port('out')
+                self.assertEqual(port.name, 'out')
+
+        comp = self._create_comp(MyFilter)
+        self.assertEqual(len(comp.output_ports), 1)
+
+    def test_flt_add_input_port(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('in')
+                self.assertEqual(port.name, 'in')
+
+        comp = self._create_comp(MyFilter)
+        self.assertEqual(len(comp.input_ports), 1)
+
+    def test_sink_add_input_port(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('in')
+                self.assertEqual(port.name, 'in')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertEqual(len(comp.input_ports), 1)
+
+    def test_user_src_output_ports_getitem(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port1 = comp_self._add_output_port('clear')
+                port2 = comp_self._add_output_port('print')
+                port3 = comp_self._add_output_port('insert')
+                self.assertEqual(port3.addr, comp_self._output_ports['insert'].addr)
+                self.assertEqual(port2.addr, comp_self._output_ports['print'].addr)
+                self.assertEqual(port1.addr, comp_self._output_ports['clear'].addr)
+
+        comp = self._create_comp(MySource)
+
+    def test_user_flt_output_ports_getitem(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port1 = comp_self._add_output_port('clear')
+                port2 = comp_self._add_output_port('print')
+                port3 = comp_self._add_output_port('insert')
+                self.assertEqual(port3.addr, comp_self._output_ports['insert'].addr)
+                self.assertEqual(port2.addr, comp_self._output_ports['print'].addr)
+                self.assertEqual(port1.addr, comp_self._output_ports['clear'].addr)
+
+        comp = self._create_comp(MyFilter)
+
+    def test_user_flt_input_ports_getitem(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port1 = comp_self._add_input_port('clear')
+                port2 = comp_self._add_input_port('print')
+                port3 = comp_self._add_input_port('insert')
+                self.assertEqual(port3.addr, comp_self._input_ports['insert'].addr)
+                self.assertEqual(port2.addr, comp_self._input_ports['print'].addr)
+                self.assertEqual(port1.addr, comp_self._input_ports['clear'].addr)
+
+        comp = self._create_comp(MyFilter)
+
+    def test_user_sink_input_ports_getitem(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port1 = comp_self._add_input_port('clear')
+                port2 = comp_self._add_input_port('print')
+                port3 = comp_self._add_input_port('insert')
+                self.assertEqual(port3.addr, comp_self._input_ports['insert'].addr)
+                self.assertEqual(port2.addr, comp_self._input_ports['print'].addr)
+                self.assertEqual(port1.addr, comp_self._input_ports['clear'].addr)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_user_src_output_ports_getitem_invalid_key(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_output_port('clear')
+                comp_self._add_output_port('print')
+                comp_self._add_output_port('insert')
+
+                with self.assertRaises(KeyError):
+                    comp_self._output_ports['hello']
+
+        comp = self._create_comp(MySource)
+
+    def test_user_flt_output_ports_getitem_invalid_key(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_output_port('clear')
+                comp_self._add_output_port('print')
+                comp_self._add_output_port('insert')
+
+                with self.assertRaises(KeyError):
+                    comp_self._output_ports['hello']
+
+        comp = self._create_comp(MyFilter)
+
+    def test_user_flt_input_ports_getitem_invalid_key(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+                comp_self._add_input_port('print')
+                comp_self._add_input_port('insert')
+
+                with self.assertRaises(KeyError):
+                    comp_self._input_ports['hello']
+
+        comp = self._create_comp(MyFilter)
+
+    def test_user_sink_input_ports_getitem_invalid_key(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+                comp_self._add_input_port('print')
+                comp_self._add_input_port('insert')
+
+                with self.assertRaises(KeyError):
+                    comp_self._input_ports['hello']
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_user_src_output_ports_len(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_output_port('clear')
+                comp_self._add_output_port('print')
+                comp_self._add_output_port('insert')
+                self.assertEqual(len(comp_self._output_ports), 3)
+
+        comp = self._create_comp(MySource)
+
+    def test_user_flt_output_ports_len(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_output_port('clear')
+                comp_self._add_output_port('print')
+                comp_self._add_output_port('insert')
+                self.assertEqual(len(comp_self._output_ports), 3)
+
+        comp = self._create_comp(MyFilter)
+
+    def test_user_flt_input_ports_len(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+                comp_self._add_input_port('print')
+                comp_self._add_input_port('insert')
+                self.assertEqual(len(comp_self._input_ports), 3)
+
+        comp = self._create_comp(MyFilter)
+
+    def test_user_sink_input_ports_len(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+                comp_self._add_input_port('print')
+                comp_self._add_input_port('insert')
+                self.assertEqual(len(comp_self._input_ports), 3)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_user_src_output_ports_iter(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port1 = comp_self._add_output_port('clear')
+                port2 = comp_self._add_output_port('print')
+                port3 = comp_self._add_output_port('insert')
+                ports = []
+
+                for port_name, port in comp_self._output_ports.items():
+                    ports.append((port_name, port))
+
+                self.assertEqual(ports[0][0], 'clear')
+                self.assertEqual(ports[0][1].addr, port1.addr)
+                self.assertEqual(ports[1][0], 'print')
+                self.assertEqual(ports[1][1].addr, port2.addr)
+                self.assertEqual(ports[2][0], 'insert')
+                self.assertEqual(ports[2][1].addr, port3.addr)
+
+        comp = self._create_comp(MySource)
+
+    def test_user_flt_output_ports_iter(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port1 = comp_self._add_output_port('clear')
+                port2 = comp_self._add_output_port('print')
+                port3 = comp_self._add_output_port('insert')
+                ports = []
+
+                for port_name, port in comp_self._output_ports.items():
+                    ports.append((port_name, port))
+
+                self.assertEqual(ports[0][0], 'clear')
+                self.assertEqual(ports[0][1].addr, port1.addr)
+                self.assertEqual(ports[1][0], 'print')
+                self.assertEqual(ports[1][1].addr, port2.addr)
+                self.assertEqual(ports[2][0], 'insert')
+                self.assertEqual(ports[2][1].addr, port3.addr)
+
+        comp = self._create_comp(MyFilter)
+
+    def test_user_flt_input_ports_iter(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                port1 = comp_self._add_input_port('clear')
+                port2 = comp_self._add_input_port('print')
+                port3 = comp_self._add_input_port('insert')
+                ports = []
+
+                for port_name, port in comp_self._input_ports.items():
+                    ports.append((port_name, port))
+
+                self.assertEqual(ports[0][0], 'clear')
+                self.assertEqual(ports[0][1].addr, port1.addr)
+                self.assertEqual(ports[1][0], 'print')
+                self.assertEqual(ports[1][1].addr, port2.addr)
+                self.assertEqual(ports[2][0], 'insert')
+                self.assertEqual(ports[2][1].addr, port3.addr)
+
+        comp = self._create_comp(MyFilter)
+
+    def test_user_sink_input_ports_iter(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port1 = comp_self._add_input_port('clear')
+                port2 = comp_self._add_input_port('print')
+                port3 = comp_self._add_input_port('insert')
+                ports = []
+
+                for port_name, port in comp_self._input_ports.items():
+                    ports.append((port_name, port))
+
+                self.assertEqual(ports[0][0], 'clear')
+                self.assertEqual(ports[0][1].addr, port1.addr)
+                self.assertEqual(ports[1][0], 'print')
+                self.assertEqual(ports[1][1].addr, port2.addr)
+                self.assertEqual(ports[2][0], 'insert')
+                self.assertEqual(ports[2][1].addr, port3.addr)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_gen_src_output_ports_getitem(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        port1 = None
+        port2 = None
+        port3 = None
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                nonlocal port1, port2, port3
+                port1 = comp_self._add_output_port('clear')
+                port2 = comp_self._add_output_port('print')
+                port3 = comp_self._add_output_port('insert')
+
+        comp = self._create_comp(MySource)
+        self.assertEqual(port3.addr, comp.output_ports['insert'].addr)
+        self.assertEqual(port2.addr, comp.output_ports['print'].addr)
+        self.assertEqual(port1.addr, comp.output_ports['clear'].addr)
+        del port1
+        del port2
+        del port3
+
+    def test_gen_flt_output_ports_getitem(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        port1 = None
+        port2 = None
+        port3 = None
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                nonlocal port1, port2, port3
+                port1 = comp_self._add_output_port('clear')
+                port2 = comp_self._add_output_port('print')
+                port3 = comp_self._add_output_port('insert')
+
+        comp = self._create_comp(MyFilter)
+        self.assertEqual(port3.addr, comp.output_ports['insert'].addr)
+        self.assertEqual(port2.addr, comp.output_ports['print'].addr)
+        self.assertEqual(port1.addr, comp.output_ports['clear'].addr)
+        del port1
+        del port2
+        del port3
+
+    def test_gen_flt_input_ports_getitem(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        port1 = None
+        port2 = None
+        port3 = None
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                nonlocal port1, port2, port3
+                port1 = comp_self._add_input_port('clear')
+                port2 = comp_self._add_input_port('print')
+                port3 = comp_self._add_input_port('insert')
+
+        comp = self._create_comp(MyFilter)
+        self.assertEqual(port3.addr, comp.input_ports['insert'].addr)
+        self.assertEqual(port2.addr, comp.input_ports['print'].addr)
+        self.assertEqual(port1.addr, comp.input_ports['clear'].addr)
+        del port1
+        del port2
+        del port3
+
+    def test_gen_sink_input_ports_getitem(self):
+        port1 = None
+        port2 = None
+        port3 = None
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                nonlocal port1, port2, port3
+                port1 = comp_self._add_input_port('clear')
+                port2 = comp_self._add_input_port('print')
+                port3 = comp_self._add_input_port('insert')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertEqual(port3.addr, comp.input_ports['insert'].addr)
+        self.assertEqual(port2.addr, comp.input_ports['print'].addr)
+        self.assertEqual(port1.addr, comp.input_ports['clear'].addr)
+        del port1
+        del port2
+        del port3
+
+    def test_gen_src_output_ports_getitem_invalid_key(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_output_port('clear')
+                comp_self._add_output_port('print')
+                comp_self._add_output_port('insert')
+
+        comp = self._create_comp(MySource)
+
+        with self.assertRaises(KeyError):
+            comp.output_ports['hello']
+
+    def test_gen_flt_output_ports_getitem_invalid_key(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_output_port('clear')
+                comp_self._add_output_port('print')
+                comp_self._add_output_port('insert')
+
+        comp = self._create_comp(MyFilter)
+
+        with self.assertRaises(KeyError):
+            comp.output_ports['hello']
+
+    def test_gen_flt_input_ports_getitem_invalid_key(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+                comp_self._add_input_port('print')
+                comp_self._add_input_port('insert')
+
+        comp = self._create_comp(MyFilter)
+
+        with self.assertRaises(KeyError):
+            comp.input_ports['hello']
+
+    def test_gen_sink_input_ports_getitem_invalid_key(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+                comp_self._add_input_port('print')
+                comp_self._add_input_port('insert')
+
+                with self.assertRaises(KeyError):
+                    comp_self._input_ports['hello']
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+        with self.assertRaises(KeyError):
+            comp.input_ports['hello']
+
+    def test_gen_src_output_ports_len(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_output_port('clear')
+                comp_self._add_output_port('print')
+                comp_self._add_output_port('insert')
+
+        comp = self._create_comp(MySource)
+        self.assertEqual(len(comp.output_ports), 3)
+
+    def test_gen_flt_output_ports_len(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_output_port('clear')
+                comp_self._add_output_port('print')
+                comp_self._add_output_port('insert')
+
+        comp = self._create_comp(MyFilter)
+        self.assertEqual(len(comp.output_ports), 3)
+
+    def test_gen_flt_input_ports_len(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+                comp_self._add_input_port('print')
+                comp_self._add_input_port('insert')
+
+        comp = self._create_comp(MyFilter)
+        self.assertEqual(len(comp.input_ports), 3)
+
+    def test_gen_sink_input_ports_len(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+                comp_self._add_input_port('print')
+                comp_self._add_input_port('insert')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertEqual(len(comp.input_ports), 3)
+
+    def test_gen_src_output_ports_iter(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        port1 = None
+        port2 = None
+        port3 = None
+
+        class MySource(bt2._UserSourceComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                nonlocal port1, port2, port3
+                port1 = comp_self._add_output_port('clear')
+                port2 = comp_self._add_output_port('print')
+                port3 = comp_self._add_output_port('insert')
+
+        comp = self._create_comp(MySource)
+        ports = []
+
+        for port_name, port in comp.output_ports.items():
+            ports.append((port_name, port))
+
+        self.assertEqual(ports[0][0], 'clear')
+        self.assertEqual(ports[0][1].addr, port1.addr)
+        self.assertEqual(ports[1][0], 'print')
+        self.assertEqual(ports[1][1].addr, port2.addr)
+        self.assertEqual(ports[2][0], 'insert')
+        self.assertEqual(ports[2][1].addr, port3.addr)
+        del port1
+        del port2
+        del port3
+
+    def test_gen_flt_output_ports_iter(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        port1 = None
+        port2 = None
+        port3 = None
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                nonlocal port1, port2, port3
+                port1 = comp_self._add_output_port('clear')
+                port2 = comp_self._add_output_port('print')
+                port3 = comp_self._add_output_port('insert')
+
+        comp = self._create_comp(MyFilter)
+        ports = []
+
+        for port_name, port in comp.output_ports.items():
+            ports.append((port_name, port))
+
+        self.assertEqual(ports[0][0], 'clear')
+        self.assertEqual(ports[0][1].addr, port1.addr)
+        self.assertEqual(ports[1][0], 'print')
+        self.assertEqual(ports[1][1].addr, port2.addr)
+        self.assertEqual(ports[2][0], 'insert')
+        self.assertEqual(ports[2][1].addr, port3.addr)
+        del port1
+        del port2
+        del port3
+
+    def test_gen_flt_input_ports_iter(self):
+        class MyIter(bt2._UserNotificationIterator):
+            def __next__(self):
+                raise bt2.Stop
+
+        port1 = None
+        port2 = None
+        port3 = None
+
+        class MyFilter(bt2._UserFilterComponent,
+                       notification_iterator_class=MyIter):
+            def __init__(comp_self, params):
+                nonlocal port1, port2, port3
+                port1 = comp_self._add_input_port('clear')
+                port2 = comp_self._add_input_port('print')
+                port3 = comp_self._add_input_port('insert')
+
+        comp = self._create_comp(MyFilter)
+        ports = []
+
+        for port_name, port in comp.input_ports.items():
+            ports.append((port_name, port))
+
+        self.assertEqual(ports[0][0], 'clear')
+        self.assertEqual(ports[0][1].addr, port1.addr)
+        self.assertEqual(ports[1][0], 'print')
+        self.assertEqual(ports[1][1].addr, port2.addr)
+        self.assertEqual(ports[2][0], 'insert')
+        self.assertEqual(ports[2][1].addr, port3.addr)
+        del port1
+        del port2
+        del port3
+
+    def test_gen_sink_input_ports_iter(self):
+        port1 = None
+        port2 = None
+        port3 = None
+
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                nonlocal port1, port2, port3
+                port1 = comp_self._add_input_port('clear')
+                port2 = comp_self._add_input_port('print')
+                port3 = comp_self._add_input_port('insert')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        ports = []
+
+        for port_name, port in comp.input_ports.items():
+            ports.append((port_name, port))
+
+        self.assertEqual(ports[0][0], 'clear')
+        self.assertEqual(ports[0][1].addr, port1.addr)
+        self.assertEqual(ports[1][0], 'print')
+        self.assertEqual(ports[1][1].addr, port2.addr)
+        self.assertEqual(ports[2][0], 'insert')
+        self.assertEqual(ports[2][1].addr, port3.addr)
+        del port1
+        del port2
+        del port3
+
+    def test_name(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertEqual(comp.input_ports['clear'].name, 'clear')
+
+    def test_component(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertEqual(comp.input_ports['clear'].component.addr, comp.addr)
+
+    def test_connection_none(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertIsNone(comp.input_ports['clear'].connection)
+
+    def test_is_connected_false(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertFalse(comp.input_ports['clear'].is_connected)
+
+    def test_eq(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertEqual(comp.input_ports['clear'],
+                         comp.input_ports['clear'])
+
+    def test_eq_invalid(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                comp_self._add_input_port('clear')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        self.assertNotEqual(comp.input_ports['clear'], 23)
+
+    def test_disconnect_no_connection(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+        comp.input_ports['clear'].disconnect()
+
+    def test_priv_name(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+                self.assertEqual(port.name, 'clear')
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_priv_component(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+                self.assertEqual(port.component, comp_self)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_priv_connection_none(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+                self.assertIsNone(port.connection)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_priv_is_connected_false(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+                self.assertFalse(port.is_connected)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_priv_eq(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+                self.assertEqual(port, port)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_priv_eq_invalid(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+                self.assertNotEqual(port, 23)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_priv_disconnect_no_connection(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+                port.disconnect()
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
+
+    def test_priv_remove_from_component(self):
+        class MySink(bt2._UserSinkComponent):
+            def __init__(comp_self, params):
+                port = comp_self._add_input_port('clear')
+                self.assertEqual(len(comp_self._input_ports), 1)
+
+                try:
+                    port.remove_from_component()
+                except:
+                    import traceback
+                    traceback.print_exc()
+
+                self.assertEqual(len(comp_self._input_ports), 0)
+                self.assertIsNone(port.component)
+
+            def _consume(self):
+                pass
+
+        comp = self._create_comp(MySink)
index afeb80fbe0c71d5e3fc277d778c0398d53abfe50..7accbcdd65a335acf5a7f1df1af5be66a13c9545 100644 (file)
@@ -7,9 +7,12 @@ import bt2
 
 class StreamTestCase(unittest.TestCase):
     def setUp(self):
-        self._stream = self._create_stream()
+        self._stream = self._create_stream(stream_id=23)
 
-    def _create_stream(self, name='my_stream'):
+    def tearDown(self):
+        del self._stream
+
+    def _create_stream(self, name='my_stream', stream_id=None):
         # event header
         eh = bt2.StructureFieldType()
         eh += OrderedDict((
@@ -71,7 +74,7 @@ class StreamTestCase(unittest.TestCase):
         tc.add_stream_class(sc)
 
         # stream
-        return sc(name=name)
+        return sc(name=name, id=stream_id)
 
     def test_attr_stream_class(self):
         self.assertIsNotNone(self._stream.stream_class)
@@ -80,13 +83,18 @@ class StreamTestCase(unittest.TestCase):
         self.assertEqual(self._stream.name, 'my_stream')
 
     def test_eq(self):
-        stream1 = self._create_stream()
-        stream2 = self._create_stream()
+        stream1 = self._create_stream(stream_id=17)
+        stream2 = self._create_stream(stream_id=17)
         self.assertEqual(stream1, stream2)
 
     def test_ne_name(self):
-        stream1 = self._create_stream()
-        stream2 = self._create_stream('lel')
+        stream1 = self._create_stream(stream_id=17)
+        stream2 = self._create_stream('lel', 17)
+        self.assertNotEqual(stream1, stream2)
+
+    def test_ne_id(self):
+        stream1 = self._create_stream(stream_id=17)
+        stream2 = self._create_stream(stream_id=23)
         self.assertNotEqual(stream1, stream2)
 
     def test_eq_invalid(self):
index 84bf286ac5dc21560dcf6891f2d2bad2aee74d86..ae005778b9d525a32b8190a5538cabd283d5fac2 100644 (file)
@@ -20,6 +20,13 @@ class StreamClassTestCase(unittest.TestCase):
                                    event_context_field_type=self._event_context_ft,
                                    event_classes=(self._ec1, self._ec2))
 
+    def tearDown(self):
+        del self._packet_context_ft
+        del self._event_header_ft
+        del self._event_context_ft
+        del self._ec1
+        del self._sc
+
     def _create_event_classes(self):
         context_ft = bt2.StructureFieldType()
         context_ft.append_field('allo', bt2.StringFieldType())
@@ -38,8 +45,9 @@ class StreamClassTestCase(unittest.TestCase):
         self.assertEqual(self._sc.packet_context_field_type, self._packet_context_ft)
         self.assertEqual(self._sc.event_header_field_type, self._event_header_ft)
         self.assertEqual(self._sc.event_context_field_type, self._event_context_ft)
-        self.assertEqual(self._sc['event23'], self._ec1)
-        self.assertEqual(self._sc['event17'], self._ec2)
+        self.assertEqual(self._sc[23], self._ec1)
+        self.assertEqual(self._sc[17], self._ec2)
+        self.assertEqual(len(self._sc), 2)
 
     def test_assign_name(self):
         self._sc.name = 'lel'
@@ -57,6 +65,10 @@ class StreamClassTestCase(unittest.TestCase):
         with self.assertRaises(TypeError):
             self._sc.id = 'lel'
 
+    def test_no_id(self):
+        sc = bt2.StreamClass()
+        self.assertIsNone(sc.id)
+
     def test_assign_packet_context_field_type(self):
         self._sc.packet_context_field_type = self._event_context_ft
         self.assertEqual(self._sc.packet_context_field_type, self._event_context_ft)
@@ -121,36 +133,29 @@ class StreamClassTestCase(unittest.TestCase):
         self.assertNotEqual(self._sc.event_context_field_type.addr, cpy.event_context_field_type.addr)
 
     def test_getitem(self):
-        self.assertEqual(self._sc['event23'], self._ec1)
-        self.assertEqual(self._sc['event17'], self._ec2)
+        self.assertEqual(self._sc[23], self._ec1)
+        self.assertEqual(self._sc[17], self._ec2)
 
     def test_getitem_wrong_key_type(self):
         with self.assertRaises(TypeError):
-            self._sc[23]
+            self._sc['event23']
 
     def test_getitem_wrong_key(self):
         with self.assertRaises(KeyError):
-            self._sc['hello']
+            self._sc[19]
 
     def test_len(self):
         self.assertEqual(len(self._sc), 2)
 
     def test_iter(self):
-        for name, event_class in self._sc.items():
+        for ec_id, event_class in self._sc.items():
             self.assertIsInstance(event_class, bt2.EventClass)
 
-            if name == 'event23':
+            if ec_id == 23:
                 self.assertEqual(event_class, self._ec1)
-            elif name == 'event17':
+            elif ec_id == 17:
                 self.assertEqual(event_class, self._ec2)
 
-    def test_event_class_with_id(self):
-        self.assertEqual(self._sc.event_class_with_id(23), self._ec1)
-
-    def test_event_class_with_id_wrong_type(self):
-        with self.assertRaises(TypeError):
-            self._sc.event_class_with_id('yes')
-
     def test_eq(self):
         ec1, ec2 = self._create_event_classes()
         sc1 = bt2.StreamClass(name='my_stream_class', id=12,
index b6979a4381ad20d3b6624062dc4b2af111353575..b2b9cdad103d98462628882bb62c502f3ad74774 100644 (file)
@@ -10,6 +10,10 @@ class TraceTestCase(unittest.TestCase):
         self._sc = self._create_stream_class('sc1', 3)
         self._tc = bt2.Trace()
 
+    def tearDown(self):
+        del self._sc
+        del self._tc
+
     def _create_stream_class(self, name, id):
         ec1, ec2 = self._create_event_classes()
         packet_context_ft = bt2.StructureFieldType()
@@ -40,22 +44,26 @@ class TraceTestCase(unittest.TestCase):
     def test_create_default(self):
         self.assertEqual(len(self._tc), 0)
 
-    def test_create_full(self):
+    def _get_std_header(self):
         header_ft = bt2.StructureFieldType()
         header_ft.append_field('magic', bt2.IntegerFieldType(32))
-        clock_classes = bt2.ClockClass('cc1'), bt2.ClockClass('cc2')
+        header_ft.append_field('stream_id', bt2.IntegerFieldType(32))
+        return header_ft
+
+    def test_create_full(self):
+        clock_classes = bt2.ClockClass('cc1', 1000), bt2.ClockClass('cc2', 30)
         sc = self._create_stream_class('sc1', 3)
         tc = bt2.Trace(name='my name',
                        native_byte_order=bt2.ByteOrder.LITTLE_ENDIAN,
                        env={'the_string': 'value', 'the_int': 23},
-                       packet_header_field_type=header_ft,
+                       packet_header_field_type=self._get_std_header(),
                        clock_classes=clock_classes,
                        stream_classes=(sc,))
         self.assertEqual(tc.name, 'my name')
         self.assertEqual(tc.native_byte_order, bt2.ByteOrder.LITTLE_ENDIAN)
         self.assertEqual(tc.env['the_string'], 'value')
         self.assertEqual(tc.env['the_int'], 23)
-        self.assertEqual(tc.packet_header_field_type, header_ft)
+        self.assertEqual(tc.packet_header_field_type, self._get_std_header())
         self.assertEqual(tc.clock_classes['cc1'], clock_classes[0])
         self.assertEqual(tc.clock_classes['cc2'], clock_classes[1])
         self.assertEqual(tc[3], sc)
@@ -68,6 +76,10 @@ class TraceTestCase(unittest.TestCase):
         with self.assertRaises(TypeError):
             self._tc.name = 17
 
+    def test_assign_static(self):
+        self._tc.set_is_static()
+        self.assertTrue(self._tc.is_static)
+
     def test_assign_native_byte_order(self):
         self._tc.native_byte_order = bt2.ByteOrder.BIG_ENDIAN
         self.assertEqual(self._tc.native_byte_order, bt2.ByteOrder.BIG_ENDIAN)
@@ -93,12 +105,13 @@ class TraceTestCase(unittest.TestCase):
         self.assertEqual(len(self._tc), len(cpy))
 
     def _pre_copy(self):
+        self._tc.packet_header_field_type = self._get_std_header()
         self._tc.name = 'the trace class'
         sc1 = self._create_stream_class('sc1', 3)
         sc2 = self._create_stream_class('sc2', 9)
         sc3 = self._create_stream_class('sc3', 17)
-        self._tc.add_clock_class(bt2.ClockClass('cc1'))
-        self._tc.add_clock_class(bt2.ClockClass('cc2'))
+        self._tc.add_clock_class(bt2.ClockClass('cc1', 1000))
+        self._tc.add_clock_class(bt2.ClockClass('cc2', 30))
         self._tc.env['allo'] = 'bateau'
         self._tc.env['bateau'] = 'cart'
         self._tc.add_stream_class(sc1)
@@ -145,6 +158,7 @@ class TraceTestCase(unittest.TestCase):
         self.assertEqual(len(self._tc), 1)
 
     def test_iter(self):
+        self._tc.packet_header_field_type = self._get_std_header()
         sc1 = self._create_stream_class('sc1', 3)
         sc2 = self._create_stream_class('sc2', 9)
         sc3 = self._create_stream_class('sc3', 17)
@@ -170,16 +184,37 @@ class TraceTestCase(unittest.TestCase):
         with self.assertRaises(KeyError):
             self._tc.clock_classes['lel']
 
+    def test_streams_none(self):
+        self.assertEqual(len(self._tc.streams), 0)
+
+    def test_streams_len(self):
+        self._tc.add_stream_class(self._create_stream_class('sc1', 3))
+        stream0 = self._tc[3]()
+        stream1 = self._tc[3]()
+        stream2 = self._tc[3]()
+        self.assertEqual(len(self._tc.streams), 3)
+
+    def test_streams_iter(self):
+        self._tc.add_stream_class(self._create_stream_class('sc1', 3))
+        stream0 = self._tc[3](id=12)
+        stream1 = self._tc[3](id=15)
+        stream2 = self._tc[3](id=17)
+        sids = set()
+
+        for stream in self._tc.streams:
+            sids.add(stream.id)
+
+        self.assertEqual(len(sids), 3)
+        self.assertTrue(12 in sids and 15 in sids and 17 in sids)
+
     def _test_eq_create_objects(self):
         cc1_uuid = uuid.UUID('bc7f2f2d-2ee4-4e03-ab1f-2e0e1304e94f')
-        cc1 = bt2.ClockClass('cc1', uuid=cc1_uuid)
+        cc1 = bt2.ClockClass('cc1', 1000, uuid=cc1_uuid)
         cc2_uuid = uuid.UUID('da7d6b6f-3108-4706-89bd-ab554732611b')
-        cc2 = bt2.ClockClass('cc2', uuid=cc2_uuid)
+        cc2 = bt2.ClockClass('cc2', 30, uuid=cc2_uuid)
         sc1 = self._create_stream_class('sc1', 3)
         sc2 = self._create_stream_class('sc2', 9)
-        header_ft = bt2.StructureFieldType()
-        header_ft.append_field('magic', bt2.IntegerFieldType(32))
-        return cc1, cc2, sc1, sc2, header_ft
+        return cc1, cc2, sc1, sc2, self._get_std_header()
 
     def test_eq(self):
         cc1, cc2, sc1, sc2, header_ft = self._test_eq_create_objects()
index f97af21af25d8e1eb6911ed4f7aee14247e860e8..57fd682b077220aca7836c3b97fc628c606ee64e 100644 (file)
@@ -19,7 +19,7 @@ class _TestFrozen:
     def test_frozen_exc(self):
         self._def.freeze()
 
-        with self.assertRaisesRegex(bt2.FrozenError, r'.* value object is frozen$') as cm:
+        with self.assertRaisesRegex(bt2.Frozen, r'.* value object is frozen$') as cm:
             self._modify_def()
 
         self.assertEqual(self._def, self._def_value)
@@ -833,6 +833,11 @@ class BoolValueTestCase(_TestFrozenSimple, _TestCopySimple, unittest.TestCase):
         self._def_value = False
         self._def_new_value = True
 
+    def tearDown(self):
+        del self._f
+        del self._t
+        del self._def
+
     def _assert_expecting_bool(self):
         return self.assertRaisesRegex(TypeError, r"expecting a 'bool' object")
 
@@ -926,6 +931,12 @@ class IntegerValueTestCase(_TestNumericValue, unittest.TestCase):
         self._def_value = self._pv
         self._def_new_value = -101
 
+    def tearDown(self):
+        del self._ip
+        del self._in
+        del self._def
+        del self._def_value
+
     def _assert_expecting_int(self):
         return self.assertRaisesRegex(TypeError, r'expecting a number object')
 
@@ -1039,6 +1050,12 @@ class FloatValueTestCase(_TestNumericValue, unittest.TestCase):
         self._def_value = self._pv
         self._def_new_value = -101.88
 
+    def tearDown(self):
+        del self._fp
+        del self._fn
+        del self._def
+        del self._def_value
+
     def _assert_expecting_float(self):
         return self.assertRaisesRegex(TypeError, r"expecting a real number object")
 
@@ -1166,6 +1183,9 @@ class StringValueTestCase(_TestCopySimple, _TestFrozenSimple, unittest.TestCase)
         self._def = bt2.StringValue(self._def_value)
         self._def_new_value = 'Yes!'
 
+    def tearDown(self):
+        del self._def
+
     def _assert_expecting_str(self):
         return self.assertRaises(TypeError)
 
@@ -1280,6 +1300,9 @@ class ArrayValueTestCase(_TestFrozen, unittest.TestCase):
         self._def_value = [None, False, True, -23, 0, 42, -42.4, 23.17, 'yes']
         self._def = bt2.ArrayValue(copy.deepcopy(self._def_value))
 
+    def tearDown(self):
+        del self._def
+
     def _modify_def(self):
         self._def[2] = 'xyz'
 
@@ -1442,6 +1465,9 @@ class MapValueTestCase(_TestFrozen, unittest.TestCase):
         }
         self._def = bt2.MapValue(copy.deepcopy(self._def_value))
 
+    def tearDown(self):
+        del self._def
+
     def _modify_def(self):
         self._def['zero'] = 1
 
index 90657537c0d583f23ca5aa2edf2afd12fed902fd..d682e4c8491a44ad21b470eeb2d8042ca285cc6d 100644 (file)
@@ -4,6 +4,9 @@ check_coverage() {
        coverage run $@
 }
 
+export BABELTRACE_PYTHON_BT2_NO_TRACEBACK=1
+export TEST_PLUGIN_PLUGINS_PATH="@abs_top_builddir@/plugins"
+export BABELTRACE_PLUGIN_PATH="@abs_top_builddir@/plugins/ctf:@abs_top_builddir@/plugins/utils:@abs_top_builddir@/plugins/text"
 PYTHON_BUILD_DIR="@abs_top_builddir@/bindings/python"
 BT2_NATIVE_LIBS_DIR="@abs_top_builddir@/bindings/python/bt2/.libs"
 TESTS_UTILS_PYTHON_DIR="@abs_top_srcdir@/tests/utils/python"
index feae65a58ada4ea328b6c846a3798168e7ace37b..1e97a81c0937016f7e64621c0aacf5a45b7d6db5 100644 (file)
@@ -1 +1,2 @@
 SUBDIRS = tap
+EXTRA_DIST = python/testrunner.py
This page took 0.199141 seconds and 4 git commands to generate.