Skip to content

Commit

Permalink
Merge pull request #61 from erezsh/qualname
Browse files Browse the repository at this point in the history
Bugfix in dispatch: Now using qualified name, so methods with same si…
  • Loading branch information
erezsh authored Aug 23, 2024
2 parents 1e7d6bd + 8b11135 commit 4a7daca
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 32 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,21 @@ assert mul([1, 2], [3, 4]) == [3, 8] # list, list
Dispatch can also be used for extending the dataclass builtin `__init__`:

```python
@dataclass(frozen=False)
@dataclass
class Point:
x: int = 0
y: int = 0

@md
def __init__(self, points: list | tuple):
self.x, self.y = points
# Call default constructor
self.__init__(*points)

@md
def __init__(self, points: dict):
self.x = points['x']
self.y = points['y']
# Call default constructor
self.__init__(points['x'], points['y'])

# Test constructors
p0 = Point() # Default constructor
assert p0 == Point(0, 0) # Default constructor
Expand Down
10 changes: 9 additions & 1 deletion runtype/dataclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Enhances Python's built-in dataclass, with type-checking and extra ergonomics.
"""

import sys
import random
from copy import copy
import dataclasses
Expand All @@ -28,6 +29,7 @@ def dataclass_transform(*a, **kw):
Skip = object()
MAX_SAMPLE_SIZE = 16

IS_PY310 = sys.version_info >= (3, 10)

class NopTypeCaster(ATypeCaster):
cache: Dict[int, Union[PythonType, type]] = {}
Expand Down Expand Up @@ -370,11 +372,17 @@ def __post_init__(self):
# __init__ may have been generated by the dataclass function
if hasattr(c, "__init__"):
# We will add it to the dispatch
c.__init__ = init_dispatcher(c.__init__)
c.__init__ = init_dispatcher(_fix_qualname(c.__init__, cls))
else:
c.__init__ = init_f
return c

def _fix_qualname(f, cls):
if not IS_PY310:
# XXX Hack for old Python versions -
# Dataclasses generated __init__ with wrong __qualname__
f.__qualname__ = f"{cls.__qualname__}.{f.__name__}"
return f

def _dataclass_getstate(self):
return [getattr(self, f.name) for f in dataclasses.fields(self)]
Expand Down
2 changes: 1 addition & 1 deletion runtype/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def __call__(self, func=None, *, priority=None):
"Must either provide a function to decorate, or set a priority"
)

fname = func.__name__
fname = func.__qualname__
try:
tree = self.fname_to_tree[fname]
except KeyError:
Expand Down
30 changes: 6 additions & 24 deletions runtype/pytypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@



py38 = sys.version_info >= (3, 8)


class LengthMismatchError(TypeMismatchError):
pass

Expand Down Expand Up @@ -486,21 +483,6 @@ def cast_from(self, obj):
}


if sys.version_info >= (3, 7):
origin_list = list
origin_dict = dict
origin_tuple = tuple
origin_set = set
origin_frozenset = frozenset
else:
origin_list = typing.List
origin_dict = typing.Dict
origin_tuple = typing.Tuple
origin_set = typing.Set
origin_frozenset = typing.FrozenSet



class ATypeCaster(ABC):
@abstractmethod
def to_canon(self, t: typing.Any): ...
Expand Down Expand Up @@ -575,19 +557,19 @@ def _to_canon(self, t):

args = getattr(t, '__args__', None)

if origin is origin_list:
if origin is list:
x ,= args
return List[to_canon(x)]
elif origin is origin_set:
elif origin is set:
x ,= args
return Set[to_canon(x)]
elif origin is origin_frozenset:
elif origin is frozenset:
x ,= args
return FrozenSet[to_canon(x)]
elif origin is origin_dict:
elif origin is dict:
k, v = args
return Dict[to_canon(k), to_canon(v)]
elif origin is origin_tuple:
elif origin is tuple:
if not args:
return Tuple
if Ellipsis in args:
Expand All @@ -603,7 +585,7 @@ def _to_canon(self, t):
elif origin is abc.Callable or origin is typing.Callable:
return Callable[ProductType(to_canon(x) for x in args[:-1]), to_canon(args[-1])]
return Callable # TODO
elif py38 and origin is typing.Literal:
elif origin is typing.Literal:
return OneOf(args)
elif origin is abc.Mapping or origin is typing.Mapping:
k, v = args
Expand Down
13 changes: 13 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,19 @@ def f(t: int):
assert f(2) == "int"
assert f(None) == "none"

def test_qualified_name(self):
md = Dispatch()

class A:
@md
def a(self, points: list):
...

class B:
@md
def a(self, points: list):
...


class TestDataclass(TestCase):
def setUp(self):
Expand Down

0 comments on commit 4a7daca

Please sign in to comment.