├── MANIFEST.in ├── xapp_render ├── models.py ├── __init__.py ├── templatetags │ ├── __init__.py │ ├── xapp_render.py │ └── xapp_render_jinja2.py ├── version.py ├── signals.py ├── template_utils.py ├── utils.py └── tests.py ├── stdeb.cfg ├── test_project ├── test_main_app │ ├── __init__.py │ └── templates │ │ └── test_main_app │ │ ├── testing.html │ │ └── blah.html ├── test_sub_app │ ├── __init__.py │ └── templates │ │ └── test_sub_app │ │ └── testing.html ├── test_project │ ├── __init__.py │ ├── urls.py │ ├── wsgi.py │ └── settings.py ├── test_main_coffin_app │ ├── __init__.py │ └── templates │ │ └── test_main_coffin_app │ │ ├── testing.html │ │ └── blah.html └── manage.py ├── docs ├── modules.rst ├── index.rst ├── xapp_render.templatetags.rst ├── xapp_render.rst ├── Makefile └── conf.py ├── test.sh ├── .gitignore ├── test_settings.py ├── README.rst ├── NOTICE ├── setup.py └── LICENSE /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include .GITVERSION 2 | -------------------------------------------------------------------------------- /xapp_render/models.py: -------------------------------------------------------------------------------- 1 | '''No models.''' 2 | -------------------------------------------------------------------------------- /stdeb.cfg: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | XS-Python-Version: >=2.6 -------------------------------------------------------------------------------- /xapp_render/__init__.py: -------------------------------------------------------------------------------- 1 | '''xapp_render package''' 2 | -------------------------------------------------------------------------------- /test_project/test_main_app/__init__.py: -------------------------------------------------------------------------------- 1 | '''test_main_app''' 2 | -------------------------------------------------------------------------------- /test_project/test_sub_app/__init__.py: -------------------------------------------------------------------------------- 1 | '''test_main_app''' 2 | -------------------------------------------------------------------------------- /test_project/test_project/__init__.py: -------------------------------------------------------------------------------- 1 | '''test project __init__''' -------------------------------------------------------------------------------- /test_project/test_main_coffin_app/__init__.py: -------------------------------------------------------------------------------- 1 | '''test_main_app''' 2 | -------------------------------------------------------------------------------- /xapp_render/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | '''Template tags for xapp_render''' 2 | -------------------------------------------------------------------------------- /test_project/test_sub_app/templates/test_sub_app/testing.html: -------------------------------------------------------------------------------- 1 | test_sub_app - testing.html 2 | 3 | -------------------------------------------------------------------------------- /test_project/test_main_app/templates/test_main_app/testing.html: -------------------------------------------------------------------------------- 1 | test_main_app - testing.html 2 | 3 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | xapp_render 2 | =========== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | xapp_render 8 | -------------------------------------------------------------------------------- /test_project/test_main_coffin_app/templates/test_main_coffin_app/testing.html: -------------------------------------------------------------------------------- 1 | test_main_app - testing.html 2 | 3 | -------------------------------------------------------------------------------- /xapp_render/version.py: -------------------------------------------------------------------------------- 1 | from gitversion import rewritable_git_version 2 | __VERSION__ = rewritable_git_version(__file__) 3 | -------------------------------------------------------------------------------- /test_project/test_main_app/templates/test_main_app/blah.html: -------------------------------------------------------------------------------- 1 | {% load xapp_render %} 2 | 3 | {% xapp_render "testing.html" %} 4 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd test_project 3 | ./manage.py jenkins xapp_render 4 | cd .. 5 | rm -r reports 6 | mv test_project/reports . 7 | -------------------------------------------------------------------------------- /test_project/test_main_coffin_app/templates/test_main_coffin_app/blah.html: -------------------------------------------------------------------------------- 1 | {% load xapp_render %} 2 | 3 | {% xapp_render "testing.html" %} 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | .GITVERSION 3 | *.pyc 4 | docs/_build 5 | deb_dist 6 | test_project/test_project/dbfile 7 | local_settings.py 8 | *.swp 9 | .sass-cache 10 | *.egg 11 | coverage.xml 12 | pep8.txt 13 | -------------------------------------------------------------------------------- /test_settings.py: -------------------------------------------------------------------------------- 1 | DATABASES = { 2 | 'default': { 3 | 'ENGINE': 'django.db.backends.sqlite3', 4 | }, 5 | } 6 | ROOT_URLCONF = 'django_autoconfig.autourlconf' 7 | INSTALLED_APPS = ['xapp_render',] 8 | STATIC_URL = '/static/' 9 | STATIC_ROOT = '' 10 | -------------------------------------------------------------------------------- /xapp_render/signals.py: -------------------------------------------------------------------------------- 1 | '''Signals provided by xapp_render.''' 2 | 3 | import django.dispatch 4 | 5 | #: Receivers to this signal should return rendered data as a string. 6 | RENDER_REQUESTED = django.dispatch.Signal(providing_args=['context']) 7 | 8 | #: Receivers to this signal should return a Form subclass 9 | FORM_REQUESTED = django.dispatch.Signal() 10 | -------------------------------------------------------------------------------- /test_project/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../')) 6 | 7 | if __name__ == "__main__": 8 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings") 9 | 10 | from django.core.management import execute_from_command_line 11 | 12 | execute_from_command_line(sys.argv) 13 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Django JOSSO documentation master file, created by 2 | sphinx-quickstart on Tue Nov 27 14:10:21 2012. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Django Cross-App Rendering documentation! 7 | ==================================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | modules 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | -------------------------------------------------------------------------------- /xapp_render/templatetags/xapp_render.py: -------------------------------------------------------------------------------- 1 | '''xapp_render templatetag''' 2 | # We require the 'register' variable for django to recognise this library 3 | # pylint: disable=C0103 4 | 5 | from django import template 6 | 7 | from ..template_utils import render_content 8 | 9 | register = template.Library() 10 | 11 | 12 | @register.simple_tag(takes_context=True) 13 | def xapp_render(context, identifier): 14 | ''' 15 | Takes an identifier, and renders the correct content for that 16 | identifier. 17 | ''' 18 | 19 | return render_content(identifier, context) 20 | -------------------------------------------------------------------------------- /test_project/test_project/urls.py: -------------------------------------------------------------------------------- 1 | '''test project urls.py''' 2 | from django.conf.urls import patterns, include, url 3 | 4 | # Uncomment the next two lines to enable the admin: 5 | #from django.contrib import admin 6 | #admin.autodiscover() 7 | 8 | urlpatterns = patterns('', 9 | # Examples: 10 | # url(r'^$', 'test_project.views.home', name='home'), 11 | # url(r'^test_project/', include('test_project.foo.urls')), 12 | 13 | # Uncomment the admin/doc line below to enable admin documentation: 14 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 15 | ) 16 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ****************** 2 | django-xapp-render 3 | ****************** 4 | 5 | Cross-app rendering utilities for Django. 6 | 7 | =========== 8 | Quick Start 9 | =========== 10 | 11 | * Install ``django-xapp-render`` with ``pip install django-xapp-render``. 12 | * Add ``xapp_render`` to your ``INSTALLED_APPS``. 13 | 14 | ============ 15 | Contributing 16 | ============ 17 | 18 | To contribute, fork the repo, do your work, and issue a pull request. We ask that contributors adhere to `PEP8 `_ standards, and include full tests for all their code. 19 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Ocado Innovation Limited 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /docs/xapp_render.templatetags.rst: -------------------------------------------------------------------------------- 1 | templatetags Package 2 | ==================== 3 | 4 | :mod:`templatetags` Package 5 | --------------------------- 6 | 7 | .. automodule:: xapp_render.templatetags 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | :mod:`xapp_render` Module 13 | ------------------------- 14 | 15 | .. automodule:: xapp_render.templatetags.xapp_render 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | :mod:`xapp_render_jinja2` Module 21 | -------------------------------- 22 | 23 | .. automodule:: xapp_render.templatetags.xapp_render_jinja2 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | '''setup.py for django-xapp-render''' 2 | from setuptools import setup, find_packages 3 | from xapp_render.version import __VERSION__ 4 | 5 | setup( 6 | name = 'django-xapp-render', 7 | version = __VERSION__, 8 | description = 'Cross app rendering utilities.', 9 | long_description = '''Cross app rendering utilities.''', 10 | author = 'Netnix', 11 | author_email = 'netnix@ocado.com', 12 | maintainer = 'Mike Bryant', 13 | maintainer_email = 'mike.bryant@ocado.com', 14 | packages = find_packages(), 15 | install_requires = ['django >= 1.4', 'jinja2'], 16 | tests_require = ['coffin', 'jinja2', 'mock'], 17 | ) 18 | -------------------------------------------------------------------------------- /docs/xapp_render.rst: -------------------------------------------------------------------------------- 1 | xapp_render Package 2 | =================== 3 | 4 | :mod:`xapp_render` Package 5 | -------------------------- 6 | 7 | .. automodule:: xapp_render.__init__ 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | :mod:`models` Module 13 | -------------------- 14 | 15 | .. automodule:: xapp_render.models 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | :mod:`template_utils` Module 21 | ---------------------------- 22 | 23 | .. automodule:: xapp_render.template_utils 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | :mod:`tests` Module 29 | ------------------- 30 | 31 | .. automodule:: xapp_render.tests 32 | :members: 33 | :undoc-members: 34 | :show-inheritance: 35 | 36 | Subpackages 37 | ----------- 38 | 39 | .. toctree:: 40 | 41 | xapp_render.templatetags 42 | 43 | -------------------------------------------------------------------------------- /test_project/test_project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for test_project project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings") 19 | 20 | # This application object is used by any WSGI server configured to use this 21 | # file. This includes Django's development server, if the WSGI_APPLICATION 22 | # setting points here. 23 | from django.core.wsgi import get_wsgi_application 24 | application = get_wsgi_application() 25 | 26 | # Apply WSGI middleware here. 27 | # from helloworld.wsgi import HelloWorldApplication 28 | # application = HelloWorldApplication(application) -------------------------------------------------------------------------------- /xapp_render/templatetags/xapp_render_jinja2.py: -------------------------------------------------------------------------------- 1 | '''xapp_render templatetag for Jinja2''' 2 | # We require the 'register' variable for django to recognise this library 3 | # pylint: disable=C0103 4 | 5 | from coffin import template 6 | import jinja2 7 | from jinja2.ext import Extension 8 | 9 | from ..template_utils import render_content 10 | 11 | register = template.Library() 12 | 13 | 14 | @register.tag() 15 | class XappRenderExtension(Extension): 16 | ''' 17 | Takes an identifier, and renders the correct content for that 18 | identifier. 19 | ''' 20 | 21 | tags = set(['xapp_render']) 22 | 23 | def parse(self, parser): 24 | # This is the xapp_render tag token. 25 | token = parser.stream.next() 26 | 27 | # This is the identifier 28 | args = [parser.parse_expression()] 29 | 30 | return jinja2.nodes.CallBlock( 31 | self.call_method('_xapp_support', args), 32 | [], [], [] 33 | ).set_lineno(token.lineno) 34 | 35 | @jinja2.contextfunction 36 | def _xapp_support(self, context, identifier, caller): 37 | """Callback for rendering the node.""" 38 | # It needs to be a method for autoloading 39 | # pylint: disable=R0201 40 | 41 | # caller is passed as a keyword argument, so we can't rename it 42 | # pylint: disable=W0613 43 | 44 | return render_content(identifier, context) 45 | -------------------------------------------------------------------------------- /xapp_render/template_utils.py: -------------------------------------------------------------------------------- 1 | '''Utilities for the template tags to use.''' 2 | 3 | from django.conf import settings 4 | from django.template import TemplateDoesNotExist 5 | from django.template.loader import render_to_string 6 | 7 | from .signals import RENDER_REQUESTED 8 | 9 | import logging 10 | LOGGER = logging.getLogger(__name__) 11 | 12 | #: Holds the template cache 13 | #: The keys are xapp identifiers, and the value 14 | #: is a list of valid templates 15 | TEMPLATE_CACHE = {} 16 | 17 | def render_content(identifier, context): 18 | '''Find all the appropriate chunks of content and render them.''' 19 | 20 | content = '' 21 | working_modules = [] 22 | 23 | cached_modules = TEMPLATE_CACHE.get(identifier, settings.INSTALLED_APPS) 24 | 25 | for module in cached_modules: 26 | short_name = module.split('.')[-1] 27 | template_name = "%s/%s" % (short_name, identifier) 28 | try: 29 | content += render_to_string(template_name, context) 30 | working_modules.append(module) 31 | except TemplateDoesNotExist as err: 32 | missing_name = err.args[0] 33 | if missing_name == template_name: 34 | LOGGER.debug( 35 | "Template %s not found during xapp_render", 36 | template_name, 37 | ) 38 | else: 39 | raise 40 | 41 | if identifier not in TEMPLATE_CACHE: 42 | TEMPLATE_CACHE[identifier] = working_modules 43 | 44 | LOGGER.debug('Calling signal handler for identifier %s', identifier) 45 | for (_receiver, response) in RENDER_REQUESTED.send( 46 | sender=identifier, 47 | context=context, 48 | ): 49 | content += response 50 | 51 | return content 52 | 53 | def reset_cache(): 54 | '''Reset the template cache.''' 55 | TEMPLATE_CACHE.clear() 56 | -------------------------------------------------------------------------------- /xapp_render/utils.py: -------------------------------------------------------------------------------- 1 | '''Utilities for xapp_render.''' 2 | 3 | from django.dispatch import receiver 4 | from functools import wraps 5 | 6 | from .signals import RENDER_REQUESTED, FORM_REQUESTED 7 | 8 | # We like magic! 9 | # pylint: disable=W0142 10 | 11 | def xapp_receiver(identifier, **kwargs): 12 | """ 13 | A decorator for connecting receivers to the RENDER_REQUESTED signal. 14 | Used by passing in the identifier you want to render for. 15 | """ 16 | def function_decorator(func): 17 | '''Decorator function.''' 18 | @receiver(RENDER_REQUESTED, **kwargs) 19 | @wraps(func) 20 | def wrapper(sender, context, *_args, **_func_kwargs): 21 | '''Wrapper for the function, only executes if the sender matches 22 | the identifier. 23 | ''' 24 | if sender == identifier: 25 | return func(context) 26 | else: 27 | return '' 28 | return wrapper 29 | return function_decorator 30 | 31 | def xapp_form(identifier, **kwargs): 32 | ''' 33 | A class decorator, which will result in the class being 34 | passed when asked for by the FORM_REQUESTED signal. 35 | ''' 36 | def class_decorator(klass): 37 | '''Decorate the class.''' 38 | 39 | @receiver(FORM_REQUESTED, **kwargs) 40 | def form_receiver(sender, *_args, **_kwargs): 41 | '''When the right identifier is asked for, return this Form.''' 42 | if sender == identifier: 43 | return klass 44 | else: 45 | return None 46 | 47 | # Deal with weak references 48 | xapp_receivers = getattr(klass, 'xapp_receivers', []) 49 | xapp_receivers.append(form_receiver) 50 | klass.xapp_receivers = xapp_receivers 51 | 52 | return klass 53 | 54 | return class_decorator 55 | 56 | def get_xapp_form(identifier): 57 | '''Return the Form.''' 58 | possible_parents = [] 59 | parents = [] 60 | 61 | for (_receiver, response) in FORM_REQUESTED.send(sender=identifier): 62 | if response is not None: 63 | possible_parents.append(response) 64 | 65 | for parent in possible_parents: 66 | for other_parent in possible_parents: 67 | if parent is not other_parent and parent in other_parent.mro(): 68 | break 69 | else: 70 | # We didn't find it in any of the mros, so we include it. 71 | parents.append(parent) 72 | 73 | return type('DynamicForm', tuple(parents), {}) 74 | 75 | def xapp_form_factory(identifier): 76 | '''Return a callable, 77 | which will return a Form instance from all the xapp signals. 78 | ''' 79 | def form_instance(*args, **kwargs): 80 | '''Instantiate the form.''' 81 | return get_xapp_form(identifier)(*args, **kwargs) 82 | 83 | return form_instance 84 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DjangoJOSSO.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DjangoJOSSO.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/DjangoJOSSO" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/DjangoJOSSO" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." -------------------------------------------------------------------------------- /test_project/test_project/settings.py: -------------------------------------------------------------------------------- 1 | '''Django settings for test_project project.''' 2 | import os 3 | 4 | DEBUG = True 5 | TEMPLATE_DEBUG = DEBUG 6 | 7 | ADMINS = ( 8 | # ('Your Name', 'your_email@example.com'), 9 | ) 10 | 11 | MANAGERS = ADMINS 12 | 13 | 14 | DATABASES = { 15 | 'default': { 16 | 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 17 | 'NAME': os.path.join(os.path.abspath(os.path.dirname(__file__)),'dbfile'),# Or path to database file if using sqlite3. 18 | 'USER': '', # Not used with sqlite3. 19 | 'PASSWORD': '', # Not used with sqlite3. 20 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 21 | 'PORT': '', # Set to empty string for default. Not used with sqlite3. 22 | } 23 | } 24 | 25 | # Local time zone for this installation. Choices can be found here: 26 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 27 | # although not all choices may be available on all operating systems. 28 | # In a Windows environment this must be set to your system time zone. 29 | TIME_ZONE = 'Europe/London' 30 | 31 | SITE_TITLE = 'django-xapp-render' 32 | 33 | # Language code for this installation. All choices can be found here: 34 | # http://www.i18nguy.com/unicode/language-identifiers.html 35 | LANGUAGE_CODE = 'en-gb' 36 | 37 | SITE_ID = 1 38 | 39 | # If you set this to False, Django will make some optimizations so as not 40 | # to load the internationalization machinery. 41 | USE_I18N = True 42 | 43 | # If you set this to False, Django will not format dates, numbers and 44 | # calendars according to the current locale. 45 | USE_L10N = True 46 | 47 | # If you set this to False, Django will not use timezone-aware datetimes. 48 | USE_TZ = True 49 | 50 | # Absolute filesystem path to the directory that will hold user-uploaded files. 51 | # Example: "/home/media/media.lawrence.com/media/" 52 | MEDIA_ROOT = '' 53 | 54 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 55 | # trailing slash. 56 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" 57 | MEDIA_URL = '' 58 | 59 | # Absolute path to the directory static files should be collected to. 60 | # Don't put anything in this directory yourself; store your static files 61 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 62 | # Example: "/home/media/media.lawrence.com/static/" 63 | STATIC_ROOT = '' 64 | 65 | # URL prefix for static files. 66 | # Example: "http://media.lawrence.com/static/" 67 | STATIC_URL = '/static/' 68 | 69 | # Additional locations of static files 70 | STATICFILES_DIRS = ( 71 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 72 | # Always use forward slashes, even on Windows. 73 | # Don't forget to use absolute paths, not relative paths. 74 | ) 75 | 76 | # List of finder classes that know how to find static files in 77 | # various locations. 78 | STATICFILES_FINDERS = ( 79 | 'django.contrib.staticfiles.finders.FileSystemFinder', 80 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 81 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 82 | ) 83 | 84 | # Make this unique, and don't share it with anybody. 85 | SECRET_KEY = 'j$w9t$1(e7k*=c!ks!z&w0s6af!xrku1%&6!c@_5wwicjg&c_c' 86 | 87 | 88 | MIDDLEWARE_CLASSES = ( 89 | 'django.middleware.common.CommonMiddleware', 90 | 'django.contrib.sessions.middleware.SessionMiddleware', 91 | 'django.middleware.csrf.CsrfViewMiddleware', 92 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 93 | 'django.contrib.messages.middleware.MessageMiddleware', 94 | 95 | # Uncomment the next line for simple clickjacking protection: 96 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 97 | ) 98 | 99 | ROOT_URLCONF = 'test_project.urls' 100 | 101 | # Python dotted path to the WSGI application used by Django's runserver. 102 | WSGI_APPLICATION = 'test_project.wsgi.application' 103 | 104 | TEMPLATE_DIRS = ( 105 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 106 | # Always use forward slashes, even on Windows. 107 | # Don't forget to use absolute paths, not relative paths. 108 | ) 109 | 110 | 111 | TEMPLATE_LOADERS = ( 112 | 'coffin.template.loaders.Loader', 113 | ) 114 | JINJA2_TEMPLATE_LOADERS = ( 115 | 'django.template.loaders.filesystem.Loader', 116 | 'django.template.loaders.app_directories.Loader', 117 | # 'django.template.loaders.eggs.Loader', 118 | ) 119 | 120 | INSTALLED_APPS = ( 121 | 'django.contrib.auth', 122 | 'django.contrib.contenttypes', 123 | 'django.contrib.sessions', 124 | 'django.contrib.messages', 125 | 'django.contrib.staticfiles', 126 | 127 | 'xapp_render', 128 | 'test_main_app', 129 | 'test_main_coffin_app', 130 | 'test_sub_app', 131 | 132 | # Uncomment the next line to enable the admin: 133 | 'django.contrib.admin', 134 | # Uncomment the next line to enable admin documentation: 135 | # 'django.contrib.admindocs', 136 | 'django_jenkins', 137 | ) 138 | 139 | JINJA2_DISABLED_TEMPLATES = ( 140 | 'test_main_app', 141 | ) 142 | 143 | # A sample logging configuration. The only tangible logging 144 | # performed by this configuration is to send an email to 145 | # the site admins on every HTTP 500 error when DEBUG=False. 146 | # See http://docs.djangoproject.com/en/dev/topics/logging for 147 | # more details on how to customize your logging configuration. 148 | LOGGING = { 149 | 'version': 1, 150 | 'disable_existing_loggers': False, 151 | 'filters': { 152 | 'require_debug_false': { 153 | '()': 'django.utils.log.RequireDebugFalse' 154 | } 155 | }, 156 | 'formatters': { 157 | 'verbose': { 158 | 'format': '<%= vipgroup %>[<%= vip %>-%(process)d]: [%(name)s][%(levelname)s] %(message)s', 159 | }, 160 | 'simple': { 161 | 'format': '%(levelname)s %(message)s', 162 | }, 163 | }, 164 | 'handlers': { 165 | 'mail_admins': { 166 | 'level': 'ERROR', 167 | 'filters': ['require_debug_false'], 168 | 'class': 'django.utils.log.AdminEmailHandler' 169 | }, 170 | 'console':{ 171 | 'level':'DEBUG', 172 | 'class':'logging.StreamHandler', 173 | 'formatter': 'simple', 174 | }, 175 | }, 176 | 'loggers': { 177 | '': { 178 | 'handlers':['console'], 179 | 'propagate': True, 180 | 'level':'DEBUG', 181 | }, 182 | 'suds': { 183 | 'level': 'CRITICAL', 184 | 'propagate': True, 185 | }, 186 | 'django.request': { 187 | 'handlers': ['mail_admins'], 188 | 'level': 'ERROR', 189 | 'propagate': True, 190 | }, 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /xapp_render/tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for xapp_render 3 | """ 4 | 5 | # pylint: disable=R0904 6 | # pylint: disable=C0103 7 | # pylint: disable=C0111 8 | # pylint: disable=W0232 9 | # pylint: disable=R0903 10 | 11 | import mock 12 | import os 13 | import shutil 14 | import sys 15 | import tempfile 16 | 17 | from django.core.management import call_command 18 | from django.dispatch import receiver 19 | from django import forms 20 | from django.template import TemplateDoesNotExist 21 | import django.template.loader 22 | from django.template.loader import render_to_string 23 | import django.template.loaders.app_directories 24 | from django.test import TestCase 25 | from django.test.signals import setting_changed 26 | from django.test.utils import override_settings 27 | 28 | from .template_utils import reset_cache 29 | from .utils import xapp_receiver, xapp_form, xapp_form_factory, get_xapp_form 30 | 31 | @receiver(setting_changed) 32 | def cache_reset_handler(*_args, **_kwargs): 33 | '''Reset the cache whenever we change installed apps.''' 34 | reset_cache() 35 | 36 | @xapp_receiver('test5.html') 37 | def test5_rendered_data(context): 38 | '''Respond with some data rendered from the context.''' 39 | return render_to_string('xapp_test_app_1/test5_data.html', context) 40 | 41 | @xapp_form('form1') 42 | @xapp_form('form3') 43 | class FormA(forms.Form): 44 | field_a = forms.CharField() 45 | 46 | @xapp_form('form2') 47 | class FormB(forms.Form): 48 | field_b = forms.CharField() 49 | 50 | @xapp_form('form2') 51 | class FormC(forms.Form): 52 | field_c = forms.CharField() 53 | 54 | @xapp_form('form3') 55 | class FormD(forms.Form): 56 | field_d = forms.CharField() 57 | 58 | @xapp_form('form3') 59 | class FormE(FormD): 60 | field_e = forms.CharField() 61 | 62 | class FormTestCase(TestCase): 63 | '''Test form functionality.''' 64 | 65 | def test_single_form(self): 66 | form = xapp_form_factory('form1')() 67 | self.assertIn('field_a', form.fields) 68 | 69 | def test_multiple_forms(self): 70 | form = get_xapp_form('form2')() 71 | self.assertIn('field_b', form.fields) 72 | self.assertIn('field_c', form.fields) 73 | self.assertNotIn('field_a', form.fields) 74 | 75 | def test_conflicting_mro(self): 76 | form = get_xapp_form('form3')() 77 | self.assertIn('field_a', form.fields) 78 | self.assertIn('field_d', form.fields) 79 | self.assertIn('field_e', form.fields) 80 | 81 | class AppCreatorTestCase(TestCase): 82 | '''Test case that creates some extra apps.''' 83 | 84 | apps = [] 85 | templates = {} 86 | 87 | def setUp(self): 88 | reload(django.template.loaders.app_directories) 89 | django.template.loader.template_source_loaders = None 90 | 91 | @classmethod 92 | def setUpClass(cls): 93 | """ 94 | Create the apps. 95 | """ 96 | cls.app_directory = tempfile.mkdtemp() 97 | for app_name in cls.apps: 98 | app_dir = "%s/%s" % (cls.app_directory, app_name) 99 | os.mkdir(app_dir) 100 | call_command('startapp', app_name, app_dir) 101 | os.mkdir("%s/templates" % app_dir) 102 | template_dir = "%s/templates/%s" % (app_dir, app_name) 103 | os.mkdir(template_dir) 104 | 105 | try: 106 | for template_name, template_content in cls.templates[app_name]: 107 | with open("%s/%s" % (template_dir, template_name), 'w') as fobj: 108 | fobj.write(template_content) 109 | except KeyError: 110 | pass 111 | 112 | sys.path.insert(0, cls.app_directory) 113 | 114 | @classmethod 115 | def tearDownClass(cls): 116 | """Clear up the apps""" 117 | sys.path.remove(cls.app_directory) 118 | shutil.rmtree(cls.app_directory) 119 | 120 | @override_settings( 121 | INSTALLED_APPS=['xapp_render', 'xapp_test_app_1', 'xapp_test_app_2', 'xapp_test_app_3'], 122 | TEMPLATE_LOADERS = ( 123 | 'django.template.loaders.filesystem.Loader', 124 | 'django.template.loaders.app_directories.Loader', 125 | ), 126 | ) 127 | class DjangoTestCase(AppCreatorTestCase): 128 | '''Test the simple case, with only templates''' 129 | 130 | apps = ['xapp_test_app_1', 'xapp_test_app_2', 'xapp_test_app_3'] 131 | templates = { 132 | 'xapp_test_app_1': ( 133 | ('base.html', '{% load xapp_render %}{% xapp_render "test1.html" %}'), 134 | ('base2.html', '{% load xapp_render %}{% xapp_render "test4.html" %}'), 135 | ('base3.html', '{% load xapp_render %}{% xapp_render "test5.html" %}'), 136 | ('test5_data.html', 'Data5: {{ context_data5 }}'), 137 | ), 138 | 'xapp_test_app_2': ( 139 | ('test1.html', '{% ifequal True True %}Flibble{% endifequal %}'), #Need to be sure we're in django 140 | ('test4.html', '{% include "notexist.html" %}'), 141 | ), 142 | 'xapp_test_app_3': ( 143 | ('test1.html', 'Dribble'), 144 | ), 145 | } 146 | 147 | def test_content(self): 148 | '''Test if rendering the templates includes the content''' 149 | self.assertIn('FlibbleDribble', render_to_string('xapp_test_app_1/base.html', {})) 150 | 151 | def test_signals(self): 152 | '''Test signals functionality.''' 153 | result = render_to_string('xapp_test_app_1/base3.html', {'context_data5': 'XXYYZZ5'}) 154 | self.assertIn('Data5: XXYYZZ5', result) 155 | self.assertNotIn('Data5: XXYYZZ5', render_to_string('xapp_test_app_1/base.html', {'context_data5': 'XXYYZZ5'})) 156 | 157 | def test_broken_templates(self): 158 | '''We want to raise TemplateDoesNotExist if the reason behind 159 | one of the xapp templates not existing is because it includes 160 | something broken. 161 | ''' 162 | with self.assertRaises(TemplateDoesNotExist): 163 | render_to_string('xapp_test_app_1/base2.html', {}) 164 | 165 | def broken_open(*_args, **_kwargs): 166 | '''Break open completely.''' 167 | raise Exception 168 | 169 | @override_settings( 170 | INSTALLED_APPS=['xapp_render', 'xapp_test_app_8', 'xapp_test_app_9', 'xapp_test_app_10'], 171 | TEMPLATE_LOADERS = ( 172 | ('django.template.loaders.cached.Loader', ( 173 | 'django.template.loaders.filesystem.Loader', 174 | 'django.template.loaders.app_directories.Loader', 175 | )), 176 | ), 177 | ) 178 | class CachedTestCase(AppCreatorTestCase): 179 | '''Test caching of templates.''' 180 | 181 | apps = ['xapp_test_app_8', 'xapp_test_app_9', 'xapp_test_app_10'] 182 | templates = { 183 | 'xapp_test_app_8': ( 184 | ('base.html', '{% load xapp_render %}{% xapp_render "test3.html" %}'), 185 | ), 186 | 'xapp_test_app_9': ( 187 | ('test3.html', 'Blah'), 188 | ), 189 | 'xapp_test_app_10': ( 190 | ), 191 | } 192 | 193 | def test_caching(self): 194 | '''Test if the missing template caching code is working.''' 195 | # If we're not doing negative caching we'll hit the open call, and things will break 196 | reset_cache() 197 | with mock.patch('__builtin__.open', broken_open): 198 | with self.assertRaises(Exception): 199 | render_to_string('xapp_test_app_8/base.html', {}) 200 | 201 | self.assertIn('Blah', render_to_string('xapp_test_app_8/base.html', {})) 202 | with mock.patch('__builtin__.open', broken_open): 203 | self.assertIn('Blah', render_to_string('xapp_test_app_8/base.html', {})) 204 | 205 | 206 | 207 | @override_settings( 208 | INSTALLED_APPS=['xapp_render', 'xapp_test_app_4', 'xapp_test_app_5', 'xapp_test_app_6', 'xapp_test_app_7'], 209 | TEMPLATE_LOADERS = ( 210 | 'coffin.template.loaders.Loader', 211 | ), 212 | JINJA2_TEMPLATE_LOADERS = ( 213 | 'django.template.loaders.filesystem.Loader', 214 | 'django.template.loaders.app_directories.Loader', 215 | ), 216 | ) 217 | class Jinja2TestCase(AppCreatorTestCase): 218 | '''Test the simple case, with only templates''' 219 | 220 | apps = ['xapp_test_app_4', 'xapp_test_app_5', 'xapp_test_app_6', 'xapp_test_app_7'] 221 | templates = { 222 | 'xapp_test_app_4': ( 223 | ('base2.html', '{% xapp_render "test2.html" %}'), 224 | ), 225 | 'xapp_test_app_5': ( 226 | ('test2.html', 'Flibble'), 227 | ), 228 | 'xapp_test_app_6': ( 229 | ('test2.html', 'Dribble'), 230 | ), 231 | } 232 | 233 | def test_content(self): 234 | '''Test if rendering the templates includes the content''' 235 | self.assertIn('FlibbleDribble', render_to_string('xapp_test_app_4/base2.html', {})) 236 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Django Django-Xapp-Render documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Nov 27 14:10:21 2012. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | from gitversion import get_git_version 16 | 17 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../')) 18 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../test_project/')) 19 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings") 20 | 21 | # If extensions (or modules to document with autodoc) are in another directory, 22 | # add these directories to sys.path here. If the directory is relative to the 23 | # documentation root, use os.path.abspath to make it absolute, like shown here. 24 | #sys.path.insert(0, os.path.abspath('.')) 25 | 26 | # -- General configuration ----------------------------------------------------- 27 | 28 | # If your documentation needs a minimal Sphinx version, state it here. 29 | #needs_sphinx = '1.0' 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be extensions 32 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 33 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.viewcode'] 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ['_templates'] 37 | 38 | # The suffix of source filenames. 39 | source_suffix = '.rst' 40 | 41 | # The encoding of source files. 42 | #source_encoding = 'utf-8-sig' 43 | 44 | # The master toctree document. 45 | master_doc = 'index' 46 | 47 | # General information about the project. 48 | project = u'Django Cross-app Rendering' 49 | copyright = u'2012, Ocado' 50 | 51 | # The version info for the project you're documenting, acts as replacement for 52 | # |version| and |release|, also used in various other places throughout the 53 | # built documents. 54 | # 55 | git_version = get_git_version(__file__) 56 | # The short X.Y version. 57 | version = git_version.split('-')[0] 58 | # The full version, including alpha/beta/rc tags. 59 | release = git_version 60 | 61 | # The language for content autogenerated by Sphinx. Refer to documentation 62 | # for a list of supported languages. 63 | #language = None 64 | 65 | # There are two options for replacing |today|: either, you set today to some 66 | # non-false value, then it is used: 67 | #today = '' 68 | # Else, today_fmt is used as the format for a strftime call. 69 | #today_fmt = '%B %d, %Y' 70 | 71 | # List of patterns, relative to source directory, that match files and 72 | # directories to ignore when looking for source files. 73 | exclude_patterns = ['_build'] 74 | 75 | # The reST default role (used for this markup: `text`) to use for all documents. 76 | #default_role = None 77 | 78 | # If true, '()' will be appended to :func: etc. cross-reference text. 79 | #add_function_parentheses = True 80 | 81 | # If true, the current module name will be prepended to all description 82 | # unit titles (such as .. function::). 83 | #add_module_names = True 84 | 85 | # If true, sectionauthor and moduleauthor directives will be shown in the 86 | # output. They are ignored by default. 87 | #show_authors = False 88 | 89 | # The name of the Pygments (syntax highlighting) style to use. 90 | pygments_style = 'sphinx' 91 | 92 | # A list of ignored prefixes for module index sorting. 93 | #modindex_common_prefix = [] 94 | 95 | 96 | # -- Options for HTML output --------------------------------------------------- 97 | 98 | # The theme to use for HTML and HTML Help pages. See the documentation for 99 | # a list of builtin themes. 100 | html_theme = 'default' 101 | 102 | # Theme options are theme-specific and customize the look and feel of a theme 103 | # further. For a list of options available for each theme, see the 104 | # documentation. 105 | #html_theme_options = {} 106 | 107 | # Add any paths that contain custom themes here, relative to this directory. 108 | #html_theme_path = [] 109 | 110 | # The name for this set of Sphinx documents. If None, it defaults to 111 | # " v documentation". 112 | #html_title = None 113 | 114 | # A shorter title for the navigation bar. Default is the same as html_title. 115 | #html_short_title = None 116 | 117 | # The name of an image file (relative to this directory) to place at the top 118 | # of the sidebar. 119 | #html_logo = None 120 | 121 | # The name of an image file (within the static path) to use as favicon of the 122 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 123 | # pixels large. 124 | #html_favicon = None 125 | 126 | # Add any paths that contain custom static files (such as style sheets) here, 127 | # relative to this directory. They are copied after the builtin static files, 128 | # so a file named "default.css" will overwrite the builtin "default.css". 129 | html_static_path = ['_static'] 130 | 131 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 132 | # using the given strftime format. 133 | #html_last_updated_fmt = '%b %d, %Y' 134 | 135 | # If true, SmartyPants will be used to convert quotes and dashes to 136 | # typographically correct entities. 137 | #html_use_smartypants = True 138 | 139 | # Custom sidebar templates, maps document names to template names. 140 | #html_sidebars = {} 141 | 142 | # Additional templates that should be rendered to pages, maps page names to 143 | # template names. 144 | #html_additional_pages = {} 145 | 146 | # If false, no module index is generated. 147 | #html_domain_indices = True 148 | 149 | # If false, no index is generated. 150 | #html_use_index = True 151 | 152 | # If true, the index is split into individual pages for each letter. 153 | #html_split_index = False 154 | 155 | # If true, links to the reST sources are added to the pages. 156 | #html_show_sourcelink = True 157 | 158 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 159 | #html_show_sphinx = True 160 | 161 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 162 | #html_show_copyright = True 163 | 164 | # If true, an OpenSearch description file will be output, and all pages will 165 | # contain a tag referring to it. The value of this option must be the 166 | # base URL from which the finished HTML is served. 167 | #html_use_opensearch = '' 168 | 169 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 170 | #html_file_suffix = None 171 | 172 | # Output file base name for HTML help builder. 173 | htmlhelp_basename = 'DjangoDjango-Xapp-Renderdoc' 174 | 175 | 176 | # -- Options for LaTeX output -------------------------------------------------- 177 | 178 | latex_elements = { 179 | # The paper size ('letterpaper' or 'a4paper'). 180 | #'papersize': 'letterpaper', 181 | 182 | # The font size ('10pt', '11pt' or '12pt'). 183 | #'pointsize': '10pt', 184 | 185 | # Additional stuff for the LaTeX preamble. 186 | #'preamble': '', 187 | } 188 | 189 | # Grouping the document tree into LaTeX files. List of tuples 190 | # (source start file, target name, title, author, documentclass [howto/manual]). 191 | latex_documents = [ 192 | ('index', 'DjangoDjango-Xapp-Render.tex', u'Django Django-Xapp-Render Documentation', 193 | u'Mike Bryant', 'manual'), 194 | ] 195 | 196 | # The name of an image file (relative to this directory) to place at the top of 197 | # the title page. 198 | #latex_logo = None 199 | 200 | # For "manual" documents, if this is true, then toplevel headings are parts, 201 | # not chapters. 202 | #latex_use_parts = False 203 | 204 | # If true, show page references after internal links. 205 | #latex_show_pagerefs = False 206 | 207 | # If true, show URL addresses after external links. 208 | #latex_show_urls = False 209 | 210 | # Documents to append as an appendix to all manuals. 211 | #latex_appendices = [] 212 | 213 | # If false, no module index is generated. 214 | #latex_domain_indices = True 215 | 216 | 217 | # -- Options for manual page output -------------------------------------------- 218 | 219 | # One entry per manual page. List of tuples 220 | # (source start file, name, description, authors, manual section). 221 | man_pages = [ 222 | ('index', 'djangodjango-xapp-render', u'Django Django-Xapp-Render Documentation', 223 | [u'Mike Bryant'], 1) 224 | ] 225 | 226 | # If true, show URL addresses after external links. 227 | #man_show_urls = False 228 | 229 | 230 | # -- Options for Texinfo output ------------------------------------------------ 231 | 232 | # Grouping the document tree into Texinfo files. List of tuples 233 | # (source start file, target name, title, author, 234 | # dir menu entry, description, category) 235 | texinfo_documents = [ 236 | ('index', 'DjangoDjango-Xapp-Render', u'Django Django-Xapp-Render Documentation', 237 | u'Mike Bryant', 'DjangoDjango-Xapp-Render', 'Cross app rendering utilities.', 238 | 'Miscellaneous'), 239 | ] 240 | 241 | # Documents to append as an appendix to all manuals. 242 | #texinfo_appendices = [] 243 | 244 | # If false, no module index is generated. 245 | #texinfo_domain_indices = True 246 | 247 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 248 | #texinfo_show_urls = 'footnote' 249 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------