-
Suggestion
-
Resolution: Unresolved
-
P3: Somewhat important
-
None
-
None
-
None
To be clear, I don't think this should replace Slot(), but could be a handy syntax for people using PySide with Python 3
Instead of this:
@Slot(int, result=int) @Slot(str, result=str) def my_func(arg): pass
You could annotate like this:
@aslot def my_func(arg: int) -> int: pass @my_func.overload def my_func(arg: str) -> str: ...
Additional support could hypothetically be made for dealing with things from typing, like handling List[str] for example.
Here is a prototype pure-python implementation. It is ported over from a PyQt-based version I made back on the PySide2 GitHub repo, and haven't tested it too closely:
from inspect import getfullargspec from PySide2.QtCore import Slot class _OverloadedSlotPlaceholder: def __init__(self, name, original_name): self.name = name self.original_name = original_name def __repr__(self): return ('<placeholder slot {name} for function {original_name}>' .format(name=self.name, original_name=self.original_name)) def _build_arguments(func, original_func=None): argspec = getfullargspec(func) args = argspec.args annotations = argspec.annotations slot_args = [] slot_kwargs = {} if 'return' in annotations: slot_kwargs['result'] = annotations['return'] if original_func and func.__name__ != original_func.__name__: slot_kwargs['name'] = func.__name__ gap = False for index, arg in enumerate(args): # Let the first arg pass by unannotated, as it may be the 'self' # argument of a function. Static methods can't be used as slots anyways if index == 0 and arg not in annotations: continue if arg in annotations and not gap: slot_args.append(annotations[arg]) elif arg not in annotations: gap = True elif arg in annotations and gap: raise TypeError('Type annotations must be in a continuous row - an argument before "{argument}" is missing' .format(argument=arg)) return slot_args, slot_kwargs def slot(func): """ A special Python 3-only Qt slot decorator, taking advantage of function annotations to provide the types for arguments. It's just syntactic sugar for the slot decorators that already come with the Python Qt bindings. This has **no effect whatsoever** on the Python side of things - it does not do type checking, it only registers a function and the types its arguments take with Qt's Meta Object system. Use like so: @slot def my_function(self, x: int, y: int) -> int: return x ** y You can also overload a function by doing this: @slot def overloaded_func(self, output=None: str): print(output) @overloaded_func.overload def overloaded_func(self, output: int): ... # And an overload for calling it with no arguments, so it will fall back # on the default argument. @overloaded_func.overload def overloaded_func(self): ... Note: you cannot set different default arguments in the overloads, you may only set a function's default arguments in the main declaration. The function body on overloads is completely ignored, so you can just use ellipses (`...`) or `pass` to fill in the body. """ slot_args, slot_kwargs = _build_arguments(func) Slot(*slot_args, **slot_kwargs)(func) def overload(new_func): slot_args, slot_kwargs = _build_arguments(new_func, func) Slot(*slot_args, **slot_kwargs)(func) if new_func.__name__ != func.__name__: return _OverloadedSlotPlaceholder(new_func.__name__, func.__name__) else: return func func.overload = overload return func