[svn] fixed supering in jinja, documented it, added lipsum()
authorArmin Ronacher <armin.ronacher@active-4.com>
Fri, 30 Mar 2007 19:58:15 +0000 (21:58 +0200)
committerArmin Ronacher <armin.ronacher@active-4.com>
Fri, 30 Mar 2007 19:58:15 +0000 (21:58 +0200)
--HG--
branch : trunk

docs/src/designerdoc.txt
jdebug.py
jinja/datastructure.py
jinja/defaults.py
jinja/environment.py
jinja/translators/python.py
jinja/utils.py
tests/runtime/exception.py

index d369eb88736594b95ad21bd6aab87bed80b52daf..6036a5cf4f35cfde5ccc7ed9c9c87dedc9401285 100644 (file)
@@ -136,6 +136,28 @@ available per default:
 
     Function that outputs the contents of the context.
 
+`lipsum`
+
+    Generate some paragraphs of random text:
+
+    .. sourcecode:: jinja
+
+        {{ lipsum(5) }}
+            five html paragraphs
+
+        {{ lipsum(2, False) }}
+            two ascii only paragraphs
+
+    Per default a paragraph is between 20 and 100 words long. You can
+    override this default with the third and fourth parameter:
+
+    .. sourcecode:: jinja
+
+        {{ lipsum(10, True, 50, 200) }}
+            generate 10 HTML paragraphs between 50 and 200 words.
+
+    *new in Jinja 1.1*
+
 Loops
 =====
 
@@ -475,6 +497,25 @@ value from the parent template is used instead.
     two similarly-named ``{% block %}`` tags in a template, that template's
     parent wouldn't know which one of the blocks' content to use.
 
+Super Blocks
+============
+
+Starting with `Jinja 1.1` it's possible to render the contents of the parent
+block. By calling it you get the results of the parent block back. If you want
+to get the data of the parent you can give it an offset:
+
+.. sourcecode:: jinja
+
+    {{ super() }}
+        return the parent data
+
+    {{ super(1) }}
+        the same as above
+
+    {{ super(2) }}
+        return the data of the second parent block
+
+
 Template Inclusion
 ==================
 
index 109c5c6c213fe17b54686d866fbbdf053974752d..257ddea485a79df662252120b42499db23936258 100644 (file)
--- a/jdebug.py
+++ b/jdebug.py
@@ -33,8 +33,8 @@ if os.environ.get('JDEBUG_SOURCEPRINT'):
     PythonTranslator.translate = debug_translate
 
 
-def p(x):
-    print PythonTranslator(e, Parser(e, x).parse()).translate()
+def p(x, f=None):
+    print PythonTranslator(e, Parser(e, x, f).parse()).translate()
 
 def l(x):
     for item in e.lexer.tokenize(x):
index 732a938fffb258acbd479ed32a2b557e62359566..abd2ce16eebeda78017b8ebfebbb12b6da7cccb1 100644 (file)
@@ -295,7 +295,7 @@ class CycleContext(object):
     """
 
     def __init__(self, seq=None):
-        self.lineno = -1
+        self.pos = -1
         # bind the correct helper function based on the constructor signature
         if seq is not None:
             self.seq = seq
@@ -306,33 +306,43 @@ class CycleContext(object):
 
     def cycle_static(self):
         """Helper function for static cycling."""
-        self.lineno = (self.lineno + 1) % self.length
-        return self.seq[self.lineno]
+        self.pos = (self.pos + 1) % self.length
+        return self.seq[self.pos]
 
     def cycle_dynamic(self, seq):
         """Helper function for dynamic cycling."""
-        self.lineno = (self.lineno + 1) % len(seq)
-        return seq[self.lineno]
+        self.pos = pos = (self.pos + 1) % len(seq)
+        return seq[pos]
 
 
-class BlockContext(object):
+class SuperBlock(object):
     """
     Helper class for ``{{ super() }}``.
     """
     jinja_allowed_attributes = ['name']
 
-    def __init__(self, name, stack, level, context):
+    def __init__(self, name, blocks, level, context):
         self.name = name
         self.context = context
-        if len(stack) > level:
-            self.block = stack[level]
+        if name in blocks:
+            self.stack = blocks[name]
+            self.level = level
         else:
-            self.block = None
+            self.stack is None
+            if len(stack) > level:
+                self.block = stack[level]
 
-    def __call__(self):
-        if self.block is None:
-            raise TemplateRuntimeError('no super block for %r' % self.name)
-        return self.block(self.context)
+    def __call__(self, offset=1):
+        level = self.level + (offset - 1)
+        if level < len(self.stack):
+            return self.stack[level](self.context)
+        raise TemplateRuntimeError('no super block for %r' % self.name)
+
+    def __repr__(self):
+        return '<SuperBlock %r (%spossible)>' % (
+            self.name,
+            self.stack is None and 'im' or ''
+        )
 
 
 class TokenStream(object):
index b634dad6f66ec6c088e2ef80ddfcff8e0f117a87..382ae0e33a72db46127cf20f137fc1ac4e781895 100644 (file)
 """
 from jinja.filters import FILTERS as DEFAULT_FILTERS
 from jinja.tests import TESTS as DEFAULT_TESTS
-from jinja.utils import debug_context, safe_range
+from jinja.utils import debug_context, safe_range, generate_lorem_ipsum
 
 
 DEFAULT_NAMESPACE = {
     'range':                safe_range,
-    'debug':                debug_context
+    'debug':                debug_context,
+    'lipsum':               generate_lorem_ipsum
 }
index 329ad816d693dca7c730531fa85761d4d550fa70..92ed4caecbdf78d1126c1f8a14ec36a3cc1465b2 100644 (file)
@@ -87,7 +87,10 @@ class Environment(object):
         """Load a template from a string."""
         from jinja.parser import Parser
         from jinja.translators.python import PythonTranslator
-        return PythonTranslator.process(self, Parser(self, source).parse())
+        rv = PythonTranslator.process(self, Parser(self, source).parse())
+        # attach the source for debugging
+        rv._source = source
+        return rv
 
     def get_template(self, filename):
         """Load a template from a filename. Only works
index e8e9a59a8ec074ad4158d4af52c6b7f2d567cffb..67ce6a4009e87c55975e59921865961bc1cea36d 100644 (file)
@@ -8,6 +8,7 @@
     :copyright: 2007 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
+import re
 import sys
 from compiler import ast
 from jinja import nodes
@@ -15,7 +16,13 @@ from jinja.nodes import get_nodes
 from jinja.parser import Parser
 from jinja.exceptions import TemplateSyntaxError
 from jinja.translators import Translator
-from jinja.utils import translate_exception, capture_generator
+from jinja.utils import translate_exception, capture_generator, \
+     RUNTIME_EXCEPTION_OFFSET
+
+
+#: regular expression for the debug symbols
+_debug_re = re.compile(r'^\s*\# DEBUG\(filename=(?P<filename>.*?), '
+                       r'lineno=(?P<lineno>\d+)\)$')
 
 
 def _to_tuple(args):
@@ -33,48 +40,60 @@ class Template(object):
     Represents a finished template.
     """
 
-    def __init__(self, environment, code, translated_source=None):
+    def __init__(self, environment, code):
         self.environment = environment
         self.code = code
-        self.translated_source = translated_source
         self.generate_func = None
+        #: holds debug information
+        self._debug_info = None
+        #: unused in loader environments but used when a template
+        #: is loaded from a string in order to be able to debug those too
+        self._source = None
 
     def dump(self, stream=None):
         """Dump the template into python bytecode."""
         if stream is not None:
             from marshal import dump
-            dump((self.code, self.translated_source), stream)
+            dump(self.code, stream)
         else:
             from marshal import dumps
-            return dumps((self.code, self.translated_source))
+            return dumps(self.code)
 
     def load(environment, data):
         """Load the template from python bytecode."""
         if isinstance(data, basestring):
             from marshal import loads
-            code, src = loads(data)
+            code = loads(data)
         else:
             from marshal import load
-            code, src = load(data)
-        return Template(environment, code, src)
+            code = load(data)
+        return Template(environment, code)
     load = staticmethod(load)
 
     def render(self, *args, **kwargs):
         """Render a template."""
+        # if there is no generation function we execute the code
+        # in a new namespace and save the generation function and
+        # debug information.
         if self.generate_func is None:
             ns = {'environment': self.environment}
             exec self.code in ns
             self.generate_func = ns['generate']
+            self._debug_info = ns['debug_info']
         ctx = self.environment.context_class(self.environment, *args, **kwargs)
         try:
             return capture_generator(self.generate_func(ctx))
         except:
+            # debugging system:
+            # on any exception we first get the current exception information
+            # and skip the internal frames (currently either one (python2.5)
+            # or two (python2.4 and lower)). After that we call a function
+            # that creates a new traceback that is easier to debug.
             exc_type, exc_value, traceback = sys.exc_info()
-            # translate the exception, We skip two frames. One
-            # frame that is the "capture_generator" frame, and another
-            # one which is the frame of this function
+            for _ in xrange(RUNTIME_EXCEPTION_OFFSET):
+                traceback = traceback.tb_next
             traceback = translate_exception(self, exc_type, exc_value,
-                                            traceback.tb_next.tb_next, ctx)
+                                            traceback, ctx)
             raise exc_type, exc_value, traceback
 
 
@@ -156,8 +175,7 @@ class PythonTranslator(Translator):
         filename = node.filename or '<template>'
         source = translator.translate()
         return Template(environment,
-                        compile(source, filename, 'exec'),
-                        source)
+                        compile(source, filename, 'exec'))
     process = staticmethod(process)
 
     # -- private helper methods
@@ -173,15 +191,10 @@ class PythonTranslator(Translator):
         Return a comment that helds the node informations or None
         if there is no need to add a debug comment.
         """
-        if node.filename is None:
-            return
-        rv = '# DEBUG(filename=%s, lineno=%s)' % (
-            node.filename,
+        return '# DEBUG(filename=%s, lineno=%s)' % (
+            node.filename or '',
             node.lineno
         )
-        if force or rv != self.last_debug_comment:
-            self.last_debug_comment = rv
-            return rv
 
     def filter(self, s, filter_nodes):
         """
@@ -236,7 +249,6 @@ class PythonTranslator(Translator):
     def reset(self):
         self.indention = 0
         self.last_cycle_id = 0
-        self.last_debug_comment = None
 
     def translate(self):
         self.reset()
@@ -303,7 +315,7 @@ class PythonTranslator(Translator):
         lines = [
             'from __future__ import division\n'
             'from jinja.datastructure import Undefined, LoopContext, '
-            'CycleContext, BlockContext\n'
+            'CycleContext, SuperBlock\n'
             'from jinja.utils import buffereater\n'
             '%s\n'
             '__name__ = %r\n\n'
@@ -357,9 +369,7 @@ class PythonTranslator(Translator):
                         '    if False:',
                         '        yield None'
                     ])
-                    nodeinfo = self.nodeinfo(item, True)
-                    if nodeinfo:
-                        lines.append(self.indent(nodeinfo))
+                    lines.append(self.indent(self.nodeinfo(item, True)))
                     lines.append(self.handle_block(item, idx + 1))
                     tmp.append('buffereater(%s)' % func_name)
                 dict_lines.append('    %r: %s' % (
@@ -368,28 +378,46 @@ class PythonTranslator(Translator):
                 ))
             lines.append('\nblocks = {\n%s\n}' % ',\n'.join(dict_lines))
 
-        return '\n'.join(lines)
+        # now get the real source lines and map the debugging symbols
+        debug_mapping = []
+        last = None
+        offset = -1
+        sourcelines = ('\n'.join(lines)).splitlines()
+        result = []
+
+        for idx, line in enumerate(sourcelines):
+            m = _debug_re.search(line)
+            if m is not None:
+                d = m.groupdict()
+                this = (d['filename'] or None, int(d['lineno']))
+                # if there is no filename in this debug symbol
+                # if it's the same as the line before we ignore it
+                if this[0] and this != last:
+                    debug_mapping.append((idx - offset,) + this)
+                    last = this
+                # for each debug symbol the line number and so the offset
+                # changes by one.
+                offset += 1
+            else:
+                result.append(line)
+
+        result.append('\ndebug_info = %r' % debug_mapping)
+        return '\n'.join(result)
 
     def handle_template_text(self, node):
         """
         Handle data around nodes.
         """
-        nodeinfo = self.nodeinfo(node) or ''
-        if nodeinfo:
-            nodeinfo = self.indent(nodeinfo) + '\n'
-        return nodeinfo + self.indent('yield %r' % node.text)
+        return self.indent(self.nodeinfo(node)) + '\n' +\
+               self.indent('yield %r' % node.text)
 
     def handle_node_list(self, node):
         """
         In some situations we might have a node list. It's just
         a collection of multiple statements.
         """
-        buf = [self.handle_node(n) for n in node]
-        if buf:
-            nodeinfo = self.nodeinfo(node)
-            if nodeinfo:
-                buf.insert(0, self.indent(nodeinfo))
-        return '\n'.join(buf)
+        return '\n'.join([self.indent(self.nodeinfo(node))] +
+                         [self.handle_node(n) for n in node])
 
     def handle_for_loop(self, node):
         """
@@ -398,9 +426,7 @@ class PythonTranslator(Translator):
         """
         buf = []
         write = lambda x: buf.append(self.indent(x))
-        nodeinfo = self.nodeinfo(node)
-        if nodeinfo:
-            write(nodeinfo)
+        write(self.nodeinfo(node))
         write('ctx_push()')
 
         # recursive loops
@@ -421,9 +447,7 @@ class PythonTranslator(Translator):
 
         # handle real loop code
         self.indention += 1
-        nodeinfo = self.nodeinfo(node.body)
-        if nodeinfo:
-            write(nodeinfo)
+        write(self.nodeinfo(node.body))
         buf.append(self.handle_node(node.body) or self.indent('pass'))
         self.indention -= 1
 
@@ -431,9 +455,7 @@ class PythonTranslator(Translator):
         if node.else_:
             write('if not context[\'loop\'].iterated:')
             self.indention += 1
-            nodeinfo = self.nodeinfo(node.else_)
-            if nodeinfo:
-                write(nodeinfo)
+            write(self.nodeinfo(node.else_))
             buf.append(self.handle_node(node.else_) or self.indent('pass'))
             self.indention -= 1
 
@@ -459,26 +481,20 @@ class PythonTranslator(Translator):
         """
         buf = []
         write = lambda x: buf.append(self.indent(x))
-        nodeinfo = self.nodeinfo(node)
-        if nodeinfo:
-            write(nodeinfo)
+        write(self.nodeinfo(node))
         for idx, (test, body) in enumerate(node.tests):
             write('%sif %s:' % (
                 idx and 'el' or '',
                 self.handle_node(test)
             ))
             self.indention += 1
-            nodeinfo = self.nodeinfo(body)
-            if nodeinfo:
-                write(nodeinfo)
+            write(self.nodeinfo(body))
             buf.append(self.handle_node(body))
             self.indention -= 1
         if node.else_ is not None:
             write('else:')
             self.indention += 1
-            nodeinfo = self.nodeinfo(node.else_)
-            if nodeinfo:
-                write(nodeinfo)
+            write(self.nodeinfo(node.else_))
             buf.append(self.handle_node(node.else_))
             self.indention -= 1
         return '\n'.join(buf)
@@ -494,9 +510,7 @@ class PythonTranslator(Translator):
 
         write('if not %r in context.current:' % name)
         self.indention += 1
-        nodeinfo = self.nodeinfo(node)
-        if nodeinfo:
-            write(nodeinfo)
+        write(self.nodeinfo(node))
         if node.seq.__class__ in (ast.Tuple, ast.List):
             write('context.current[%r] = CycleContext(%s)' % (
                 name,
@@ -522,11 +536,9 @@ class PythonTranslator(Translator):
         """
         Handle a print statement.
         """
-        nodeinfo = self.nodeinfo(node) or ''
-        if nodeinfo:
-            nodeinfo = self.indent(nodeinfo) + '\n'
-        return nodeinfo + self.indent('yield finish_var(%s, context)' %
-                                      self.handle_node(node.variable))
+        return self.indent(self.nodeinfo(node)) + '\n' +\
+               self.indent('yield finish_var(%s, context)' %
+                           self.handle_node(node.variable))
 
     def handle_macro(self, node):
         """
@@ -537,9 +549,7 @@ class PythonTranslator(Translator):
 
         write('def macro(*args):')
         self.indention += 1
-        nodeinfo = self.nodeinfo(node)
-        if nodeinfo:
-            write(nodeinfo)
+        write(self.nodeinfo(node))
 
         if node.arguments:
             write('argcount = len(args)')
@@ -555,9 +565,7 @@ class PythonTranslator(Translator):
         else:
             write('ctx_push()')
 
-        nodeinfo = self.nodeinfo(node.body)
-        if nodeinfo:
-            write(nodeinfo)
+        write(self.nodeinfo(node.body))
         buf.append(self.handle_node(node.body))
         write('ctx_pop()')
         write('if False:')
@@ -572,10 +580,8 @@ class PythonTranslator(Translator):
         """
         Handle variable assignments.
         """
-        nodeinfo = self.nodeinfo(node) or ''
-        if nodeinfo:
-            nodeinfo = self.indent(nodeinfo) + '\n'
-        return nodeinfo + self.indent('context[%r] = %s' % (
+        return self.indent(self.nodeinfo(node)) + '\n' + \
+               self.indent('context[%r] = %s' % (
             node.name,
             self.handle_node(node.expr)
         ))
@@ -589,9 +595,7 @@ class PythonTranslator(Translator):
         write('def filtered():')
         self.indention += 1
         write('ctx_push()')
-        nodeinfo = self.nodeinfo(node.body)
-        if nodeinfo:
-            write(nodeinfo)
+        write(self.nodeinfo(node.body))
         buf.append(self.handle_node(node.body))
         write('ctx_pop()')
         write('if False:')
@@ -614,14 +618,12 @@ class PythonTranslator(Translator):
         buf = []
         write = lambda x: buf.append(self.indent(x))
 
-        write('ctx_push({\'super\': BlockContext(%r, blocks[%r], %r, context)})' % (
-            str(node.name),
+        write(self.nodeinfo(node))
+        write('ctx_push({\'super\': SuperBlock(%r, blocks, %r, context)})' % (
             str(node.name),
             level
         ))
-        nodeinfo = self.nodeinfo(node.body)
-        if nodeinfo:
-            write(nodeinfo)
+        write(self.nodeinfo(node.body))
         buf.append(self.handle_node(node.body))
         write('ctx_pop()')
         return '\n'.join(buf)
@@ -649,10 +651,8 @@ class PythonTranslator(Translator):
             replacements = '{%s}' % ', '.join(replacements)
         else:
             replacements = 'None'
-        nodeinfo = self.nodeinfo(node) or ''
-        if nodeinfo:
-            nodeinfo = self.indent(nodeinfo) + '\n'
-        return nodeinfo + self.indent('yield translate(%r, %r, %r, %s)' % (
+        return self.indent(self.nodeinfo(node)) + '\n' +\
+               self.indent('yield translate(%r, %r, %r, %s)' % (
             node.singular,
             node.plural,
             node.indicator,
index e9f63185c14ba107cf5bcb819596a5a12bbd4339..4e0183e3b660a41bcab5de8d9259e4ef2b308884 100644 (file)
@@ -19,7 +19,7 @@ from types import MethodType, FunctionType
 from compiler.ast import CallFunc, Name, Const
 from jinja.nodes import Trans
 from jinja.datastructure import Context, TemplateData
-from jinja.exceptions import SecurityException
+from jinja.exceptions import SecurityException, TemplateNotFound
 
 try:
     from collections import deque
@@ -29,8 +29,6 @@ except ImportError:
 #: number of maximal range items
 MAX_RANGE = 1000000
 
-_debug_info_re = re.compile(r'^\s*\# DEBUG\(filename=(.*?), lineno=(.*?)\)$')
-
 _integer_re = re.compile('^(\d+)$')
 
 _word_split_re = re.compile(r'(\s+)')
@@ -150,13 +148,68 @@ def safe_range(start, stop=None, step=None):
     return range(start, stop, step)
 
 
+def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
+    """
+    Generate some lorem impsum for the template.
+    """
+    from jinja.constants import LOREM_IPSUM_WORDS
+    from random import choice, random, randrange
+    words = LOREM_IPSUM_WORDS.split()
+    result = []
+
+    for _ in xrange(n):
+        next_capitalized = True
+        last_comma = last_fullstop = 0
+        word = None
+        last = None
+        p = []
+
+        # each paragraph contains out of 20 to 100 words.
+        for idx, _ in enumerate(xrange(randrange(min, max))):
+            while True:
+                word = choice(words)
+                if word != last:
+                    last = word
+                    break
+            if next_capitalized:
+                word = word.capitalize()
+                next_capitalized = False
+            # add commas
+            if idx - randrange(3, 8) > last_comma:
+                last_comma = idx
+                last_fullstop += 2
+                word += ','
+            # add end of sentences
+            if idx - randrange(10, 20) > last_fullstop:
+                last_comma = last_fullstop = idx
+                word += '.'
+                next_capitalized = True
+            p.append(word)
+
+        # ensure that the paragraph ends with a dot.
+        p = u' '.join(p)
+        if p.endswith(','):
+            p = p[:-1] + '.'
+        elif not p.endswith('.'):
+            p += '.'
+        result.append(p)
+
+    if not html:
+        return u'\n\n'.join(result)
+    return u'\n'.join([u'<p>%s</p>' % escape(x) for x in result])
+
+
 # python2.4 and lower has a bug regarding joining of broken generators
+# because of the runtime debugging system we have to keep track of the
+# number of frames to skip. that's what RUNTIME_EXCEPTION_OFFSET is for.
 if sys.version_info < (2, 5):
     capture_generator = lambda gen: u''.join(tuple(gen))
+    RUNTIME_EXCEPTION_OFFSET = 2
 
 # this should be faster and used in python2.5 and higher
 else:
     capture_generator = u''.join
+    RUNTIME_EXCEPTION_OFFSET = 1
 
 
 def buffereater(f):
@@ -169,7 +222,8 @@ def buffereater(f):
     return wrapped
 
 
-def fake_template_exception(exception, filename, lineno, context_or_env):
+def fake_template_exception(exception, filename, lineno, template,
+                            context_or_env):
     """
     Raise an exception "in a template". Return a traceback
     object. This is used for runtime debugging, not compile time.
@@ -188,7 +242,7 @@ def fake_template_exception(exception, filename, lineno, context_or_env):
     globals = {
         '__name__':                 filename,
         '__file__':                 filename,
-        '__loader__':               TracebackLoader(env, filename),
+        '__loader__':               TracebackLoader(env, template, filename),
         '__exception_to_raise__':   exception
     }
     try:
@@ -201,31 +255,16 @@ def translate_exception(template, exc_type, exc_value, traceback, context):
     """
     Translate an exception and return the new traceback.
     """
-    sourcelines = template.translated_source.splitlines()
-    startpos = traceback.tb_lineno - 1
-    filename = None
-    # looks like we loaded the template from string. we cannot
-    # do anything here.
-    if startpos > len(sourcelines):
-        return traceback
-
-    while startpos > 0:
-        m = _debug_info_re.search(sourcelines[startpos])
-        if m is not None:
-            filename, lineno = m.groups()
-            if filename == 'None':
-                filename = None
-            if lineno != 'None':
-                lineno = int(lineno)
+    error_line = traceback.tb_lineno
+    for code_line, tmpl_filename, tmpl_line in template._debug_info[::-1]:
+        if code_line <= error_line:
             break
-        startpos -= 1
-
-    # no traceback information found, reraise unchanged
-    if not filename:
+    else:
+        # no debug symbol found. give up
         return traceback
 
-    return fake_template_exception(exc_value, filename,
-                                   lineno, context)[2]
+    return fake_template_exception(exc_value, tmpl_filename, tmpl_line,
+                                   template, context)[2]
 
 
 def raise_syntax_error(exception, env):
@@ -236,7 +275,7 @@ def raise_syntax_error(exception, env):
     the traceback.
     """
     exc_info = fake_template_exception(exception, exception.filename,
-                                       exception.lineno, env)
+                                       exception.lineno, None, env)
     raise exc_info[0], exc_info[1], exc_info[2]
 
 
@@ -276,12 +315,20 @@ class TracebackLoader(object):
     Fake importer that just returns the source of a template.
     """
 
-    def __init__(self, environment, filename):
+    def __init__(self, environment, template, filename):
         self.loader = environment.loader
+        self.template = template
         self.filename = filename
 
     def get_source(self, impname):
-        return self.loader.get_source(self.filename)
+        if self.loader is not None:
+            try:
+                return self.loader.get_source(self.filename)
+            except TemplateNotFound:
+                pass
+        if self.template is not None:
+            return self.template._source or ''
+        return ''
 
 
 class CacheDict(object):
index 392623d08da790e59672e67b8ad1478b1f1fbc7e..c27a6df7a091b945aa7169e0b286a9a5825da123 100644 (file)
@@ -1,6 +1,7 @@
+import jdebug
+import sys
 from jinja import Environment, DictLoader
 from jinja.exceptions import TemplateNotFound
-from colubrid.debug import DebuggedApplication
 from wsgiref.simple_server import make_server
 
 e = Environment(loader=DictLoader({
@@ -68,4 +69,7 @@ def test(environ, start_response):
     start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
     return [tmpl.render().encode('utf-8')]
 
-make_server("localhost", 7000, DebuggedApplication(test)).serve_forever()
+if __name__ == '__main__':
+    from colubrid.debug import DebuggedApplication
+    app = DebuggedApplication(test)
+    make_server("localhost", 7000, app).serve_forever()