1from ..utils.subclass_with_meta import SubclassWithMeta
2from ..utils.trim_docstring import trim_docstring
3import six
4
5if six.PY3:
6    from typing import Type
7
8
9class BaseOptions(object):
10    name = None  # type: str
11    description = None  # type: str
12
13    _frozen = False  # type: bool
14
15    def __init__(self, class_type):
16        self.class_type = class_type  # type: Type
17
18    def freeze(self):
19        self._frozen = True
20
21    def __setattr__(self, name, value):
22        if not self._frozen:
23            super(BaseOptions, self).__setattr__(name, value)
24        else:
25            raise Exception("Can't modify frozen Options {}".format(self))
26
27    def __repr__(self):
28        return "<{} name={}>".format(self.__class__.__name__, repr(self.name))
29
30
31class BaseType(SubclassWithMeta):
32    @classmethod
33    def create_type(cls, class_name, **options):
34        return type(class_name, (cls,), {"Meta": options})
35
36    @classmethod
37    def __init_subclass_with_meta__(
38        cls, name=None, description=None, _meta=None, **_kwargs
39    ):
40        assert "_meta" not in cls.__dict__, "Can't assign directly meta"
41        if not _meta:
42            return
43        _meta.name = name or cls.__name__
44        _meta.description = description or trim_docstring(cls.__doc__)
45        _meta.freeze()
46        cls._meta = _meta
47        super(BaseType, cls).__init_subclass_with_meta__()
48