Ticket #2539: patch_2539_code_tests.diff

File patch_2539_code_tests.diff, 17.4 KB (added by durdinator, 8 years ago)

Patch against [6589], including tests and docs

  • django/templatetags/__init__.py

     
    11from django.conf import settings
    22
    3 for a in settings.INSTALLED_APPS:
    4     try:
    5         __path__.extend(__import__(a + '.templatetags', {}, {}, ['']).__path__)
    6     except ImportError:
    7         pass
     3# Make django.template.* tag libraries available from django.templatetags.* for consistent loading
     4__path__.extend(__import__('django.template', {}, {}, ['']).__path__)
  • django/contrib/admin/views/doc.py

     
    1 from django import template, templatetags
     1from django import template
    22from django.template import RequestContext
    33from django.conf import settings
    44from django.contrib.admin.views.decorators import staff_member_required
     
    4040    load_all_installed_template_libraries()
    4141
    4242    tags = []
    43     for module_name, library in template.libraries.items():
     43    for library_name, (library, app_name, module_name) in template.libraries.items():
    4444        for tag_name, tag_func in library.tags.items():
    4545            title, body, metadata = utils.parse_docstring(tag_func.__doc__)
    4646            if title:
     
    4949                body = utils.parse_rst(body, 'tag', _('tag:') + tag_name)
    5050            for key in metadata:
    5151                metadata[key] = utils.parse_rst(metadata[key], 'tag', _('tag:') + tag_name)
    52             if library in template.builtins:
     52            if library in zip(*template.builtins)[0]:
    5353                tag_library = None
    5454            else:
    55                 tag_library = module_name.split('.')[-1]
     55                tag_library = module_name, library_name
    5656            tags.append({
    5757                'name': tag_name,
    5858                'title': title,
     
    7171    load_all_installed_template_libraries()
    7272
    7373    filters = []
    74     for module_name, library in template.libraries.items():
     74    for library_name, (library, app_name, module_name) in template.libraries.items():
    7575        for filter_name, filter_func in library.filters.items():
    7676            title, body, metadata = utils.parse_docstring(filter_func.__doc__)
    7777            if title:
     
    8080                body = utils.parse_rst(body, 'filter', _('filter:') + filter_name)
    8181            for key in metadata:
    8282                metadata[key] = utils.parse_rst(metadata[key], 'filter', _('filter:') + filter_name)
    83             if library in template.builtins:
     83            if library in zip(*template.builtins)[0]:
    8484                tag_library = None
    8585            else:
    86                 tag_library = module_name.split('.')[-1]
     86                tag_library = module_name, library_name
    8787            filters.append({
    8888                'name': filter_name,
    8989                'title': title,
     
    267267
    268268def load_all_installed_template_libraries():
    269269    # Load/register all template tag libraries from installed apps.
    270     for e in templatetags.__path__:
    271         libraries = [os.path.splitext(p)[0] for p in os.listdir(e) if p.endswith('.py') and p[0].isalpha()]
     270    for a in settings.INSTALLED_APPS:
     271        try:
     272            path = __import__(a + '.templatetags', {}, {}, ['']).__path__[0]
     273        except ImportError:
     274            continue
     275        libraries = []
     276
     277        for dirpath, dirnames, filenames in os.walk(path):
     278            libraries.extend([os.path.splitext(p)[0] for p in filenames if p.endswith('.py') and p[0].isalpha()])
     279            libraries.extend([p for p in dirnames if '.' not in p and os.path.exists(os.path.join(p, '__init__.py')) and p[0].isalpha()])
     280
    272281        for library_name in libraries:
    273282            try:
    274                 lib = template.get_library("django.templatetags.%s" % library_name.split('.')[-1])
     283                lib = template.get_library("%s.%s" % (a, library_name))
    275284            except template.InvalidTemplateLibrary:
    276285                pass
    277286
  • django/contrib/admin/templates/admin_doc/template_tag_index.html

     
    1212{% regroup tags|dictsort:"library" by library as tag_libraries %}
    1313{% for library in tag_libraries %}
    1414<div class="module">
    15     <h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in tags{% endif %}</h2>
    16     {% if library.grouper %}<p class="small quiet">To use these tags, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the tag.</p><hr>{% endif %}
     15    <h2>{% if library.grouper %}{{ library.grouper.0 }} ({{ library.grouper.1 }}){% else %}Built-in tags{% endif %}</h2>
     16    {% if library.grouper %}<p class="small quiet">To use these tags, put <code>{% templatetag openblock %} load {{ library.grouper.0 }} {% templatetag closeblock %}</code> in your template before using the tag.</p><hr>{% endif %}
    1717    {% for tag in library.list|dictsort:"name" %}
    1818    <h3 id="{{ tag.name }}">{{ tag.name }}</h3>
    1919    <h4>{{ tag.title }}</h4>
     
    3333{% regroup tags|dictsort:"library" by library as tag_libraries %}
    3434{% for library in tag_libraries %}
    3535<div class="module">
    36     <h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in tags{% endif %}</h2>
     36    <h2>{% if library.grouper %}{{ library.grouper.0 }}{% else %}Built-in tags{% endif %}</h2>
    3737    <ul>
    3838    {% for tag in library.list|dictsort:"name" %}
    3939        <li><a href="#{{ tag.name }}">{{ tag.name }}</a></li>
  • django/contrib/admin/templates/admin_doc/template_filter_index.html

     
    1212{% regroup filters|dictsort:"library" by library as filter_libraries %}
    1313{% for library in filter_libraries %}
    1414<div class="module">
    15     <h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in filters{% endif %}</h2>
    16     {% if library.grouper %}<p class="small quiet">To use these filters, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the filter.</p><hr>{% endif %}
     15    <h2>{% if library.grouper %}{{ library.grouper.0 }} ({{ library.grouper.1 }}){% else %}Built-in filters{% endif %}</h2>
     16    {% if library.grouper %}<p class="small quiet">To use these filters, put <code>{% templatetag openblock %} load {{ library.grouper.0 }} {% templatetag closeblock %}</code> in your template before using the filter.</p><hr>{% endif %}
    1717    {% for filter in library.list|dictsort:"name" %}
    1818    <h3 id="{{ filter.name }}">{{ filter.name }}</h3>
    1919    <p>{{ filter.title }}</p>
     
    3333{% regroup filters|dictsort:"library" by library as filter_libraries %}
    3434{% for library in filter_libraries %}
    3535<div class="module">
    36     <h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in filters{% endif %}</h2>
     36    <h2>{% if library.grouper %}{{ library.grouper.0 }}{% else %}Built-in filters{% endif %}</h2>
    3737    <ul>
    3838    {% for filter in library.list|dictsort:"name" %}
    3939        <li><a href="#{{ filter.name }}">{{ filter.name }}</a></li>
  • django/contrib/markup/tests.py

     
    44import re
    55import unittest
    66
    7 add_to_builtins('django.contrib.markup.templatetags.markup')
     7add_to_builtins('django.contrib.markup', 'markup')
    88
    99class Templates(unittest.TestCase):
    1010    def test_textile(self):
  • django/template/__init__.py

     
    253253        self.tokens = tokens
    254254        self.tags = {}
    255255        self.filters = {}
    256         for lib in builtins:
    257             self.add_library(lib)
     256        for lib, app, ref in builtins:
     257            self.add_library(lib, ref)
     258            self.add_library(lib, app + '.' + ref)
    258259
    259260    def parse(self, parse_until=None):
    260261        if parse_until is None: parse_until = []
     
    344345    def delete_first_token(self):
    345346        del self.tokens[0]
    346347
    347     def add_library(self, lib):
     348    def add_library(self, lib, ref):
     349        def with_ref(d):
     350            return dict([(ref + '.' + k, v) for (k, v) in d.items()])
    348351        self.tags.update(lib.tags)
     352        self.tags.update(with_ref(lib.tags))
    349353        self.filters.update(lib.filters)
     354        self.filters.update(with_ref(lib.filters))
    350355
    351356    def compile_filter(self, token):
    352357        "Convenient wrapper for FilterExpression"
     
    495500^"(?P<constant>%(str)s)"|
    496501^(?P<var>[%(var_chars)s]+)|
    497502 (?:%(filter_sep)s
    498      (?P<filter_name>\w+)
     503     (?P<filter_name>[\w\.]+)
    499504         (?:%(arg_sep)s
    500505             (?:
    501506              %(i18n_open)s"(?P<i18n_arg>%(str)s)"%(i18n_close)s|
     
    969974            return func
    970975        return dec
    971976
    972 def get_library(module_name):
    973     lib = libraries.get(module_name, None)
    974     if not lib:
     977def get_library(library_name):
     978    return get_library_details(library_name)[0]
     979
     980def get_library_details(library_name):
     981    library_details = libraries.get(library_name)
     982    if not library_details:
     983        mod = None
     984        class ModFound(Exception): pass
     985        tried = []
     986        apps = ['django'] + settings.INSTALLED_APPS
    975987        try:
    976             mod = __import__(module_name, {}, {}, [''])
    977         except ImportError, e:
    978             raise InvalidTemplateLibrary, "Could not load template library from %s, %s" % (module_name, e)
    979         try:
    980             lib = mod.register
    981             libraries[module_name] = lib
    982         except AttributeError:
    983             raise InvalidTemplateLibrary, "Template library %s does not have a variable named 'register'" % module_name
    984     return lib
     988            # For library_name of the form <app.path>.<library.path>
     989            for app_name in apps:
     990                if library_name.startswith(app_name + '.'):
     991                    module_name = library_name[len(app_name) + 1:]
     992                    try:
     993                        mod = __import__(app_name + '.templatetags.' + module_name, {}, {}, [''])
     994                    except ImportError, e:
     995                        tried.append((module_name, app_name))
     996                    else:
     997                        raise ModFound, (mod, app_name, module_name)
     998            # For library_name of the form <library.path>
     999            for app_name in apps:
     1000                try:
     1001                    mod = __import__(app_name + '.templatetags.' + library_name, {}, {}, [''])
     1002                except ImportError, e:
     1003                    tried.append((library_name, app_name))
     1004                else:
     1005                    raise ModFound, (mod, app_name, library_name)
     1006        except ModFound, e:
     1007            mod, app_name, module_name = e.args
     1008            try:
     1009                lib = mod.register
     1010                library_details = libraries[app_name + '.' + module_name] = (lib, app_name, module_name)
     1011            except AttributeError:
     1012                raise InvalidTemplateLibrary, "Template library %s does not have a variable named 'register'" % library_name
     1013        else:
     1014            tried_s = ", ".join(["'%s' from app '%s'" % t for t in tried])
     1015            raise InvalidTemplateLibrary, "Could not load template library %s; tried %s" % (library_name, tried_s)
     1016    return library_details
    9851017
    986 def add_to_builtins(module_name):
    987     builtins.append(get_library(module_name))
     1018def add_to_builtins(app_name, library_name):
     1019    builtins.append((get_library(app_name + '.' + library_name), app_name, library_name))
    9881020
    989 add_to_builtins('django.template.defaulttags')
    990 add_to_builtins('django.template.defaultfilters')
     1021add_to_builtins('django', 'defaulttags')
     1022add_to_builtins('django', 'defaultfilters')
  • django/template/defaulttags.py

     
    22
    33from django.template import Node, NodeList, Template, Context, Variable
    44from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
    5 from django.template import get_library, Library, InvalidTemplateLibrary
     5from django.template import get_library_details, Library, InvalidTemplateLibrary
    66from django.conf import settings
    77from django.utils.encoding import smart_str, smart_unicode
    88from django.utils.itercompat import groupby
     
    801801    for taglib in bits[1:]:
    802802        # add the library to the parser
    803803        try:
    804             lib = get_library("django.templatetags.%s" % taglib)
    805             parser.add_library(lib)
     804            lib, app_name, ref = get_library_details(taglib)
     805            parser.add_library(lib, taglib)
    806806        except InvalidTemplateLibrary, e:
    807807            raise TemplateSyntaxError, "'%s' is not a valid tag library: %s" % (taglib, e)
    808808    return LoadNode()
  • django/template/loader.py

     
    115115    # If we get here, none of the templates could be loaded
    116116    raise TemplateDoesNotExist, ', '.join(template_name_list)
    117117
    118 add_to_builtins('django.template.loader_tags')
     118add_to_builtins('django', 'loader_tags')
  • tests/regressiontests/humanize/tests.py

     
    44from django.utils.dateformat import DateFormat
    55from django.utils.translation import ugettext as _
    66
    7 add_to_builtins('django.contrib.humanize.templatetags.humanize')
     7add_to_builtins('django.contrib.humanize', 'humanize')
    88
    99class HumanizeTests(unittest.TestCase):
    1010
  • tests/regressiontests/templates/tests.py

     
    4141
    4242register.tag("echo", do_echo)
    4343
    44 template.libraries['django.templatetags.testtags'] = register
     44template.libraries['testtags'] = (register, 'django', 'testtags')
    4545
    4646#####################################
    4747# Helper objects for template tests #
     
    819819            'cache08' : ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
    820820            'cache09' : ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
    821821            'cache10' : ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
     822
     823            ### TAG LIBRARY NAMESPACING ###############################################
     824            'library-namespacing01': ("{% load defaulttags %}", {}, ""),
     825            'library-namespacing02': ("{% load django.defaulttags %}", {}, ""),
     826
     827            ### TAG NAMESPACING #######################################################
     828            'tag-namespacing01': ('{% defaulttags.templatetag openbrace %}', {}, '{'),
     829            'tag-namespacing02': ('{% django.defaulttags.templatetag openbrace %}', {}, '{'),
     830
     831            'tag-namespacing03': ('{% defaulttags.with a as b %}{{ b }}{% endwith %}', {'a': 'a'}, 'a'),
     832            'tag-namespacing04': ('{% django.defaulttags.with a as b %}{{ b }}{% endwith %}', {'a': 'a'}, 'a'),
     833
     834            'tag-namespacing05': ('{{ a|defaultfilters.upper }}', {'a': 'a'}, 'A'),
     835            'tag-namespacing06': ('{{ a|django.defaultfilters.upper }}', {'a': 'a'}, 'A'),
    822836        }
    823837
    824838        # Register our custom template loader.
  • docs/templates.txt

     
    363363
    364364This is a feature for the sake of maintainability and sanity.
    365365
     366Custom libraries and name conflicts
     367-----------------------------------
     368
     369If two or more libraries in different apps share the same name, then you will
     370have to load them by giving the app name and the library name, separated by
     371a dot (``.``)::
     372
     373    {% load someapp.taglibrary %}
     374    {% load otherapp.taglibrary %}
     375
     376In a similar fashion, if two different libraries offer tags or filters with
     377the same name, you can prefix the use of the tag or filter with the library
     378name to make it clear which tag or filter you wish to use::
     379
     380    {% i18n.trans "this is a test" %}
     381
     382If there is a conflict in both the library names and the tag or filter names,
     383the tag or filter prefix must be the name you loaded the library with:
     384
     385    {% load someapp.taglibrary otherapp.taglibrary %}
     386    {% someapp.taglibrary.sometag "This is the tag in someapp" %}
     387    {% otherapp.taglibrary.sometag "A completely different tag in otherapp" %}
     388
    366389Built-in tag and filter reference
    367390=================================
    368391
Back to Top