Metaclass for Auto Initialization

class InitMeta(type):
    '''MetaClass to reduce boilerplate
    
    Example usage:
    
        Instea of defining a clas initializer with explicity initialization
        class A:
            def __init__(self, a, b, c, d):
                self.a = a
                self.b = b
                self.c = c
                self.d = d

        specifying the metaclass as InitMeta modifies the original init
            adding class-initialization boilerplate
        class A(metaclass=InitMeta):
            def __init__(self, a, b, c, d):

                print(self.a) # This works even though self.a was not explicitly set

        This reduces the clutter when multiple attributes are passed in to the class constructor

        Raises:
            RuntimeError: if __init__ is not defined 
    '''



    import inspect

    def __new__(cls, name, bases, attributes):
        if not (cls_init := attributes.get('__init__', None)):
            raise RuntimeError('__init__ must be specified')

        init_args = list(InitMeta.inspect.signature(cls_init).parameters.keys())[1:]

        def meta_init(self, *args, **kwargs):
            # set kwargs first, else non-kwarg is overritten by get() returning None
            for arg in init_args:
                setattr(self, arg, kwargs.get(arg))

            for arg_name, arg in zip(init_args, args):
                setattr(self, arg_name, arg)


            cls_init(self, *args, **kwargs)

        attributes['__init__'] = meta_init

        return super(InitMeta, cls).__new__(cls, name, bases, attributes)