Example #1
0
    def visit_decorator(self, dec: Decorator) -> None:
        if dec.decorators:
            decorators_to_store = dec.decorators.copy()
            decorators_to_remove: List[int] = []
            # the index of the last non-register decorator before finding a register decorator
            # when going through decorators from top to bottom
            last_non_register: Optional[int] = None
            for i, d in enumerate(decorators_to_store):
                impl = get_singledispatch_register_call_info(d, dec.func)
                if impl is not None:
                    self.singledispatch_impls[impl.singledispatch_func].append(
                        (impl.dispatch_type, dec.func))
                    decorators_to_remove.append(i)
                    if last_non_register is not None:
                        # found a register decorator after a non-register decorator, which we
                        # don't support because we'd have to make a copy of the function before
                        # calling the decorator so that we can call it later, which complicates
                        # the implementation for something that is probably not commonly used
                        self.errors.error(
                            "Calling decorator after registering function not supported",
                            self.current_path,
                            decorators_to_store[last_non_register].line,
                        )
                else:
                    if refers_to_fullname(d, 'functools.singledispatch'):
                        decorators_to_remove.append(i)
                        # make sure that we still treat the function as a singledispatch function
                        # even if we don't find any registered implementations (which might happen
                        # if all registered implementations are registered dynamically)
                        self.singledispatch_impls.setdefault(dec.func, [])
                    last_non_register = i

            if decorators_to_remove:
                # calling register on a function that tries to dispatch based on type annotations
                # raises a TypeError because compiled functions don't have an __annotations__
                # attribute
                self.decorators_to_remove[dec.func] = decorators_to_remove

        super().visit_decorator(dec)