def override(func, auto = False):
    """Decorator applicable to methods only.
    For a version applicable also to classes or modules use auto_override.
    Asserts that for the decorated method a parent method exists in its mro.
    If both the decorated method and its parent method are type annotated,
    the decorator additionally asserts compatibility of the annotated types.
    Note that the return type is checked in contravariant manner.
    A successful check guarantees that the child method can always be used in
    places that support the parent method's signature.
    Use pytypes.check_override_at_runtime and pytypes.check_override_at_class_definition_time
    to control whether checks happen at class definition time or at "actual runtime".
    """
    if not pytypes.checking_enabled:
        return func
    # notes:
    # - don't use @override on __init__ (raise warning? Error for now!),
    #   because __init__ is not intended to be called after creation
    # - @override applies typechecking to every match in mro, because class might be used as
    #   replacement for each class in its mro. So each must be compatible.
    # - @override does not/cannot check signature of builtin ancestors (for now).
    # - @override starts checking only at its declaration level. If in a subclass an @override
    #   annotated method is not s.t. @override any more.
    #   This is difficult to achieve in case of a call to super. Runtime-override checking
    #   would use the subclass-self and thus unintentionally would also check the submethod's
    #   signature. We actively avoid this here.
    func.override_checked = True
    _actualfunc(func).override_checked = True
    if pytypes.check_override_at_class_definition_time:
        # We need some trickery here, because details of the class are not yet available
        # as it is just getting defined. Luckily we can get base-classes via inspect.stack():
        stack = inspect.stack()
        try:
            base_classes = _re.search(r'class.+\((.+)\)\s*\:', stack[2][4][0]).group(1)
        except IndexError:
            raise _function_instead_of_method_error(func)
        except AttributeError:
            base_classes = 'object'
        meth_cls_name = stack[1][3]
        if func.__name__ == '__init__':
            raise OverrideError(
                    'Invalid use of @override in %s:\n  @override must not be applied to __init__.'
                    % util._fully_qualified_func_name(func, True, None, meth_cls_name))
        # handle multiple inheritance
        base_classes = [s.strip() for s in base_classes.split(',')]
        if not base_classes:
            raise ValueError('@override: unable to determine base class') 

        # stack[0]=overrides, stack[1]=inside class def'n, stack[2]=outside class def'n
        derived_class_locals = stack[2][0].f_locals
        derived_class_globals = stack[2][0].f_globals

        # replace each class name in base_classes with the actual class type
        for i, base_class in enumerate(base_classes):
            if '.' not in base_class:
                if base_class in derived_class_locals:
                    base_classes[i] = derived_class_locals[base_class]
                elif base_class in derived_class_globals:
                    base_classes[i] = derived_class_globals[base_class]
                elif base_class in types.__builtins__:
                    base_classes[i] = types.__builtins__[base_class]
                else:
                    raise TypeError("Could not lookup type: "+base_class)
            else:
                components = base_class.split('.')
                # obj is either a module or a class
                if components[0] in derived_class_locals:
                    obj = derived_class_locals[components[0]]
                elif components[0] in derived_class_globals:
                    obj = derived_class_globals[components[0]]
                elif components[0] in types.__builtins__:
                    obj = types.__builtins__[components[0]]
                elif components[0] in sys.modules:
                    obj = sys.modules[components[0]]
                else:
                    raise TypeError("Could not lookup type or module: "+base_class)
                for c in components[1:]:
                    assert(ismodule(obj) or isclass(obj))
                    obj = getattr(obj, c)
                base_classes[i] = obj

        mro_set = set() # contains everything in would-be-mro, however in unspecified order
        mro_pool = [base_classes]
        while len(mro_pool) > 0:
            lst = mro_pool.pop()
            for base_cls in lst:
                if not is_builtin_type(base_cls):
                    mro_set.add(base_cls)
                    mro_pool.append(base_cls.__bases__)

        base_method_exists = False
        argSpecs = util.getargspecs(func)
        for cls in mro_set:
            if hasattr(cls, func.__name__):
                base_method_exists = True
                base_method = getattr(cls, func.__name__)
                _check_override_argspecs(func, argSpecs, meth_cls_name, base_method, cls)
                if has_type_hints(func):
                    try:
                        _check_override_types(func, _funcsigtypes(func, True, cls), meth_cls_name,
                                base_method, cls)
                    except NameError:
                        _delayed_checks.append(_DelayedCheck(func, func, meth_cls_name, base_method,
                                cls, sys.exc_info()))
        if not base_method_exists:
            if not auto:
                raise _no_base_method_error(func)

    if pytypes.check_override_at_runtime:
        specs = util.getargspecs(func)
        argNames = util.getargnames(specs)
        def checker_ov(*args, **kw):
            if hasattr(checker_ov, '__annotations__') and len(checker_ov.__annotations__) > 0:
                checker_ov.ov_func.__annotations__ = checker_ov.__annotations__
            args_kw = util.getargskw(args, kw, specs)
            if len(argNames) > 0 and argNames[0] == 'self':
                if hasattr(args_kw[0].__class__, func.__name__) and \
                        ismethod(getattr(args_kw[0], func.__name__)):
                    actual_class = args_kw[0].__class__
                    if _actualfunc(getattr(args_kw[0], func.__name__)) != func:
                        for acls in util.mro(args_kw[0].__class__):
                            if not is_builtin_type(acls):
                                if hasattr(acls, func.__name__) and func.__name__ in acls.__dict__ and \
                                        _actualfunc(acls.__dict__[func.__name__]) == func:
                                    actual_class = acls
                    if func.__name__ == '__init__':
                        raise OverrideError(
                                'Invalid use of @override in %s:\n    @override must not be applied to __init__.'
                                % util._fully_qualified_func_name(func, True, actual_class))
                    ovmro = []
                    base_method_exists = False
                    for mc in util.mro(actual_class)[1:]:
                        if hasattr(mc, func.__name__):
                            ovf = getattr(mc, func.__name__)
                            base_method_exists = True
                            if not is_builtin_type(mc):
                                ovmro.append(mc)
                    if not base_method_exists:
                        if not auto:
                            raise _no_base_method_error(func)
                        else:
                            return func(*args, **kw)
                    # Not yet support overloading
                    # Check arg-count compatibility
                    for ovcls in ovmro:
                        ovf = getattr(ovcls, func.__name__)
                        _check_override_argspecs(func, specs, actual_class.__name__, ovf, ovcls)
                    # Check arg/res-type compatibility
                    meth_types = _funcsigtypes(func, True, args_kw[0].__class__)
                    if has_type_hints(func):
                        for ovcls in ovmro:
                            ovf = getattr(ovcls, func.__name__)
                            _check_override_types(func, meth_types, actual_class.__name__, ovf, ovcls)
                else:
                    raise OverrideError('@override was applied to a non-method: %s.%s.\n'
                        % (func.__module__, func.__name__)
                        + "that declares 'self' although not a method.")
            else:
                raise _function_instead_of_method_error(func)
            return func(*args, **kw)
    
        checker_ov.ov_func = func
        if hasattr(func, '__func__'):
            checker_ov.__func__ = func.__func__
        checker_ov.__name__ = func.__name__
        checker_ov.__module__ = func.__module__
        checker_ov.__globals__.update(func.__globals__)
        if hasattr(func, '__annotations__'):
            checker_ov.__annotations__ = func.__annotations__
        if hasattr(func, '__qualname__'):
            checker_ov.__qualname__ = func.__qualname__
        checker_ov.__doc__ = func.__doc__
        # Todo: Check what other attributes might be needed (e.g. by debuggers).
        checker_ov._check_parent_types = True
        return checker_ov
    else:
        func._check_parent_types = True
        return func