Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
duedil-python / duedil / models / base.py
Size: Mime:
from __future__ import unicode_literals

# import sys
import six

from ..api import api_client


class Model(object):
    attribute_names = None
    id = None
    path = None
    related_models = None
    parent_model = None

    def __init__(self, id=None, parent_model=None, load=False, **kwargs):

        if self.attribute_names:
            for allowed in self.attribute_names:
                if not hasattr(self, allowed):
                    self.__setattr__(allowed, None)

        self.id = id
        self.parent_model = parent_model

        if load:
            self.load()

        if kwargs:
            self.update(**kwargs)

    def __getattribute__(self, name):
        try:
            return super(Model, self).__getattribute__(name)
        except AttributeError:
            key = name.replace('_', '-')
            if (self.related_models and key in self.related_models.keys()):
                return self.load_related(key,
                                         self.related_models[key])
            raise

    def load(self):
        result = api_client.get(self.endpoint)
        if result and 'response' in result:
            self.update(**result['response'])

    def update(self, **data):
        for k, v in six.iteritems(data):
            if k in self.attribute_names:
                self.__setattr__(k, v)

    @property
    def endpoint(self):
        if not self.path:
            raise ValueError(
                "{model} does not have a path to load specified".format(
                    model=self.__class__.__name__))
        endpoint = self.path
        if self.id:
            endpoint += '/{id}'.format(id=self.id)

        if self.parent_model:

            par_endpoint = self.parent_model.endpoint

            endpoint = "{parent}/{child}".format(parent=par_endpoint,
                                                 child=endpoint)
        return endpoint

    def load_related(self, key, klass=None):
        internal_key = '_' + key.replace('-', '_')

        related = getattr(self, internal_key, None)

        if related is None:
            uri = '{endpoint}/{model}'.format(endpoint=self.endpoint,
                                              model=key)
            result = api_client.get(uri)
            if result:
                response = result['response']
                related = None

                if (
                    'data' in response and
                    isinstance(response['data'], (list, tuple))
                ):
                    related = []
                    for r in result['response']['data']:
                        related.append(
                            klass(**r) if klass else r)
                elif response:
                    related = klass(**response) if klass else response
                setattr(self, internal_key, related)
        return related


"""
def model_property(endpoint):
    def wrap(getter_fn):
        def inner(self, *args, **kwargs):
            return getter_fn(self, endpoint, *args, **kwargs)
        return inner
    return wrap


class RelatedModelMeta(type):

    def __init__(klass, name, bases, ns):
        related_models = ns.get('related_models') or {}

        for ep in related_models.keys():

            @model_property(ep)
            def getter(self, endpoint):
                model = self.related_models[endpoint]

                if isinstance(model, six.string_types):
                    model = getattr(sys.modules[__name__], model)

                return self.load_related(endpoint, model)

            attr_name = ep.replace('-', '_')
            setattr(klass, attr_name,
                    property(getter, None, None, attr_name))
"""