Skip to main content

Easy, minimalist tools for function side-effects and observer pattern with weak references

Project description

observer_hooks

An easy way to attach side effects to functions and methods. Intended to accomplish something similar to the "observer pattern" in simple context.

For methods, an instance member to hold weak references to functions and methods is automatically created. By default the instance member is the same name as the method with an underscore prepended. This can be changed with the event_name argument.

Side effects can be chained normally.

Install

pip install observer-hooks

Documentation (wip)

Usage

Attach a side effect to a function:

from observer_hooks import notify

@notify()
def some_function(param):
    return f"param: {param}"


def side_effect(param):
    print(param)


some_function.subscribe(side_effect)
assert some_function(1) == 'param: 1'
# this will print "1"

Attach a side effect to a method:

from observer_hooks import notify

class A:
    @notify()
    def notify_some_action(self):
        pass

class B:
    def __init__(self, a:A):
        self.a = a
        a.notify_some_action.subscribe(self.a_some_action)
    
    def a_some_action(self):
        print('received')

b = B(A())
b.a.notify_some_action()
# this will print "received"

Example with slots:

from observer_hooks import notify

class A:
    __slots__ = '_notify_some_action',
    
    @notify()
    def notify_some_action(self):
        pass

def a_some_action():
    print('received')

a = A()
a.notify_some_action.subscribe(a_some_action)
a.notify_some_action()
# this will print "received"

Block certain side effects from firing:

from observer_hooks import notify
from observer_hooks.block_events import BlockSideEffects


class A:
    __slots__ = '_notify_some_action',

    @notify()
    def notify_some_action(self):
        pass


def a_some_action():
    print('blocked')


def a_some_action2():
    print('not blocked')


a = A()
a.notify_some_action.subscribe(a_some_action)
a.notify_some_action.subscribe(a_some_action2)
with BlockSideEffects(a.notify_some_action, only=(a_some_action,)):
    a.notify_some_action()

The HardRefEventHandler will hold non-weak references to lambda and partial functions

from observer_hooks import notify, HardRefEventHandler

@notify(handler_t=HardRefEventHandler)
def notify_some_action():
    return 'return value'

def some_action():
    print('Hi')

def scope():
    notify_some_action.subscribe(lambda: some_action())

scope()
print(notify_some_action())

The "pass_ref" parameter will pass the "self" reference to side-effect functions and the switch_event_handler method on descriptors will switch the event handler type

from observer_hooks import notify, HardRefEventHandler
class SomeClass:
    @notify(pass_ref=True)
    def method(self):
        pass

s = SomeClass()

def method(other):
    assert other is s

s.method.switch_event_handler(HardRefEventHandler())
s.method.subscribe(method)
s.method()

Inherit or copy parameters from a superclasses descriptor with 'notify_copy_super'

from observer_hooks import notify, notify_copy_super


class A:
    @notify(pass_ref=True, no_origin=True, auto_fire=False)
    def method(self):
        print('this wont print')


class B(A):
    pass


class C(B):
    @notify_copy_super(auto_fire=True)
    def method(self):
        print('neither will this')


def side_effect(x):
    print('hi', x)


c = C()
c.method.subscribe(side_effect)
c.method()

Notes:

  • The parameter "auto_fire", when set to false, will disable all side effects and instead the .emit() function can be used to manually trigger the side effects
  • Redefined methods in child classes also need a decorator to retain the behavior and will override behavior to the specifications of the new decorator
  • Inherited methods will only fire once even if they are re-defined and super is called
  • Inherited methods do not need to be re-defined

Future plans

  • Implement access to the originating functions return value
    • Either a member of the object that replaces the function for non-thread safe applications or a special parameter

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

observer-hooks-1.3.0.tar.gz (8.7 kB view details)

Uploaded Source

Built Distribution

observer_hooks-1.3.0-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

Details for the file observer-hooks-1.3.0.tar.gz.

File metadata

  • Download URL: observer-hooks-1.3.0.tar.gz
  • Upload date:
  • Size: 8.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.0rc1

File hashes

Hashes for observer-hooks-1.3.0.tar.gz
Algorithm Hash digest
SHA256 6c4a366c0d926201be93a25ee8322d8e7aab9b2120daaea3261b5afb7d29777f
MD5 a9038d9ccf5d92bdd1a9ccf379bab9ca
BLAKE2b-256 e30dbf4f1d7ed8307d1c88f9d5784b2d63b9a7e8a45cbe699185e40f8f937711

See more details on using hashes here.

File details

Details for the file observer_hooks-1.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for observer_hooks-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3fd8c490139693cde65941a7bcb26e45eca6485d7c17d1967f3fc518db105fc6
MD5 fb68f3c4f5a50a69136ff1a779b546fe
BLAKE2b-256 e9e3cb73c6a99e5b6cca6064a417bf55c3e03db4d0a2cf591efe3df691565192

See more details on using hashes here.

Supported by

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