Source code for parameter.model

#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""Model and Argument."""
from __future__ import print_function, division, unicode_literals

import abc
import inspect

import six

from .types import Nested
from .exception import ConvertError, ArgumentMissError, ArgumentInvalidError


@six.add_metaclass(abc.ABCMeta)
[docs]class BaseAdapter(object): """To implement your own adapter, you need inherit from :class:`~parameter.model.BaseAdapter`. There two methods must be overwirtten: - ``get_argument``: Returns a single value - ``get_arguments``: Returns a sequence of values. Example:: from parameter.model import BaseAdapter class DemoAdapter(BaseAdapter): "demo adapter" def __init__(self, arguments): self.arguments = arguments def get_argument(self, name, default): return self.arguments.get(name, default) def get_arguments(self, name): return self.arguments.getlist(name) If you want your adapter to support nested, you need to override the ``spawn`` method, this method use the given value to return an new instance of the current adapter. :: from parameter.model import BaseAdapter class DemoAdapter(BaseAdapter): # see above def spawn(self, arguments): return DemoAdapter(arguments) """ @abc.abstractmethod
[docs] def get_argument(self, name, default, *args, **kwargs): """Returns the argument's value via ``name``. :param name: The name of the argument. :param default: The default value. :raises: :class:`~parameter.exception.ArgumentMissError` :raises: :class:`~parameter.exception.ArgumentInvalidError` """
@abc.abstractmethod
[docs] def get_arguments(self, name, *args, **kwargs): """Returns the argument's values via ``name``. :param name: The name of the argument. :raises: :class:`~parameter.exception.ArgumentMissError` :raises: :class:`~parameter.exception.ArgumentInvalidError` """
@staticmethod
[docs] def spawn(val): """Use the new value to spawn an new adapter of this adapter. """ raise NotImplementedError()
[docs]class Argument(object): """Represents a parameter in HTTP request.""" _DEFAULT = [] # type: list
[docs] def __init__(self, type_, default=_DEFAULT, alias=None, multiple=False, miss_message=None, invalid_message=None): """Initialize :param type_: The parameter's type, indicated using an instance which subclasses :class:`parameter.types.BaseType`. :type type_: :class:`parameter.types.BaseType`. :param default: The default value. :param alias: The alias name of this argument as represented in the HTTP request. :param multiple: This argument have multiple values. :param miss_message: The message of :class:`~parameter.exception.ArgumentMissError` :param invalid_message: The message of :class:`~parameter.exception.ArgumentInvalidError` """ self.name = None self.alias = alias self.type_ = type_() if inspect.isclass(type_) else type_ self.default = default self.multiple = multiple self.miss_message = miss_message self.invalid_message = invalid_message
@classmethod
[docs] def is_init_default(cls, value): """Returns ``True`` if the ``value`` is the initial default.""" return value is cls._DEFAULT
[docs] def convert(self, value): """Check and convert the value to the specified type. :raises: :class:`~parameter.exception.ArgumentMissError` :raises: :class:`~parameter.exception.ArgumentInvalidError` """ if self.is_init_default(value): raise ArgumentMissError(self.miss_message, self.name) try: return self.type_.convert(value) except ConvertError as e: raise ArgumentInvalidError(self.invalid_message, self.name, e)
class ModelMeta(type): def __new__(cls, name, base, __dict__): arguments = [] for attr, val in __dict__.items(): if not isinstance(val, Argument): continue # If not specify alias for this argument, set argument's name # to current attribute name. if val.alias is None: val.name = attr else: # Otherwise set to the alias that user specified val.name = val.alias arguments.append((attr, val)) __dict__["_meta_arguments"] = arguments for key, _ in arguments: __dict__.pop(key) return type.__new__(cls, name, base, __dict__) @six.add_metaclass(ModelMeta) class Model(object): _meta_arguments = None # type: list def __init__(self, adapter): """Initialize :param adapter: The adapter to get argument, indicate using an instance which subclasses :class:`BaseAdapter` :type adapter: :class:`BaseAdapter` """ self.adapter = adapter self._arguments = {} self._init() def _attempt_construct_adapter(self, arg, val): """Attempt construct an instance which subclasses :class:`~BaseAdapter` if the type of arg's is :class:`~parameter.types.Nested`. """ if isinstance(arg.type_, Nested): return self.adapter.spawn(val) return val def _init(self): """Initialize arguments""" for attr, arg in self._meta_arguments: if arg.multiple: val = self.adapter.get_arguments(arg.name) val = [arg.convert(self._attempt_construct_adapter(arg, v)) for v in val] else: val = self.adapter.get_argument(arg.name, arg.default) val = arg.convert(self._attempt_construct_adapter(arg, val)) self._arguments[attr] = val def __getattr__(self, key): return self._arguments[key] def __repr__(self): args = " ".join("<%s: %s>" % (attr, arg.type_.__class__.__name__) for attr, arg in self._meta_arguments) return "<%s [%s]>" % (self.__class__.__name__, args)