Usage

Building your first HERO is very simple. Just write your custom class and make it inherit from heros.LocalHero.

A simple example can be seen

import time
from heros import LocalHERO


class TestObject(LocalHERO):

    testme: int = 0

    def read_temp(self, min: int, max: int) -> float:
        return (max + min) / 2

    def hello(self) -> str:
        self.testme += 1
        return "world"


with TestObject("my_hero") as obj:

    # keep running with infinite loop
    while True:
        time.sleep(1)

Due to the infinite loop, the script will not terminate and keep the object obj alive. Since it inherits from heros.LocalHERO, the object was analyzed upon instantiation and provided as a HERO to the network. This means, we can now simply access the method attributes of the object from a remote site.

To get remote access we can run the following in a different process or on a different machine in the same network (UDP broadcast needs to reach the other machine for discovery):

from heros import RemoteHERO

with RemoteHERO("my_hero") as obj:

    # call remote functions
    print(obj.read_temp(0, 10))
    print(obj.hello())

    # access remote attribute
    obj.testme = 10

Nested HEROs

HEROS is able to serialize HEROs as references to a HERO. This allows to pass a HERO between the local and the remote site. When either of the sites receives such a reference, it creates a RemoteHERO to access the referenced HERO. This allows things like

  1. Deep access to HEROs nested inside of HEROs.

  2. Passing HEROs as arguments into methods exposed by a HERO.

  3. Retrieving HEROs returned by a HERO.

Unserializable Objects

A HERO attribute or method might return an object that is not a HERO and can not be serialized. In that case, the returned object is cached on the side of the LocalHERO and an identifier is sent to the remote side. The remote side can store the reference locally. If the reference is sent back to the LocalHERO side, the corresponding object is taken from the cache and inserted into the request instead of the reference. This allows to instruct the LocalHERO to do something with an object that cannot be transferred. This allows, for example, to hand over an unserializable object retrieved earlier as argument to a function.

Note

The cache that keeps the object references uses only weak references to to avoid memory leaks. That means that an object can be garbage collected if not any other instance keeps a reference on it.