Skip to main content

observed allows you to to sign up functions or methods to "observe" other functions or methods:

from observed import observable_function

@observable_function
def observed_func(arg):
    print("observed_func: %s"%(arg,))

def observer_func(arg):
    print("observer_func: %s"%(arg,))

observed_func.add_observer(observer_func)
observed_func('banana')

>>> observed_func: banana
>>> observer_func: banana

You can also register observers for bound methods:

from observed import observable_method

class Foo:
    def __init__(self, name):
        self.name = name

    @observable_method()
    def bar(self, arg):
        print("Object %s invoked bar with arg='%s'"%(self.name, arg))

    def baz(self, arg):
        print("Object %s invoked baz with arg='%s'"%(self.name, arg))

def callback(arg):
    print("callback was invoked with arg='%s'"%(arg,))

a = Foo('a')
b = Foo('b')
a.bar.add_observer(b.bar)
a.bar.add_observer(b.baz)
a.bar.add_observer(callback)
a.bar('banana')

>>> Object a invoked bar with arg='banana'
>>> Object b invoked bar with arg='banana'
>>> Object b invoked baz with arg='banana'
>>> callback was invoked with arg='banana'

You can ask that the observed object pass itself as the first argument whenever it calls observers:

from observed import observable_function

@observable_function
def observed_func():
    print("observed_func: I was called")

def observer_func(observed):
    print("observer_func: %s called me"%(observed.__name__,))

observed_func.add_observer(observer_func, identify_observed=True)
observed_func()

>>> observed_func: I was called
>>> observer_func: observed_func called me

When observed bound methods pass themselves as the observed object, keep in mind that you can always access the associated instance via __self__:

from observed import observable_method

class Foo:
    def __init__(self, name):
        self.name = name

    @observable_method()
    def bar(self):
        print("Object %s invoked bar"%(self.name,))

def callback(observed):
    print("callback was invoked by='%s'"%(observed.__self__.name,))

a = Foo('a')
a.bar.add_observer(callback, identify_observed=True)
a.bar()

>>> Object a invoked bar
>>> callback was invoked by a

Notable features include:

  • A function or bound method is not kept alive just because it is observing something else. This is because the observed object does not keep any strong references to the observing objects. In CPython this means that your observers are automatically detached whenever the reference count to that observer goes to zero.

  • The observable_method decorator can be used on methods in classes which are unhashable types, and can be used on an arbitrary number of methods in each class...

  • ...but the descriptor which handles observable_method does not paste any data onto the instances it manages. There is zero chance of name collision on the observed instances.

Installation

observed exists on the python package index, so you can do pip install observed to install it. Alternatively, you can download the source distribution and in the root directory of the distribution do

$ python setup.py install

News

See the file NEWS for the user-visible changes from previous releases.

License

See LICENSE.txt.

Downloading

observed can be obtained from the python package index at or via GitHub.

Documentation

Basic usage is illustrated at the top of this file. Further examples are given in example.py.

Development

observed development is hosted on github. The current working repository is given in the Downloading section above.

Bug Reporting

Please submit bug tickets on the GitHub tracking system.

Release files for observed 0.5.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for observed 0.5.3
File Size Uploaded
observed-0.5.3.tar.gz 8.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for observed 0.5.3
File Interpreter ABI Platform
observed-0.5.3-py3-none-any.whl Python 3 none any Details

Total release size: 18.3 kB

Release files / observed-0.5.3.tar.gz

Download URL observed-0.5.3.tar.gz
Size 8.8 kB
Tags Source
SHA-256 checksum
How to use checksums
b7e925ef174f6b8587b6d0890958de95da0203c874f968397dbd1ce24002fef6
BLAKE2b-256 checksum
How to use checksums
a12194244e118a162a320b19cc4d96d5398ebdf8482aa39a61a8a10a13403307
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.6.5

Release files / observed-0.5.3-py3-none-any.whl

Download URL observed-0.5.3-py3-none-any.whl
Size 9.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aabf021739cb0c79aca2cfd97caed6a1e0146883ec56dcf15bfa9cdb83860a88
BLAKE2b-256 checksum
How to use checksums
87afff0eb909e299225d4c750551893270863ba1b61f7280c8d7b6a8e4d61b36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.6.5

Release history Release notifications | RSS feed

This release

0.5.3 This release

2 release files

0.5.1

2 release files

0.4

1 release file

0.3

1 release file

0.2.4

1 release file

0.2.2

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page