lib: Add functions to borrow specialized component classes from specialized components
[babeltrace.git] / bindings / python / bt2 / bt2 / component.py
CommitLineData
81447b5b
PP
1# The MIT License (MIT)
2#
3# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21# THE SOFTWARE.
22
23from bt2 import native_bt, object, utils
5602ef81 24import bt2.message_iterator
81447b5b 25import collections.abc
c4239792 26import bt2.value
811644b8
PP
27import traceback
28import bt2.port
40910fbb 29import sys
81447b5b 30import bt2
811644b8
PP
31import os
32
33
34_env_var = os.environ.get('BABELTRACE_PYTHON_BT2_NO_TRACEBACK')
35_NO_PRINT_TRACEBACK = _env_var == '1'
81447b5b
PP
36
37
38# This class wraps a component class pointer. This component class could
39# have been created by Python code, but since we only have the pointer,
40# we can only wrap it in a generic way and lose the original Python
41# class.
78288f58 42class _GenericComponentClass(object._SharedObject):
81447b5b
PP
43 @property
44 def name(self):
811644b8
PP
45 name = native_bt.component_class_get_name(self._ptr)
46 assert(name is not None)
47 return name
81447b5b
PP
48
49 @property
50 def description(self):
51 return native_bt.component_class_get_description(self._ptr)
52
40910fbb
PP
53 @property
54 def help(self):
55 return native_bt.component_class_get_help(self._ptr)
56
811644b8
PP
57 def __eq__(self, other):
58 if not isinstance(other, _GenericComponentClass):
59 try:
60 if not issubclass(other, _UserComponent):
61 return False
62 except TypeError:
63 return False
81447b5b 64
811644b8 65 return self.addr == other.addr
81447b5b
PP
66
67
68class _GenericSourceComponentClass(_GenericComponentClass):
69 pass
70
71
72class _GenericFilterComponentClass(_GenericComponentClass):
73 pass
74
75
76class _GenericSinkComponentClass(_GenericComponentClass):
77 pass
78
79
811644b8
PP
80def _handle_component_status(status, gen_error_msg):
81 if status == native_bt.COMPONENT_STATUS_END:
82 raise bt2.Stop
83 elif status == native_bt.COMPONENT_STATUS_AGAIN:
84 raise bt2.TryAgain
85 elif status == native_bt.COMPONENT_STATUS_UNSUPPORTED:
86 raise bt2.UnsupportedFeature
87 elif status == native_bt.COMPONENT_STATUS_REFUSE_PORT_CONNECTION:
88 raise bt2.PortConnectionRefused
89 elif status == native_bt.COMPONENT_STATUS_GRAPH_IS_CANCELED:
90 raise bt2.GraphCanceled
91 elif status < 0:
92 raise bt2.Error(gen_error_msg)
93
94
95class _PortIterator(collections.abc.Iterator):
96 def __init__(self, comp_ports):
97 self._comp_ports = comp_ports
98 self._at = 0
99
100 def __next__(self):
101 if self._at == len(self._comp_ports):
102 raise StopIteration
103
104 comp_ports = self._comp_ports
105 comp_ptr = comp_ports._component._ptr
106 port_ptr = comp_ports._get_port_at_index_fn(comp_ptr, self._at)
107 assert(port_ptr)
108
109 if comp_ports._is_private:
6d137876 110 port_pub_ptr = native_bt.port_from_private(port_ptr)
811644b8
PP
111 name = native_bt.port_get_name(port_pub_ptr)
112 native_bt.put(port_pub_ptr)
113 else:
114 name = native_bt.port_get_name(port_ptr)
115
116 assert(name is not None)
117 native_bt.put(port_ptr)
118 self._at += 1
119 return name
120
121
122class _ComponentPorts(collections.abc.Mapping):
123 def __init__(self, is_private, component,
124 get_port_by_name_fn, get_port_at_index_fn,
125 get_port_count_fn):
126 self._is_private = is_private
127 self._component = component
128 self._get_port_by_name_fn = get_port_by_name_fn
129 self._get_port_at_index_fn = get_port_at_index_fn
130 self._get_port_count_fn = get_port_count_fn
131
132 def __getitem__(self, key):
133 utils._check_str(key)
134 port_ptr = self._get_port_by_name_fn(self._component._ptr, key)
135
136 if port_ptr is None:
137 raise KeyError(key)
138
139 if self._is_private:
140 return bt2.port._create_private_from_ptr(port_ptr)
141 else:
142 return bt2.port._create_from_ptr(port_ptr)
143
144 def __len__(self):
145 if self._is_private:
6d137876 146 pub_ptr = native_bt.component_from_private(self._component._ptr)
811644b8
PP
147 count = self._get_port_count_fn(pub_ptr)
148 native_bt.put(pub_ptr)
149 else:
150 count = self._get_port_count_fn(self._component._ptr)
151
152 assert(count >= 0)
153 return count
154
155 def __iter__(self):
156 return _PortIterator(self)
157
158
81447b5b
PP
159# This class holds the methods which are common to both generic
160# component objects and Python user component objects. They use the
161# internal native _ptr, however it was set, to call native API
162# functions.
811644b8 163class _Component:
81447b5b
PP
164 @property
165 def name(self):
811644b8
PP
166 name = native_bt.component_get_name(self._ptr)
167 assert(name is not None)
168 return name
169
170 @property
171 def graph(self):
172 ptr = native_bt.component_get_graph(self._ptr)
173 assert(ptr)
174 return bt2.Graph._create_from_ptr(ptr)
81447b5b
PP
175
176 @property
177 def component_class(self):
178 cc_ptr = native_bt.component_get_class(self._ptr)
811644b8 179 assert(cc_ptr)
81447b5b
PP
180 return _create_generic_component_class_from_ptr(cc_ptr)
181
811644b8
PP
182 def __eq__(self, other):
183 if not hasattr(other, 'addr'):
184 return False
81447b5b 185
811644b8 186 return self.addr == other.addr
81447b5b 187
81447b5b 188
811644b8
PP
189class _SourceComponent(_Component):
190 pass
81447b5b 191
81447b5b 192
811644b8
PP
193class _FilterComponent(_Component):
194 pass
81447b5b 195
81447b5b 196
811644b8
PP
197class _SinkComponent(_Component):
198 pass
81447b5b
PP
199
200
201# This is analogous to _GenericSourceComponentClass, but for source
202# component objects.
78288f58 203class _GenericSourceComponent(object._SharedObject, _SourceComponent):
811644b8
PP
204 @property
205 def output_ports(self):
206 return _ComponentPorts(False, self,
207 native_bt.component_source_get_output_port_by_name,
208 native_bt.component_source_get_output_port_by_index,
209 native_bt.component_source_get_output_port_count)
81447b5b
PP
210
211
212# This is analogous to _GenericFilterComponentClass, but for filter
213# component objects.
78288f58 214class _GenericFilterComponent(object._SharedObject, _FilterComponent):
811644b8
PP
215 @property
216 def output_ports(self):
217 return _ComponentPorts(False, self,
218 native_bt.component_filter_get_output_port_by_name,
219 native_bt.component_filter_get_output_port_by_index,
220 native_bt.component_filter_get_output_port_count)
221
222 @property
223 def input_ports(self):
224 return _ComponentPorts(False, self,
225 native_bt.component_filter_get_input_port_by_name,
226 native_bt.component_filter_get_input_port_by_index,
227 native_bt.component_filter_get_input_port_count)
81447b5b
PP
228
229
230# This is analogous to _GenericSinkComponentClass, but for sink
231# component objects.
78288f58 232class _GenericSinkComponent(object._SharedObject, _SinkComponent):
811644b8
PP
233 @property
234 def input_ports(self):
235 return _ComponentPorts(False, self,
236 native_bt.component_sink_get_input_port_by_name,
237 native_bt.component_sink_get_input_port_by_index,
238 native_bt.component_sink_get_input_port_count)
81447b5b
PP
239
240
811644b8 241_COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS = {
81447b5b
PP
242 native_bt.COMPONENT_CLASS_TYPE_SOURCE: _GenericSourceComponent,
243 native_bt.COMPONENT_CLASS_TYPE_FILTER: _GenericFilterComponent,
244 native_bt.COMPONENT_CLASS_TYPE_SINK: _GenericSinkComponent,
245}
246
247
811644b8 248_COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS = {
81447b5b
PP
249 native_bt.COMPONENT_CLASS_TYPE_SOURCE: _GenericSourceComponentClass,
250 native_bt.COMPONENT_CLASS_TYPE_FILTER: _GenericFilterComponentClass,
251 native_bt.COMPONENT_CLASS_TYPE_SINK: _GenericSinkComponentClass,
252}
253
254
255def _create_generic_component_from_ptr(ptr):
256 comp_cls_type = native_bt.component_get_class_type(ptr)
811644b8 257 return _COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS[comp_cls_type]._create_from_ptr(ptr)
81447b5b
PP
258
259
260def _create_generic_component_class_from_ptr(ptr):
261 comp_cls_type = native_bt.component_class_get_type(ptr)
811644b8 262 return _COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS[comp_cls_type]._create_from_ptr(ptr)
81447b5b
PP
263
264
40910fbb
PP
265def _trim_docstring(docstring):
266 lines = docstring.expandtabs().splitlines()
267 indent = sys.maxsize
268
269 for line in lines[1:]:
270 stripped = line.lstrip()
271
272 if stripped:
273 indent = min(indent, len(line) - len(stripped))
274
275 trimmed = [lines[0].strip()]
276
277 if indent < sys.maxsize:
278 for line in lines[1:]:
279 trimmed.append(line[indent:].rstrip())
280
281 while trimmed and not trimmed[-1]:
282 trimmed.pop()
283
284 while trimmed and not trimmed[0]:
285 trimmed.pop(0)
286
287 return '\n'.join(trimmed)
288
289
81447b5b
PP
290# Metaclass for component classes defined by Python code.
291#
292# The Python user can create a standard Python class which inherits one
811644b8
PP
293# of the three base classes (_UserSourceComponent, _UserFilterComponent,
294# or _UserSinkComponent). Those base classes set this class
81447b5b
PP
295# (_UserComponentType) as their metaclass.
296#
297# Once the body of a user-defined component class is executed, this
298# metaclass is used to create and initialize the class. The metaclass
299# creates a native BT component class of the corresponding type and
300# associates it with this user-defined class. The metaclass also defines
301# class methods like the `name` and `description` properties to match
302# the _GenericComponentClass interface.
303#
304# The component class name which is used is either:
305#
306# * The `name` parameter of the class:
307#
308# class MySink(bt2.SinkComponent, name='my-custom-sink'):
309# ...
310#
311# * If the `name` class parameter is not used: the name of the class
312# itself (`MySink` in the example above).
313#
314# The component class description which is used is the user-defined
315# class's docstring:
316#
317# class MySink(bt2.SinkComponent):
318# 'Description goes here'
319# ...
320#
321# A user-defined Python component class can have an __init__() method
322# which must at least accept the `params` and `name` arguments:
323#
324# def __init__(self, params, name, something_else):
325# ...
326#
811644b8 327# The user-defined component class can also have a _finalize() method
81447b5b 328# (do NOT use __del__()) to be notified when the component object is
811644b8 329# finalized.
81447b5b
PP
330#
331# User-defined source and filter component classes must use the
5602ef81
SM
332# `message_iterator_class` class parameter to specify the
333# message iterator class to use for this component class:
81447b5b 334#
5602ef81 335# class MyMessageIterator(bt2._UserMessageIterator):
81447b5b
PP
336# ...
337#
811644b8 338# class MySource(bt2._UserSourceComponent,
5602ef81 339# message_iterator_class=MyMessageIterator):
81447b5b
PP
340# ...
341#
5602ef81
SM
342# This message iterator class must inherit
343# bt2._UserMessageIterator, and it must define the _get() and
344# _next() methods. The message iterator class can also define an
81447b5b
PP
345# __init__() method: this method has access to the original Python
346# component object which was used to create it as the `component`
5602ef81 347# property. The message iterator class can also define a
811644b8 348# _finalize() method (again, do NOT use __del__()): this is called when
5602ef81 349# the message iterator is (really) destroyed.
81447b5b
PP
350#
351# When the user-defined class is destroyed, this metaclass's __del__()
352# method is called: the native BT component class pointer is put (not
353# needed anymore, at least not by any Python code since all references
354# are dropped for __del__() to be called).
355class _UserComponentType(type):
356 # __new__() is used to catch custom class parameters
357 def __new__(meta_cls, class_name, bases, attrs, **kwargs):
358 return super().__new__(meta_cls, class_name, bases, attrs)
359
360 def __init__(cls, class_name, bases, namespace, **kwargs):
361 super().__init__(class_name, bases, namespace)
362
363 # skip our own bases; they are never directly instantiated by the user
811644b8
PP
364 own_bases = (
365 '_UserComponent',
366 '_UserFilterSinkComponent',
367 '_UserSourceComponent',
368 '_UserFilterComponent',
369 '_UserSinkComponent',
370 )
371
372 if class_name in own_bases:
81447b5b
PP
373 return
374
375 comp_cls_name = kwargs.get('name', class_name)
811644b8 376 utils._check_str(comp_cls_name)
40910fbb
PP
377 comp_cls_descr = None
378 comp_cls_help = None
379
380 if hasattr(cls, '__doc__') and cls.__doc__ is not None:
811644b8 381 utils._check_str(cls.__doc__)
40910fbb
PP
382 docstring = _trim_docstring(cls.__doc__)
383 lines = docstring.splitlines()
384
385 if len(lines) >= 1:
386 comp_cls_descr = lines[0]
387
388 if len(lines) >= 3:
389 comp_cls_help = '\n'.join(lines[2:])
390
5602ef81 391 iter_cls = kwargs.get('message_iterator_class')
81447b5b 392
811644b8 393 if _UserSourceComponent in bases:
81447b5b 394 _UserComponentType._set_iterator_class(cls, iter_cls)
81447b5b
PP
395 cc_ptr = native_bt.py3_component_class_source_create(cls,
396 comp_cls_name,
397 comp_cls_descr,
811644b8
PP
398 comp_cls_help)
399 elif _UserFilterComponent in bases:
81447b5b 400 _UserComponentType._set_iterator_class(cls, iter_cls)
81447b5b
PP
401 cc_ptr = native_bt.py3_component_class_filter_create(cls,
402 comp_cls_name,
403 comp_cls_descr,
811644b8
PP
404 comp_cls_help)
405 elif _UserSinkComponent in bases:
81447b5b 406 if not hasattr(cls, '_consume'):
811644b8 407 raise bt2.IncompleteUserClass("cannot create component class '{}': missing a _consume() method".format(class_name))
81447b5b
PP
408
409 cc_ptr = native_bt.py3_component_class_sink_create(cls,
410 comp_cls_name,
40910fbb
PP
411 comp_cls_descr,
412 comp_cls_help)
81447b5b 413 else:
811644b8 414 raise bt2.IncompleteUserClass("cannot find a known component class base in the bases of '{}'".format(class_name))
81447b5b
PP
415
416 if cc_ptr is None:
417 raise bt2.CreationError("cannot create component class '{}'".format(class_name))
418
419 cls._cc_ptr = cc_ptr
420
811644b8
PP
421 def _init_from_native(cls, comp_ptr, params_ptr):
422 # create instance, not user-initialized yet
81447b5b
PP
423 self = cls.__new__(cls)
424
811644b8
PP
425 # pointer to native private component object (weak/borrowed)
426 self._ptr = comp_ptr
81447b5b 427
811644b8
PP
428 # call user's __init__() method
429 if params_ptr is not None:
430 native_bt.get(params_ptr)
c4239792 431 params = bt2.value._create_from_ptr(params_ptr)
811644b8
PP
432 else:
433 params = None
81447b5b 434
811644b8 435 self.__init__(params)
81447b5b
PP
436 return self
437
811644b8
PP
438 def __call__(cls, *args, **kwargs):
439 raise bt2.Error('cannot directly instantiate a user component from a Python module')
81447b5b
PP
440
441 @staticmethod
442 def _set_iterator_class(cls, iter_cls):
443 if iter_cls is None:
5602ef81 444 raise bt2.IncompleteUserClass("cannot create component class '{}': missing message iterator class".format(cls.__name__))
81447b5b 445
5602ef81
SM
446 if not issubclass(iter_cls, bt2.message_iterator._UserMessageIterator):
447 raise bt2.IncompleteUserClass("cannot create component class '{}': message iterator class does not inherit bt2._UserMessageIterator".format(cls.__name__))
81447b5b 448
811644b8 449 if not hasattr(iter_cls, '__next__'):
5602ef81 450 raise bt2.IncompleteUserClass("cannot create component class '{}': message iterator class is missing a __next__() method".format(cls.__name__))
81447b5b
PP
451
452 cls._iter_cls = iter_cls
453
454 @property
455 def name(cls):
456 return native_bt.component_class_get_name(cls._cc_ptr)
457
458 @property
459 def description(cls):
460 return native_bt.component_class_get_description(cls._cc_ptr)
461
40910fbb
PP
462 @property
463 def help(cls):
464 return native_bt.component_class_get_help(cls._cc_ptr)
465
81447b5b
PP
466 @property
467 def addr(cls):
468 return int(cls._cc_ptr)
469
c7eee084 470 def _query_from_native(cls, query_exec_ptr, obj, params_ptr):
911dec08 471 # this can raise, in which case the native call to
a67681c1 472 # bt_component_class_query() returns NULL
811644b8
PP
473 if params_ptr is not None:
474 native_bt.get(params_ptr)
c4239792 475 params = bt2.value._create_from_ptr(params_ptr)
811644b8
PP
476 else:
477 params = None
478
c7eee084
PP
479 native_bt.get(query_exec_ptr)
480 query_exec = bt2.QueryExecutor._create_from_ptr(query_exec_ptr)
811644b8 481
c7eee084
PP
482 # this can raise, but the native side checks the exception
483 results = cls._query(query_exec, obj, params)
811644b8
PP
484
485 if results is NotImplemented:
486 return results
487
c7eee084
PP
488 # this can raise, but the native side checks the exception
489 results = bt2.create_value(results)
911dec08
PP
490
491 if results is None:
492 results_addr = int(native_bt.value_null)
493 else:
811644b8
PP
494 # return new reference
495 results._get()
911dec08 496 results_addr = int(results._ptr)
911dec08
PP
497
498 return results_addr
499
c7eee084 500 def _query(cls, query_executor, obj, params):
911dec08 501 # BT catches this and returns NULL to the user
811644b8
PP
502 return NotImplemented
503
504 def __eq__(self, other):
505 if not hasattr(other, 'addr'):
506 return False
507
508 return self.addr == other.addr
911dec08 509
81447b5b
PP
510 def __del__(cls):
511 if hasattr(cls, '_cc_ptr'):
512 native_bt.put(cls._cc_ptr)
513
514
811644b8
PP
515class _UserComponent(metaclass=_UserComponentType):
516 @property
517 def name(self):
6d137876 518 pub_ptr = native_bt.component_from_private(self._ptr)
811644b8
PP
519 name = native_bt.component_get_name(pub_ptr)
520 native_bt.put(pub_ptr)
521 assert(name is not None)
522 return name
81447b5b 523
811644b8
PP
524 @property
525 def graph(self):
6d137876 526 pub_ptr = native_bt.component_from_private(self._ptr)
811644b8
PP
527 ptr = native_bt.component_get_graph(pub_ptr)
528 native_bt.put(pub_ptr)
529 assert(ptr)
530 return bt2.Graph._create_from_ptr(ptr)
81447b5b 531
811644b8
PP
532 @property
533 def component_class(self):
6d137876 534 pub_ptr = native_bt.component_from_private(self._ptr)
811644b8
PP
535 cc_ptr = native_bt.component_get_class(pub_ptr)
536 native_bt.put(pub_ptr)
537 assert(cc_ptr)
538 return _create_generic_component_class_from_ptr(cc_ptr)
81447b5b 539
81447b5b
PP
540 @property
541 def addr(self):
542 return int(self._ptr)
543
811644b8 544 def __init__(self, params=None):
81447b5b
PP
545 pass
546
811644b8 547 def _finalize(self):
81447b5b
PP
548 pass
549
811644b8
PP
550 def _accept_port_connection(self, port, other_port):
551 return True
81447b5b 552
811644b8
PP
553 def _accept_port_connection_from_native(self, port_ptr, other_port_ptr):
554 native_bt.get(port_ptr)
555 native_bt.get(other_port_ptr)
556 port = bt2.port._create_private_from_ptr(port_ptr)
557 other_port = bt2.port._create_from_ptr(other_port_ptr)
558 res = self._accept_port_connection(port, other_port_ptr)
81447b5b 559
811644b8
PP
560 if type(res) is not bool:
561 raise TypeError("'{}' is not a 'bool' object")
81447b5b 562
811644b8 563 return res
81447b5b 564
811644b8
PP
565 def _port_connected(self, port, other_port):
566 pass
81447b5b 567
811644b8
PP
568 def _port_connected_from_native(self, port_ptr, other_port_ptr):
569 native_bt.get(port_ptr)
570 native_bt.get(other_port_ptr)
571 port = bt2.port._create_private_from_ptr(port_ptr)
572 other_port = bt2.port._create_from_ptr(other_port_ptr)
81447b5b 573
811644b8 574 try:
88a77ab5 575 self._port_connected(port, other_port)
811644b8
PP
576 except:
577 if not _NO_PRINT_TRACEBACK:
578 traceback.print_exc()
81447b5b 579
811644b8 580 def _port_disconnected(self, port):
81447b5b
PP
581 pass
582
811644b8
PP
583 def _port_disconnected_from_native(self, port_ptr):
584 native_bt.get(port_ptr)
585 port = bt2.port._create_private_from_ptr(port_ptr)
81447b5b 586
811644b8
PP
587 try:
588 self._port_disconnected(port)
589 except:
590 if not _NO_PRINT_TRACEBACK:
591 traceback.print_exc()
81447b5b 592
81447b5b 593
811644b8 594class _UserSourceComponent(_UserComponent, _SourceComponent):
81447b5b 595 @property
811644b8
PP
596 def _output_ports(self):
597 return _ComponentPorts(True, self,
598 native_bt.private_component_source_get_output_private_port_by_name,
599 native_bt.private_component_source_get_output_private_port_by_index,
600 native_bt.component_source_get_output_port_count)
601
602 def _add_output_port(self, name):
603 utils._check_str(name)
604 fn = native_bt.private_component_source_add_output_private_port
605 comp_status, priv_port_ptr = fn(self._ptr, name, None)
606 _handle_component_status(comp_status,
607 'cannot add output port to source component object')
608 assert(priv_port_ptr)
609 return bt2.port._create_private_from_ptr(priv_port_ptr)
610
611
612class _UserFilterComponent(_UserComponent, _FilterComponent):
613 @property
614 def _output_ports(self):
615 return _ComponentPorts(True, self,
616 native_bt.private_component_filter_get_output_private_port_by_name,
617 native_bt.private_component_filter_get_output_private_port_by_index,
618 native_bt.component_filter_get_output_port_count)
81447b5b 619
811644b8
PP
620 @property
621 def _input_ports(self):
622 return _ComponentPorts(True, self,
623 native_bt.private_component_filter_get_input_private_port_by_name,
624 native_bt.private_component_filter_get_input_private_port_by_index,
625 native_bt.component_filter_get_input_port_count)
626
627 def _add_output_port(self, name):
628 utils._check_str(name)
629 fn = native_bt.private_component_filter_add_output_private_port
630 comp_status, priv_port_ptr = fn(self._ptr, name, None)
631 _handle_component_status(comp_status,
632 'cannot add output port to filter component object')
633 assert(priv_port_ptr)
634 return bt2.port._create_private_from_ptr(priv_port_ptr)
635
636 def _add_input_port(self, name):
637 utils._check_str(name)
638 fn = native_bt.private_component_filter_add_input_private_port
639 comp_status, priv_port_ptr = fn(self._ptr, name, None)
640 _handle_component_status(comp_status,
641 'cannot add input port to filter component object')
642 assert(priv_port_ptr)
643 return bt2.port._create_private_from_ptr(priv_port_ptr)
644
645
646class _UserSinkComponent(_UserComponent, _SinkComponent):
647 @property
648 def _input_ports(self):
649 return _ComponentPorts(True, self,
650 native_bt.private_component_sink_get_input_private_port_by_name,
651 native_bt.private_component_sink_get_input_private_port_by_index,
652 native_bt.component_sink_get_input_port_count)
653
654 def _add_input_port(self, name):
655 utils._check_str(name)
656 fn = native_bt.private_component_sink_add_input_private_port
657 comp_status, priv_port_ptr = fn(self._ptr, name, None)
658 _handle_component_status(comp_status,
659 'cannot add input port to sink component object')
660 assert(priv_port_ptr)
661 return bt2.port._create_private_from_ptr(priv_port_ptr)
This page took 0.064004 seconds and 4 git commands to generate.