from enum import Enum from typing import Any from marshmallow import post_load from marshmallow.fields import DateTime, List, String from marshmallow.schema import SchemaMeta from teal.marshmallow import URL from teal.resource import Schema from ereuse_devicehub.resources import models as m class UnitCodes(Enum): mbyte = '4L' mbps = 'E20' mhz = 'MHZ' gbyte = 'E34' ghz = 'A86' bit = 'A99' kgm = 'KGM' m = 'MTR' def __str__(self): return self.name # The following SchemaMeta modifications allow us to generate # documentation using our directive. This is their only purpose. # Marshmallow's meta class removes variables from our defined # classes, so we put some home made proxies in order to intercept # those values and safe them in our classes. # What we do is: # 1. Make our ``Meta`` class be the superclass of Marshmallow's # SchemaMeta and provide a new that stores in class, so we # can save some vars. # 2. Substitute SchemaMeta.get_declared_fields with our own method # that saves more variables. # Then the directive in our docs/config.py file reads these variables # generating the documentation. class Meta(type): def __new__(cls, *args, **kw) -> Any: base_name = args[1][0].__name__ y = super().__new__(cls, *args, **kw) y._base_class = base_name return y SchemaMeta.__bases__ = Meta, @classmethod def get_declared_fields(mcs, klass, cls_fields, inherited_fields, dict_cls): klass._own = cls_fields klass._inherited = inherited_fields return dict_cls(inherited_fields + cls_fields) SchemaMeta.get_declared_fields = get_declared_fields _type_description = """The name of the type of Thing, like "Device" or "Receive". This is the same as JSON-LD ``@type``. This field is required when submitting values so Devicehub knows the type of object. Devicehub always returns this value. """ class Thing(Schema): type = String(description=_type_description) same_as = List(URL(dump_only=True), dump_only=True, data_key='sameAs') updated = DateTime('iso', dump_only=True, description=m.Thing.updated.comment) created = DateTime('iso', dump_only=True, description=m.Thing.created.comment) @post_load def remove_type(self, data: dict): data.pop('type', None)