Skip to content

Instantly share code, notes, and snippets.

@bigjason
Created April 23, 2019 23:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bigjason/3b1ae586fe81556d273a7e8890168150 to your computer and use it in GitHub Desktop.
Save bigjason/3b1ae586fe81556d273a7e8890168150 to your computer and use it in GitHub Desktop.
Partial function application supporting any arg order (WIP)
_sentinal = object()
@dataclass(frozen=True)
class Placeholder(DataClassEnrichment):
keyword: Optional[str] = None
default: Optional[Any] = _sentinal
annotation: Type = Any
def type_repr_of(self, obj):
"""Return the repr() of an object, special-casing types (internal helper).
If obj is a type, we return a shorter version than the default
type.__repr__, based on the module and qualified name, which is
typically enough to uniquely identify a type. For everything
else, we fall back on repr(obj).
"""
if isinstance(obj, type):
if obj.__module__ == 'builtins':
return obj.__qualname__
return f'{obj.__module__}.{obj.__qualname__}'
if obj is ...:
return ('...')
if isinstance(obj, FunctionType):
return obj.__name__
return repr(obj)
def _as_arg(self):
assert self.keyword is not None
assert self.keyword.strip() != ''
result = f"{self.keyword}: {self.type_repr_of(self.annotation)}"
if self.default is _sentinal:
result += f" = {repr(self.default)}"
return result
Arg = Placeholder('__')
__ = Arg
def partlet(func: Callable[..., Any], *args_template, **kwargs_template):
"""
>>> checker = partlet(isinstance, __, str)
>>> checker("Asd")
True
>>> checker(22)
False
"""
args = list(copy.deepcopy(args_template))
kwargs = copy.deepcopy(kwargs_template)
parameters = []
i = 0
for f in args:
if isinstance(f, Placeholder):
if f.keyword == __.keyword or f.keyword is None:
new = f.replace(keyword=f"arg{i}")
args[args.index(f)] = new
i += 1
else:
new = f
parameters.append(new)
def wrapped(*args_internal, **kwargs_internal):
vals = deque(args_internal)
new_args = deque()
new_kwargs = copy.deepcopy(kwargs)
new_kwargs.update(kwargs_internal)
for val in args:
if isinstance(val, Placeholder):
try:
new_args.append(vals.popleft())
except IndexError as exc:
raise TypeError(f"Missing argument {val.keyword}") from exc
else:
new_args.append(val)
return func(*new_args, **kwargs)
wrapped.__doc__ = f"""
Has an effective signature similar to:
def {func.__name__}({', '.join((f._as_arg() for f in parameters))}):
...
"""
wrapped.__name__ = func.__name__
return wrapped
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment