Skip to content

Commit

Permalink
Merge 4de0cdc into e85cdcb
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo Geoffroy committed Jun 30, 2014
2 parents e85cdcb + 4de0cdc commit c2c857f
Show file tree
Hide file tree
Showing 8 changed files with 438 additions and 21 deletions.
59 changes: 54 additions & 5 deletions django_crucrudile/entities/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,71 @@
decorates a entity store class, adding an object to its base store.
"""

from functools import wraps
from abc import ABCMeta

__all__ = ['provides', 'EntityStoreMetaclass', 'EntityStore']


def provides(provided, **kwargs):
"""Return a decorator that uses :func:`EntityStore.register_class` to
register a class in the base store
register the given object in the base store.
:argument provided: Object to register in the base store. This
can be an object since it may be transformed
by register_class_map.
:type provided: object
"""

def register_class_to_router(router):
"""Register the provided class"""
def register_obj_in_store(router):
"""Register the provided class to :argument:`store`
:argument route: Router to register provided object to
:type router: :class:`EntityStore`"""
router.register_class(provided, **kwargs)
return router
return register_class_to_router
return register_obj_in_store


def register_instances(to_store):
"""Return a decorator that makes all instances of this class (and its
subclasses) automatically register themselves to :argument:`to_store`.
:argument to_store: Store to register instances to.
:type to_store: :class:`EntityStore`
"""
def patch_constructor(entity_class):
"""Wrap original entity_class __init__, to register instance to
:argument:`to_store`.
"""
orig_init = entity_class.__init__

@wraps(orig_init)
def new_init(self, *args, **kwargs):
orig_init(self, *args, **kwargs)
to_store.register(self)

entity_class.__init__ = new_init
return entity_class
return patch_constructor


def register_class(to_store_class):
"""Return a decorator that registers the decorated class in the store
class provided as argument, using :class:`EntityStore.register_class`.
:argument to_store_class: Store class to register class to.
:type to_store_class: subclass of :class:`EntityStore`
"""
def register_obj_as_class(entity_class):
"""Register decorated class to :argument:`to_store_class`."""
to_store_class.register_class(entity_class)
return entity_class
return register_obj_as_class


class EntityStoreMetaclass(ABCMeta):
Expand Down
18 changes: 9 additions & 9 deletions django_crucrudile/routers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class Router(EntityStore, Entity):
"""
:attribute add_redirect: Add redirect pattern when calling
:func:`patterns`. If None, will be
guessed using :attribute:`redirect`
guessed using :attr:`redirect`
:type add_redirect: bool or None
"""
add_redirect_silent = False
Expand All @@ -89,11 +89,11 @@ class Router(EntityStore, Entity):
attribute is not set (on
self). Defaults to False, because
in the default configuration,
:attribute:`add_redirect` is
:attr:`add_redirect` is
guessed using
:attribute:`redirect`, using
:attr:`redirect`, using
``bool``. Set to True if you're
using :attribute:`add_redirect`
using :attr:`add_redirect`
explicitly and want the redirect
attribute to be optional.
:type add_redirect_silent: bool
Expand Down Expand Up @@ -174,15 +174,15 @@ def register(self, entity, index=False, map_kwargs=None):

def get_redirect_pattern(self, namespaces=None, silent=None):
"""Compile the URL name to this router's redirect path (found by
following :attribute:`Router.redirect`), and that return a lazy
following :attr:`Router.redirect`), and that return a lazy
``RedirectView`` that redirects to this URL name
:argument namespaces: The list of namespaces will be used to
get the current namespaces when building
the redirect URL name
:type namespaces: list of str
:argument silent: Override
:attribute:`Router.get_redirect_silent`
:attr:`Router.get_redirect_silent`
:type silent: bool
:raise ValueError: If no redirect found when following
Expand Down Expand Up @@ -225,7 +225,7 @@ def _follow_redirect(redirect):
# getattr(redirect, 'namespace', None)).

# can't decide either
if issubclass(redirect, Router) and redirect.namespace:
if isinstance(redirect, Router) and redirect.namespace:
namespaces.append(redirect.namespace)
# save last redirect in case of exception
_last_redirect_found = redirect
Expand Down Expand Up @@ -305,10 +305,10 @@ def patterns(self, namespaces=None,
``namespaces`` recursively, because it
may be needed to make redirect URL patterns
:type namespaces: list of str
:argument add_redirect: Override :attribute:`Router.add_redirect`
:argument add_redirect: Override :attr:`Router.add_redirect`
:type add_redirect: bool
:argument add_redirect_silent: Override
:attribute:`Router.add_redirect_silent`
:attr:`Router.add_redirect_silent`
:type add_redirect: bool
"""
# initialize default arguments
Expand Down
122 changes: 122 additions & 0 deletions django_crucrudile/routers/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""This module contains an :class:`AppRouter` class, which subclasses
:class:`django_crucrudile.routers.Router`. This class is initialized
with an application name, and automatically registers (when
initializing) entities it can found in the (by default) ``entities``
attribute of the application's ``router`` module.
"""
from importlib import import_module
from . import Router


class AppRouter(Router):
"""Router that gets initialized with an application name, and
automatically registers entities that :func:`get_routing_entities` can
find in :func:`get_routing_module`. By defaults, this results to a
lookup on the ``entities`` attribute of ``routing`` module of the
given application.
"""
routing_module_name = "routing"
"""
:attribute routing_module_name: Module to load in application, in
order to get the entities.
:type routing_module_name: str
"""
entities_attribute_name = "entities"
"""
:attribute entities_attribute_name: Attribute to use when looking
for entities in the routing
module.
:type entities_attribute_name: str
"""
add_app_namespace = True
"""
:attribute add_app_namespace: Add application name as a namespace.
:type add_app_namespace: bool
"""
no_app_entities_silent = True
"""
:attribute no_app_entities_silent: Don't fail if the entities list
loaded from the routing module
is empty.
:type no_app_entities_silent: bool
"""
def __init__(self, app_module_name, add_app_namespace=None, **kwargs):
"""Initialize application router, get namespace if required, run
superclass init and load entities to register from module.
:argument app_module_name: Application module name to
load. Must be importable from
project root.
:type app_module_name: str
:argument add_app_namespace: Override
:attr:`add_app_namespace`
:type add_app_namespace: bool or None
"""
self.app_module_name = app_module_name
if add_app_namespace is None:
add_app_namespace = self.add_app_namespace

if add_app_namespace:
self.namespace = ':'.join(
self.app_module_name.split('.')
)

super().__init__(**kwargs)

self.register_module_entities()

def get_routing_module_path(self):
"""Get routing module path (compiled from application name given in
:func:`__init__` and :attr:`routing_module_name`)
"""
return '.'.join([
self.app_module_name,
self.routing_module_name
])

def get_routing_module(self):
"""Load routing module using path from
:func:`get_routing_module_path`.
"""
return import_module(
self.get_routing_module_path()
)

def get_routing_entities(self):
"""Get entities using module from :func:`get_routing_module` and
attribute name from :attr:`self.entities_attribute_name`.
"""
return getattr(
self.get_routing_module(),
self.entities_attribute_name
)

def register_module_entities(self, silent=None):
"""Register entities returned by :func:`self.get_routing_entities`.
:argument silent: Override :attr:`no_app_entities_silent`
:type silent: bool or None
"""
if silent is None:
silent = self.no_app_entities_silent

entities = self.get_routing_entities()

if entities:
for entity in entities:
self.register(entity)

elif not silent:
raise ValueError(
"'{}' attribute not set (or empty) on {}"
"".format(
self.routing_module_name,
self.get_routing_module_path()
)
)
12 changes: 12 additions & 0 deletions docs/app_router.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Application router (``AppRouter``)
===================================

.. module:: django_crucrudile.routers.app

.. automodule:: django_crucrudile.routers.app
:noindex:

.. autoclass:: AppRouter
:members:
:undoc-members:
:show-inheritance:
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ django-crucrudile
entity_store
entities
routers
app_router
routes
tests

Expand Down
Loading

0 comments on commit c2c857f

Please sign in to comment.