Source code for flask_open_directory.model.model

# -*- coding: utf-8 -*-

from typing import Dict, Union, Iterable
from .model_abc import ModelABC


def _quote_if_str(val):
    """Helper used in __repr__ statements

    """
    if isinstance(val, str):
        return "'{}'".format(val)
    return val


[docs]class Attribute(object): """Represents an LDAP entry attribute. It maps the ldap entry key to an attribute on a Model. :param ldap_key: The ldap entry key for the attribute. :param allow_multiple: If ``False`` (default) then any lists only return the first item. If ``True`` return the whole list of values. """ def __init__(self, ldap_key, allow_multiple=False): self.ldap_key = ldap_key self.allow_multiple = allow_multiple def __str__(self): return str(self.ldap_key) def __repr__(self): return "{}('{}', allow_multiple={})".format( self.__class__.__name__, self.ldap_key, self.allow_multiple )
[docs]class BaseModel(ModelABC): """Implementation of :class:`ModelABC`. Used to map ldap entry keys to python attributes. :param kwargs: Values to set for the attributes of an instance. These can be passed in with the python attribute name as the key or the ldap entry name as the key and the values will be stored and accessible appropriately. :Example: >>> class User(BaseModel): ... id = Attribute('apple-generateduid') >>> user = User(id='123') >>> user.id == '123' True >>> user2 = User(**{'apple-generateduid': '456'}) >>> user2.id == '456' True """ def __init__(self, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) @classmethod def _attributes(cls): """Returns the :class:`Attribute` instances on a class """ return (v for v in vars(cls).values() if isinstance(v, Attribute)) @classmethod
[docs] def attribute_for_key(cls, key: str) -> Union[Attribute, None]: """Return :class:`Attribute` for the given key, which can be the python attribute or the ldap entry key. Returns ``None`` if not found """ if key in cls.ldap_attribute_map().values(): key = cls.attribute_name_for(key) return next((v for (k, v) in vars(cls).items() if k == key), None)
@classmethod
[docs] def ldap_attribute_map(cls) -> Dict[str, str]: """Returns the mapping between python attributes and ldap entry keys. The python attribute name is the key and ldap entry key is the value in the mapping. """ return {k: v.ldap_key for (k, v) in vars(cls).items() if isinstance(v, Attribute)}
@property def ldap_values(self) -> Dict[str, Union[str, Iterable[str]]]: """Stores the actual values for the :class:`Attribute`. These are the values returned when accessing an :class:`Attribute` instance set on a Model. """ if not getattr(self, '_ldap_values', None): self._ldap_values = {} return self._ldap_values def _get_ldap_value(self, key) -> Union[Iterable[str], str, None]: """Helper to get the internal value (if available) from the internal storage. """ value = self.ldap_values.get(key) if value and object.__getattribute__(self, key).allow_multiple is False: if isinstance(value, list) and len(value) > 0: return value[0] return value def __setattr__(self, key, value) -> None: """Properly set the :class:`Attribute` values in the internal storage, or fallback to the default implementation. """ if key in self.ldap_attribute_map().keys(): self.ldap_values[key] = value elif key in self.ldap_attribute_map().values(): self.ldap_values[self.attribute_name_for(key)] = value else: super().__setattr__(key, value) def __getattribute__(self, key): """Retrieve the appropriate values for an attribute, possibly from the internal storage, if the attribute being accessed is a :class:`Attribute`. """ ldap_key = None attr_map = object.__getattribute__(self, 'ldap_attribute_map')() if key in attr_map.keys(): ldap_key = key elif key in attr_map.values(): ldap_key = object.__getattribute__(self, 'attribute_name_for')(key) if ldap_key is not None: # return the ldap value or ``None`` if it's not set yet. return object.__getattribute__(self, '_get_ldap_value')(ldap_key) # fallback to default return object.__getattribute__(self, key) def __repr__(self) -> str: rv = '{}('.format(self.__class__.__name__) attr_strs = map( lambda key: "{}={}".format( key, _quote_if_str(self._get_ldap_value(key)) ), self.ldap_attribute_map().keys() ) rv += ', '.join(attr_strs) + ')' return rv