Ticket #6262: cached_templates.3.diff

File cached_templates.3.diff, 28.4 KB (added by Michael Malone, 15 years ago)
  • django/template/__init__.py

     
    175175
    176176    def render(self, context):
    177177        "Display stage -- can be called many times"
    178         return self.nodelist.render(context)
     178        context.parser_context.push()
     179        try:
     180            return self.nodelist.render(context)
     181        finally:
     182            context.parser_context.pop()
    179183
    180184def compile_string(template_string, origin):
    181185    "Compiles template_string into NodeList ready for rendering"
  • django/template/loaders/app_directories.py

     
    88
    99from django.conf import settings
    1010from django.core.exceptions import ImproperlyConfigured
    11 from django.template import TemplateDoesNotExist
     11from django.template import loader, TemplateDoesNotExist
    1212from django.utils._os import safe_join
    1313from django.utils.importlib import import_module
    1414
     
    2727# It won't change, so convert it to a tuple to save memory.
    2828app_template_dirs = tuple(app_template_dirs)
    2929
    30 def get_template_sources(template_name, template_dirs=None):
    31     """
    32     Returns the absolute paths to "template_name", when appended to each
    33     directory in "template_dirs". Any paths that don't lie inside one of the
    34     template dirs are excluded from the result set, for security reasons.
    35     """
    36     if not template_dirs:
    37         template_dirs = app_template_dirs
    38     for template_dir in template_dirs:
    39         try:
    40             yield safe_join(template_dir, template_name)
    41         except UnicodeDecodeError:
    42             # The template dir name was a bytestring that wasn't valid UTF-8.
    43             raise
    44         except ValueError:
    45             # The joined path was located outside of template_dir.
    46             pass
     30class Loader(loader.Loader):
     31    def get_template_sources(self, template_name, template_dirs=None):
     32        """
     33        Returns the absolute paths to "template_name", when appended to each
     34        directory in "template_dirs". Any paths that don't lie inside one of the
     35        template dirs are excluded from the result set, for security reasons.
     36        """
     37        if not template_dirs:
     38            template_dirs = app_template_dirs
     39        for template_dir in template_dirs:
     40            try:
     41                yield safe_join(template_dir, template_name)
     42            except UnicodeDecodeError:
     43                # The template dir name was a bytestring that wasn't valid UTF-8.
     44                raise
     45            except ValueError:
     46                # The joined path was located outside of template_dir.
     47                pass
    4748
     49    def load_template_source(self, template_name, template_dirs=None):
     50        for filepath in self.get_template_sources(template_name, template_dirs):
     51            try:
     52                return (open(filepath).read().decode(settings.FILE_CHARSET), filepath)
     53            except IOError:
     54                pass
     55        raise TemplateDoesNotExist, template_name
     56    load_template_source.is_usable = True
     57
     58loader = Loader()
     59
    4860def load_template_source(template_name, template_dirs=None):
    49     for filepath in get_template_sources(template_name, template_dirs):
    50         try:
    51             return (open(filepath).read().decode(settings.FILE_CHARSET), filepath)
    52         except IOError:
    53             pass
    54     raise TemplateDoesNotExist, template_name
     61    # For backwards compatibility
     62    return loader.load_template_source(template_name, template_dirs)
    5563load_template_source.is_usable = True
  • django/template/loaders/filesystem.py

     
    33"""
    44
    55from django.conf import settings
    6 from django.template import TemplateDoesNotExist
     6from django.template import loader, TemplateDoesNotExist
    77from django.utils._os import safe_join
    88
    9 def get_template_sources(template_name, template_dirs=None):
    10     """
    11     Returns the absolute paths to "template_name", when appended to each
    12     directory in "template_dirs". Any paths that don't lie inside one of the
    13     template dirs are excluded from the result set, for security reasons.
    14     """
    15     if not template_dirs:
    16         template_dirs = settings.TEMPLATE_DIRS
    17     for template_dir in template_dirs:
    18         try:
    19             yield safe_join(template_dir, template_name)
    20         except UnicodeDecodeError:
    21             # The template dir name was a bytestring that wasn't valid UTF-8.
    22             raise
    23         except ValueError:
    24             # The joined path was located outside of this particular
    25             # template_dir (it might be inside another one, so this isn't
    26             # fatal).
    27             pass
     9class Loader(loader.Loader):
     10    def get_template_sources(self, template_name, template_dirs=None):
     11        """
     12        Returns the absolute paths to "template_name", when appended to each
     13        directory in "template_dirs". Any paths that don't lie inside one of the
     14        template dirs are excluded from the result set, for security reasons.
     15        """
     16        if not template_dirs:
     17            template_dirs = settings.TEMPLATE_DIRS
     18        for template_dir in template_dirs:
     19            try:
     20                yield safe_join(template_dir, template_name)
     21            except UnicodeDecodeError:
     22                # The template dir name was a bytestring that wasn't valid UTF-8.
     23                raise
     24            except ValueError:
     25                # The joined path was located outside of this particular
     26                # template_dir (it might be inside another one, so this isn't
     27                # fatal).
     28                pass
    2829
     30    def load_template_source(self, template_name, template_dirs=None):
     31        tried = []
     32        for filepath in self.get_template_sources(template_name, template_dirs):
     33            try:
     34                return (open(filepath).read().decode(settings.FILE_CHARSET), filepath)
     35            except IOError:
     36                tried.append(filepath)
     37        if tried:
     38            error_msg = "Tried %s" % tried
     39        else:
     40            error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory."
     41        raise TemplateDoesNotExist, error_msg
     42    load_template_source.is_usable = True
     43
     44loader = Loader()
     45
    2946def load_template_source(template_name, template_dirs=None):
    30     tried = []
    31     for filepath in get_template_sources(template_name, template_dirs):
    32         try:
    33             return (open(filepath).read().decode(settings.FILE_CHARSET), filepath)
    34         except IOError:
    35             tried.append(filepath)
    36     if tried:
    37         error_msg = "Tried %s" % tried
    38     else:
    39         error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory."
    40     raise TemplateDoesNotExist, error_msg
     47    # For backwards compatibility
     48    return loader.load_template_source(template_name, template_dirs)
    4149load_template_source.is_usable = True
  • django/template/loaders/eggs.py

     
    55except ImportError:
    66    resource_string = None
    77
    8 from django.template import TemplateDoesNotExist
     8from django.template import loader, TemplateDoesNotExist
    99from django.conf import settings
    1010
     11class Loader(loader.Loader):
     12    def load_template_source(self, template_name, template_dirs=None):
     13        """
     14        Loads templates from Python eggs via pkg_resource.resource_string.
     15
     16        For every installed app, it tries to get the resource (app, template_name).
     17        """
     18        if resource_string is not None:
     19            pkg_name = 'templates/' + template_name
     20            for app in settings.INSTALLED_APPS:
     21                try:
     22                    return (resource_string(app, pkg_name).decode(settings.FILE_CHARSET), 'egg:%s:%s' % (app, pkg_name))
     23                except:
     24                    pass
     25        raise TemplateDoesNotExist, template_name
     26    load_template_source.is_usable = resource_string is not None
     27
     28loader = Loader()
     29
    1130def load_template_source(template_name, template_dirs=None):
    12     """
    13     Loads templates from Python eggs via pkg_resource.resource_string.
    14 
    15     For every installed app, it tries to get the resource (app, template_name).
    16     """
    17     if resource_string is not None:
    18         pkg_name = 'templates/' + template_name
    19         for app in settings.INSTALLED_APPS:
    20             try:
    21                 return (resource_string(app, pkg_name).decode(settings.FILE_CHARSET), 'egg:%s:%s' % (app, pkg_name))
    22             except:
    23                 pass
    24     raise TemplateDoesNotExist, template_name
     31    return loader.load_template_source(template_name, template_dirs)
    2532load_template_source.is_usable = resource_string is not None
  • django/template/loaders/cached.py

     
     1"""
     2Wrapper class that takes a list of template loaders as an argument and attempts
     3to load templates from them in order, caching the result.
     4"""
     5
     6from django.template import loader
     7from django.utils.importlib import import_module
     8from django.core.exceptions import ImproperlyConfigured
     9
     10class Loader(loader.Loader):
     11    template_cache = {}
     12
     13    def __init__(self, loader):
     14        if isinstance(loader, basestring):
     15            self._loader_name = loader
     16            self._loader = None
     17        else:
     18            self._loader_name = None
     19            self._loader = loader.load_template
     20
     21    @property
     22    def loader(self):
     23        # Resolve loader on demand to avoid circular imports
     24        if self._loader is None:
     25            loader_name = self._loader_name
     26            i = loader_name.rfind('.')
     27            module, attr = loader_name[:i], loader_name[i+1:]
     28            try:
     29                mod = import_module(module)
     30            except ImportError, e:
     31                raise ImproperlyConfigured, 'Error importing template source loader %s: "%s"' % (module, e)
     32            try:
     33                loader = getattr(mod, attr)
     34            except AttributeError:
     35                raise ImproperlyConfigured, 'Module "%s" does not define a "%s" callable template source loader' % (module, attr)
     36            self._loader = loader.load_template_source
     37        return self._loader
     38
     39    def load_template(self, template_name, template_dirs=None):
     40        if template_name not in self.template_cache:
     41            source, origin = self.loader(template_name, template_dirs)
     42            template = loader.get_template_from_string(source, name=origin)
     43            self.template_cache[template_name] = (template, origin)
     44        return self.template_cache[template_name]
     45    load_template.is_usable = True
     46
     47    def reset(self):
     48        "Empty the template cache."
     49        self.template_cache = {}
  • django/template/defaulttags.py

     
    3939
    4040class CycleNode(Node):
    4141    def __init__(self, cyclevars, variable_name=None):
    42         self.cycle_iter = itertools_cycle(cyclevars)
     42        self.cyclevars = cyclevars
    4343        self.variable_name = variable_name
    4444
    4545    def render(self, context):
    46         value = self.cycle_iter.next().resolve(context)
     46        if self not in context.parser_context:
     47            context.parser_context[self] = {'cycle_iter': itertools_cycle(self.cyclevars)}
     48        cycle_iter = context.parser_context[self]['cycle_iter']
     49        value = cycle_iter.next().resolve(context)
    4750        if self.variable_name:
    4851            context[self.variable_name] = value
    4952        return value
  • django/template/context.py

     
    1414        self.dicts = [dict_]
    1515        self.autoescape = autoescape
    1616        self.current_app = current_app
     17        self.parser_context = ParserContext()
    1718
    1819    def __repr__(self):
    1920        return repr(self.dicts)
     
    6869        self.dicts = [other_dict] + self.dicts
    6970        return other_dict
    7071
     72class ParserContext(object):
     73    """A stack container for storing Template state."""
     74    def __init__(self, dict_=None):
     75        dict_ = dict_ or {}
     76        self.dicts = [dict_]
     77
     78    def __repr__(self):
     79        return repr(self.dicts)
     80   
     81    def __iter__(self):
     82        for d in self.dicts[0]:
     83            yield d
     84
     85    def push(self):
     86        d = {}
     87        self.dicts = [d] + self.dicts
     88        return d
     89
     90    def pop(self):
     91        if len(self.dicts) == 1:
     92            raise ContextPopException
     93        return self.dicts.pop(0)
     94
     95    def __setitem__(self, key, value):
     96        "Set a variable in the current context"
     97        self.dicts[0][key] = value
     98
     99    def __getitem__(self, key):
     100        "Get a variable's value from the current context"
     101        return self.dicts[0][key]
     102   
     103    def __delitem__(self, key):
     104        "Deletes a variable from the current context"
     105        del self.dicts[0][key]
     106
     107    def has_key(self, key):
     108        return key in self.dicts[0]
     109
     110    __contains__ = has_key
     111
     112    def get(self, key, otherwise=None):
     113        d = self.dicts[0]
     114        if key in d:
     115            return d[key]
     116        return otherwise
     117
    71118# This is a function rather than module-level procedural code because we only
    72119# want it to execute if somebody uses RequestContext.
    73120def get_standard_processors():
  • django/template/loader_tags.py

     
    11from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
    22from django.template import Library, Node, TextNode
    3 from django.template.loader import get_template, get_template_from_string, find_template_source
     3from django.template.loader import get_template
    44from django.conf import settings
    55from django.utils.safestring import mark_safe
    66
    77register = Library()
    88
     9BLOCK_CONTEXT_KEY = 'block_context'
     10
    911class ExtendsError(Exception):
    1012    pass
    1113
     14class BlockContext(object):
     15    def __init__(self):
     16        # Dictionary of FIFO queues.
     17        self.blocks = {}
     18
     19    def add_blocks(self, blocks):
     20        for name, block in blocks.iteritems():
     21            if name in self.blocks:
     22                self.blocks[name].insert(0, block)
     23            else:
     24                self.blocks[name] = [block]
     25
     26    def pop(self, name):
     27        try:
     28            return self.blocks[name].pop()
     29        except (IndexError, KeyError):
     30            return None
     31
     32    def push(self, name, block):
     33        self.blocks[name].append(block)
     34
     35    def get_block(self, name):
     36        try:
     37            return self.blocks[name][-1]
     38        except (IndexError, KeyError):
     39            return None
     40
    1241class BlockNode(Node):
    1342    def __init__(self, name, nodelist, parent=None):
    1443        self.name, self.nodelist, self.parent = name, nodelist, parent
     
    1746        return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist)
    1847
    1948    def render(self, context):
     49        block_context = context.parser_context.get(BLOCK_CONTEXT_KEY, None)
    2050        context.push()
    21         # Save context in case of block.super().
    22         self.context = context
    23         context['block'] = self
    24         result = self.nodelist.render(context)
     51        if block_context is None:
     52            context['block'] = self
     53            result = self.nodelist.render(context)
     54        else:
     55            push = block = block_context.pop(self.name)
     56            if block is None:
     57                block = self
     58            # Create new block so we can store context without thread-safetly issues.
     59            block = BlockNode(block.name, block.nodelist)
     60            block.context = context
     61            context['block'] = block
     62            result = block.nodelist.render(context)
     63            if push is not None:
     64                block_context.push(self.name, push)
    2565        context.pop()
    2666        return result
    2767
    2868    def super(self):
    29         if self.parent:
    30             return mark_safe(self.parent.render(self.context))
     69        parser_context = self.context.parser_context
     70        if (BLOCK_CONTEXT_KEY in parser_context and
     71            parser_context[BLOCK_CONTEXT_KEY].get_block(self.name) is not None):
     72            return mark_safe(self.render(self.context))
    3173        return ''
    3274
    33     def add_parent(self, nodelist):
    34         if self.parent:
    35             self.parent.add_parent(nodelist)
    36         else:
    37             self.parent = BlockNode(self.name, nodelist)
    38 
    3975class ExtendsNode(Node):
    4076    must_be_first = True
    4177
     
    4379        self.nodelist = nodelist
    4480        self.parent_name, self.parent_name_expr = parent_name, parent_name_expr
    4581        self.template_dirs = template_dirs
    46 
     82        self.blocks = dict([(n.name, n) for n in nodelist.get_nodes_by_type(BlockNode)])
     83 
    4784    def __repr__(self):
    4885        if self.parent_name_expr:
    4986            return "<ExtendsNode: extends %s>" % self.parent_name_expr.token
     
    6198        if hasattr(parent, 'render'):
    6299            return parent # parent is a Template object
    63100        try:
    64             source, origin = find_template_source(parent, self.template_dirs)
     101            return get_template(parent)
    65102        except TemplateDoesNotExist:
    66103            raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
    67         else:
    68             return get_template_from_string(source, origin, parent)
    69104
    70105    def render(self, context):
    71106        compiled_parent = self.get_parent(context)
    72         parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
    73         for block_node in self.nodelist.get_nodes_by_type(BlockNode):
    74             # Check for a BlockNode with this node's name, and replace it if found.
    75             try:
    76                 parent_block = parent_blocks[block_node.name]
    77             except KeyError:
    78                 # This BlockNode wasn't found in the parent template, but the
    79                 # parent block might be defined in the parent's *parent*, so we
    80                 # add this BlockNode to the parent's ExtendsNode nodelist, so
    81                 # it'll be checked when the parent node's render() is called.
    82107
    83                 # Find out if the parent template has a parent itself
    84                 for node in compiled_parent.nodelist:
    85                     if not isinstance(node, TextNode):
    86                         # If the first non-text node is an extends, handle it.
    87                         if isinstance(node, ExtendsNode):
    88                             node.nodelist.append(block_node)
    89                         # Extends must be the first non-text node, so once you find
    90                         # the first non-text node you can stop looking.
    91                         break
    92             else:
    93                 # Keep any existing parents and add a new one. Used by BlockNode.
    94                 parent_block.parent = block_node.parent
    95                 parent_block.add_parent(parent_block.nodelist)
    96                 parent_block.nodelist = block_node.nodelist
    97         return compiled_parent.render(context)
     108        if BLOCK_CONTEXT_KEY not in context.parser_context:
     109            context.parser_context[BLOCK_CONTEXT_KEY] = BlockContext()
     110        block_context = context.parser_context[BLOCK_CONTEXT_KEY]
    98111
     112        # Add the block nodes from this node to the block context
     113        block_context.add_blocks(self.blocks)
     114
     115        # If this block's parent doesn't have an extends node it is the root,
     116        # and its block nodes also need to be added to the block context.
     117        for node in compiled_parent.nodelist:
     118            # The ExtendsNode has to be the first non-text node.
     119            if not isinstance(node, TextNode):
     120                if not isinstance(node, ExtendsNode):
     121                    blocks = dict([(n.name, n) for n in
     122                                   compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
     123                    block_context.add_blocks(blocks)
     124                break
     125
     126        # Call render on nodelist explicitly so the block context stays
     127        # the same.
     128        return compiled_parent.nodelist.render(context)
     129
    99130class ConstantIncludeNode(Node):
    100131    def __init__(self, template_path):
    101132        try:
  • django/template/loader.py

     
    2727
    2828template_source_loaders = None
    2929
     30class Loader(object):
     31    def load_template(self, template_name, template_dirs=None):
     32        source, origin = self.load_template_source(template_name, template_dirs)
     33        template = get_template_from_string(source, name=template_name)
     34        return template, origin
     35   
     36    def load_template_from_source(self, template_name, template_dirs=None):
     37        raise NotImplementedError
     38
    3039class LoaderOrigin(Origin):
    3140    def __init__(self, display_name, loader, name, dirs):
    3241        super(LoaderOrigin, self).__init__(display_name)
     
    4857    global template_source_loaders
    4958    if template_source_loaders is None:
    5059        loaders = []
    51         for path in settings.TEMPLATE_LOADERS:
    52             i = path.rfind('.')
    53             module, attr = path[:i], path[i+1:]
    54             try:
    55                 mod = import_module(module)
    56             except ImportError, e:
    57                 raise ImproperlyConfigured, 'Error importing template source loader %s: "%s"' % (module, e)
    58             try:
    59                 func = getattr(mod, attr)
    60             except AttributeError:
    61                 raise ImproperlyConfigured, 'Module "%s" does not define a "%s" callable template source loader' % (module, attr)
    62             if not func.is_usable:
    63                 import warnings
    64                 warnings.warn("Your TEMPLATE_LOADERS setting includes %r, but your Python installation doesn't support that type of template loading. Consider removing that line from TEMPLATE_LOADERS." % path)
     60        for loader in settings.TEMPLATE_LOADERS:
     61            if isinstance(loader, basestring):
     62                i = loader.rfind('.')
     63                module, attr = loader[:i], loader[i+1:]
     64                try:
     65                    mod = import_module(module)
     66                except ImportError, e:
     67                    raise ImproperlyConfigured, 'Error importing template source loader %s: "%s"' % (module, e)
     68                try:
     69                    func = getattr(mod, attr)
     70                except AttributeError:
     71                    raise ImproperlyConfigured, 'Module "%s" does not define a "%s" callable template source loader' % (module, attr)
     72                if not func.is_usable:
     73                    import warnings
     74                    warnings.warn("Your TEMPLATE_LOADERS setting includes %r, but your Python installation doesn't support that type of template loading. Consider removing that line from TEMPLATE_LOADERS." % loader)
     75                else:
     76                    loaders.append(func)
     77            elif hasattr(loader, 'load_template'):
     78                loaders.append(loader.load_template)
    6579            else:
    66                 loaders.append(func)
     80                raise ImproperlyConfigured, 'Loader does not define a "load_template" callable template source loader'
    6781        template_source_loaders = tuple(loaders)
    6882    for loader in template_source_loaders:
    6983        try:
     
    7892    Returns a compiled Template object for the given template name,
    7993    handling template inheritance recursively.
    8094    """
    81     source, origin = find_template_source(template_name)
    82     template = get_template_from_string(source, origin, template_name)
     95    source_or_template, origin = find_template_source(template_name)
     96    if hasattr(source_or_template, 'render'):
     97        # source is a compiled template
     98        return source_or_template
     99    template = get_template_from_string(source_or_template, origin, template_name)
    83100    return template
    84101
    85102def get_template_from_string(source, origin=None, name=None):
  • tests/regressiontests/templates/tests.py

     
    105105                # Fix expected sources so they are normcased and abspathed
    106106                expected_sources = [os.path.normcase(os.path.abspath(s)) for s in expected_sources]
    107107            # Test the two loaders (app_directores and filesystem).
    108             func1 = lambda p, t: list(app_directories.get_template_sources(p, t))
    109             func2 = lambda p, t: list(filesystem.get_template_sources(p, t))
     108            func1 = lambda p, t: list(app_directories.loader.get_template_sources(p, t))
     109            func2 = lambda p, t: list(filesystem.loader.get_template_sources(p, t))
    110110            for func in (func1, func2):
    111111                if isinstance(expected_sources, list):
    112112                    self.assertEqual(func(path, template_dirs), expected_sources)
     
    197197            except KeyError:
    198198                raise template.TemplateDoesNotExist, template_name
    199199
     200        from django.template.loaders.cached import Loader
     201        cache_loader = Loader(test_template_loader)
     202
    200203        old_template_loaders = loader.template_source_loaders
    201         loader.template_source_loaders = [test_template_loader]
     204        loader.template_source_loaders = [cache_loader.load_template]
    202205
    203206        failures = []
    204207        tests = template_tests.items()
     
    231234            for invalid_str, result in [('', normal_string_result),
    232235                                        (expected_invalid_str, invalid_string_result)]:
    233236                settings.TEMPLATE_STRING_IF_INVALID = invalid_str
    234                 try:
    235                     test_template = loader.get_template(name)
    236                     output = self.render(test_template, vals)
    237                 except ContextStackException:
    238                     failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Context stack was left imbalanced" % (invalid_str, name))
    239                     continue
    240                 except Exception:
    241                     exc_type, exc_value, exc_tb = sys.exc_info()
    242                     if exc_type != result:
    243                         tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
    244                         failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s\n%s" % (invalid_str, name, exc_type, exc_value, tb))
    245                     continue
    246                 if output != result:
    247                     failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (invalid_str, name, result, output))
     237                for cached in (False, True):
     238                    try:
     239                        test_template = loader.get_template(name)
     240                        output = self.render(test_template, vals)
     241                    except ContextStackException:
     242                        failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Context stack was left imbalanced" % (cached, invalid_str, name))
     243                        continue
     244                    except Exception:
     245                        exc_type, exc_value, exc_tb = sys.exc_info()
     246                        if exc_type != result:
     247                            tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
     248                            failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s\n%s" % (cached, invalid_str, name, exc_type, exc_value, tb))
     249                        continue
     250                    if output != result:
     251                        failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (cached, invalid_str, name, result, output))
     252                cache_loader.reset()
    248253
    249254            if 'LANGUAGE_CODE' in vals[1]:
    250255                deactivate()
Back to Top