def publish(self,
                package,
                endpoint=Endpoints.RESULT,
                command=Commands.THREAD_HANDLE):
        """
        Publishes a package to all the subscribers of an endpoint

        By default, will publish to the RESULT endpoint with a command of THREAD_HANDLE.
        You may wish to provide a different endpoint or command depending on how
        the application is set up.
        """
        try:
            for queue in self.subscriptions[endpoint]:
                queue.put(Message(self.name, command, package))
        except KeyError:
            logging.error(
                f"Thread {self.name} trying to publish to endpoint {endpoint} which was not created"
            )
            raise
        except AttributeError:
            logging.error(
                f"Thread {self.name} trying to publish to endpoint {endpoint} which was not created"
            )
            raise
        except Exception:
            logging.error(
                f"Isse publishing to endpoing {endpoint} on thread {self.name}"
            )
            raise
Esempio n. 2
0
 def process_outgoing_messsages(self, message: Message):
     """Process only the outgoing messages"""
     # Check sender is not in list of destroyed threads
     if len(message.sender) > 1:
         # Append name to front of sender and pass up
         message.sender = [self.owner, *message.sender]
         self.output_queue.put(message)
     else:
         self.logger.error(
             f"Sender {message.sender} does not have enough information")
def test_multi_run_thread_puts_message_in_queue(make_thread):
    m = make_thread(ExampleMultiRunThread, "M")

    q = Queue()

    send_subscription_message(m, q)
    m.start()
    m.start()
    m.start()
    m.start()
    m.end()

    min_sleep()

    assert threading.active_count() == 2
    assert q.qsize() == 4
    assert q.get() == Message("M", Commands.THREAD_HANDLE, 1)
    assert q.get() == Message("M", Commands.THREAD_HANDLE, 2)
    assert q.get() == Message("M", Commands.THREAD_HANDLE, 3)
    assert q.get() == Message("M", Commands.THREAD_HANDLE, 4)
    def _message_handle(self, message: Message):
        """Takes a slightly different approach to messages as it needs to handle
        different situations"""

        # Run garbage collection
        self.garbage_collect()

        self.logger.debug(
            f"MESSAGE Sender: {message.sender}, Command {message.command}, Package: {message.package}"
        )

        # Addressed to self
        if message.receiver == [self.name]:
            # Process as normal
            super()._message_handle(message)
        # Addressed to child thread
        elif self.name in message.receiver:
            # Strip name off front and pass on
            message.receiver = message.receiver[1:]
            # Send to appropriate thread input queue
            if message.receiver[0] in self.active_threads.keys():
                self.active_threads[message.receiver[0]].input_queue.put(
                    message)
        else:
            # Check sender is not in list of destroyed threads
            if len(message.sender) > 1:
                if message.sender[1] not in self.destroyed_threads:
                    # Append name to front of sender and pass up
                    message.sender = [self.owner, *message.sender]
                    self.output_queue.put(message)
                else:
                    self.logger.error(
                        f"Sender {message.sender[1]} is a destroyed thread")
            else:
                self.logger.error(
                    f"Sender {message.sender} does not have enough information"
                )

        # Run garbage collection
        self.garbage_collect()
def test_single_run_thread_puts_message_in_queue(make_thread):
    e = make_thread(ExampleSingleRunThread, "E")

    q = Queue()

    send_subscription_message(e, q)
    e.start()

    min_sleep()

    assert threading.active_count() == 2
    assert q.qsize() == 1
    assert q.get() == Message("E", Commands.THREAD_HANDLE, None)
    def _thread_end(self, message: Message):
        # Mark all children to be destroyed
        self.destroyed_threads = set(self.active_threads.keys())
        # Send them all a thread end message
        for thread_name in self.active_threads.keys():
            self.active_threads[thread_name].input_queue.put(
                Message(self.name, thread_name, "THREAD_END", None))

        # Ensure that all child threads have ended before raising end flag
        while len(self.active_threads.keys()) > 0:
            # Wait for them to end and delete them
            self.garbage_collect()

        self.end_flag.set()
    def destroy_thread(self, message: Message):
        """Send a THREAD_END message to a thread and add it to the list of deleted threads"""
        try:
            thread_name = message.package["thread_name"]
        except KeyError:
            self.logger(
                "Could not find thread name to DELETE in message package")

        if thread_name not in self.active_threads.keys():
            self.logger.error(
                f"Tried to DESTROY thread named {thread_name} but not found in active threads"
            )
            return
        elif thread_name in self.destroyed_threads:
            self.logger.error(
                f"Thread named {thread_name} already marked to be DESTROYED")
            return

        # Send the thread end command
        self.active_threads[thread_name].input_queue.put(
            Message(self.name, thread_name, "THREAD_END", None))
        # Mark out to be destroyed
        self.destroyed_threads.add(thread_name)
Esempio n. 8
0
    def _message_handle(self, message: Message):
        """Based on ThreadManager approach to handling messages from the outside
        and from children
        Have to do some things manually as they do not have scope for the new functions
        when being used from super
        """
        self.logger.debug(
            f"MESSAGE Sender: {message.sender}, Command {message.command}, Package: {message.package}"
        )

        # Addressed to self
        if message.receiver == self.name or message.receiver == [self.name]:
            # Process as normal
            super()._message_handle(message)
        # Addressed to screen
        elif self.name in message.receiver:
            # Strip name off front and pass on
            message.receiver = message.receiver[1:]
            # If the screen is active pass the message
            # Should inactive screens be able to receive messsages?
            if message.receiver[0] in self.active_screens:
                self.screens[message.receiver[0]].update(message)
        else:
            self.process_outgoing_messsages(message)
 def end(self):
     """Put THREAD_END message in queue"""
     self.message_queue.put(
         Message((self.name, ), Commands.THREAD_END, None))
Esempio n. 10
0
 def stop(self):
     """Put THREAD_STOP message in queue"""
     self.message_queue.put(
         Message((self.name, ), Commands.THREAD_STOP, None))
Esempio n. 11
0
 def start(self):
     """Put THREAD_START message in queue"""
     self.message_queue.put(
         Message((self.name, ), Commands.THREAD_START, None))
Esempio n. 12
0
        if message.command == "UPDATE":
            self.extra_label.configure(text=message.package)


if __name__ == "__main__":

    inq1 = Queue()
    outq1 = Queue()

    Manager = "Screen Manager"
    home_screen = "Screen Manager Example"

    print("Running Tk Screen Manager")
    Tk1 = TkScreenManager(Manager, "owner", inq1, outq1)

    Tk1.input_queue.put(Message("owner", [Manager], "THREAD_START", None))
    Tk1.input_queue.put(
        Message(
            "owner",
            [Manager],
            "NEW_SCREEN",
            {
                "screen_name": home_screen,
                "screen_type": MyFirstGUI
            },
        ))
    time.sleep(5)
    Tk1.input_queue.put(Message("owner", [Manager], "SHOW_SCREEN",
                                home_screen))

    time.sleep(5)
Esempio n. 13
0
    out_queue = Queue()

    manager = "Example Manager"
    owner = "Owner"

    print(f"Active Threads: {threading.active_count()}")

    # Create the ThreadManager
    print("Creating Example Manager")
    example_manager = ThreadManager(manager, owner, in_queue, out_queue)
    print(f"Active Threads: {threading.active_count()}")

    # Supply a dictionary of thread types
    print("Providing thread types")
    in_queue.put(
        Message(owner, [manager], "SET_THREAD_TYPES",
                {"Single Run": ExampleSingleRunThread}))

    # Create a new single run thread
    print("New single run thread")
    in_queue.put(
        Message(
            owner,
            [manager],
            "NEW_THREAD",
            {
                "thread_name": "S1",
                "thread_type": "Single Run"
            },
        ))
    time.sleep(0.1)
    print(f"Active Threads: {threading.active_count()}")
Esempio n. 14
0
 def quit_command(self):
     # Directly call the end thread function
     self._thread_end(Message(None, None, None, None))
if __name__ == "__main__":
    in_queue = Queue()
    out_queue = Queue()

    # See that all the threads are running
    print(f"Active threads: {threading.active_count()}")

    # Create the ThreadManager
    example_manager = ThreadManager("Example Manager", "Owner", in_queue,
                                    out_queue)
    # Set the thread types with human readable names
    in_queue.put(
        Message(
            "Owner",
            ["Example Manager"],
            "SET_THREAD_TYPES",
            {"Multi Run": ExampleMultiRunThread},
        ))

    # Create multipe Multi Run thread instances
    in_queue.put(
        Message(
            "Owner",
            ["Example Manager"],
            "NEW_THREAD",
            {
                "thread_name": "Multi 1",
                "thread_type": "Multi Run"
            },
        ))
    in_queue.put(
Esempio n. 16
0
def send_subscription_message(thread: SimpleThread,
                              queue,
                              endpoint=SimpleThread.Endpoints.RESULT):
    thread.message_queue.put(
        Message("Test", Commands.THREAD_SUBSCRIBE,
                SubscriptionPackage(endpoint, queue)))
Esempio n. 17
0
 def send_to(self, receiver: List[str], command: str, package: any):
     """Helper function for sending information from a thread correctly"""
     self.output_queue.put(
         Message([self.owner, self.name], receiver, command, package))

if __name__ == "__main__":

    inq1 = Queue()
    outq1 = Queue()

    Manager = "Screen Manager"
    choice_screen = "Choice"
    blue_screen = "Blue"
    red_screen = "Red"

    print("Running Tk Screen Manager")
    Tk1 = TkScreenManager(Manager, "owner", inq1, outq1)

    Tk1.input_queue.put(Message("owner", [Manager], "THREAD_START", None))
    Tk1.input_queue.put(
        Message(
            "owner",
            [Manager],
            "NEW_SCREEN",
            {"screen_name": choice_screen, "screen_type": ChoiceScreen},
        )
    )
    Tk1.input_queue.put(
        Message(
            "owner",
            [Manager],
            "NEW_SCREEN",
            {"screen_name": blue_screen, "screen_type": BlueScreen},
        )
Esempio n. 19
0
 def repeating_start(self):
     """Command to set the *main* function going again"""
     self.message_queue.put(Message(self.name, "THREAD_REPEAT", None))
    flash_screen = "Flash Screen"
    flash_thread = "Flash Thread"

    print(f"Active Threads: {threading.active_count()}")

    # Create the ThreadManager
    print("Creating Example Manager")
    example_manager = ThreadManager(manager, owner, in_queue, out_queue)
    print(f"Active Threads: {threading.active_count()}")

    # Supply a dictionary of thread types
    print("Providing thread types")
    in_queue.put(
        Message(
            owner,
            [manager],
            "SET_THREAD_TYPES",
            {"SCREEN": TkScreenManager, "FLASH_THREAD": FlashThread},
        )
    )

    # Create Threads
    in_queue.put(
        Message(
            owner,
            [manager],
            "NEW_THREAD",
            {"thread_name": screen_manager_1, "thread_type": "SCREEN"},
        )
    )
    in_queue.put(
        Message(