diff --git a/ibis/common/dispatch.py b/ibis/common/dispatch.py index b023cab000b4..16563bd1bb4d 100644 --- a/ibis/common/dispatch.py +++ b/ibis/common/dispatch.py @@ -2,8 +2,6 @@ import abc import functools -import inspect -import re from collections import defaultdict from types import UnionType from typing import Union @@ -16,24 +14,6 @@ from ibis.util import import_object, unalias_package -def normalize(r: str | re.Pattern): - """Normalize a expression by wrapping it with `'^'` and `'$'`. - - Parameters - ---------- - r - The pattern to normalize. - - Returns - ------- - Pattern - The compiled regex. - - """ - r = getattr(r, "pattern", r) - return re.compile("^" + r.lstrip("^").rstrip("$") + "$") - - class SingleDispatch: def __init__(self, func, typ=None): self.lookup = {} @@ -142,70 +122,3 @@ def call(arg, *args, **kwargs): call.dispatch = dispatcher.dispatch call.register = dispatcher.register return call - - -class _MultiDict(dict): - """A dictionary that allows multiple values for a single key.""" - - def __setitem__(self, key, value): - if key in self: - self[key].append(value) - else: - super().__setitem__(key, [value]) - - -class DispatchedMeta(type): - """Metaclass that allows multiple implementations of a method to be defined.""" - - def __new__(cls, name, bases, dct): - namespace = {} - for key, value in dct.items(): - if len(value) == 1: - # there is just a single attribute so pick that - namespace[key] = value[0] - elif all(inspect.isfunction(v) for v in value): - # multiple functions are defined with the same name, so create - # a dispatcher function - first, *rest = value - func = SingleDispatch(first) - for impl in rest: - func.add(impl) - namespace[key] = func - elif all(isinstance(v, classmethod) for v in value): - first, *rest = value - func = SingleDispatch(first.__func__) - for impl in rest: - func.add(impl.__func__) - namespace[key] = classmethod(func) - elif all(isinstance(v, staticmethod) for v in value): - first, *rest = value - func = SingleDispatch(first.__func__) - for impl in rest: - func.add(impl.__func__) - namespace[key] = staticmethod(func) - else: - raise TypeError(f"Multiple attributes are defined with name {key}") - - return type.__new__(cls, name, bases, namespace) - - @classmethod - def __prepare__(cls, name, bases): - return _MultiDict() - - -class Dispatched(metaclass=DispatchedMeta): - """Base class supporting multiple implementations of a method. - - Methods with the same name can be defined multiple times. The first method - defined is the default implementation, and subsequent methods are registered - as implementations for specific types of the first argument. - - The constructed methods are equivalent as if they were defined with - `functools.singledispatchmethod` but without the need to use the decorator - syntax. The recommended application of this class is to implement visitor - patterns. - - Besides ordinary methods, classmethods and staticmethods are also supported. - The implementation can be extended to overload multiple arguments by using - `multimethod` instead of `singledispatchmethod` as the dispatcher. - """ diff --git a/ibis/common/tests/test_dispatch.py b/ibis/common/tests/test_dispatch.py index c6dde6157164..4b3a34ff5b7c 100644 --- a/ibis/common/tests/test_dispatch.py +++ b/ibis/common/tests/test_dispatch.py @@ -2,16 +2,8 @@ import collections import decimal -from typing import TYPE_CHECKING, Union -import pytest - -from ibis.common.dispatch import Dispatched, lazy_singledispatch - -# ruff: noqa: F811 -if TYPE_CHECKING: - import pandas as pd - import pyarrow as pa +from ibis.common.dispatch import lazy_singledispatch def test_lazy_singledispatch(): @@ -126,110 +118,3 @@ def _(a): assert foo({}) == "mapping" assert foo(mydict()) == "mydict" # concrete takes precedence assert foo(sum) == "callable" - - -class A: - pass - - -class B: - pass - - -class Visitor(Dispatched): - def a(self): - return "a" - - def b(self, x: int): - return "b_int" - - def b(self, x: str): - return "b_str" - - def b(self, x: Union[A, B]): - return "b_union" - - @classmethod - def c(cls, x: int, **kwargs): - return "c_int" - - @classmethod - def c(cls, x: str, a=0, b=1): - return "c_str" - - def d(self, x: int): - return "d_int" - - def d(self, x: str): - return "d_str" - - @staticmethod - def e(x: int): - return "e_int" - - @staticmethod - def e(x: str): - return "e_str" - - def f(self, df: dict): - return "f_dict" - - def f(self, df: pd.DataFrame): - return "f_pandas" - - def f(self, df: pa.Table): - return "f_pyarrow" - - -class Subvisitor(Visitor): - def b(self, x): - return super().b(x) - - def b(self, x: float): - return "b_float" - - @classmethod - def c(cls, x): - return super().c(x) - - @classmethod - def c(cls, s: float): - return "c_float" - - -def test_dispatched(): - v = Visitor() - assert v.a() == "a" - assert v.b(1) == "b_int" - assert v.b("1") == "b_str" - assert v.b(A()) == "b_union" - assert v.b(B()) == "b_union" - assert v.d(1) == "d_int" - assert v.d("1") == "d_str" - - w = Subvisitor() - assert w.b(1) == "b_int" - assert w.b(1.1) == "b_float" - - assert Visitor.c(1, a=0, b=0) == "c_int" - assert Visitor.c("1") == "c_str" - - assert Visitor.e("1") == "e_str" - assert Visitor.e(1) == "e_int" - - assert Subvisitor.c(1) == "c_int" - assert Subvisitor.c(1.1) == "c_float" - - assert Subvisitor.e(1) == "e_int" - - -def test_dispatched_lazy(): - pa = pytest.importorskip("pyarrow") - - empty_pyarrow_table = pa.Table.from_arrays([]) - empty_pandas_table = empty_pyarrow_table.to_pandas() - - v = Visitor() - assert v.f({}) == "f_dict" - assert v.f(empty_pyarrow_table) == "f_pyarrow" - assert v.f(empty_pandas_table) == "f_pandas"