text: import inspect
  import textwrap
  
  from pankoff.base import BaseValidator
  from pankoff.validators import UNSET, LazyLoad
  
  init_template = "def __init__({arguments}):\n\t{assignments}"
  
  
  def autoinit(klass=None, verbose=False, merge=False):
      """
      Auto generates ``__init__`` method for your class based on its validators.
  
      :param merge: in case you have existing ``__init__`` in your class, you can merge them
      :type merge: bool
  
      :param klass: Class to decorate
      :type klass: type
  
      :param verbose: In case its ``True``, it'll print out the generated source for ``__init__`` method,
       defaults to ``False``
      :type verbose: bool
  
      :returns: Same class but with newly created ``__init__``
      :raises RuntimeError: raised in case class already has ``__init__`` defined
  
      .. code-block:: python
         :emphasize-lines: 1,3
  
          @autoinit(verbose=True)
          class Person:
              name = String()
  
      Prints:
  
      .. code-block::
  
          Generated __init__ method for <class '__main__.Person'>
          def __init__(self, name):
              self.name = name
  
      You can merge existing ``__init__`` with generated one by using ``merge=True``, e.g:
  
      .. code-block:: python
          :emphasize-lines: 1
  
          @autoinit(verbose=True, merge=True)
          class Person:
              name = String()
  
              def __init__(self, surname):
                  self.full_name = self.name + " " + surname
  
      Which prints:
  
      .. code-block::
  
          Generated __init__ method for <class '__main__.Person'>
          def __init__(self, name, *args, **kwargs):
              self.name = name
              user_defined_init(self, *args, **kwargs)
  
      As you can see, you can use ``self.name`` straight away.
  
      .. code-block:: python
  
          person = Person(name="Yaroslav", surname=Pankovych)
          print(person.full_name)  # Yaroslav Pankovych
      """
  
      def inner(cls):
          has_default_init = cls.__init__ is object.__init__
          if not has_default_init and not merge:
              raise RuntimeError(f"{cls} already has __init__ method defined, pass `merge=True` to merge them")
  
          attrs = ["self"]
          assignments = []
          namespace = {"UNSET": UNSET}
          for attr in vars(cls).values():
              if isinstance(attr, BaseValidator):
                  if not isinstance(attr, LazyLoad):
                      attrs.append(attr.field_name)
                  if isinstance(attr, LazyLoad):
                      assignments.append(f"self.{attr.field_name} = UNSET")
                  else:
                      assignments.append(f"self.{attr.field_name} = {attr.field_name}")
          attrs.sort(key=lambda item: "=" in item)  # move default parameters to the end
  
          if merge and not has_default_init:
              namespace["user_defined_init"] = cls.__init__
              attrs.extend(("*args", "**kwargs"))
              assignments.append("user_defined_init(self, *args, **kwargs)")
  
          init = init_template.format(
              arguments=", ".join(attrs),
              assignments="\n\t".join(assignments or ["pass"])
          )
          if verbose:
              print(f"Generated __init__ method for {cls}\n{init}")
          exec(init, namespace)
          cls.__init__ = namespace["__init__"]
          return cls
  
      if klass is not None:
          return inner(klass)
      return inner
  
  
  def _replace_method(method):
      ns = {
          "UNSET": UNSET,
          "method": method
      }
      mixin_method_template = textwrap.dedent("""
      def mixed_method_{method_name}(self, *args, **kwargs):
          parent = eval(f"getattr(super(klass, self), '{method_name}', UNSET)")
          if parent is UNSET:
              return method(self, *args, **kwargs)
          else:
              return method(self, parent(*args, **kwargs))
      """)
      exec(mixin_method_template.format(method_name=method.__name__), ns)
      return ns[f"mixed_method_{method.__name__}"], ns
  
  
  class MixinMeta(type):
  
      def __new__(mcs, name, bases, namespace):
          nss = []
          if all(issubclass(base, MagicMixin) for base in bases):
              for k, v in namespace.items():
                  if inspect.isfunction(v) or isinstance(v, classmethod):
                      new_f, ns = _replace_method(v)
                      namespace[k] = new_f
                      nss.append(ns)
          klass = super().__new__(mcs, name, bases, namespace)
          for ns in nss:
              ns["klass"] = klass
          return klass
  
  
  class MagicMixin(metaclass=MixinMeta):
      """
      Create ``MagicMixin`` by inheriting from it.
  
      See examples: :ref:`magic mixins`
      """
      pass
  
  
  class Alias:
      """
      Create and alias for your fields.
  
      :param source: Attribute name to reffer to
      :type source: str
  
      >>> class Person:
      ...     full_person_name = String()
      ...     name = Alias("full_person_name")
  
      >>> obj = Person("Yaroslav Pankovych")
      >>> obj.name
      "Yaroslav Pankovych"
      """
  
      def __init__(self, source):
          self.source = source
  
      def __get__(self, instance, owner):
          if not instance:
              return self
          return getattr(instance, self.source)
  