Decorators on Python AbstractMethods

Use __init_subclass__ to apply the timer decorator for you. (timer, by the way, doesn't need to be defined in the class; it's more general than that.) __init_subclass__ is also a more appropriate place to determine if apply is callable.

import abc
import functools
import time


def timer(func):
    @functools.wraps(func)
    def wrapper_timer(*args, **kwargs):
        start_time = time.perf_counter()
        value = func(*args, **kwargs)
        end_time = time.perf_counter()
        run_time = end_time - start_time
        print(f"Finished {func.__name__!r} in {run_time:.4f} secs")
        return value
    return wrapper_timer


class Test(metaclass=abc.ABCMeta):
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        # ABCMeta doesn't let us get this far if cls.apply isn't defined
        if not callable(cls.apply):
            raise TypeError("apply not callable")
        cls.apply = timer(cls.apply)

    @abc.abstractmethod
    def apply(self, a: str) -> str:
        raise NotImplementedError

class T2(Test):
    def apply(self, a: str) -> str:
        return a

if __name__ == '__main__':
    t = T2()
    t.apply('a')