Skip to main content

Event exchanging nodes framework

Project description

XNodes (Exchanging nodes)

WORK IN PROGRESS, CURRENTLY NOT FUNCTIONAL

About

XNodes is an application framework which provides an event mechanism for unrelated nodes by utilizing a global event bus. The framework's initial purpose was to establish a lightweigth mechanism for exchanging information between UI widgets and a data model, all without necessitating their mutual awareness. Upon receiving an event which alters the state of a node, the receiving node can provide an event in return which undos the made changes. This way an easy to use but powerful undo/redo mechanism is realized.

How to use

Application start

Before any node is constructed, all events with their parameters which are used within the system have to be registers in the event bus called XNodeBus. XNodeBus consists of staticmethods only, so instantiating it is not necessary. When adding an event to the bus, one can provide an optional log level for that event which will be used during logging when that event is published, default log level is INFO.

import logging

from xnodes import XNodeBus

EVENT_A = "EVENT_A"
EVENT_B = "EVENT_B"

XNodeBus.add_event(EVENT_A, (int, str))
XNodeBus.add_event(EVENT_B, (bool, list), logging.DEBUG)

If a node wants to publish an event, the types of the parameters have to match the types provided during registration. If the parameter types do not match, a ValueError is raised during publication.

Node initialization

To create a node, a class has to inherit from the XNode class. Every node has a type and when a class inherits from XNode, the type has to be provided to XNode. Purpose of this type is easier identification of nodes and the possibility of other nodes to publish events to all nodes of a certain type.

from xnodes import XNode

MY_NODE_TYPE = "MY_NODE"

class MyNode(XNode):
    
    def __init__():
        XNode.__init__(self, MY_NODE_TYPE)

instance1 = MyNode()  # ID: MY_NODE
instance2 = MyNode()  # ID: MY_NODE_1
instance3 = MyNode()  # ID: MY_NODE_2

The created instances of MyNode both have unique IDs within the node type MY_NODE. Note that the first instance will receive an ID equal to the node type, but the second ID has a suffix. Background for this is that if only one node instance of a type exists in the application, it can be directly referred to by its type. This makes it easier to address services in the application.

Receiving events

In order to receive an event, a node has to implement an event handler function and decorate it with the xevent decorator function.

from xnodes import XNode, xevent

MY_NODE_TYPE = "MY_NODE"
EVENT_A = "EVENT_A"
EVENT_B = "EVENT_B"

class MyNode(XNode):
    
    def __init__():
        XNode.__init__(self, MY_NODE_TYPE)
    
    @xevent(EVENT_A)
    def handle_event(self, parameter_1: int, parameter_2: str):
        pass  # Do something with the event.
    
    @xevent(EVENT_B)
    def handle_event(self, parameter_1: bool, parameter_2: list):
        pass  # Do something with the event.

The decorator xevent takes as argument the identifier of the event which the decorated function is supposed to handle. Note that the names of both of the event handler functions above are the same, which is not possible in standard Python. This is achieved by a custom metaclass of XNode, which stores all functions which are decorated with xevent in a separate dictionary and identifies the function by the event identifier and not by its name. In fact, the name of an event handler function is completely irrelevant and one is free to name them all the same or give them different names.

Publishing events

XNode provides two functions to publish events. The first is the publish function, which delivers one single event to one single node which is specified by its ID. The second is the broadcast function which delivers an event to every node which subscribed to the published event.

from xnodes import XNode

MY_NODE_TYPE = "MY_NODE"
EVENT_A = "EVENT_A"
EVENT_B = "EVENT_B"

class MyNode(XNode):
    
    def __init__():
        XNode.__init__(self, MY_NODE_TYPE)
    
    def publish_event_a(self, target_node_id: str, parameter_1: int, parameter_2: str):
        self.publish(EVENT_A, target_node_id, parameter_1, parameter_2)
    
    def broadcast_event_b(self, parameter_1: bool, parameter_2: list):
        self.broadcast(EVENT_B, parameter_1, parameter_2)

Conflicting metaclasses

If you want to convert a class to an XNode, but also need the class to derive from another class which also has a custom metaclass, one has to combine the metaclasses of both into a common metaclass. In order to do this, xnodes provdides a function for this called create_xnode:

import ConflictingMetaclassType

from xnodes import create_xnode

MY_NODE_TYPE = "MY_NODE"

class MyNode(create_xnode(ConflictingMetaclassType, MY_NODE_TYPE)):
    
    def __init__():
        super().__init__(parameters_of_conflicting_metaclass_type)

Instead of deriving from ConflictingMetaclassType and XNode in the super class list, one can call create_xnode inside the super class list and pass the conflicting class together with the xnode type to combine the metaclasses. In the init of the new class, one now only has to provide the super class init arguments of the conflicting metaclass type. One example of a conflicting metaclass type are any widgets of the Python Qt bindings. If the goal is to implement a custom QLineEdit and send an XEvent whenever the text changes for example, one has to use the create_xnode function to combine QLineEdit with XNode to resolve this issue.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xnodes-0.0.13b0.tar.gz (18.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xnodes-0.0.13b0-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file xnodes-0.0.13b0.tar.gz.

File metadata

  • Download URL: xnodes-0.0.13b0.tar.gz
  • Upload date:
  • Size: 18.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.17

File hashes

Hashes for xnodes-0.0.13b0.tar.gz
Algorithm Hash digest
SHA256 4185597bdc866c0c9615568f412d5cc4bbc12ca85093c5567f7c436c78704a14
MD5 d30e3275c47874a5f5fa8cb4c1320a00
BLAKE2b-256 04c4f2ba61f4add05587cb65b0f8472d726194b780b33ec8a044dc14def5e25a

See more details on using hashes here.

File details

Details for the file xnodes-0.0.13b0-py3-none-any.whl.

File metadata

  • Download URL: xnodes-0.0.13b0-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.17

File hashes

Hashes for xnodes-0.0.13b0-py3-none-any.whl
Algorithm Hash digest
SHA256 e52644ac892e2a39dad0b50afc038dd61f0bc516f3ead7792adeaa4f797a5017
MD5 6319fd4ac877ea22fd81d81d16f5a422
BLAKE2b-256 180ffce3fde4329beb6527b9e178d658c1a010674ff7af56b91b2818d358a46b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page