Skip to main content

XNodes is an application framework which provides an event mechanism for unrelated nodes by utilizing a global event bus

Project description

XNodes (Exchanging nodes)

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 lightweight 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 undoes 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 registered in the core called XCore. XCore consists of static methods only, so instantiating it is not necessary. When adding an event to the core, 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 Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

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

xnodes-0.1.0-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

File details

Details for the file xnodes-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: xnodes-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.10.13 Linux/6.5.0-1018-azure

File hashes

Hashes for xnodes-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1229c527f2920aa82eb3aebe5a91ebd697e389a92d2edd3d85f7d2f4dc0b9f4a
MD5 6a035c395b992880ce1888d10bb8470e
BLAKE2b-256 83888c8730e9e6641a4d2bcaf1f7d1aa07202d07d3e0d336bcaf578b9a6aad24

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