@@ -80,12 +80,14 @@ def generic(f):
8080 # Dispatcher - this will replace the original f.
8181 @wraps (f )
8282 def multidispatch (* args , ** kwargs ):
83- def match (signature ):
84- # TODO: handle *args (bindings["vararg"])
85- # TODO: handle **kwargs (bindings["kwarg"])
83+ # signature comes from typing.get_type_hints.
84+ def match_argument_types (signature ):
85+ # TODO: handle *args (bindings["vararg"], bindings["vararg_name"])
86+ # TODO: handle **kwargs (bindings["kwarg"], bindings["kwarg_name"])
8687 # TODO: handle advanced features such as Sequence[int], Optional[str], ...
8788 for parameter , value in bindings ["args" ].items ():
88- p = signature [parameter ] # TODO: what if parameter is not there? TypeError?
89+ assert parameter in signature # resolve_bindings should already TypeError when not.
90+ p = signature [parameter ]
8991 if p is not typing .Any and not isinstance (value , p ):
9092 return False
9193 return True
@@ -98,7 +100,7 @@ def methods():
98100 bindings = resolve_bindings (method , * args , ** kwargs )
99101 except TypeError : # arity mismatch, so this method can't be the one the call is looking for.
100102 continue
101- if match (signature ):
103+ if match_argument_types (signature ):
102104 return method (* args , ** kwargs )
103105
104106 # No match, report error.
@@ -129,7 +131,7 @@ def format_method(method): # Taking a page from Julia and some artistic liberty
129131
130132 # fullname = "{}.{}".format(f.__module__, f.__qualname__)
131133 multidispatch ._registry = []
132- def register (function ):
134+ def register (thecallable ):
133135 """Decorator. Register a new method for this generic function.
134136
135137 The method must have type annotations for all of its parameters;
@@ -138,11 +140,11 @@ def register(function):
138140 # Using `inspect.signature` et al., we could auto-`Any` parameters
139141 # that have no type annotation, but that would likely be a footgun.
140142 # So we require a type annotation for each parameter.
141- signature = typing .get_type_hints (function )
143+ signature = typing .get_type_hints (thecallable )
142144
143145 # Verify that the method has a type annotation for each parameter.
144- f , _ = _getfunc (function )
145- params = inspect .signature (f ).parameters
146+ function , _ = _getfunc (thecallable )
147+ params = inspect .signature (function ).parameters
146148 allparamnames = [p .name for p in params .values ()]
147149 if not all (name in signature for name in allparamnames ):
148150 failures = [name for name in allparamnames if name not in signature ]
@@ -152,8 +154,10 @@ def register(function):
152154 ", " .join (wrapped ))
153155 raise TypeError (msg )
154156
155- multidispatch ._registry .append ((function , signature ))
156- return multidispatch # Replace the function with the dispatcher for this generic function.
157+ multidispatch ._registry .append ((thecallable , signature ))
158+ # TODO: Does this work properly with instance methods and class methods?
159+ # TODO: (At the moment, probably not. Just might, if `self` has a type annotation.)
160+ return multidispatch # Replace the callable with the dispatcher for this generic function.
157161 multidispatch .register = register # publish the @f.register decorator
158162
159163 return multidispatch
0 commit comments