Source code for jsl.exceptions

# coding: utf-8
import collections
import contextlib

from .roles import DEFAULT_ROLE
from ._compat import implements_to_string, text_type


@contextlib.contextmanager
def processing(step):
    """
    A context manager. If an :class:`SchemaGenerationException` occurs within
    its nested code block, it adds ``step`` to it and reraises.
    """
    try:
        yield
    except SchemaGenerationException as e:
        e.steps.appendleft(step)
        raise


[docs]class Step(object): """A step of the schema generation process that caused the error.""" def __init__(self, entity, role=DEFAULT_ROLE): """ :param entity: An entity being processed. :param str role: A current role. """ #: An entity being processed. self.entity = entity #: A current role. self.role = role def __eq__(self, other): if isinstance(other, self.__class__): return self.__dict__ == other.__dict__ return NotImplemented def __ne__(self, other): if isinstance(other, self.__class__): return not self.__eq__(other) return NotImplemented def __repr__(self): return '{0}({1!r}, role={2})'.format( self.__class__.__name__, self.entity, self.role)
@implements_to_string
[docs]class DocumentStep(Step): """ A step of processing a :class:`document <.Document>`. :type entity: subclass of :class:`~.Document` """ def __str__(self): return self.entity.__name__
@implements_to_string
[docs]class FieldStep(Step): """ A step of processing a :class:`field <.BaseField>`. :type entity: instance of :class:`~.BaseField` """ def __str__(self): return self.entity.__class__.__name__
@implements_to_string
[docs]class AttributeStep(Step): """ A step of processing an attribute of a field. ``entity`` is the name of an attribute (e.g., ``"properties"``, ``"additional_properties"``, etc.) :type entity: str """ def __str__(self): return self.entity
@implements_to_string
[docs]class ItemStep(Step): """ A step of processing an item of an attribute. ``entity`` is either a key or an index (e.g., it can be ``"created_at"`` if the current attribute is ``properties`` of a :class:`~.DictField` or ``0`` if the current attribute is ``items`` of a :class:`~.ArrayField`). :type entity: str or int """ def __str__(self): return repr(self.entity)
@implements_to_string
[docs]class SchemaGenerationException(Exception): """ Raised when a valid JSON schema can not be generated from a JSL object. Examples of such situation are the following: * A :class:`variable <.Var>` resolves to an integer but a :class:`.BaseField` expected; * All choices of :class:`.OneOfField` are variables and all resolve to ``None``. Note: this error can only happen if variables are used in a document or field description. :param str message: A message. """ def __init__(self, message): self.message = message """A message.""" self.steps = collections.deque() """ A deque of :class:`steps <.Step>`, ordered from the first (the least specific) to the last (the most specific). """ def _format_steps(self): if not self.steps: return '' parts = [] steps = iter(self.steps) parts.append(str(next(steps))) for step in steps: if isinstance(step, (DocumentStep, FieldStep)): parts.append(' -> {0}'.format(step)) elif isinstance(step, AttributeStep): parts.append('.{0}'.format(step)) elif isinstance(step, ItemStep): parts.append('[{0}]'.format(step)) return ''.join(parts) def __str__(self): rv = text_type(self.message) steps = self._format_steps() if steps: rv += u'\nSteps: {0}'.format(steps) return rv