From 18f43e542117f089f0688076836423a2ece091ca Mon Sep 17 00:00:00 2001 From: Robert Wittams Date: Tue, 1 Nov 2005 15:11:28 +0000 Subject: [PATCH] Regex based filter profiler. 150% -> 170% speed up of parsing a filter. Also preserves i18n behaviour from i18n branch. Fix for auto populated field js and setup.py git-svn-id: http://code.djangoproject.com/svn/django/branches/new-admin@1040 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- .../admin/templatetags/admin_modify.py | 2 +- django/core/handlers/profiler-hotshot.py | 2 +- django/core/template/__init__.py | 76 ++++++++++++++++++- setup.py | 14 ++-- tests/othertests/templates.py | 16 ++++ 5 files changed, 102 insertions(+), 8 deletions(-) diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py index 995b2844f5..df9f4e70eb 100644 --- a/django/contrib/admin/templatetags/admin_modify.py +++ b/django/contrib/admin/templatetags/admin_modify.py @@ -205,7 +205,7 @@ def auto_populated_field_script(auto_pop_fields, change = False): for f in field.prepopulate_from: t.append('document.getElementById("id_%s").onkeyup = function() {' \ ' var e = document.getElementById("id_%s");' \ - ' if(!e._changed) { e.value = URLify(%s, %s);} } ' % ( + ' if(!e._changed) { e.value = URLify(%s, %s);} }; ' % ( f, field.name, add_values, field.maxlength) ) return ''.join(t) auto_populated_field_script = simple_tag(auto_populated_field_script) diff --git a/django/core/handlers/profiler-hotshot.py b/django/core/handlers/profiler-hotshot.py index 953cf0a722..6cf94b0c00 100644 --- a/django/core/handlers/profiler-hotshot.py +++ b/django/core/handlers/profiler-hotshot.py @@ -1,7 +1,7 @@ import hotshot, time, os from django.core.handlers.modpython import ModPythonHandler -PROFILE_DATA_DIR = "/var/log/cmsprofile/" +PROFILE_DATA_DIR = "/var/log/cmsprofile" def handler(req): ''' diff --git a/django/core/template/__init__.py b/django/core/template/__init__.py index 1b4056b9ca..7437a71e3f 100644 --- a/django/core/template/__init__.py +++ b/django/core/template/__init__.py @@ -516,9 +516,83 @@ class FilterParser: self.next_char() return arg + +filter_raw_string = r""" +^%(i18n_open)s"(?P%(str)s)"%(i18n_close)s| +^"(?P%(str)s)"| +^(?P[%(var_chars)s]+)| + (?:%(filter_sep)s + (?P\w+) + (?:%(arg_sep)s + (?: + %(i18n_open)s"(?P%(str)s)"%(i18n_close)s| + "(?P%(str)s)" + ) + ){0,1} + )"""% { + 'str': r"""[^"\\]*(?:\\.[^"\\]*)*""", + 'var_chars': "A-Za-z0-9\_\." , + 'filter_sep': re.escape(FILTER_SEPARATOR), + 'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR), + 'i18n_open' : re.escape("_("), + 'i18n_close' : re.escape(")"), + } + +filter_raw_string = filter_raw_string.replace("\n", "").replace(" ", "") + +filter_re = re.compile(filter_raw_string) + +class RegexFilterParser(object): + """ Not used yet because of i18n""" + + def __init__(self, token): + matches = filter_re.finditer(token) + var = None + filters = [] + upto = 0 + for match in matches: + start = match.start() + if upto != start: + raise TemplateSyntaxError, "Could not parse some characters: %s|%s|%s" % \ + (token[:upto], token[upto:start], token[start:]) + if var == None: + var, constant, i18n_constant = match.group("var", "constant", "i18n_constant") + if i18n_constant: + #HACK:i18n + #var = """_("%s")""" % i18n_constant + var = '"%s"' % i18n_constant + elif constant: + var = '"%s"' % constant + upto = match.end() + if var == None: + raise TemplateSyntaxError, "Could not find variable at start of %s" % token + elif var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or var[0] == '_': + raise TemplateSyntaxError, "Variables and attributes may not begin with underscores: '%s'" % var + else: + filter_name = match.group("filter_name") + arg, i18n_arg = match.group("arg","i18n_arg") + if i18n_arg: + #HACK:i18n + #arg =_(i18n_arg.replace('\\', '')) + arg = i18n_arg.replace('\\', '') + if arg: + arg = arg.replace('\\', '') + if not registered_filters.has_key(filter_name): + raise TemplateSyntaxError, "Invalid filter: '%s'" % filter_name + if registered_filters[filter_name][1] == True and arg is None: + raise TemplateSyntaxError, "Filter '%s' requires an argument" % filter_name + if registered_filters[filter_name][1] == False and arg is not None: + raise TemplateSyntaxError, "Filter '%s' should not have an argument (argument is %r)" % (filter_name, arg) + filters.append( (filter_name,arg) ) + upto = match.end() + if upto != len(token): + raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:] + self.var , self.filters = var, filters + + def get_filters_from_token(token): "Convenient wrapper for FilterParser" - p = FilterParser(token) + p = RegexFilterParser(token) return (p.var, p.filters) def resolve_variable(path, context): diff --git a/setup.py b/setup.py index def9ad1360..69a7a153f3 100644 --- a/setup.py +++ b/setup.py @@ -13,11 +13,15 @@ setup( license = 'BSD', packages = find_packages(), package_data = { - 'django.contrib.admin': ['templates/admin/*.html', 'templates/admin_doc/*.html', - 'templates/registration/*.html', - 'media/css/*.css', 'media/img/admin/*.gif', - 'media/img/admin/*.png', 'media/js/*.js', - 'media/js/admin/*js'], + 'django.contrib.admin': ['templates/admin/*.html', + 'templates/admin_doc/*.html', + 'templates/registration/*.html', + 'templates/widget/*.html', + 'media/css/*.css', + 'media/img/admin/*.gif', + 'media/img/admin/*.png', + 'media/js/*.js', + 'media/js/admin/*js'], }, scripts = ['django/bin/django-admin.py'], zip_safe = False, diff --git a/tests/othertests/templates.py b/tests/othertests/templates.py index 2f2039eadb..03e133970b 100644 --- a/tests/othertests/templates.py +++ b/tests/othertests/templates.py @@ -96,6 +96,10 @@ TEMPLATE_TESTS = { # Chained filters, with an argument to the first one 'basic-syntax29': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "Yes"}, "yes"), + #Escaped string as argument + 'basic-syntax30': (r"""{{ var|default_if_none:" endquote\" hah" }}""", {"var": None}, ' endquote" hah'), + + ### IF TAG ################################################################ 'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"), 'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"), @@ -233,6 +237,18 @@ TEMPLATE_TESTS = { you gentlemen. """ ), + # translation of string without i18n tag + 'i18n11': ('{{ _("blah") }}', {}, "blah"), + + # translation of string without i18n tag but with interpolation + 'i18n12': ('{{ _("blah%(anton)s") }}', {'anton': 'blubb'}, "blahblubb"), + + # translation of a variable with a translated filter + 'i18n13': ('{{ bool|yesno:_("ja,nein") }}', {'bool': True}, 'ja'), + + # translation of a variable with a non-translated filter + 'i18n14': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'), + } def test_template_loader(template_name, template_dirs=None):