Exemplo n.º 1
0
    def __init__(self, bus: Bus, context: Context, *_: Any, **__: Any) -> None:
        super().__init__(*_, **__)

        self._bus = bus
        self._context = context

        self._grid_x_size = "12"
        self._grid_y_size = "12"
        self._grid_edges_keep = "100"

        self._json_distortion_level = "46"
        self._json_map_path = "romania.json"

        self._context.show_props = ShowProps()

        self._show_node_labels = self._context.show_props.show_node_labels
        self._show_node_costs = self._context.show_props.show_node_costs
        self._show_edge_costs = self._context.show_props.show_edge_costs

        self.bind(_show_node_labels=self.update_show_node_labels)
        self.bind(_show_node_costs=self.update_show_node_costs)
        self.bind(_show_edge_costs=self.update_show_edge_costs)

        bus.subscribe(SEARCH_RESET_EVENT, self.reload_path_nodes_properties)

        self.display_enabled()
Exemplo n.º 2
0
def test_timed_signal_with_eventbus():
    time = datetime.now()

    # Create a signal
    a = TimedSignal('<1,2>', time)

    b = Bus()

    def callback(bus, signal=None):
        eq_(signal.time, time, "Expected same time value!")
        eq_(signal.neuron, '<1,2>', "Expected same neuron index!")

    b.subscribe('Fired', callback)

    # Fire the signal
    b.publish('Fired', signal=a)
Exemplo n.º 3
0
def test_timed_signal_with_eventbus():
  time = datetime.now()

  # Create a signal
  a = TimedSignal('<1,2>', time)

  b = Bus()
  
  def callback(bus, signal=None):
    eq_(signal.time, time, "Expected same time value!")
    eq_(signal.neuron, '<1,2>', "Expected same neuron index!")

  b.subscribe('Fired', callback)

  # Fire the signal
  b.publish('Fired', signal=a)
Exemplo n.º 4
0
class Limiter(object):
    def __init__(self, limiter_miss_timeout_ms=None):
        self.bus = Bus()
        self.limiter_miss_timeout_ms = limiter_miss_timeout_ms
        if self.limiter_miss_timeout_ms is None:
            self.limiter_miss_timeout_ms = 500

    def handle_callbacks(self, callback):
        def handle(bus, *args, **kw):
            callback(*args, **kw)
        return handle

    def subscribe_to_lock_miss(self, callback):
        self.bus.subscribe('limiter.miss', self.handle_callbacks(callback))

    def publish_lock_miss(self, url):
        self.bus.publish('limiter.miss', url)
Exemplo n.º 5
0
class Limiter(object):
    def __init__(self, limiter_miss_timeout_ms=None):
        self.bus = Bus()
        self.limiter_miss_timeout_ms = limiter_miss_timeout_ms
        if self.limiter_miss_timeout_ms is None:
            self.limiter_miss_timeout_ms = 500

    def handle_callbacks(self, callback):
        def handle(bus, *args, **kw):
            callback(*args, **kw)

        return handle

    def subscribe_to_lock_miss(self, callback):
        self.bus.subscribe('limiter.miss', self.handle_callbacks(callback))

    def publish_lock_miss(self, url):
        self.bus.publish('limiter.miss', url)
Exemplo n.º 6
0
class BusClient():

	def __init__(self, bus = Bus()):
		if bus is None:
			self.bus = Bus()
		else:
			self.bus = bus
		self.bus.subscribe(KILL_EVENT, self.kill)
		self.running = False
		
	def kill(self,signum, frame):
		print 'kill', signum, frame
		self.running = False

	def listen(self,eventName):
		self.bus.subscribe(eventName,self.printMsg)
		print 'Subscribed to ' + eventName

	def printMsg(self, *args, **kwargs):
		print args, kwargs		
Exemplo n.º 7
0
    def __init__(self, bus: Bus, context: Context, *_: Any, **__: Any) -> None:
        super().__init__(*_, **__)

        bus.subscribe(SEARCH_LOADED_EVENT, self.toggle_visibility_enabled)
        bus.subscribe(SEARCH_RESET_EVENT, self.restart_play)
        bus.subscribe(MAP_RESET_EVENT, self.restart_play)

        self._bus: Bus = bus
        self._context: Context = context
        self._clock: Optional[Clock] = None
Exemplo n.º 8
0
    def __init__(self, bus: Bus, context: Context, *_: Any, **__: Any) -> None:
        super().__init__(*_, **__)

        self.nodes: Dict[str, PathNode] = {}
        self.bus: Bus = bus
        self.context: Context = context

        self._initial_from: Optional[str] = None
        self._initial_to: Optional[str] = None

        bus.subscribe(MAP_NODES_LOADED_EVENT, self.preload_search_settings)
        bus.subscribe(MAP_READY_EVENT, self.display_enabled)
        bus.subscribe(MAP_RESET_EVENT, self.restart_search_settings)
            proc = pickle.load(file)
    return proc

    # def eventHandler(self, msg):
    #     self.updateLamportClock()
    #
    #     # if msg.sourceID == self.uid or msg.sourceID == self.uid:
    #     if msg.sourceID == self.uid:
    #         localEvent(msg)
    #     else:
    #         remoteEvent(msg)


class TestController(unittest.TestCase):
     def setUp(self):
         self.process1 = process(1, 2)
         self.process2 = process(2,2)
         pass

     def testJava(self):
         pass


def busTester(self,  text):
    print(str(text))

if __name__ == "__main__":
    bus = Bus()
    bus.subscribe("tester",busTester)
    bus.publish("tester",text="Hi there!")
class OctoPiControlPanel():
    """
    @var done: anything can set to True to forcequit
    @var screen: points to: pygame.display.get_surface()        
    """

    def __init__(self, config):
        """
        .
        """
        self.bus = Bus()
        self.bus.subscribe("viewchange", self.handle_viewchange)

        self.config = config
        self.octopi_client = OctoPiClient(self.config.api_baseurl, self.config.apikey)
        self.printer = Printer()

        self.done = False

        self.background_image = pygame.image.load(os.path.join(self.config.script_directory, 'assets/background.png'))
        self.menu_button_image = os.path.join(self.config.script_directory, 'assets/button-menu.png')
        self.temperature_icon = pygame.image.load(
            os.path.join(self.config.script_directory, 'assets/icon-temperature.png'))

        self.menu = MenuView(self.config, self.bus)

        self.views = dict()
        self.views["dashboard"] = DashboardView(self.config, self.bus, self.octopi_client, self.printer)
        self.views["graph"] = GraphView(self.config, self.bus, self.printer)
        self.views["control"] = ControlView(self.config, self.bus, self.octopi_client)
        self.views["settings"] = SettingsView(self.config, self.bus)

        self.active_view = self.views["dashboard"]

        self.menu_open = False

        # Status flags
        self.getstate_ticks = pygame.time.get_ticks()

        if platform.system() == 'Linux':
            # Init framebuffer/touchscreen environment variables
            os.putenv('SDL_VIDEODRIVER', 'fbcon')
            os.putenv('SDL_FBDEV', '/dev/fb1')
            os.putenv('SDL_MOUSEDRV', 'TSLIB')
            os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')

        # init pygame and set up screen
        pygame.init()
        if platform.system() == 'Windows' or platform.system() == 'Darwin':
            pygame.mouse.set_visible(True)
        else:
            pygame.mouse.set_visible(False)

        self.screen = pygame.display.set_mode((self.config.width, self.config.height))
        pygame.display.set_caption(self.config.caption)

        # Set font
        self.fntText = pygame.font.Font(os.path.join(self.config.script_directory, "assets/Roboto-Regular.ttf"), 12)
        self.fntTextSmall = pygame.font.Font(os.path.join(self.config.script_directory, "assets/Roboto-Regular.ttf"),
                                             10)
        self.percent_txt = pygame.font.Font(os.path.join(self.config.script_directory, "assets/Roboto-Regular.ttf"), 30)

        # backlight on off status and control
        self.bglight_ticks = pygame.time.get_ticks()
        self.bglight_on = True

        self.clock = pygame.time.Clock()

        self.btnMenu = pygbutton.PygButton((260, 0, 40, 40), normal=self.menu_button_image)

        # I couldnt seem to get at pin 252 for the backlight using the usual method, 
        # but this seems to work
        if platform.system() == 'Linux':
            os.system("echo 252 > /sys/class/gpio/export")
            os.system("echo 'out' > /sys/class/gpio/gpio252/direction")
            os.system("echo '1' > /sys/class/gpio/gpio252/value")

        # Init of class done
        print "OctoPiControlPanel initiated"

    def start(self):
        # OctoPiControlPanel started
        print "OctoPiControlPanel started!"
        print "---"

        # self.thread = Thread(target=self.state_thread)
        # self.thread.start()

        # Set status interval
        pygame.time.set_timer(USEREVENT + 1, self.config.updatetime)

        """ game loop: input, move, render"""
        while not self.done:
            # Handle events
            self.handle_events()

            # Is it time to turn of the backlight?
            if pygame.time.get_ticks() - self.bglight_ticks > self.config.backlightofftime and platform.system() == 'Linux':
                # disable the backlight
                os.system("echo '0' > /sys/class/gpio/gpio252/value")
                self.bglight_ticks = pygame.time.get_ticks()
                self.bglight_on = False

            # Draw everything
            self.draw()

        """ Clean up """
        # enable the backlight before quiting
        if platform.system() == 'Linux':
            os.system("echo '1' > /sys/class/gpio/gpio252/value")

        # OctoPiControlPanel is going down.
        print "OctoPiControlPanel is going down."

        """ Quit """
        pygame.quit()

    def handle_events(self):
        """handle all events."""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                print "quit"
                self.done = True

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    print "Got escape key"
                    self.done = True

            # It should only be possible to click a button if you can see it
            #  e.g. the backlight is on
            if self.bglight_on:

                if self.menu_open:
                    self.menu.handle_event(event)
                else:
                    self.active_view.handle_event(event)

                if 'click' in self.btnMenu.handleEvent(event):
                    self.menu_open = not self.menu_open

            # Did the user click on the screen?
            if event.type == pygame.MOUSEBUTTONDOWN:
                # Reset backlight counter
                self.bglight_ticks = pygame.time.get_ticks()

                if self.bglight_on == False and platform.system() == 'Linux':
                    # enable the backlight
                    os.system("echo '1' > /sys/class/gpio/gpio252/value")
                    self.bglight_on = True
                    print "Background light on."

            # Handle status update
            if event.type == USEREVENT + 1:
                self.state_thread()
                print "State update..."

    """
    Get status update from API, regarding temp etc.
    """

    def state_thread(self):
        # while not self.done:
        self.octopi_client.get_printer_status(self.printer)
        self.octopi_client.get_job_status(self.printer)
        self.octopi_client.get_connection_status(self.printer)

        # time.sleep(self.config.updatetime / 1000.0)

    def draw(self):
        self.clock.tick(30)

        # clear whole screen
        self.screen.blit(self.background_image, (0, 0))

        # render print progress background shade
        s = pygame.Surface((320 * self.printer.Completion / 100, 240), pygame.SRCALPHA)
        s.fill((0, 0, 0, 160))
        self.screen.blit(s, (0, 0))

        # Render current view
        if self.menu_open:
            self.menu.draw(self.screen)
        else:
            self.active_view.draw(self.screen)

        # Render menu button
        self.btnMenu.draw(self.screen)

        # Draw status bar
        self.screen.blit(self.temperature_icon, (0, 200))
        hot_end_label = self.fntText.render(
            u'Hot end: {0}\N{DEGREE SIGN}C ({1}\N{DEGREE SIGN}C)'.format(self.printer.HotEndTemp,
                                                                         self.printer.HotEndTempTarget), 1,
            (255, 255, 255))
        self.screen.blit(hot_end_label, (40, 205))
        bed_temp_label = self.fntText.render(
            u'Bed: {0}\N{DEGREE SIGN}C ({1}\N{DEGREE SIGN}C)'.format(self.printer.BedTemp, self.printer.BedTempTarget),
            1, (255, 255, 255))
        self.screen.blit(bed_temp_label, (40, 220))

        completion_label = self.percent_txt.render("{0:.1f}%".format(self.printer.Completion), 1, (255, 255, 255))
        self.screen.blit(completion_label, (310 - (completion_label.get_width()), 205))

        # update screen
        pygame.display.update()

    def handle_viewchange(self, eventkey, view_name):
        if view_name in self.views:
            self.active_view = self.views[view_name]
            self.menu_open = False

    # Reboot system
    def _reboot(self):
        if platform.system() == 'Linux':
            os.system("reboot")
        else:
            pygame.image.save(self.screen, "screenshot.jpg")

        self.done = True
        print "reboot"

        return

    # Shutdown system
    def _shutdown(self):
        if platform.system() == 'Linux':
            os.system("shutdown -h 0")

        self.done = True
        print "shutdown"

        return
Exemplo n.º 11
0
class SpikingNeuron(object):
  def __init__(self, index, network_bus, 
      efficacy_pause=2,
      efficacy_duration=4, 
      arp=2,
      threshold=1.5):
    """
    A :class:`SpikingNeuron` object is created with the bus for the
    current network as an argument.  It communicates with the network
    solely through this bus.

    Neurons have their own event buses to which they broadcast their
    firings.  To attach neurons to this bus, simply call the attach
    method on the pre-synaptic neuron passing the post-synaptic neuron
    as an argument.

    The firing of a neuron is contained within a :class:'TimedSignal'
    object.
    """
    self._network_bus = network_bus
    self._firing_bus  = Bus()
    self._index       = index

    # Internal plumbing
    self._activation_signals = []
    self._firing_times       = []

    # Neuron parameters
    self._efficacy_pause = efficacy_pause
    self._efficacy_duration = efficacy_duration
    self._arp = arp
    self._threshold = threshold

  def get_index(self):
    """ Returns the index for this neuron. This should be an immutable
    property. As such, only the get method is implemented."""
    return self._index

  index = property(get_index)

  def _fire(self):
    """ 
    Private method.  Used to create a signal and to broadcast it to
    the private event bus of this neuron.
    """
    time = datetime.now()
    signal = TimedSignal(self.index, time)

    # Append the current firing time to the _firing_times
    self._firing_times.append(time)

    # Broadcast the signal
    self._firing_bus.publish(NEURON_FIRE_EVENT_KEY, signal)

  def attach(self, post_synaptic_neuron):
    """
    Attaches :obj:`post_synaptic_neuron` as a synaptic connection to
    which it will send signals.  This is managed by simply adding
    :obj:`post_synaptic_neuron`.activate() to the private event bus
    for this neuron.
    """
    self._firing_bus.subscribe(NEURON_FIRE_EVENT_KEY,
        post_synaptic_neuron.activate)
    return

  def activate(self, bus, signal=None):
    if signal is not None:
      # Add this activation to the _activation_signals list
      self._activation_signals.append(signal)

  def compute(self):
    """
    Computes the activation level at this time.  Considers the signals
    in :obj:`self._activation_signals`, reverse chronologically.  Only
    considers those signals which were fired less than
    :obj:`self._efficacy_duration` ago. Beyond this value, all
    activation levels due to those signals should be zero.

    Additional notes:  This implementation is based on a piecewise
    constant model as defined in 

    Maass, 1995 | Analog Computations on Networks of Spiking Neurons

    Type A
    """
    level = 0
    current_time = datetime.now()

    for signal in reversed(self._activation_signals):
      delta = current_time - signal.time
      delta = delta.seconds * 1000 + delta.microseconds * 0.001
      # Adjust to miliseconds

      if delta > self._efficacy_duration:
        # If the signal was fired more than self._efficacy_duration ms
        # ago, it and all the signals before it will have no effect on
        # the computation.
        break

      if delta < self._efficacy_duration and \
         delta > self._efficacy_pause:
           # Only consider if the signal has started having effects at
           # all.
           level += NEURON_ACTIVATION_LEVEL

    return level

  def touch(self):
    """
    Checks whether the current value of the activation is higher than
    the threshold.  If so, and the current time is more than the
    absolute refractory period since the last firing, neuron sends out
    a synapse.
    """
    if len(self._firing_times) != 0:
      # Makes sense to compute delta_t only if there have been firings
      current_time = datetime.now()
      delta = current_time - self._firing_times[-1] 
      delta = delta.seconds * 1000 + delta.microseconds * 0.001 

      if delta < self._arp: 
        # No point in computing the activation level if still in the
        # absolute refractory period
        return 

    activation_level = self.compute()

    if activation_level > self._threshold:
      self._fire()
    return proc

    # def eventHandler(self, msg):
    #     self.updateLamportClock()
    #
    #     # if msg.sourceID == self.uid or msg.sourceID == self.uid:
    #     if msg.sourceID == self.uid:
    #         localEvent(msg)
    #     else:
    #         remoteEvent(msg)


class TestController(unittest.TestCase):
    def setUp(self):
        self.process1 = process(1, 2)
        self.process2 = process(2, 2)
        pass

    def testJava(self):
        pass


def busTester(self, text):
    print(str(text))


if __name__ == "__main__":
    bus = Bus()
    bus.subscribe("tester", busTester)
    bus.publish("tester", text="Hi there!")
Exemplo n.º 13
0
class TestBus(unittest.TestCase):
    def callback(self, bus, argument):
        self.called_bus = bus
        self.has_run = True
        self.argument = argument

    def setUp(self):
        self.bus = Bus()
        self.has_run = False
        self.called_bus = None

    def test_can_haz_bus(self):
        assert self.bus

    def test_has_no_subscriptions(self):
        assert not self.bus.subscriptions

    def test_subscribe_is_chainable(self):
        bus = self.bus.subscribe('test.key', self.callback)
        assert bus == self.bus

    def test_can_subscribe_to_event(self):
        self.bus.subscribe('test.key', self.callback)
        expected = [{'key': 'test.key', 'callback': self.callback}]

        assert 'test.key' in self.bus.subscriptions
        assert self.bus.subscriptions['test.key']
        assert expected == self.bus.subscriptions['test.key']

    def test_subscribing_twice_with_same_subject_and_callback_ignores_second_call(
            self):
        self.bus.subscribe('test.key',
                           self.callback).subscribe('test.key', self.callback)

        assert len(self.bus.subscriptions['test.key']) == 1, len(
            self.bus.subscriptions['test.key'])

    def test_subscribing_by_force(self):
        self.bus.subscribe('test.key', self.callback).subscribe('test.key',
                                                                self.callback,
                                                                force=True)

        assert len(self.bus.subscriptions['test.key']) == 2, len(
            self.bus.subscriptions['test.key'])

    def test_subscribe_to_all_events(self):
        self.bus.subscribe('*', self.callback)

        self.bus.publish('test.key1')
        assert self.has_run and self.argument == 'test.key1'

        self.has_run = False
        self.bus.publish('test.key2')
        assert self.has_run and self.argument == 'test.key2'

    def test_unsubscribe_is_chainable(self):
        bus = self.bus.unsubscribe('test.key', self.callback)
        assert bus == self.bus

    def test_unsubscribe_to_invalid_subject_does_nothing(self):
        self.bus.unsubscribe('test.key', self.callback)

        assert 'test.key' not in self.bus.subscriptions

    def test_unsubscribe_to_invalid_callback_does_nothing(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.unsubscribe('test.key', lambda obj: obj)

        assert len(self.bus.subscriptions['test.key']) == 1, len(
            self.bus.subscriptions['test.key'])

    def test_can_unsubscribe_to_event(self):
        self.bus.subscribe('test.key',
                           self.callback).unsubscribe('test.key',
                                                      self.callback)

        assert len(self.bus.subscriptions['test.key']) == 0, len(
            self.bus.subscriptions['test.key'])

    def test_unsubscribe_all_does_nothing_for_nonexistent_key(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.unsubscribe_all('other.key')

        assert len(self.bus.subscriptions['test.key']) == 1, len(
            self.bus.subscriptions['test.key'])

    def test_unsubscribe_all_is_chainable(self):
        bus = self.bus.unsubscribe_all('test.key')
        assert bus == self.bus

    def test_unsubscribe_all(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key', lambda obj: obj)

        self.bus.unsubscribe_all('test.key')

        assert len(self.bus.subscriptions['test.key']) == 0, len(
            self.bus.subscriptions['test.key'])

    def test_has_subscription(self):
        self.bus.subscribe('test.key', self.callback)

        assert self.bus.has_subscription('test.key', self.callback)

        self.bus.unsubscribe('test.key', self.callback)

        assert not self.bus.has_subscription('test.key', self.callback)

    def test_does_not_have_subscription_for_invalid_key(self):
        assert not self.bus.has_subscription('test.key', self.callback)

    def test_does_not_have_subscription_for_invalid_calback(self):
        self.bus.subscribe('test.key', self.callback)

        assert not self.bus.has_subscription('test.key', lambda obj: obj)

    def test_has_any_subscriptions_for_invalid_key(self):
        assert not self.bus.has_any_subscriptions('test.key')

    def test_has_any_subscriptions(self):
        self.bus.subscribe('test.key', self.callback)

        assert self.bus.has_any_subscriptions('test.key')

        self.bus.unsubscribe('test.key', self.callback)

        assert not self.bus.has_any_subscriptions('test.key')

    def test_can_publish(self):
        self.bus.subscribe('test.key', self.callback)

        self.bus.publish('test.key', argument="something")

        assert self.has_run
        assert self.argument == "something"
        assert self.called_bus == self.bus

    def test_can_publish_with_noone_listening(self):
        self.bus.publish('test.key', something="whatever")

    def test_publish_is_chainable(self):
        bus = self.bus.publish('test.key', something="whatever")
        assert bus == self.bus

    def test_subscribing_to_different_keys(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key2', self.callback)
        self.bus.subscribe('test.key3', self.callback)

        assert 'test.key' in self.bus.subscriptions
        assert 'test.key2' in self.bus.subscriptions
        assert 'test.key3' in self.bus.subscriptions

        assert self.bus.subscriptions['test.key']
        assert self.bus.subscriptions['test.key2']
        assert self.bus.subscriptions['test.key3']

    def test_can_reset_bus(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key2', self.callback)
        self.bus.subscribe('test.key3', self.callback)

        self.bus.reset()

        assert 'test.key' not in self.bus.subscriptions
        assert 'test.key2' not in self.bus.subscriptions
        assert 'test.key3' not in self.bus.subscriptions

    def test_only_one_instance_of_the_bus(self):
        bus_a = Bus.get_or_create('bus_a')
        bus_b = Bus.get_bus('bus_a')
        bus_c = Bus.get_or_create('bus_c')
        bus_d = Bus()

        assert bus_a is bus_b
        assert bus_a is not bus_c
        assert bus_d is not bus_a

    def test_get_or_create_only_once(self):
        bus_a = Bus.get_or_create('bus_a')
        bus_b = Bus.get_or_create('bus_a')

        assert bus_a is bus_b

    def test_delete_bus_instances(self):
        bus_x = Bus.get_or_create('bus_x')

        assert bus_x in Bus._instances.values()

        Bus.delete_bus('bus_x')

        assert bus_x not in Bus._instances.values()

        with self.assertRaises(KeyError):
            Bus.delete_bus('bus_x')

    def test_bus_is_not_specific(self):
        bus_y = Bus()
        bus_z = Bus.get_or_create('bus_z')

        assert bus_y is not bus_z

    def test_get_bus_name_none(self):
        bus_name = Bus.get_bus_name(self.bus)
        assert bus_name is None

    def test_get_bus_name_string(self):
        bus_x = Bus('bus_x')
        assert Bus.get_bus_name(bus_x) == 'bus_x'
Exemplo n.º 14
0
class TestBus(unittest.TestCase):
    def callback(self, bus, argument):
        self.called_bus = bus
        self.has_run = True
        self.argument = argument

    def setUp(self):
        self.bus = Bus()
        self.has_run = False
        self.called_bus = None

    def test_can_haz_bus(self):
        assert self.bus

    def test_has_no_subscriptions(self):
        assert not self.bus.subscriptions

    def test_subscribe_is_chainable(self):
        bus = self.bus.subscribe('test.key', self.callback)
        assert bus == self.bus

    def test_can_subscribe_to_event(self):
        self.bus.subscribe('test.key', self.callback)
        expected = [{'key': 'test.key', 'callback': self.callback}]

        assert 'test.key' in self.bus.subscriptions
        assert self.bus.subscriptions['test.key']
        assert expected == self.bus.subscriptions['test.key']

    def test_subscribing_twice_with_same_subject_and_callback_ignores_second_call(
            self):
        self.bus.subscribe('test.key',
                           self.callback).subscribe('test.key', self.callback)

        assert len(self.bus.subscriptions['test.key']) == 1, len(
            self.bus.subscriptions['test.key'])

    def test_subscribing_by_force(self):
        self.bus.subscribe('test.key', self.callback).subscribe('test.key',
                                                                self.callback,
                                                                force=True)

        assert len(self.bus.subscriptions['test.key']) == 2, len(
            self.bus.subscriptions['test.key'])

    def test_unsubscribe_is_chainable(self):
        bus = self.bus.unsubscribe('test.key', self.callback)
        assert bus == self.bus

    def test_unsubscribe_to_invalid_subject_does_nothing(self):
        self.bus.unsubscribe('test.key', self.callback)

        assert 'test.key' not in self.bus.subscriptions

    def test_unsubscribe_to_invalid_callback_does_nothing(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.unsubscribe('test.key', lambda obj: obj)

        assert len(self.bus.subscriptions['test.key']) == 1, len(
            self.bus.subscriptions['test.key'])

    def test_can_unsubscribe_to_event(self):
        self.bus.subscribe('test.key',
                           self.callback).unsubscribe('test.key',
                                                      self.callback)

        assert len(self.bus.subscriptions['test.key']) == 0, len(
            self.bus.subscriptions['test.key'])

    def test_unsubscribe_all_does_nothing_for_nonexistent_key(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.unsubscribe_all('other.key')

        assert len(self.bus.subscriptions['test.key']) == 1, len(
            self.bus.subscriptions['test.key'])

    def test_unsubscribe_all_is_chainable(self):
        bus = self.bus.unsubscribe_all('test.key')
        assert bus == self.bus

    def test_unsubscribe_all(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key', lambda obj: obj)

        self.bus.unsubscribe_all('test.key')

        assert len(self.bus.subscriptions['test.key']) == 0, len(
            self.bus.subscriptions['test.key'])

    def test_has_subscription(self):
        self.bus.subscribe('test.key', self.callback)

        assert self.bus.has_subscription('test.key', self.callback)

        self.bus.unsubscribe('test.key', self.callback)

        assert not self.bus.has_subscription('test.key', self.callback)

    def test_does_not_have_subscription_for_invalid_key(self):
        assert not self.bus.has_subscription('test.key', self.callback)

    def test_does_not_have_subscription_for_invalid_calback(self):
        self.bus.subscribe('test.key', self.callback)

        assert not self.bus.has_subscription('test.key', lambda obj: obj)

    def test_has_any_subscriptions_for_invalid_key(self):
        assert not self.bus.has_any_subscriptions('test.key')

    def test_has_any_subscriptions(self):
        self.bus.subscribe('test.key', self.callback)

        assert self.bus.has_any_subscriptions('test.key')

        self.bus.unsubscribe('test.key', self.callback)

        assert not self.bus.has_any_subscriptions('test.key')

    def test_can_publish(self):
        self.bus.subscribe('test.key', self.callback)

        self.bus.publish('test.key', argument="something")

        assert self.has_run
        assert self.argument == "something"
        assert self.called_bus == self.bus

    def test_can_publish_with_noone_listening(self):
        self.bus.publish('test.key', something="whatever")

    def test_publish_is_chainable(self):
        bus = self.bus.publish('test.key', something="whatever")
        assert bus == self.bus

    def test_subscribing_to_different_keys(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key2', self.callback)
        self.bus.subscribe('test.key3', self.callback)

        assert 'test.key' in self.bus.subscriptions
        assert 'test.key2' in self.bus.subscriptions
        assert 'test.key3' in self.bus.subscriptions

        assert self.bus.subscriptions['test.key']
        assert self.bus.subscriptions['test.key2']
        assert self.bus.subscriptions['test.key3']

    def test_can_reset_bus(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key2', self.callback)
        self.bus.subscribe('test.key3', self.callback)

        self.bus.reset()

        assert 'test.key' not in self.bus.subscriptions
        assert 'test.key2' not in self.bus.subscriptions
        assert 'test.key3' not in self.bus.subscriptions
Exemplo n.º 15
0
class AeroApp(tornado.web.Application):
    def __init__(self, handlers=[], **settings):
        handlers = list(handlers)

        self.bus = Bus()
        self.apps = []
        if not settings:
            settings = {}

        if "installed_apps" in settings:
            apps = settings["installed_apps"]

            for app_module_name in apps:
                self.apps.append(self.__load_app(app_module_name))

            for app in self.apps:
                for url in app["urls"]:
                    handlers.append(url)

            if "template_path" in settings:
                self.loader = AppTemplateLoader(self, settings["template_path"])
            else:
                self.loader = AppTemplateLoader(self)

            settings["template_loader"] = self.loader

        handlers.append(
            (
                r"/static/(.*)",
                AeroStaticFileHandler,
                {"path": "static_path" in settings and settings["static_path"] or None, "apps": self.apps},
            )
        )
        if "static_path" in settings:
            settings.pop("static_path")

        for app in self.apps:
            if not app["has_listeners"]:
                continue

            if hasattr(app["listeners"], "listen"):
                app["listeners"].listen(self)

        super(AeroApp, self).__init__(handlers, **settings)
        self.publish("app_started", app=self)

    def subscribe(self, key, callback, force=False):
        return self.bus.subscribe(key, callback, force)

    def publish(self, key, *args, **kwargs):
        return self.bus.publish(key, *args, **kwargs)

    def importable(self, module):
        try:
            __import__(module)
            return True
        except ImportError:
            return False

    def __load_app(self, app_name):
        try:
            module = reduce(getattr, app_name.split(".")[1:], __import__(app_name))
        except ImportError, err:
            print "Could not import app %s! Error:" % app_name
            raise err

        app_path = abspath(dirname(module.__file__))

        urls = []
        urls_module = None

        urls_app_name = "%s.urls" % app_name
        if self.importable(urls_app_name):
            urls_module = reduce(getattr, urls_app_name.split(".")[1:], __import__(urls_app_name))

            if hasattr(urls_module, "urls"):
                for url in urls_module.urls:
                    urls.append(url)

        listeners_module = None
        listeners_module_name = "%s.listeners" % app_name
        if self.importable(listeners_module_name):
            listeners_module = reduce(getattr, listeners_module_name.split(".")[1:], __import__(listeners_module_name))

        template_path = abspath(join(dirname(module.__file__), "templates"))
        has_templates = exists(template_path)

        static_path = abspath(join(dirname(module.__file__), "static"))
        has_static = exists(static_path)

        return {
            "name": app_name,
            "module": module,
            "path": app_path,
            "urls_module": urls_module,
            "urls": urls,
            "has_listeners": listeners_module is not None,
            "listeners": listeners_module,
            "has_templates": has_templates,
            "template_path": template_path,
            "has_static": has_static,
            "static_path": static_path,
        }
Exemplo n.º 16
0
class TestBus(unittest.TestCase):
    def callback(self, bus, argument):
        self.called_bus = bus
        self.has_run = True
        self.argument = argument
        self.callback_count = self.callback_count + 1

    def setUp(self):
        self.bus = Bus()
        self.reset_test()

    def reset_test(self):
        self.has_run = False
        self.called_bus = None
        self.argument = ""
        self.callback_count = 0

    def test_can_haz_bus(self):
        assert self.bus

    def test_has_no_subscriptions(self):
        assert not self.bus.subscriptions

    def test_subscribe_is_chainable(self):
        bus = self.bus.subscribe('test.key', self.callback)
        assert bus == self.bus

    def test_can_subscribe_to_event(self):
        self.bus.subscribe('test.key', self.callback)
        expected = [{ 'key': 'test.key', 'callback': self.callback }]

        assert 'test.key' in self.bus.subscriptions
        assert self.bus.subscriptions['test.key']
        assert expected == self.bus.subscriptions['test.key']

    def test_subscribing_twice_with_same_subject_and_callback_ignores_second_call(self):
        self.bus.subscribe('test.key', self.callback).subscribe('test.key', self.callback)

        assert len(self.bus.subscriptions['test.key']) == 1, len(self.bus.subscriptions['test.key'])

    def test_subscribing_by_force(self):
        self.bus.subscribe('test.key', self.callback).subscribe('test.key', self.callback, force=True)

        assert len(self.bus.subscriptions['test.key']) == 2, len(self.bus.subscriptions['test.key'])

    def test_subscribe_to_all_events(self):
        self.bus.subscribe('*', self.callback)

        self.bus.publish('test.key1')
        assert self.has_run and self.argument == 'test.key1'

        self.has_run = False
        self.bus.publish('test.key2')
        assert self.has_run and self.argument == 'test.key2'


    def test_unsubscribe_is_chainable(self):
        bus = self.bus.unsubscribe('test.key', self.callback)
        assert bus == self.bus

    def test_unsubscribe_to_invalid_subject_does_nothing(self):
        self.bus.unsubscribe('test.key', self.callback)

        assert 'test.key' not in self.bus.subscriptions

    def test_unsubscribe_to_invalid_callback_does_nothing(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.unsubscribe('test.key', lambda obj: obj)

        assert len(self.bus.subscriptions['test.key']) == 1, len(self.bus.subscriptions['test.key'])

    def test_can_unsubscribe_to_event(self):
        self.bus.subscribe('test.key', self.callback).unsubscribe('test.key', self.callback)

        assert len(self.bus.subscriptions['test.key']) == 0, len(self.bus.subscriptions['test.key'])

    def test_unsubscribe_all_does_nothing_for_nonexistent_key(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.unsubscribe_all('other.key')

        assert len(self.bus.subscriptions['test.key']) == 1, len(self.bus.subscriptions['test.key'])

    def test_unsubscribe_all_is_chainable(self):
        bus = self.bus.unsubscribe_all('test.key')
        assert bus == self.bus

    def test_unsubscribe_all(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key', lambda obj: obj)

        self.bus.unsubscribe_all('test.key')

        assert len(self.bus.subscriptions['test.key']) == 0, len(self.bus.subscriptions['test.key'])

    def test_has_subscription(self):
        self.bus.subscribe('test.key', self.callback)

        assert self.bus.has_subscription('test.key', self.callback)

        self.bus.unsubscribe('test.key', self.callback)

        assert not self.bus.has_subscription('test.key', self.callback)

    def test_does_not_have_subscription_for_invalid_key(self):
        assert not self.bus.has_subscription('test.key', self.callback)

    def test_does_not_have_subscription_for_invalid_calback(self):
        self.bus.subscribe('test.key', self.callback)

        assert not self.bus.has_subscription('test.key', lambda obj: obj)

    def test_has_any_subscriptions_for_invalid_key(self):
        assert not self.bus.has_any_subscriptions('test.key')

    def test_has_any_subscriptions(self):
        self.bus.subscribe('test.key', self.callback)

        assert self.bus.has_any_subscriptions('test.key')

        self.bus.unsubscribe('test.key', self.callback)

        assert not self.bus.has_any_subscriptions('test.key')

    def test_can_publish(self):
        self.bus.subscribe('test.key', self.callback)

        self.bus.publish('test.key', argument="something")

        assert self.has_run
        assert self.argument == "something"
        assert self.called_bus == self.bus

    def test_can_publish_with_noone_listening(self):
        self.bus.publish('test.key', something="whatever")

    def test_publish_is_chainable(self):
        bus = self.bus.publish('test.key', something="whatever")
        assert bus == self.bus

    def test_subscribing_to_different_keys(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key2', self.callback)
        self.bus.subscribe('test.key3', self.callback)

        assert 'test.key' in self.bus.subscriptions
        assert 'test.key2' in self.bus.subscriptions
        assert 'test.key3' in self.bus.subscriptions

        assert self.bus.subscriptions['test.key']
        assert self.bus.subscriptions['test.key2']
        assert self.bus.subscriptions['test.key3']

    def test_can_reset_bus(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key2', self.callback)
        self.bus.subscribe('test.key3', self.callback)

        self.bus.reset()

        assert 'test.key' not in self.bus.subscriptions
        assert 'test.key2' not in self.bus.subscriptions
        assert 'test.key3' not in self.bus.subscriptions

    def test_only_one_instance_of_the_bus(self):
        bus_a = Bus.get_or_create('bus_a')
        bus_b = Bus.get_bus('bus_a')
        bus_c = Bus.get_or_create('bus_c')
        bus_d = Bus()

        assert bus_a is bus_b
        assert bus_a is not bus_c
        assert bus_d is not bus_a

    def test_get_or_create_only_once(self):
        bus_a = Bus.get_or_create('bus_a')
        bus_b = Bus.get_or_create('bus_a')

        assert bus_a is bus_b

    def test_delete_bus_instances(self):
        bus_x = Bus.get_or_create('bus_x')

        assert bus_x in Bus._instances.values()

        Bus.delete_bus('bus_x')

        assert bus_x not in Bus._instances.values()

        with self.assertRaises(KeyError):
            Bus.delete_bus('bus_x')

    def test_bus_is_not_specific(self):
        bus_y = Bus()
        bus_z = Bus.get_or_create('bus_z')

        assert bus_y is not bus_z

    def test_get_bus_name_none(self):
        bus_name = Bus.get_bus_name(self.bus)
        assert bus_name is None

    def test_get_bus_name_string(self):
        bus_x = Bus('bus_x')
        assert Bus.get_bus_name(bus_x) == 'bus_x'

    def test_subkey_subscriptions_simple(self):
        self.bus.subscribe('level1a.level2a', self.callback)

        # we have subscribed to a parent level thus we should receive this publish
        self.bus.publish('level1a.level2a.level3a', argument="something")

        assert self.has_run
        assert self.argument == "something"
        assert self.called_bus == self.bus
        assert self.callback_count == 1

    def test_subkey_subscriptions_no_start_match(self):
        # make sure that we only get publishes if the start of the key is an exact match
        self.reset_test()

        self.bus.subscribe('level1a.level2a', self.callback)
        self.bus.publish('blah.level1a.level2a.level3a', argument="something")

        assert not self.has_run
        assert self.argument == ""
        assert self.called_bus == None
        assert self.callback_count == 0

    def test_subkey_subscriptions_complex(self):
        self.reset_test()
        self.bus.subscribe('level1a.level2a', self.callback)
        self.bus.subscribe('level1a.level2a.level3a', self.callback)
        self.bus.subscribe('level1a.level2a.level3b', self.callback)

        # we have subscribed to a parent level thus we should receive this publish
        self.bus.publish('level1a.level2a.level3a', argument="something")

        assert self.has_run
        assert self.argument == "something"
        assert self.called_bus == self.bus
        assert self.callback_count == 2

        # following test should get callback for level1a.level2a and level1a.level2a.level3a
        self.reset_test()
        self.bus.publish('level1a.level2a.level3b', argument="something2")

        assert self.has_run
        assert self.argument == "something2"
        assert self.called_bus == self.bus
        assert self.callback_count == 2

        self.reset_test()
        self.bus.subscribe('level1a', self.callback)
        self.bus.publish('level1a.level2b', argument="something2")

        assert self.has_run
        assert self.argument == "something2"
        assert self.called_bus == self.bus
        assert self.callback_count == 1

    def test_messages_across_threads_thread_subscribe1(self):
        # in this example we create a thread and then from outside that thread we create a subscription to one of the
        # threads functions
        bus_a = Bus.get_or_create('bus_a')
        new_thread = ThreadClass1()
        new_thread.start()

        bus_a.subscribe('level1a.level2a', new_thread.message_callback)

        # we have subscribed to a parent level thus we should receive this publish
        bus_a.publish('level1a.level2a.level3a', argument="hello")

        #assert self.has_run
        assert new_thread.get_latest_argument() == "hello"
        assert new_thread.get_bus() == bus_a
        assert new_thread.get_latest_counter() == 1

        new_thread.stop()

    def test_messages_across_threads_thread_subscribe2(self):
        # in this example we create a thread and then from outside that thread we create a subscription to one of the
        # threads functions
        bus_a = Bus.get_or_create('bus_a')
        new_thread = ThreadClass2()
        new_thread.start()

        while not new_thread.running():
            time.sleep(0.05)

        # we have subscribed to a parent level thus we should receive this publish
        bus_a.publish('level1a.level2a.level3a', argument="hello_there")

        new_thread.stop()

        #assert self.has_run
        assert new_thread.get_latest_argument() == "hello_there"
        assert new_thread.get_bus() == bus_a
        assert new_thread.get_latest_counter() == 1

    def test_messages_across_threads_thread_publish(self):
        # in this example we create a thread and then from inside that thread we perform a publish which eventuates
        # in this main thread
        self.reset_test()
        bus_a = Bus.get_or_create('bus_a')
        bus_a.subscribe('level1a.level2a', self.callback)

        new_thread = ThreadClass3()
        new_thread.start()

        while not new_thread.running():
            time.sleep(0.05)
            
        new_thread.stop()

        assert self.has_run
        assert self.argument == "hello from thread"
        assert self.called_bus == bus_a
        assert self.callback_count == 1
Exemplo n.º 17
0
class EventBus:
    def __init__(self):
        #TODO: convert to singleton
        global log
        self._bus = Bus()
        self._channel = 'default/'
        self._log_channel_key = 'log/'
        self._sensor_channel_key = 'sensor/'
        self._event_channel_key = 'event/'
        self._command_channel_key = 'command/'
        self._type = 'EventBus'
        self._capabilities = {'get_nodes':self.register_sensorbus,
                              'get_eventbus_nodes':self.register_sensorbus,
                              'get_commandbus_nodes':self.register_sensorbus,
                              'get_logbus_nodes':self.register_sensorbus,
                              }
        self._container = {}

        #log.info('EventBus Initalized')
    def get_nodes(self):
        return

    def register_sensorbus(self, callback):
        self._bus.subscribe(self._sensor_channel_key, callback)
        log.debug(str(callback) + ' registered to sensor bus.' )
        # todo: log subs

    def register_eventbus(self, callback):
        self._bus.subscribe(self._event_channel_key, callback)
        log.debug(str(callback) + ' registered to event bus.')
        # todo: log subs

    def register_logbus(self, callback):
        self._bus.subscribe(self._log_channel_key, callback)
        log.debug(str(callback) + ' registered to error bus.')
        # todo: log subs

    def register_commandbus(self, callback):
        self._bus.subscribe(self._command_channel_key, callback)
        log.debug(str(callback) + ' registered to command bus.')
        # todo: log subs

    def unregister(self, channel, callback):
        # todo: log unsub

        self._bus.unsubscribe(channel, callback)
        log.debug('%s unregistered from %s') % (str(callback), channel)

    def publish(self, data):
        self._bus.publish(self._sensor_channel_key, data)

    def publish_sensor(self, data):
        self._bus.publish(self._sensor_channel_key, data)

    def publish_log(self, data):
        self._bus.publish(self._log_channel_key, data)

    def publish_event(self, data):
        self._bus.publish(self._event_channel_key, data)

    def publish_command(self, data):
        self._bus.publish(self._command_channel_key, data)
Exemplo n.º 18
0
class TestBus(unittest.TestCase):
    def callback(self, bus, argument):
        self.called_bus = bus
        self.has_run = True
        self.argument = argument

    def setUp(self):
        self.bus = Bus()
        self.has_run = False
        self.called_bus = None

    def test_can_haz_bus(self):
        assert self.bus

    def test_has_no_subscriptions(self):
        assert not self.bus.subscriptions

    def test_subscribe_is_chainable(self):
        bus = self.bus.subscribe('test.key', self.callback)
        assert bus == self.bus

    def test_can_subscribe_to_event(self):
        self.bus.subscribe('test.key', self.callback)
        expected = [{ 'key': 'test.key', 'callback': self.callback }]

        assert 'test.key' in self.bus.subscriptions
        assert self.bus.subscriptions['test.key']
        assert expected == self.bus.subscriptions['test.key']

    def test_subscribing_twice_with_same_subject_and_callback_ignores_second_call(self):
        self.bus.subscribe('test.key', self.callback).subscribe('test.key', self.callback)

        assert len(self.bus.subscriptions['test.key']) == 1, len(self.bus.subscriptions['test.key'])

    def test_subscribing_by_force(self):
        self.bus.subscribe('test.key', self.callback).subscribe('test.key', self.callback, force=True)

        assert len(self.bus.subscriptions['test.key']) == 2, len(self.bus.subscriptions['test.key'])

    def test_unsubscribe_is_chainable(self):
        bus = self.bus.unsubscribe('test.key', self.callback)
        assert bus == self.bus

    def test_unsubscribe_to_invalid_subject_does_nothing(self):
        self.bus.unsubscribe('test.key', self.callback)

        assert 'test.key' not in self.bus.subscriptions

    def test_unsubscribe_to_invalid_callback_does_nothing(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.unsubscribe('test.key', lambda obj: obj)

        assert len(self.bus.subscriptions['test.key']) == 1, len(self.bus.subscriptions['test.key'])

    def test_can_unsubscribe_to_event(self):
        self.bus.subscribe('test.key', self.callback).unsubscribe('test.key', self.callback)

        assert len(self.bus.subscriptions['test.key']) == 0, len(self.bus.subscriptions['test.key'])

    def test_unsubscribe_all_does_nothing_for_nonexistent_key(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.unsubscribe_all('other.key')

        assert len(self.bus.subscriptions['test.key']) == 1, len(self.bus.subscriptions['test.key'])

    def test_unsubscribe_all_is_chainable(self):
        bus = self.bus.unsubscribe_all('test.key')
        assert bus == self.bus

    def test_unsubscribe_all(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key', lambda obj: obj)

        self.bus.unsubscribe_all('test.key')

        assert len(self.bus.subscriptions['test.key']) == 0, len(self.bus.subscriptions['test.key'])

    def test_has_subscription(self):
        self.bus.subscribe('test.key', self.callback)

        assert self.bus.has_subscription('test.key', self.callback)

        self.bus.unsubscribe('test.key', self.callback)

        assert not self.bus.has_subscription('test.key', self.callback)

    def test_does_not_have_subscription_for_invalid_key(self):
        assert not self.bus.has_subscription('test.key', self.callback)

    def test_does_not_have_subscription_for_invalid_calback(self):
        self.bus.subscribe('test.key', self.callback)

        assert not self.bus.has_subscription('test.key', lambda obj: obj)

    def test_has_any_subscriptions_for_invalid_key(self):
        assert not self.bus.has_any_subscriptions('test.key')

    def test_has_any_subscriptions(self):
        self.bus.subscribe('test.key', self.callback)

        assert self.bus.has_any_subscriptions('test.key')

        self.bus.unsubscribe('test.key', self.callback)

        assert not self.bus.has_any_subscriptions('test.key')

    def test_can_publish(self):
        self.bus.subscribe('test.key', self.callback)

        self.bus.publish('test.key', argument="something")

        assert self.has_run
        assert self.argument == "something"
        assert self.called_bus == self.bus

    def test_can_publish_with_noone_listening(self):
        self.bus.publish('test.key', something="whatever")

    def test_publish_is_chainable(self):
        bus = self.bus.publish('test.key', something="whatever")
        assert bus == self.bus

    def test_subscribing_to_different_keys(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key2', self.callback)
        self.bus.subscribe('test.key3', self.callback)

        assert 'test.key' in self.bus.subscriptions
        assert 'test.key2' in self.bus.subscriptions
        assert 'test.key3' in self.bus.subscriptions

        assert self.bus.subscriptions['test.key']
        assert self.bus.subscriptions['test.key2']
        assert self.bus.subscriptions['test.key3']

    def test_can_reset_bus(self):
        self.bus.subscribe('test.key', self.callback)
        self.bus.subscribe('test.key2', self.callback)
        self.bus.subscribe('test.key3', self.callback)

        self.bus.reset()

        assert 'test.key' not in self.bus.subscriptions
        assert 'test.key2' not in self.bus.subscriptions
        assert 'test.key3' not in self.bus.subscriptions