Decorators

Decorators for Autopilot classes

Add functionality to autopilot classes without entering into or depending on the inheritance hierarchy.

Classes:

Introspect()

Decorator to be used around methods (particularly __init__) to store arguments given on call.

class Introspect[source]

Bases: object

Decorator to be used around methods (particularly __init__) to store arguments given on call.

Stores args and kwargs in self._introspect[wrapped_function.__name__] = {'kwarg_1': val_1, 'kwarg_2': val_2}

Note that this will unpack positional arguments into keyword arguments. If the topmost class is given positional arguments, they will be stored in the special field 'args': [arg1,arg2,...]

Works by wrapping the method in such a way that self is preserved, and can patch into the existing MRO.

Note

This class was intended for use on __init__ methods and has not been tested on other methods. Though they should work in theory, there may be unexpected behavior in introspecting across multiple frames, as the check is for whether we are within the calling object’s calling hierarchy.

For example, given a Superclass and a Subclass (and a mock Introspect object) like this:

class Introspect:
    def __call__(self, func) -> typing.Callable:
        @wraps(func)
        def wrapped_fn(wrapped_self, *args, **kwargs):
            print('2. start of introspection')
            ret = func(wrapped_self, *args, **kwargs)
            print('4. end of introspection')
            return ret
        return wrapped_fn

class Superclass:

    @Introspect()
    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        print(f"3. superclass function call")

class Subclass(Superclass):
    def __init__(self, *args, **kwargs):
        print('1. inheriting class, pre super call')
        super(Subclass, self).__init__(*args, **kwargs)
        print('5. inheriting class, post super call')

One would get the following output:

>>> instance = Subclass('a', 'b', 'c')
1. inheriting class, pre super call
2. start of introspection
3. superclass function call
4. end of introspection
5. inheriting class, post super call

To hoist the call back up into the (potentially multiple) subclass frames, we use inspect and iterate through frames, grabbing their arguments, until we reach a frame that is no longer in our calling hierarchy.