Skip to main content

Dispatchlib

Dispatchlib is a metaprogramming library for creating single-dispatched generic functions, similar to functools.singledispatch, with a few additional goodies:

  • Supports type annotations that utilize Python's builtin typing module.
  • Lazy-loads string annotations (i.e. types declared via string).
  • Priority dispatching: you can set the "priority" of an overloaded implementation. Basically dispatchlib.dispatch is a big ol if elif elif factory, and the order is determined by @f.register(priority=?)
  • A "metadispatch" that lets you overload the dispatcher itself. (Hard to explain; see example for clarification.)

Dispatchlib's dispatch decorator is not a strict superset of functools.singledispatch. There are a few things in functools.singledispatch that are not in single:

  • dispatchlib.dispatch requires that you always call the register decorator like this: @f.regsiter() whereas functools.singledispatch. The reason why is because dispatchlib.dispatch can dispatch not just based on types but also based on functions , so the first arg in the register decorator being a function is not sufficient to conclude whether it's being called or not prior to decoration.
  • functools.singledispatch supports dynamic polymorphism using __mro__, whereas dispatchlib.dispatch dispatches based on running a check for each overloaded implementation; by default, checks are run in FIFO order, with the exception of the "base" function, which is always run last.
  • functools.singledispatch is faster.

Install

pip install dispatchlib

Examples

Basic Example 1

from dispatchlib import dispatch
from typing import Any, Dict, List

@dispatch
def mul_by_two(x: Any):
    """Multiply numbers by two"""
    return x * 2

# Support for builtin typing module:

@mul_by_two.register()
def _(x: Dict[Any, int]):
    return {k: v * 2 for k, v in x.items()}

@mul_by_two.register()
def _(x: List[int]):
    return [i * 2 for i in x]

# lazy-loaded type hints:

@mul_by_two.register()
def _(x: 'pandas.DataFrame'):
    return x.select_dtypes(include='number') * 2

# Assert it all works as intended:

assert mul_by_two(3) == 6
assert mul_by_two([2, 3, 4]) == [4, 6, 8]
assert mul_by_two({'a': 2, 'b': 3}) == {'a': 4, 'b': 6}

# Testing lazy-load functionality:

try:
    import pandas as pd
except ModuleNotFoundError:
    pass
else:
    print(mul_by_two(pd.DataFrame({
        'a': range(10),
        'b': ['exclude me'] * 10
    })))

Basic Example 2

from dispatchlib import Dispatcher
from types import FunctionType

# You can call Dispatcher() to skip a implementation
# It's also useful for type-checking.

always_return_figure = Dispatcher()

assert isinstance(always_return_figure, Dispatcher)
assert isinstance(always_return_figure, FunctionType)

import matplotlib
import matplotlib.pyplot as plt


# Implementations can be chained together:

@always_return_figure.register('matplotlib.pyplot.Axes')
@always_return_figure.register('matplotlib.pyplot.Subplot')
def return_figure1(x):
    return x.figure

@always_return_figure.register('matplotlib.pyplot.Figure')
def return_figure2(x):
    return x


fig, ax = plt.subplots()

assert always_return_figure(ax) == always_return_figure(fig)

plt.close(fig)

Metadispatch example

from dispatchlib import dispatch
from dispatchlib import metadispatch

class HTTPException(Exception):
    status_code: int

class PageNotFoundError(HTTPException):
    status_code: int = 404

class ForbiddenError(HTTPException):
    status_code: int = 403

custom_metadispatcher = metadispatch()

# This metadispatcher knows how to interpret when a user registers a function
# with an integer: The integer represents an HTTP status code.

@custom_metadispatcher.register(lambda val: isinstance(val, int))
def _(val: int):
    def checker(x: HTTPException):
        return x.status_code == val
    return checker

@dispatch(metadispatcher=custom_metadispatcher)
def status_code_message(code):
    raise TypeError('Unknown status code.')

@status_code_message.register(404)
def _(code):
    return 'Page not found.'

@status_code_message.register(403)
def _(code):
    return 'Forbidden.'

assert status_code_message(PageNotFoundError()) == 'Page not found.'
assert status_code_message(ForbiddenError()) == 'Forbidden.'

Warning

I'm currently using Dispatchlib as part of another larger project. Dispatchlib exists separately of that project because I think it makes sense as its own separate thing. With that said, I plan on doing some bugfixing of use-cases as that project unfolds. So for this version of dispatchlib:

  • There may be some bugs.
  • The API may break between changes.

When this message is no longer here, consider the module more stable.

I'm interested to

Todo

  • create dispatchmethod akin to singledispatchmethod.
  • decorator for making functions and methods dispatchable without immediately registering them to a dispatcher.
  • support MRO for dispatching somehow.
  • make code faster.
  • make code more DRY via abstracting out the shared stuff in both metadispatch and dispatch.
  • flesh out docs.
  • add unit-tests.

Metadata

Release files for dispatchlib 0.0.1

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

Source distribution (sdist)

Source distribution for dispatchlib 0.0.1
File Size Uploaded
dispatchlib-0.0.1.tar.gz 3.9 kB Details

Release files / dispatchlib-0.0.1.tar.gz

Download URL dispatchlib-0.0.1.tar.gz
Size 3.9 kB
Tags Source
SHA-256 checksum
How to use checksums
61e77a5ef4bf7e2566fecb21c6575e96564e2f55c4904a1acb425ae231be7719
BLAKE2b-256 checksum
How to use checksums
2bc4a222801b827f61207d5a39bdec5d4d70e32efa3affa0af5e290395673347
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/49.6.0 requests-toolbelt/0.9.1 tqdm/4.49.0 CPython/3.8.5

Release history Release notifications | RSS feed

This release

0.0.1 This release

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