def test_downstream_port(self): class MyIter(bt2._UserMessageIterator): def __next__(self): raise bt2.Stop class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): def __init__(self, config, params, obj): self._add_output_port('out') class MySink(bt2._UserSinkComponent): def __init__(self, config, params, obj): self._add_input_port('in') def _user_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) self.assertIs(type(conn), bt2_connection._ConnectionConst) self.assertIs(type(conn.downstream_port), bt2_port._InputPortConst)
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_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_invalid(self): class MyIter(bt2._UserMessageIterator): def __next__(self): raise bt2.Stop class MySource(bt2._UserSourceComponent, message_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
def test_raise_in_ports_connected_listener(self): class MyIter(bt2._UserMessageIterator): def __next__(self): raise bt2.Stop class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): def __init__(self, config, params, obj): self._add_output_port('out') class MySink(bt2._UserSinkComponent): def __init__(self, config, params, obj): self._add_input_port('in') def _user_consume(self): raise bt2.Stop def ports_connected_listener(upstream_component, upstream_port, downstream_component, downstream_port): raise ValueError('oh noes!') graph = bt2.Graph() graph.add_ports_connected_listener(ports_connected_listener) up = graph.add_component(MySource, 'down') down = graph.add_component(MySink, 'up') with self.assertRaises(bt2._Error): graph.connect_ports(up.output_ports['out'], down.input_ports['in'])
def translate_to_ctf(input_db, output): graph = bt2.Graph() plugin_path = os.path.join( pathlib.Path(__file__).parent, "bt_plugin_rocm.py") rocm_plugin = bt2.find_plugins_in_path(plugin_path, fail_on_load_error=True)[0] source_component = graph.add_component( rocm_plugin.source_component_classes["RocmSource"], "rocm_source", {"input": input_db}) ctf_plugin = bt2.find_plugin("ctf").sink_component_classes["fs"] sink_component = graph.add_component(ctf_plugin, "ctf_sink", { "path": output, "assume-single-trace": True }) utils_plugin = bt2.find_plugin("utils").filter_component_classes["muxer"] muxer_component = graph.add_component(utils_plugin, "muxer") for i, port in enumerate(source_component.output_ports): graph.connect_ports(source_component.output_ports[port], muxer_component.input_ports["in{}".format(i)]) graph.connect_ports(muxer_component.output_ports["out"], sink_component.input_ports["in"]) graph.run()
def _create_comp(comp_cls, name=None, log_level=bt2.LoggingLevel.NONE): graph = bt2.Graph() if name is None: name = 'comp' return graph.add_component(comp_cls, name, logging_level=log_level)
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
def run_in_component_init(func): class MySink(bt2._UserSinkComponent): def __init__(self, config, params, obj): nonlocal res_bound res_bound = func(self) def _user_consume(self): pass g = bt2.Graph() res_bound = None g.add_component(MySink, 'comp') # We deliberately use a different variable for returning the result than # the variable bound to the MySink.__init__ context and delete res_bound. # The MySink.__init__ context stays alive until the end of the program, so # if res_bound were to still point to our result, it would contribute an # unexpected reference to the refcount of the result, from the point of view # of the user of this function. It would then affect destruction tests, # for example, which want to test what happens when the refcount of a Python # object reaches 0. res = res_bound del res_bound return res
def translate_to_ctf(inputs, output): graph = bt2.Graph() rocm_plugin = bt2.find_plugins_in_path("./bt_plugin_rocm.py")[0] source_component = graph.add_component( rocm_plugin.source_component_classes["RocmSource"], "rocm_source", {"inputs": inputs}) ctf_plugin = bt2.find_plugin("ctf").sink_component_classes["fs"] sink_component = graph.add_component(ctf_plugin, "ctf_sink", { "path": output, "assume-single-trace": True }) utils_plugin = bt2.find_plugin("utils").filter_component_classes["muxer"] muxer_component = graph.add_component(utils_plugin, "muxer") for i, port in enumerate(source_component.output_ports): graph.connect_ports(source_component.output_ports[port], muxer_component.input_ports["in{}".format(i)]) graph.connect_ports(muxer_component.output_ports["out"], sink_component.input_ports["in"]) graph.run()
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 _run_failing_graph(self, source_cc, sink_cc): with self.assertRaises(bt2._Error) as ctx: graph = bt2.Graph() src = graph.add_component(source_cc, 'src') snk = graph.add_component(sink_cc, 'snk') graph.connect_ports(src.output_ports['out'], snk.input_ports['in']) graph.run() return ctx.exception
def test_error_in_iterator_with_cycle_after_having_created_upstream_iterator( self): # Test a failure that triggered an abort in libbabeltrace2, in this situation: # # - The filter iterator creates an upstream iterator. # - The filter iterator creates a reference cycle, including itself. # - An exception is raised, causing the filter iterator's # initialization method to fail. class MySourceIter(bt2._UserMessageIterator): pass class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter): def __init__(self, config, params, obj): self._add_output_port('out') class MyFilterIter(bt2._UserMessageIterator): def __init__(self, config, port): # First, create an upstream iterator. self._upstream_iter = self._create_message_iterator( self._component._input_ports['in']) # Then, voluntarily make a reference cycle that will keep this # Python object alive, which will keep the upstream iterator # Babeltrace object alive. self._self = self # Finally, raise an exception to make __init__ fail. raise ValueError('woops') class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter): def __init__(self, config, params, obj): self._in = self._add_input_port('in') self._out = self._add_output_port('out') class MySink(bt2._UserSinkComponent): def __init__(self, config, params, obj): self._input_port = self._add_input_port('in') def _user_graph_is_configured(self): self._upstream_iter = self._create_message_iterator( self._input_port) def _user_consume(self): # We should not reach this. assert False g = bt2.Graph() src = g.add_component(MySource, 'src') flt = g.add_component(MyFilter, 'flt') snk = g.add_component(MySink, 'snk') g.connect_ports(src.output_ports['out'], flt.input_ports['in']) g.connect_ports(flt.output_ports['out'], snk.input_ports['in']) with self.assertRaisesRegex(bt2._Error, 'ValueError: woops'): g.run()
def _build_graph(self): self._graph = bt2.Graph() self._graph.add_listener(bt2.GraphListenerType.PORT_ADDED, self._graph_port_added) self._muxer_comp = self._create_muxer() if self._begin_ns is not None or self._end_ns is not None: trimmer_comp = self._create_trimmer(self._begin_ns, self._end_ns, 'trimmer') self._graph.connect_ports(self._muxer_comp.output_ports['out'], trimmer_comp.input_ports['in']) msg_iter_port = trimmer_comp.output_ports['out'] else: msg_iter_port = self._muxer_comp.output_ports['out'] # create extra filter components (chained) for comp_spec in self._flt_comp_specs: comp = self._create_comp(comp_spec, _CompClsType.FILTER) self._flt_comps_and_specs.append(_ComponentAndSpec(comp, comp_spec)) # connect the extra filter chain for comp_and_spec in self._flt_comps_and_specs: in_port = list(comp_and_spec.comp.input_ports.values())[0] out_port = list(comp_and_spec.comp.output_ports.values())[0] self._graph.connect_ports(msg_iter_port, in_port) msg_iter_port = out_port # Here we create the components, self._graph_port_added() is # called when they add ports, but the callback returns early # because self._connect_ports is False. This is because the # self._graph_port_added() could not find the associated source # component specification in self._src_comps_and_specs because # it does not exist yet (it needs the created component to # exist). for comp_spec in self._src_comp_specs: comp = self._create_comp(comp_spec, _CompClsType.SOURCE) self._src_comps_and_specs.append(_ComponentAndSpec(comp, comp_spec)) # Now we connect the ports which exist at this point. We allow # self._graph_port_added() to automatically connect _new_ ports. self._connect_ports = True for comp_and_spec in self._src_comps_and_specs: # Keep a separate list because comp_and_spec.output_ports # could change during the connection of one of its ports. # Any new port is handled by self._graph_port_added(). out_ports = [port for port in comp_and_spec.comp.output_ports.values()] for out_port in out_ports: if not out_port.component or out_port.is_connected: continue self._connect_src_comp_port(out_port) # create this trace collection iterator's message iterator self._msg_iter = msg_iter_port.create_message_iterator(self._message_types)
def test_unconnected_port_raises(self): graph = bt2.Graph() graph.add_component( bt2.find_plugin('text').sink_component_classes['pretty'], 'snk' ) with self.assertRaisesRegex( bt2._Error, 'Single input port is not connected: port-name="in"' ): graph.run()
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 _get_msg(self): class MyIter(bt2._UserMessageIterator): 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: msg = bt2.EventMessage(self._ev1) elif self._at == 1: msg = bt2.EventMessage(self._ev2) else: raise bt2.Stop self._at += 1 return msg class MySource(bt2._UserSourceComponent, message_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_msg msg = next(comp_self._msg_iter) if type(msg) is bt2._DiscardedPacketsMessage: the_msg = msg raise bt2.Stop def _port_connected(self, port, other_port): self._msg_iter = port.connection.create_message_iterator() the_msg = 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_msg
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 setUp(self): def f(comp_self): cc = comp_self._create_clock_class( 1000, 'my_cc', offset=bt2.ClockClassOffset(45, 354) ) tc = comp_self._create_trace_class() return (cc, tc) _cc, _tc = run_in_component_init(f) _trace = _tc() _sc = _tc.create_stream_class(default_clock_class=_cc) _ec = _sc.create_event_class(name='salut') _stream = _trace.create_stream(_sc) self._stream = _stream self._ec = _ec self._cc = _cc class MyIter(bt2._UserMessageIterator): def __init__(self, config, self_port_output): self._at = 0 def __next__(self): if self._at == 0: notif = self._create_stream_beginning_message(_stream) elif self._at == 1: notif = self._create_event_message(_ec, _stream, 123) elif self._at == 2: notif = self._create_event_message(_ec, _stream, 2 ** 63) elif self._at == 3: notif = self._create_stream_end_message(_stream) else: raise bt2.Stop self._at += 1 return notif class MySrc(bt2._UserSourceComponent, message_iterator_class=MyIter): def __init__(self, config, params, obj): self._add_output_port('out') self._graph = bt2.Graph() self._src_comp = self._graph.add_component(MySrc, 'my_source') self._msg_iter = TestOutputPortMessageIterator( self._graph, self._src_comp.output_ports['out'] ) for i, msg in enumerate(self._msg_iter): if i == 1: self._msg = msg elif i == 2: self._msg_clock_overflow = msg break
def test_raise_in_component_init(self): class MySink(bt2._UserSinkComponent): def __init__(self, config, params, obj): raise ValueError('oops!') def _user_consume(self): raise bt2.Stop graph = bt2.Graph() with self.assertRaises(bt2._Error): graph.add_component(MySink, 'comp')
def _create_graph(src_comp_cls, sink_comp_cls, flt_comp_cls=None): graph = bt2.Graph() src_comp = graph.add_component(src_comp_cls, 'src') sink_comp = graph.add_component(sink_comp_cls, 'sink') if flt_comp_cls is not None: flt_comp = graph.add_component(flt_comp_cls, 'flt') graph.connect_ports(src_comp.output_ports['out'], flt_comp.input_ports['in']) graph.connect_ports(flt_comp.output_ports['out'], sink_comp.input_ports['in']) else: graph.connect_ports(src_comp.output_ports['out'], sink_comp.input_ports['in']) return graph
def test_component(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') graph = bt2.Graph() src = graph.add_component(MySource, 'src') types = [bt2.EventNotification] notif_iter = src.output_ports['out'].create_notification_iterator( types) for at, notif in enumerate(notif_iter): self.assertIsInstance(notif, bt2.EventNotification) self.assertEqual(notif.event.event_class.name, 'salut') field = notif.event.payload_field['my_int'] self.assertEqual(field, at * 3)
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)
def test_raise_in_port_added_listener(self): class MySink(bt2._UserSinkComponent): def __init__(self, config, params, obj): self._add_input_port('in') def _user_consume(self): raise bt2.Stop def port_added_listener(component, port): raise ValueError('oh noes!') graph = bt2.Graph() graph.add_port_added_listener(port_added_listener) with self.assertRaises(bt2._Error): graph.add_component(MySink, 'comp')
def test_reuse_message(self): class MyIter(bt2._UserMessageIterator): def __init__(self, config, port): tc, sc, ec = port.user_data trace = tc() stream = trace.create_stream(sc) packet = stream.create_packet() # This message will be returned twice by __next__. event_message = self._create_event_message(ec, packet) self._msgs = [ self._create_stream_beginning_message(stream), self._create_packet_beginning_message(packet), event_message, event_message, ] def __next__(self): return self._msgs.pop(0) class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): def __init__(self, config, params, obj): tc = self._create_trace_class() sc = tc.create_stream_class(supports_packets=True) ec = sc.create_event_class() self._add_output_port('out', (tc, sc, ec)) graph = bt2.Graph() src = graph.add_component(MySource, 'src') it = TestOutputPortMessageIterator(graph, src.output_ports['out']) # Skip beginning messages. msg = next(it) self.assertIs(type(msg), bt2._StreamBeginningMessageConst) msg = next(it) self.assertIs(type(msg), bt2._PacketBeginningMessageConst) msg_ev1 = next(it) msg_ev2 = next(it) self.assertIs(type(msg_ev1), bt2._EventMessageConst) self.assertIs(type(msg_ev2), bt2._EventMessageConst) self.assertEqual(msg_ev1.addr, msg_ev2.addr)
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 run_in_message_iterator_next(create_stream_class_func, msg_iter_next_func): class MyIter(bt2._UserMessageIterator): def __init__(self, config, port): tc, sc = port.user_data trace = tc() self._stream = trace.create_stream(sc) def __next__(self): nonlocal res_bound res_bound = msg_iter_next_func(self, self._stream) raise bt2.Stop class MySrc(bt2._UserSourceComponent, message_iterator_class=MyIter): def __init__(self, config, params, obj): tc = self._create_trace_class() cc = self._create_clock_class() sc = create_stream_class_func(tc, cc) self._add_output_port('out', (tc, sc)) class MySink(bt2._UserSinkComponent): def __init__(self, config, params, obj): self._input_port = self._add_input_port('in') def _user_graph_is_configured(self): self._input_iter = self._create_message_iterator(self._input_port) def _user_consume(self): next(self._input_iter) graph = bt2.Graph() res_bound = None src = graph.add_component(MySrc, 'ze source') snk = graph.add_component(MySink, 'ze sink') graph.connect_ports(src.output_ports['out'], snk.input_ports['in']) graph.run() # We deliberately use a different variable for returning the result than # the variable bound to the MyIter.__next__ context. See the big comment # about that in `run_in_component_init`. res = res_bound del res_bound return res
def create_const_field(tc, field_class, field_value_setter_fn): field_name = 'const field' class MyIter(bt2._UserMessageIterator): def __init__(self, config, self_port_output): nonlocal field_class nonlocal field_value_setter_fn trace = tc() packet_context_fc = tc.create_structure_field_class() packet_context_fc.append_member(field_name, field_class) sc = tc.create_stream_class( packet_context_field_class=packet_context_fc, supports_packets=True) stream = trace.create_stream(sc) packet = stream.create_packet() field_value_setter_fn(packet.context_field[field_name]) self._msgs = [ self._create_stream_beginning_message(stream), self._create_packet_beginning_message(packet), ] def __next__(self): if len(self._msgs) == 0: raise StopIteration return self._msgs.pop(0) class MySrc(bt2._UserSourceComponent, message_iterator_class=MyIter): def __init__(self, config, params, obj): self._add_output_port('out', params) graph = bt2.Graph() src_comp = graph.add_component(MySrc, 'my_source', None) msg_iter = TestOutputPortMessageIterator(graph, src_comp.output_ports['out']) # Ignore first message, stream beginning _ = next(msg_iter) packet_beg_msg = next(msg_iter) return packet_beg_msg.packet.context_field[field_name]
def setUp(self): class MySink(bt2._UserSinkComponent): ''' The description. The help. ''' def _user_consume(self): pass @classmethod def _user_query(cls, priv_query_exec, obj, params, method_obj): return [obj, params, 23] self._py_comp_cls = MySink graph = bt2.Graph() comp = graph.add_component(MySink, 'salut') self._comp_cls = comp.cls self.assertIs(type(self._comp_cls), bt2._SinkComponentClassConst)
def test_try_again_many_times(self): class MyIter(bt2._UserMessageIterator): def __next__(self): raise bt2.TryAgain class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): def __init__(self, config, params, obj): self._add_output_port('out') class MyFilterIter(bt2._UserMessageIterator): def __init__(self, port): input_port = port.user_data self._upstream_iter = self._create_input_port_message_iterator( input_port) def __next__(self): return next(self._upstream_iter) def _user_seek_beginning(self): self._upstream_iter.seek_beginning() def _user_can_seek_beginning(self): return self._upstream_iter.can_seek_beginning() class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter): def __init__(self, config, params, obj): input_port = self._add_input_port('in') self._add_output_port('out', input_port) graph = bt2.Graph() src = graph.add_component(MySource, 'src') it = TestOutputPortMessageIterator(graph, src.output_ports['out']) # Three times the initial ref count of `None` iterations should # be enough to catch the bug even if there are small differences # between configurations. none_ref_count = sys.getrefcount(None) * 3 for i in range(none_ref_count): with self.assertRaises(bt2.TryAgain): next(it)