Source code for django_crucrudile.entities

"""An entity is an abstract class of objects that can be used to make
an URL pattern tree.

.. seealso:: In ``django-crucrudile``, there are two classes that
             directly subclass :class:`Entity` :

              - :class:`django_crucrudile.routers.Router` (concrete)
              - :class:`django_crucrudile.routes.base.BaseRoute` (abstract)

"""
from abc import ABCMeta, abstractmethod


[docs]class Entity(metaclass=ABCMeta): """An entity is an abstract class of objects that can be used to make an URL pattern tree. Abstract class that defines an attribute (:attr:`Entity.index`), and an abstract method (:func:`Entity.patterns`). Entity implementations should provide the :func:`Entity.patterns` method, that should return a generator yielding Django URL patterns. .. warning:: Abstract class ! Subclasses should define the abstract :func:`patterns` method, that should return a generator yielding Django URL objects (:class:`django.core.urlresolvers.RegexURLPattern` or `:class:`django.core.urlresolvers.RegexURLResolver`). See warning in :func:`__init__`. .. inheritance-diagram:: Entity """ index = False """ :attribute index: Used when routed entity is registered, to know if it should be registered as index. :type index: bool """ def __init__(self, index=None): """Initialize entity, allow setting :attr:`index` from arguments, and add ``redirect`` instance attribute :argument index: See :attr:`index` """ if index is not None: # pragma: no cover self.index = index self.redirect = None @abstractmethod
[docs] def patterns(self, parents=None, add_redirect=None, add_redirect_silent=None): # pragma: no cover """Yield URL patterns .. note:: For argument specification, see implementations of this abstract function (in particular :func:`django_crucrudile.routers.Router.patterns`) .. warning:: Abstract method ! Should be defined by subclasses, and should return a generator yielding Django URL objects (``RegexURLPattern`` or ``RegexURLResolver``) """ pass
[docs] def get_str_tree(self, patterns_kwargs=None, indent_char=' ', indent_size=2): """Return the representation of a entity patterns structure :argument patterns_kwargs: Keyword arguments to pass to :func:`patterns` :type patterns_kwargs: dict :argument indent_char: String to use for tree indentation :type indent_char: str :argument indent_size: Indent size :type indent_size: int >>> import tests.unit >>> from django.db.models import Model >>> from django_crucrudile.routers import Router, ModelRouter >>> >>> # needed to subclass Django Model >>> __name__ = "tests.doctests" >>> >>> class TestModel(Model): ... pass >>> router = Router(generic=True) >>> >>> router.register(TestModel) is not None True >>> print(router.get_str_tree()) ... # doctest: +NORMALIZE_WHITESPACE - Router @ ^ - GenericModelRouter testmodel @ ^testmodel/ - testmodel-list-redirect @ ^$ RedirectView - testmodel-delete @ ^delete/(?P<pk>\d+)$ DeleteView - testmodel-delete @ ^delete/(?P<slug>[\w-]+)$ DeleteView - testmodel-update @ ^update/(?P<pk>\d+)$ UpdateView - testmodel-update @ ^update/(?P<slug>[\w-]+)$ UpdateView - testmodel-create @ ^create$ CreateView - testmodel-detail @ ^detail/(?P<pk>\d+)$ DetailView - testmodel-detail @ ^detail/(?P<slug>[\w-]+)$ DetailView - testmodel-list @ ^list$ ListView """ def _walk_tree(patterns, level=0): """Walk the tree, yielding at tuple of form : ``(level, namespace|router_class|model, callback)`` """ for pattern in patterns: callback = ( pattern.callback.__name__ if pattern.callback else None ) if hasattr(pattern, 'url_patterns'): # Resolver # Yield a line with the resolver metadata _model = getattr(pattern.router, 'model', None) yield ( level, pattern.namespace or "{} {}".format( pattern.router.__class__.__name__ or '', _model._meta.model_name if _model else '' ), pattern.regex.pattern, callback ) # Then, yield lines with the pattern subpatterns # (incrementing level) for line_tuple in _walk_tree( pattern.url_patterns, level+1): yield line_tuple else: # Pattern # Yield a line with the pattern metadata yield ( level, pattern.name, pattern.regex.pattern, callback ) def _str_tree(lines): """Iterate over the tuple returned by _walk_tree, formatting it.""" for _level, _name, _pattern, _callback in lines: yield "{} - {} @ {} {}".format( indent_char*indent_size*_level, _name or '', _pattern or '', _callback or '', ) patterns_kwargs = patterns_kwargs or {} patterns = self.patterns(**patterns_kwargs) pattern_tuples = _walk_tree(patterns) pattern_lines = _str_tree(pattern_tuples) return '\n'.join( pattern_lines )