Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class DirtyTemplateMeta(type):
- '''
- Metaclass for :class:`DirtyTemplate`
- '''
- def __new__(cls, name, bases, dct, *, template_bases=()):
- new_cls = super().__new__(cls, name, bases, dct)
- new_cls.template_dict = dct
- new_cls.template_bases = template_bases
- return new_cls
- class DirtyTemplate(metaclass=DirtyTemplateMeta):
- '''
- Define a DirtyTemplate.
- This is a horrible hack job that allows (in theory anyway) to define
- a 'Template' class which can be used a bit like templates in C++, in
- particular to define a class once that can be rendered into multiple
- defined classes each with different base classes.
- This allows for some pretty wild stuff.
- So we can define a template that bases ``dict``, implements a method, and
- overrides another.
- Warning
- -------
- As I say, this is a terrible hack. I was experimenting with ways to be able
- to avoid repeating definitions but, due to some third-party dark magics,
- was unable to rely on mixin's or composition to get the job done.
- I'm not saying it's a good idea, or that it'll work, just a bit of
- experimentation.
- Examples
- --------
- >>> class SomeTemplate(DirtyTemplate, template_bases=(dict,)):
- ... def some_method(self):
- ... return "hello world"
- ... def __getitem__(self, key):
- ... return "constant"
- ...
- This shouldn't be instansiated directly. Instead it can be used to
- render different versions of the same class with different base classes.
- >>> @SomeTemplate.template
- ... class ImplA:
- ... def some_method(self):
- ... return "not hello"
- ...
- However, each rendering always has the template as the 'top class' rather
- than what you might expect.
- >>> a = ImplA()
- >>> a.some_method()
- 'hello world'
- >>> a["thing"]
- 'constant'
- It even has the base classes defined on the template;
- >>> ImplA.__bases__
- (<class 'dirty_templates.ImplA'>, <class 'dict'>)
- The behaviour from these base classes works as expected.
- >>> a["thing"] = 4
- >>> a.values()
- dict_values([4])
- In the next example we render a version of the template that inherits from
- a subclass of one of the bases of the template;
- >>> import collections
- >>> @SomeTemplate.template
- ... class ImplB(collections.OrderedDict):
- ... pass
- ...
- Here again the template behaviour is used;
- >>> b = ImplB()
- >>> b.some_method()
- 'hello world'
- >>> b["thing"]
- 'constant'
- Note though, because the wrapped ``ImplB`` class already bases ``dict``
- (via OrderedDict) it's not added to the list of ``__bases__`` like it was
- in ``ImplA``
- >>> ImplB.__bases__
- (<class 'dirty_templates.ImplB'>,)
- but again the behaviour of ``OrderedDict`` is accessible;
- >>> b["thing"] = 4
- >>> b.move_to_end("thing")
- Finally we can obviously define new methods in the rendered classes;
- >>> @SomeTemplate.template
- ... class ImplC(collections.OrderedDict):
- ... def some_new_method(self):
- ... return "new hello"
- ...
- ...
- >>> c = ImplC()
- >>> c.some_method()
- 'hello world'
- >>> c.some_new_method()
- 'new hello'
- >>> c["thing"]
- 'constant'
- '''
- # This is set by metaclass
- template_dict = None
- template_bases = ()
- @classmethod
- def template(cls, new_cls):
- '''
- Decorator to generate new templated classes.
- '''
- name = new_cls.__name__
- new_cls.__name__ = f'{name}_inner'
- bases = [new_cls]
- bases.extend(
- base for base in cls.template_bases
- if not issubclass(new_cls, base)
- )
- return type(name, tuple(bases), cls.template_dict)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement