Source code for eve_resource.resource

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

from typing import Optional, Callable, Any, Dict, NamedTuple
from collections import namedtuple

from eve import Eve

from . import hooks
from . import utils


OptionalFunc = Optional[Callable[..., Any]]


[docs]class Resource(object): """A domain resource for :class:`eve.Eve` api. This class has some conveninence methods for creating a resource as well registering event hooks with the :class:`eve.Eve` api. :param name: The resource name to be registered with the api. :param keys: Iterable of strings used as a key for the fields of the resource schema. Example:: persons = Resource('persons', keys=('first_name', 'last_name')) """ def __init__(self, name, keys=[]): self.name = name self._key = None # type: NamedTuple self._definition = None # type: Dict[str, Any] self._schema = None # type: Dict[str, Any] self._hooks = None # type: hooks.Hooks if len(keys) > 0: self.keys(*keys) @property def key(self) -> NamedTuple: """An optional namedtuple of the fields for the schema fields of an instance. This get's created if there are args passed in on instantiation or by calling the :meth:`keys` method. If using the :meth:`schema` decorator, then this will get passed into the wrapped function, to be used in building the schema. """ return self._key @property def hooks(self): """Holds event hooks for that can be registered with an :class:`eve.Eve` api. .. seealso:: :class:`hooks.Hooks` """ if self._hooks is None: self._hooks = hooks.Hooks(self.name) return self._hooks
[docs] def keys(self, *keys) -> None: """Creates a namedtuple of the keys. :param keys: Strings that are the fields and values for the namedtuple """ Key = namedtuple('Key', keys) self._key = Key(*keys)
def _validate_func(self, func: OptionalFunc, callback: OptionalFunc=None ) -> Any: func = utils.callable_or_error(func) return callback(func) if callback is not None else func @property def definition_value(self) -> Dict[str, Any]: """The main configuration for an :class:`eve.Eve` domain resource. If a value for ``schema`` is set inside the definition_value, then this instances :attr:`schema_value` will be ignored. If not then when accessing the :meth:`domain` we will use :attr:`schema_value` as the value for ``schema`` in the definition. .. seealso:: `Eve Domain Configuration <http://python-eve.org/config.html#domain-configuration>`_ """ return self._definition if self._definition is not None else {} @definition_value.setter def definition_value(self, data: Dict[str, Any]) -> None: if not isinstance(data, dict): raise TypeError(data) self._definition = data @definition_value.deleter def definition_value(self): del(self._definition) @property def schema_value(self) -> Dict[str, Any]: """The settings for the database and validation portion of the domain resource definition. This is a :class:`dict` with string keys. This will get added to the definiton when accessing the :meth:`domain` method as the value for ``schema`` in the domain resource definition, unless a schema is declared in :attr:`definition_value` .. seealso:: `Eve Schema Definition <http://python-eve.org/config.html#schema-definition>`_ """ return self._schema if self._schema is not None else {} @schema_value.setter def schema_value(self, data: Dict[str, Any]) -> None: if not isinstance(data, dict): raise TypeError self._schema = data @schema_value.deleter def schema_value(self): del(self._schema)
[docs] def definition(self, func: Callable[[], Dict[str, Any]] ) -> Callable[[], Dict[str, Any]]: """A decorator that uses the return value of the wrapped function to set :attr:`definition_value` for an instance. The function should take no args, or kwargs and should return a :class:`dict`. See also: :attr:`definition_value`. :raises TypeError: If the return type is not valid for :attr:`definition_value` """ def callback(func): self.definition_value = func() self._validate_func(func, callback) return func
[docs] def schema(self, func: Callable[..., Any]) -> Callable[..., Any]: """A decorator that uses the return value of the wrapped function to set :attr:`schema_value` for an instance. The function can take one arg which will be this instances :attr:`key` attribute, will work if the function accepts no args and no kwarrgs as well, and should return a :class:`dict`.See also: :attr:`schema_value`. :raises TypeError: If the return type is not valid for :attr:`definition_value` """ def callback(func): try: self.schema_value = func(self.key) except TypeError: self.schema_value = func() self._validate_func(func, callback) return func
[docs] def domain(self) -> Dict[str, Any]: """Build's the domain resource definition for an instance. Uses the :attr:`definition_value` and :attr:`schema_value` to build a :class:`dict` that can be used to register an :class:`eve.Eve` api. """ domain = self.definition_value.copy() domain.setdefault('schema', self.schema_value) return domain
[docs] def init_api(self, api: Eve) -> None: """Register's the event hooks with the api and also will register the domain with the api, if one does not exist for the resource. :param api: An :class:`eve.Eve` instance. :raises TypeError: If api is not an :class:`eve.Eve` instance. """ if not isinstance(api, Eve): raise TypeError(api) if self._hooks is not None: # add event hooks to the api self.hooks.init_api(api) # register the domain with the api. api.config['DOMAIN'].setdefault(self.name, self.domain())