elasticai.creator.function_dispatch#

Module Contents#

Classes#

Registrar

A decorator to register values. Keys are derived from values or provided explicitly.

KeyedDispatcher

Automatically dispatch registered functions based on a key derived from the arguments.

KeyedDispatcherWithRegistrars

Automatically dispatch registered functions based on a key derived from the arguments.

KeyedDispatcherForDescriptor

KeyedDispatcherDescriptor

Automatically dispatch registered functions based on a key derived from the arguments.

Functions#

registrar_method

Turn a method into a registrar.

registrar

Turn a function into a registrar.

create_keyed_dispatch

The created decorator allows to register functions that will be passed to the decorated function based on a key.

dispatch_method

A decorator to create a KeyedDispatcherDescriptor for methods.

API#

class elasticai.creator.function_dispatch.Registrar[source]#

Bases: typing.Protocol

A decorator to register values. Keys are derived from values or provided explicitly.

elasticai.creator.function_dispatch.registrar_method(wrapped: collections.abc.Callable[Concatenate[elasticai.creator.function_dispatch.registrar_method.Owner, elasticai.creator.function_dispatch.registrar_method.K | None, elasticai.creator.function_dispatch.registrar_method.V], elasticai.creator.function_dispatch.registrar_method.R]) elasticai.creator.function_dispatch.Registrar[elasticai.creator.function_dispatch.registrar_method.K, elasticai.creator.function_dispatch.registrar_method.V, elasticai.creator.function_dispatch.registrar_method.R][source]#

Turn a method into a registrar.

elasticai.creator.function_dispatch.registrar(wrapped: collections.abc.Callable[Concatenate[elasticai.creator.function_dispatch.registrar.K | None, elasticai.creator.function_dispatch.registrar.V], elasticai.creator.function_dispatch.registrar.R]) elasticai.creator.function_dispatch.Registrar[elasticai.creator.function_dispatch.registrar.K, elasticai.creator.function_dispatch.registrar.V, elasticai.creator.function_dispatch.registrar.R][source]#

Turn a function into a registrar.

class elasticai.creator.function_dispatch.KeyedDispatcher[source]#

Bases: typing.Protocol

Automatically dispatch registered functions based on a key derived from the arguments.

register(key: K, fn: collections.abc.Callable[P2, R1], /) collections.abc.Callable[P2, R1][source]#
override(key: K, fn: collections.abc.Callable[P2, R1], /) collections.abc.Callable[P2, R1][source]#
property registry: collections.abc.Mapping[K, collections.abc.Callable[P2, R1]]#
__call__(*args: P1.args, **kwargs: P1.kwargs) R2[source]#
class elasticai.creator.function_dispatch.KeyedDispatcherWithRegistrars[source]#

Bases: typing.Protocol

Automatically dispatch registered functions based on a key derived from the arguments.

property register: elasticai.creator.function_dispatch.Registrar[K, [collections.abc.Callable[P2, R1]], collections.abc.Callable[P2, R1]]#
property override: elasticai.creator.function_dispatch.Registrar[K, [collections.abc.Callable[P2, R1]], collections.abc.Callable[P2, R1]]#
property registry: collections.abc.Mapping[K, collections.abc.Callable[P2, R1]]#
__call__(*args: P1.args, **kwargs: P1.kwargs) R2[source]#
elasticai.creator.function_dispatch.create_keyed_dispatch(key_from_obj: collections.abc.Callable[elasticai.creator.function_dispatch.create_keyed_dispatch.P1, elasticai.creator.function_dispatch.create_keyed_dispatch.K], key_from_fn: collections.abc.Callable[[collections.abc.Callable[elasticai.creator.function_dispatch.create_keyed_dispatch.P2, elasticai.creator.function_dispatch.create_keyed_dispatch.R1]], elasticai.creator.function_dispatch.create_keyed_dispatch.K]) collections.abc.Callable[[collections.abc.Callable[Concatenate[collections.abc.Callable[elasticai.creator.function_dispatch.create_keyed_dispatch.P2, elasticai.creator.function_dispatch.create_keyed_dispatch.R1], elasticai.creator.function_dispatch.create_keyed_dispatch.P1], elasticai.creator.function_dispatch.create_keyed_dispatch.R2]], elasticai.creator.function_dispatch.KeyedDispatcherWithRegistrars[elasticai.creator.function_dispatch.create_keyed_dispatch.P1, elasticai.creator.function_dispatch.create_keyed_dispatch.P2, elasticai.creator.function_dispatch.create_keyed_dispatch.R1, elasticai.creator.function_dispatch.create_keyed_dispatch.R2, elasticai.creator.function_dispatch.create_keyed_dispatch.K]][source]#

The created decorator allows to register functions that will be passed to the decorated function based on a key.

This is useful to create functions that dispatch based on some property of the arguments. Additionally, it allows to override previously registered functions. The decorated function will receive the dispatched function as its first argument, thus allowing clients to decide how to call the dispatched function.

class elasticai.creator.function_dispatch.KeyedDispatcherForDescriptor(owner: Owner, registry_name: str, key_from_obj: str, fn: collections.abc.Callable[Concatenate[Owner, collections.abc.Callable[P2, R1], P1], R2])[source]#

Bases: elasticai.creator.function_dispatch.KeyedDispatcher[elasticai.creator.function_dispatch.KeyedDispatcherForDescriptor.P1, elasticai.creator.function_dispatch.KeyedDispatcherForDescriptor.P2, elasticai.creator.function_dispatch.KeyedDispatcherForDescriptor.R1, elasticai.creator.function_dispatch.KeyedDispatcherForDescriptor.R2, elasticai.creator.function_dispatch.KeyedDispatcherForDescriptor.K]

__slots__#

(‘_owner’, ‘_key_from_obj’, ‘_registry_name’, ‘_fn’)

property registry: collections.abc.Mapping[K, collections.abc.Callable[P2, R1]]#
register(key: K, fn: collections.abc.Callable[P2, R1]) collections.abc.Callable[P2, R1][source]#
override(key: K, fn: collections.abc.Callable[P2, R1]) collections.abc.Callable[P2, R1][source]#
__call__(*args: P1.args, **kwargs: P1.kwargs) R2[source]#
class elasticai.creator.function_dispatch.KeyedDispatcherDescriptor(fn: collections.abc.Callable[Concatenate[Owner, collections.abc.Callable[P2, R1], P1], R2] | None = None)[source]#

Automatically dispatch registered functions based on a key derived from the arguments.

Opposed to its function counterpart, this descriptor is intended to be used as a class attribute.

Use the decorators as follows

  • key_from_args on a method of the owning class to define how to derive the key from the arguments

  • dispatch_for on a method of the owning class to define the dispatching behavior. The method will receive the dispatched function as its first argument followed by the original arguments.

Initialization

__slots__#

(‘_key_from_obj’, ‘_registry’, ‘_name’, ‘_fn’)

__get__(instance: Owner | None, owner: type[Owner]) elasticai.creator.function_dispatch.KeyedDispatcher[P1, P2, R1, R2, K][source]#
key_from_args(key_from_obj: collections.abc.Callable[Concatenate[Owner, P1], K]) collections.abc.Callable[Concatenate[Owner, P1], K][source]#
__set_name__(instance: Owner, name: str) None[source]#
dispatch_for(fn: collections.abc.Callable[Concatenate[Owner, collections.abc.Callable[P2, R1], P1], R2]) Self[source]#
elasticai.creator.function_dispatch.dispatch_method(_: type[elasticai.creator.function_dispatch.dispatch_method.K]) collections.abc.Callable[[collections.abc.Callable[Concatenate[elasticai.creator.function_dispatch.dispatch_method.Owner, collections.abc.Callable[elasticai.creator.function_dispatch.dispatch_method.P2, elasticai.creator.function_dispatch.dispatch_method.R1], elasticai.creator.function_dispatch.dispatch_method.P1], elasticai.creator.function_dispatch.dispatch_method.R2]], elasticai.creator.function_dispatch.KeyedDispatcherDescriptor[elasticai.creator.function_dispatch.dispatch_method.P1, elasticai.creator.function_dispatch.dispatch_method.P2, elasticai.creator.function_dispatch.dispatch_method.R1, elasticai.creator.function_dispatch.dispatch_method.R2, elasticai.creator.function_dispatch.dispatch_method.Owner, elasticai.creator.function_dispatch.dispatch_method.K]][source]#

A decorator to create a KeyedDispatcherDescriptor for methods.

This often has the advantage of not needing to specify the generic parameters explicitly. However, the type of keys cannot be inferred automatically, this is why it needs to be provided as an argument to the decorator.

Note: The ParamSpec **P will narrow down to the most concrete type. Thus if you decorate a method with a signature like

@dispatch_method(str)
def call(self, fn: Callable[[str], str], item: str) -> str:
    ...

The type checker will assume that P is (item: str). This means that annotating another method that should be compatible with this dispatcher might (rightly) lead to type errors. A registration method could e.g., look like this:

def register(self, name: str | None, fn: Callable[[str], str]) -> Callable[[str], str]:
    if name is None:
        name = fn.__name__
    self.call.register(name, fn)
    return fn

However, this will not pass type checking, as the checker expects the signature to be Callable[[Arg('item', str)], str]. Sadly there is no way to express this inline in current python versions. You have the following options - make the arguments more generic (e.g., using Any) and loose type safety - use positional only arguments in the call method like so: python       @dispatch_method(str)       def call(self, fn: Callable[[str], str], item: str, /) -> str:             ...       - explicitly annotate the descriptor attribute in the class like so: ```python class MyClass: call: KeyedDispatcherDescriptor[[str], str, str, “MyClass”, str] = KeyedDispatcherDescriptor()

Using a protocol to define the expected signature of the registered functions will not help here, as the type checker will not be able to map the protocol to the ParamSpec P and return value R1.