API Reference

Note

This page is WIP, PRs are welcome!

class oop_ext.foundation.callback.Callback[source]

Object that provides a way for others to connect in it and later call it to call those connected.

Callbacks are stored as weakrefs to objects connected.

Determining kind of callable (Python 3)

Many parts of callback implementation rely on identifying the kind of callable: is it a free function? is it a function bound to an object?

Below there is a table to help understand how different objects are classified:

                    |has__self__|has__call__|has__call__self__|isbuiltin|isfunction|ismethod
--------------------|-----------|-----------|-----------------|---------|----------|--------
free function       |False      |True       |True             |False    |True      |False
bound method        |True       |True       |True             |False    |False     |True
class method        |True       |True       |True             |False    |False     |True
bound class method  |True       |True       |True             |False    |False     |True
function object     |False      |True       |True             |False    |False     |False
builtin function    |True       |True       |True             |True     |False     |False
object              |True       |True       |True             |True     |False     |False
custom object       |False      |False      |False            |False    |False     |False
string              |False      |False      |False            |False    |False     |False

where rows are:

def free_fn(foo):
    # `free function`
    pass


class Foo:
    def bound_fn(self, foo):
        pass


class Bar:
    @classmethod
    def class_fn(cls, foo):
        pass


class ObjectFn:
    def __call__(self, foo):
        pass


foo = Foo()  # foo is `custom object`, foo.bound_fn is `bound method`
bar = Bar()  # Bar.class_fn is `class method`, bar.class_fn is `bound class method`

object_fn = ObjectFn()  # `function object`

obj = object()  # `object`
string = "foo"  # `string`
builtin_fn = string.split  # `builtin function`

And where columns are:

  • isbuiltin: inspect.isbuiltin

  • isfunction: inspect.isfunction

  • ismethod: inspect.ismethod

  • has__self__: hasattr(obj, ‘__self__’)

  • has__call__: hasattr(obj, ‘__call__’)

  • has__call__self__: hasattr(obj.__call__, ‘__self__’) if hasattr(obj, ‘__call__’) else False

Note

After an internal refactoring, __slots__ has been added, so, it cannot have weakrefs to it (but as it stores weakrefs internally, that shouldn’t be a problem). If weakrefs are really needed, __weakref__ should be added to the slots.

Contains(func: Callable[[...], Any], extra_args: Sequence[object] = ()) bool[source]
Parameters:

func (object) – The function that may be contained in this callback.

Return type:

bool

Returns:

True if the function is already registered within the callbacks and False otherwise.

Register(func: Callable[[...], Any], extra_args: Sequence[object] = ()) _UnregisterContext[source]

Registers a function in the callback.

Parameters:
  • func – Method or function that will be called later.

  • extra_args – Arguments that will be passed automatically to the passed function when the callback is called.

Returns:

A context which can be used to unregister this call.

The context object provides this low level functionality, if you are registering many callbacks at once and plan to unregister them all at the same time, consider using Callbacks instead.

Unregister(func: Callable[[...], Any], extra_args: Sequence[object] = ()) None[source]

Unregister a function previously registered with Register.

Parameters:

func (object) – The function to be unregistered.

UnregisterAll() None[source]

Unregisters all functions

class oop_ext.foundation.callback.Callbacks[source]

Holds created callbacks, making it easy to disconnect later.

This class provides two methods of operation:

  • Before() and After():

    This provides connection support for arbitrary functions and methods, similar to mocking them.

  • Register():

    Registers a function into a Callback, making the callback call the registered function when it gets itself called.

In both modes, RemoveAll() can be used to unregister all callbacks.

The class can also be used in context-manager form, in which case all callbacks are unregistered when the context-manager ends.

Note

This class keeps a strong reference to the callback and the sender, thus they won’t be garbage-collected while still connected.

After(sender: T, callback: Callable, *, sender_as_parameter: bool = False) T[source]

Same as Before(), but will call the callback after the sender function has been called.

Before(sender: T, callback: Callable, *, sender_as_parameter: bool = False) T[source]

Registers a callback to be executed before an arbitrary function.

Example:

class C:
    def foo(self, x): ...

def callback(x): ...


Before(C.foo, callback)

The call above will result in callback to be called for every instance of C.

Register(callback: Callback, func: Callable) None[source]

Registers the given function into the given callback.

This will automatically unregister the function from the given callback when Callbacks.RemoveAll() is called or the context manager ends in the context manager form.

RemoveAll() None[source]

Remove all registered functions, either from Before(), After(), or Register().

class oop_ext.interface.Interface(class_: ~typing.Any = <object object>)[source]

Base class for interfaces.

A interface describes a behavior that some objects must implement.

TypeCheckingSupport

New in version 1.1.0.

Interfaces that which to support static type checkers such as mypy also need to subclass from this class:

from oop_ext.interface import Interface, TypeCheckingSupport


class IDataSaver(Interface, TypeCheckingSupport):
    ...

The TypeCheckingSupport exists solely for the benefit of type checkers, and has zero runtime cost associated with it.

oop_ext.interface.ImplementsInterface(*interfaces: Any, no_check: bool = False) Callable[[T], T][source]

Make sure a class implements the given interfaces. Must be used in as class decorator:

@ImplementsInterface(IFoo)
class Foo(object):
    ...
Parameters:

no_check – If True, does not check if the class implements the declared interfaces during import time.

oop_ext.interface.GetProxy(interface: Type[Any], obj: T) T[source]

Obtains a proxy object for obj, which contains only methods and attributes declared in interface.

Usage:

def run_simulation(params: SimulationParameters, saver: IDataSaver) -> None:
    data = calculate(params)
    proxy = GetProxy(IDataSaver, saver)
    proxy.save(data)

Note however this is redundant when used with type checkers: saver: IDataSaver already tells the type checker to only allow access to legal members. This is useful however when type annotating legacy code which doesn’t have any type annotations and makes use of the runtime mechanism to ensure interface compliance.

Note

As of mypy 0.812, there’s a bug that prevents GetProxy from being properly type annotated. Hopefully this will be improved in the future.