示例#1
0
 def __init__(self, application, global_conf=None,
              error_template_filename=None,
              xmlhttp_key=None, media_paths=None, 
              templating_formatters=None, head_html='', footer_html='',
              reporters=None, libraries=None,
              **params):
     self.libraries = libraries or []
     self.application = application
     self.debug_infos = {}
     self.templating_formatters = templating_formatters or []
     self.head_html = HTMLTemplate(head_html)
     self.footer_html = HTMLTemplate(footer_html)
     if error_template_filename is None:
         error_template_filename = resource_filename( "weberror", 
                                                      "eval_template.html" )
     if xmlhttp_key is None:
         if global_conf is None:
             xmlhttp_key = '_'
         else:
             xmlhttp_key = global_conf.get('xmlhttp_key', '_')
     self.xmlhttp_key = xmlhttp_key
     self.media_paths = media_paths or {}
     self.error_template = HTMLTemplate.from_filename(error_template_filename)
     if reporters is None:
         reporters = []
     self.reporters = reporters
 def login(self, req):
     """
     The login form.
     """
     if not self.check_ip(req):
         template = HTMLTemplate.from_filename(os.path.join(os.path.dirname(__file__), 'ip_denied.html'))
         return Response(template.substitute(req=req), status='403 Forbidden')
     if req.method == 'POST':
         username = req.str_POST['username']
         password = req.str_POST['password']
         if not self.check_login(username, password):
             msg = 'Invalid username or password'
         else:
             resp = exc.HTTPFound(location=req.params.get('back') or req.application_url)
             resp.set_cookie('__devauth', self.create_cookie(req, username))
             return resp
     else:
         msg = req.params.get('msg')
     back = req.params.get('back') or req.application_url
     if msg == 'expired':
         msg = 'Your session has expired.  You can log in again, or just <a href="%s">return to your previous page</a>' % (
             html_escape(back))
     template = HTMLTemplate.from_filename(os.path.join(os.path.dirname(__file__), 'login.html'))
     resp = Response(template.substitute(req=req, msg=msg, back=back, middleware=self))
     try:
         if req.cookies.get('__devauth'):
             self.read_cookie(req, req.str_cookies['__devauth'])
     except exc.HTTPException:
         # This means the cookie is invalid
         resp.delete_cookie('__devauth')
     return resp
示例#3
0
 def __init__(self, pagename):
     lines = []
     with open('web/' + pagename + '.tmplt', 'rb') as f:
         for l in f:
             l = l.decode('utf-8')
             if l:
                 lines.append(l[:-1])
     self.html = HTMLTemplate(''.join(lines))
示例#4
0
def rebuild_static_files():
    """
    Rebuilds static files
    """
    public_html_path = join(current_path(), '..', 'public_html')
    if not exists(public_html_path):
        os.mkdir(public_html_path)

    # Create index.html
    template = HTMLTemplate.from_filename(join(current_path(), '..',
                                               'templates' , 'index.html'))
    products_data = load_products_data()
    all_products = sorted(products_data,
           key=lambda product: product['version'][0]['publish_time'])
    all_products.reverse()

    # Build index html files
    # First remove any existing files
    html_files_list = glob(join(public_html_path, 'index.html.*'))
    for html_filename in html_files_list:
        os.unlink(html_filename)
    # Create per page files
    for i in xrange(0, len(all_products), 5):
        products = all_products[i:i+5]
        page_nr = (i/5)+1
        next_page_nr = page_nr + 1 if len(all_products) > i+5 else 0
        prev_page_nr = page_nr - 1 if page_nr > 1 else 0
        index_fname = join(public_html_path, 'index.html.%d' % page_nr)
        with open(index_fname, 'w') as index_html_file:
            index_html_file.write(template.substitute(locals()))

    # Build per product files
    template = HTMLTemplate.from_filename(join(current_path(), '..',
                                               'templates' , 'product.html'))

    products_path = join(public_html_path, 'products')
    if not exists(products_path):
        os.mkdir(products_path)
    html_files_list = glob(join(products_path, '*.html'))
    # First remove any existing files
    for html_filename in html_files_list:
        os.unlink(html_filename)
    for product in all_products:
        index_name = basename(product['index_name'])
        product_fname = join(products_path, '%s.html' % index_name)
        with open(product_fname, 'w') as html_file:
           html_file.write(template.substitute(locals()))

    # Create/update screenshot thumbnails
    update_thumbs()
示例#5
0
    def __init__(self, template, language=None):
        if language:
            translation(language)

        self._page = HTMLTemplate.from_filename(template)
        # Render full page
        self._full = True
示例#6
0
	def __init__(self, pagename):
		lines = []
		with open('web/' + pagename + '.tmplt', 'rb') as f:
			for l in f:
				l = l.decode('utf-8')
				if l:
					lines.append(l[:-1])
		self.html = HTMLTemplate(''.join(lines))
示例#7
0
 def find_template(self, template):
     """find a template of a given name"""
     # TODO: make this faster; the application should probably cache
     # a dict of the (loaded) templates unless (e.g.) debug is given
     
     for d in self.template_dirs:
         path = os.path.join(d, template)
         if os.path.exists(path):
             return HTMLTemplate.from_filename(path)
示例#8
0
def render_template(filename, namespace, filters_module=None):                    
    # Install template filters if given
    if filters_module:
        filters_namespace = {}
        for name in filters_module.__all__:
            filter = getattr(filters_module, name)
            filters_namespace[filter.name] = filter
        # @@HACK Remove conflicting filter with HTMLTemplate
        del filters_namespace['html'] 
        # Update namespace, possibly overriding names
        namespace.update(filters_namespace)
    return HTMLTemplate.from_filename(filename, namespace=namespace).substitute()
示例#9
0
def render_template(filename, namespace, filters_module=None):                    
    # Install template filters if given
    if filters_module:
        filters_namespace = {}
        for name in filters_module.__all__:
            filter = getattr(filters_module, name)
            filters_namespace[filter.name] = filter
        # @@HACK Remove conflicting filter with HTMLTemplate
        del filters_namespace['html'] 
        # Update namespace, possibly overriding names
        namespace.update(filters_namespace)
    return HTMLTemplate.from_filename(filename, namespace=namespace).substitute()
示例#10
0
 def find_template(self, name):
     """find a template of a given name"""
     # the application caches a dict of the templates if app.reload is False
     if name in self.template_cache:
         return self.template_cache[name]
     
     for d in self.template_dirs:
         path = os.path.join(d, name)
         if os.path.exists(path):
             template = HTMLTemplate.from_filename(path)
             if not self.app.reload:
                 self.template_cache[name] = template
             return template
示例#11
0
class PageTemplate:
	'''Class to load a page template from file and i18n it, implementation using tempita'''
	# Constructor
	def __init__(self, pagename):
		lines = []
		with open('web/' + pagename + '.tmplt', 'rb') as f:
			for l in f:
				l = l.decode('utf-8')
				if l:
					lines.append(l[:-1])
		self.html = HTMLTemplate(''.join(lines))

	def getHtml(self, params=None):
		'''Use the given dictionary (if any) to populate the template'''
		if params is None:
			params = {}
		params["langs"] = I18nManager.texts
		return self.html.substitute(params)
示例#12
0
class PageTemplate:
    '''Class to load a page template from file and i18n it, implementation using tempita'''

    # Constructor
    def __init__(self, pagename):
        lines = []
        with open('web/' + pagename + '.tmplt', 'rb') as f:
            for l in f:
                l = l.decode('utf-8')
                if l:
                    lines.append(l[:-1])
        self.html = HTMLTemplate(''.join(lines))

    def getHtml(self, params=None):
        '''Use the given dictionary (if any) to populate the template'''
        if params is None:
            params = {}
        params["langs"] = I18nManager.texts
        return self.html.substitute(params)
示例#13
0
 def __init__(
     self,
     application,
     global_conf=None,
     error_template_filename=None,
     xmlhttp_key=None,
     media_paths=None,
     templating_formatters=None,
     head_html="",
     footer_html="",
     reporters=None,
     libraries=None,
     debug_url_prefix=None,
     **params
 ):
     self.libraries = libraries or []
     self.application = application
     self.debug_infos = {}
     self.templating_formatters = templating_formatters or []
     self.head_html = HTMLTemplate(head_html)
     self.footer_html = HTMLTemplate(footer_html)
     if error_template_filename is None:
         error_template_filename = resource_filename("weberror", "eval_template.html")
     if xmlhttp_key is None:
         if global_conf is None:
             xmlhttp_key = "_"
         else:
             xmlhttp_key = global_conf.get("xmlhttp_key", "_")
     self.xmlhttp_key = xmlhttp_key
     if debug_url_prefix is None:
         if global_conf is None:
             debug_url_prefix = "_debug"
         else:
             debug_url_prefix = global_conf.get("debug_url_prefix", "_debug")
     self.debug_url_prefix = debug_url_prefix.split("/")
     self.media_paths = media_paths or {}
     self.error_template = HTMLTemplate.from_filename(error_template_filename)
     if reporters is None:
         reporters = []
     self.reporters = reporters
示例#14
0
文件: wsgiapp.py 项目: ianb/emailit
from formencode.api import Invalid
from lxml import html
try:
    # Python 2.5:
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
except ImportError:
    # Python 2.4:
    from email.MIMEMultipart import MIMEMultipart
    from email.MIMEText import MIMEText
import smtplib

here = os.path.dirname(__file__)

## FIXME: these don't auto-reload or restart the server on edit:
form_html = HTMLTemplate.from_filename(os.path.join(here, 'form.html'))
result_html = HTMLTemplate.from_filename(os.path.join(here, 'result.html'))

class EmailIt(object):

    ## FIXME: should have some kind of host restriction, like ScriptTranscluder
    def __init__(self, smtp_server='localhost', smtp_username=None, smtp_password=None, smtp_use_tls=False):
        self.smtp_server = smtp_server
        self.smtp_username = smtp_username
        self.smtp_password = smtp_password
        self.smtp_use_tls = smtp_use_tls

    def __call__(self, environ, start_response):
        req = Request(environ)
        if req.method == 'GET':
            meth = self.form
示例#15
0
            message.tail = doc.body.text
            doc.body.text = ''
        doc.body.insert(0, message)
        text = tostring(doc)
        return Response(text)

    def _el_in_head(self, el):
        """True if the given element is in the HTML ``<head>``"""
        while el is not None:
            if el.tag == 'head':
                return True
            el = el.getparent()
        return False

    _not_found_template = HTMLTemplate(
        '''\
    There were no elements that matched the selector <code>{{selector}}</code>
    ''', 'deliverance.middleware.DeliveranceMiddleware._not_found_template')

    _found_template = HTMLTemplate(
        '''\
    {{if len(elements) == 1}}
      One element matched the selector <code>{{selector}}</code>;
      {{if elements[0][0]}}
        <a href="{{base_url}}#{{elements[0][0]}}">jump to element</a>
      {{else}}
        element is in head: {{highlight(elements[0][1])}}
      {{endif}}
    {{else}}
      {{len(elements)}} elements matched the selector <code>{{selector}}</code>:
      <ol>
      {{for anchor, el in elements}}
示例#16
0
def render_template(filename, namespace):                    
    return HTMLTemplate.from_filename(filename, namespace=namespace).substitute()
示例#17
0
 def homepage(self, req):
     tmpl = HTMLTemplate.from_filename(os.path.join(here, 'homepage.html'))
     resp = tmpl.substitute(app=self, req=req, appIncludeJs=self.appinclude_js)
     return Response(body=resp)
示例#18
0
class Editor(object):

    def __init__(self, base_dir=None, filename=None,
                 title=None, force_syntax=None):
        assert base_dir or filename
        assert not base_dir or not filename
        if base_dir:
            self.base_dir = os.path.normcase(os.path.abspath(base_dir))
        else:
            self.base_dir = None
        self.filename = filename
        self.title = title
        self.force_syntax = force_syntax

    def __call__(self, environ, start_response):
        req = Request(environ)
        if req.path_info_peek() == '.media':
            req.path_info_pop()
            app = StaticURLParser(os.path.join(os.path.dirname(__file__), 'media'))
            return app(environ, start_response)
        if self.base_dir:
            filename = os.path.join(self.base_dir, req.path_info.lstrip('/'))
            assert filename.startswith(self.base_dir)
        else:
            filename = self.filename
        if req.method not in ('GET', 'POST'):
            resp = exc.HTTPMethodNotAllowed('Bad method: %s' % req.method,
                                            allow='GET,POST')
        elif os.path.isdir(filename):
            if req.method == 'POST':
                resp = self.save_create(req, filename)
            else:
                if not req.path.endswith('/'):
                    resp = exc.HTTPMovedPermanently(add_slash=True)
                else:
                    resp = self.view_dir(req, filename)
        else:
            if req.method == 'POST':
                resp = self.save_file(req, filename)
            elif req.method == 'GET':
                resp = self.edit_file(req, filename)
        return resp(environ, start_response)

    def edit_url(self, req, filename):
        if self.filename:
            assert self.filename == filename
            return req.application_url
        else:
            assert filename.startswith(self.base_dir)
            filename = filename[len(self.base_dir):].lstrip('/').lstrip('\\')
            return req.application_url + '/' + filename

    def save_file(self, req, filename):
        content = req.POST['content']
        f = open(filename, 'wb')
        f.write(content)
        f.close()
        return exc.HTTPFound(
            location=self.edit_url(req, filename))

    syntax_map = {
        '.c': 'c',
        '.cf': 'coldfusion',
        '.cpp': 'cpp',
        '.c++': 'cpp',
        '.css': 'css',
        '.html': 'html',
        '.htm': 'html',
        '.xhtml': 'html',
        '.js': 'js',
        '.pas': '******',
        '.pl': 'perl',
        '.php': 'php',
        '.py': 'python',
        'robots.txt': 'robotstxt',
        '.rb': 'ruby',
        '.sql': 'sql',
        '.tsql': 'tsql',
        '.vb': 'vb',
        '.xml': 'xml',
        }

    def syntax_for_filename(self, filename):
        if self.force_syntax:
            return self.force_syntax
        basename = os.path.basename(filename)
        if basename in self.syntax_map:
            return self.syntax_map[basename]
        else:
            ext = os.path.splitext(filename)[1].lower()
            if ext in self.syntax_map:
                return self.syntax_map[ext]
        mimetype, enc = mimetypes.guess_type(os.path.splitext(filename)[1])
        if mimetype.startswith('application/') and mimetype.endswith('+xml'):
            return 'xml'
        return None

    def edit_file(self, req, filename):
        f = open(filename, 'rb')
        content = f.read()
        f.close()
        title = self.title or filename
        syntax = self.syntax_for_filename(filename)
        body = self.edit_template.substitute(
            content=content, filename=filename, title=title, 
            req=req, edit_url=self.edit_url(req, filename),
            syntax=syntax)
        resp = Response(body=body)
        resp.cache_expires()
        return resp

    edit_template = HTMLTemplate.from_filename(
        os.path.join(os.path.dirname(__file__), 'editor_template.html'))

    def save_create(self, req, dir):
        file = req.POST.get('file')
        if file is None or file == '':
            content = req.POST['content']
            filename = req.POST['filename']
        else:
            content = file.value
            filename = req.POST.get('filename') or file.filename
        filename = filename.replace('\\', '/')
        filename = os.path.basename(os.path.normpath(filename))
        filename = os.path.join(dir, filename)
        if os.path.exists(filename):
            return exc.HTTPForbidden(
                "The file %s already exists, you cannot upload over it" % filename)
        f = open(filename, 'wb')
        f.write(content)
        f.close()
        return exc.HTTPFound(
            location=self.edit_url(req, filename))

    skip_files = ['.svn', 'CVS', '.hg']

    def view_dir(self, req, dir):
        dir = os.path.normpath(dir)
        show_parent = dir != self.base_dir
        children = [os.path.join(dir, name) for name in os.listdir(dir)
                    if name not in self.skip_files]
        def edit_url(filename):
            return self.edit_url(req, filename)
        title = self.title or dir
        body = self.view_dir_template.substitute(
            req=req,
            dir=dir,
            show_parent=show_parent,
            title=title,
            basename=os.path.basename,
            dirname=os.path.dirname,
            isdir=os.path.isdir,
            children=children,
            edit_url=edit_url,
            )
        resp = Response(body=body)
        resp.cache_expires()
        return resp

    view_dir_template = HTMLTemplate.from_filename(
        os.path.join(os.path.dirname(__file__), 'view_dir_template.html'))
示例#19
0
class Annotate(object):
    def __init__(self, dir):
        self.dir = dir
        self.static_app = Subber(
            'package:seeitservices.annotate:./static-annotate/')

    @wsgify
    def __call__(self, req):
        req.charset = None
        peek = req.path_info_peek()
        if peek == 'save':
            return self.save(req)
        elif peek == 'page':
            return self.page(req)
        elif peek == 'annotation':
            return self.annotation(req)
        if req.path_info == '/describe':
            return self.describe(req)
        return self.static_app

    def split_path(self, req, prefix):
        path = req.path_info.strip('/')
        assert path.startswith(prefix + '/')
        path = path[len(prefix):].strip('/')
        email, rest = path.split('/', 1)
        return email, rest

    def make_filename(self, type, email, path):
        path = os.path.join(self.dir, type, urllib.quote(email, ''),
                            urllib.quote(path, ''))
        assert os.path.abspath(path).startswith(os.path.abspath(self.dir))
        return path

    @wsgify
    def describe(self, req):
        data = dict(
            name='Annotate a document',
            sendToPage=req.application_url + '/create.html',
            sendToPageFunction='savePage',
            types=['html'],
        )
        return Response(json=data)

    @wsgify
    def save(self, req):
        if not req.email:
            return Response(status=403,
                            content_type='text/plain',
                            body='Not logged in')
        email, path = self.split_path(req, 'save')
        if email != req.email:
            return Response(status=403,
                            content_type='text/plain',
                            body='Email not correct (%r, not %r)' %
                            (req.email, email))
        if req.method != 'PUT':
            return exc.HTTPMethodNotAllowed(allow='PUT')
        data = req.json
        filename = self.make_filename('page', email, path)
        write_file(filename, json.dumps(data))
        location = req.application_url + '/page/' + urllib.quote(
            email) + '/' + urllib.quote(path, '')
        return Response(json={'location': location})

    page_template = HTMLTemplate('''\
<html>
 <head>
  <meta charset="UTF-8">
  <base href="{{location}}">
  {{head | html}}
  <link href="{{application_url}}/annotate.css" rel="stylesheet" type="text/css">
 </head>
 <body{{body_attrs | html}}>
  {{body | html}}
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
  <script src="{{application_url}}/annotate.js"></script>
  <script>annotationUrl = {{repr(annotation_url)}};</script>
  {{auth_html | html}}
 </body>
</html>
''')

    @wsgify
    def page(self, req):
        email, path = self.split_path(req, 'page')
        filename = self.make_filename('page', email, path)
        if not os.path.exists(filename):
            return exc.HTTPNotFound()
        with open(filename, 'rb') as fp:
            data = json.loads(fp.read())
        if data['data'].get('bodyAttrs'):
            body_attrs = [
                ' %s="%s"' % (name, cgi.escape(value))
                for name, value in data['data']['bodyAttrs'].items()
            ]
        else:
            body_attrs = ''
        page = self.page_template.substitute(
            location=data['location'],
            head=data['data']['head'],
            application_url=req.application_url,
            body_attrs=body_attrs,
            body=data['data']['body'],
            auth_html=req.get_sub('auth'),
            annotation_url=req.url.replace('/page/', '/annotation/'),
        )
        return Response(page)

    @wsgify
    def annotation(self, req):
        email, path = self.split_path(req, 'annotation')
        filename = self.make_filename('annotation', email, path)
        if not os.path.exists(filename):
            data = {'annotations': []}
        else:
            with open(filename, 'rb') as fp:
                data = json.loads(fp.read())
        if req.method == 'GET':
            return Response(json=data)
        elif req.method == 'POST':
            req_data = req.json
            if req_data.get('annotations'):
                data['annotations'].extend(req_data['annotations'])
            if req_data.get('deletes'):
                for delete in req_data['deletes']:
                    for ann in list(data['annotations']):
                        if ann['id'] == delete['id']:
                            data['annotations'].remove(ann)
            if not os.path.exists(os.path.dirname(filename)):
                os.makedirs(os.path.dirname(filename))
            with open(filename, 'wb') as fp:
                fp.write(json.dumps(data))
            return Response(json=data)
        else:
            return exc.HTTPMethodNotAllowed(allow='GET,POST')
示例#20
0
def render_template(filename, namespace):
    return HTMLTemplate.from_filename(filename,
                                      namespace=namespace).substitute()
示例#21
0
class Recorder(object):

    def __init__(self, app, file, intercept='/.webtestrecorder',
                 require_devauth=False):
        self.app = app
        if isinstance(file, basestring):
            file = open(file, 'ab')
        self.file = file
        self.lock = threading.Lock()
        self.intercept = intercept
        self.require_devauth = require_devauth

    @classmethod
    def entry_point(cls, app, global_conf, filename, intercept='/.webtestrecorder',
                    require_devauth=False):
        from paste.deploy.converters import asbool
        require_devauth = asbool(require_devauth)
        return cls(app, filename, intercept, require_devauth)

    @wsgify
    def __call__(self, req):
        if self.intercept and req.path_info.startswith(self.intercept):
            return self.internal(req)
        resp = req.get_response(self.app)
        self.write_record(req, resp)
        return resp

    def write_record(self, req, resp):
        data = []
        data.append('--Request:\n')
        data.append(str(req))
        if not req.content_length:
            data.append('\n')
        data.append('\n--Response:\n')
        data.append(str(resp))
        if not resp.body:
            data.append('\n')
        data.append('\n')
        self.lock.acquire()
        try:
            self.file.write(''.join(data))
        finally:
            self.lock.release()

    @wsgify
    def internal(self, req):
        if (self.require_devauth
            and not req.environ.get('x-wsgiorg.developer_user')):
            raise exc.HTTPForbidden('You must login')
        if req.method == 'POST':
            if req.params.get('clear'):
                name = self.file.name
                self.file.close()
                self.file = open(name, 'wb')
            else:
                false_req = Request.blank('/')
                false_resp = Response('', status='200 Internal Note')
                false_resp.write(req.params['note'])
                self.write_record(false_req, false_resp)
            raise exc.HTTPFound(req.url)
        if req.params.get('download'):
            if req.params['download'] == 'doctest':
                text = self.doctest(req)
            else:
                text = self.function_unittest(req)
            return Response(text, content_type='text/plain')
        return Response(self._intercept_template.substitute(req=req, s=self))

    _intercept_template = HTMLTemplate('''\
<html>
 <head>
  <title>WebTest Recorder</title>
  <style type="text/css">
    body {
      font-family: sans-serif;
    }
    pre {
      overflow: auto;
    }
  </style>
 </head>
 <body>
  <h1>WebTest Recorder</h1>

  <div>
   <a href="#doctest">doctest</a> (<a href="{{req.url}}?download=doctest">download</a>)
     | <a href="#function_unittest">function unittest</a>
       (<a href="{{req.url}}?download=function_unittest">download</a>)
  </div>

  <form action="{{req.url}}" method="POST">
   <fieldset>
   You may add a note/comment to the record:<br>
   <textarea name="note" rows=4 style="width: 100%"></textarea><br>
   <button type="submit">Save note</button>
   <button type="submit" name="clear" value="1"
    style="background-color: #f99">Clear!</button>
   </fieldset>
  </form>

  <h1 id="doctest">Current tests as a doctest</h1>

  <pre>{{s.doctest(req)}}</pre>

  <h1 id="function_unittest">Current tests as a function unittest</h1>

  <pre>{{s.function_unittest(req)}}</pre>

 </body>
</html>
''', name='_intercept_template')

    def doctest(self, req):
        records = self.get_records()
        out = StringIO()
        write_doctest(records, out, default_host=req.host)
        return out.getvalue()

    def function_unittest(self, req):
        records = self.get_records()
        out = StringIO()
        write_function_unittest(records, out, default_host=req.host)
        return out.getvalue()

    def get_records(self):
        self.file.flush()
        fn = self.file.name
        fp = open(fn, 'rb')
        content = StringIO(fp.read())
        fp.close()
        return get_records(content)
示例#22
0
    "names" : [ "alice", "bob", "eve" ],
    "people" : [
        { "name" : "alice", "role" : "communicator" },
        { "name" : "bob", "role" : "communicator" },
        { "name" : "eve", "role" : "eavesdropper", "blackhat" : True },
        ],
    "a_bunch" : bunch(a=1,b=2,c=3),
    "plus_filter" : plus_filter,  # Make available as filter
}

print t.substitute(context_params)

print "\nDoing HTML subsitution..."

html_template_string="""
{{# A little counter-intuitive, but use 'html()' to substitute without quotes }}
<a href="{{ target_url | html }}">{{ target_name }}</a>
"""

t2 = HTMLTemplate(html_template_string)

context_params2 = {
    "target_url" : "https://example.com/hello?world&value=2",
    "target_name" : "Here & There",
}

print t2.substitute(context_params2)

sys.exit(0)

示例#23
0
        make_wrappable=formatter.make_wrappable,
        pprint_format=pprint_format)

table_template = HTMLTemplate('''
{{py:i = 0}}
<table>
{{for name, value in items:}}
  {{py:i += 1}}
{{py:
value_html = html_quote(pprint_format(value, safe=True))
value_html = make_wrappable(value_html)
if len(value_html) > 100:
    ## FIXME: This can break HTML; truncate before quoting?
    value_html, expand_html = value_html[:100], value_html[100:]
else:
    expand_html = ''
}}
  <tr class="{{if i%2}}even{{else}}odd{{endif}}"
      style="vertical-align: top">
    <td><b>{{name}}</b></td>
    <td style="overflow: auto">{{preserve_whitespace(value_html, quote=False)|html}}{{if expand_html}}
      <a class="switch_source" style="background-color: #999" href="#" onclick="return expandLong(this)">...</a>
      <span style="display: none">{{expand_html|html}}</span>
    {{endif}}
    </td>
  </tr>
{{endfor}}
</table>
''', name='table_template')

def pprint_format(value, safe=False):
    out = StringIO()
示例#24
0
class SavingLogger(object):
    """
    Logger that saves all its messages locally.
    """
    def __init__(self, request, middleware):
        self.messages = []
        self.middleware = middleware
        self.request = request
        # This is writable:
        self.theme_url = None
        # Also writable (list of (url, name))
        self.edit_urls = []

    def message(self, level, el, msg, *args, **kw):
        """Add one message at the given log level"""
        if args:
            msg = msg % args
        elif kw:
            msg = msg % kw
        self.messages.append((level, el, msg))
        return msg

    def debug(self, el, msg, *args, **kw):
        """Log at the DEBUG level"""
        return self.message(logging.DEBUG, el, msg, *args, **kw)

    def info(self, el, msg, *args, **kw):
        """Log at the INFO level"""
        return self.message(logging.INFO, el, msg, *args, **kw)

    def notify(self, el, msg, *args, **kw):
        """Log at the NOTIFY level"""
        return self.message(NOTIFY, el, msg, *args, **kw)

    def warn(self, el, msg, *args, **kw):
        """Log at the WARN level"""
        return self.message(logging.WARN, el, msg, *args, **kw)

    warning = warn

    def error(self, el, msg, *args, **kw):
        """Log at the ERROR level"""
        return self.message(logging.ERROR, el, msg, *args, **kw)

    def fatal(self, el, msg, *args, **kw):
        """Log at the FATAL level"""
        return self.message(logging.FATAL, el, msg, *args, **kw)

    def finish_request(self, req, resp):
        """Called by the middleware at the end of the request.

        This gives the log an opportunity to add information to the
        page.
        """
        if 'deliv_log' in req.GET and display_logging(req):
            resp.body += self.format_html_log()
            resp.cache_expires()
        return resp

    log_template = HTMLTemplate(
        '''\
    <H1 style="border-top: 3px dotted #f00">Deliverance Information</h1>

    <div>
      {{if log.theme_url}}
        <a href="{{theme_url}}" target="_blank">theme</a>
      {{else}}
        theme: no theme set
      {{endif}}
      | <a href="{{unthemed_url}}" target="_blank">unthemed content</a>
      | <a href="{{content_source}}" target="_blank">content source</a>
      | <a href="{{content_browse}}" target="_blank">browse content</a>
        / <a href="{{theme_browse}}" target="_blank">theme</a>
      {{if log.edit_urls}}
      | <select onchange="if (this.value) {window.open(this.value, '_blank')}; this.selectedIndex=0;">
          <option value="">edit location</option>
        {{for url, name in log.edit_urls}}
          <option value="{{url}}">{{name}}</option>
        {{endfor}}
        </select>
      {{endif}}
      {{if edit_rules}}
      | <a href="{{edit_rules}}" target="_blank">edit rules</a>
      {{endif}}
    </div>

    {{if log.messages}}
      {{div}}
      {{h2}}Log</h2>
      {{div_inner}}
      <table>
          <tr>
            <th>Level</th><th>Message</th><th>Context</th>
          </tr>
        {{for level, level_name, el, message in log.resolved_messages():}}
          {{py:color, bgcolor = log.color_for_level(level)}}
          <tr style="color: {{color}}; background-color: {{bgcolor}}; vertical-align: top">
            {{td}}{{level_name}}</td>
            {{td}}{{message}}</td>
            {{td}}{{log.obj_as_html(el) | html}}</td>
          </tr>
        {{endfor}}
      </table>
      </div></div>
    {{else}}
      {{h2}}No Log Messages</h2>
    {{endif}}
    ''',
        name='deliverance.log.SavingLogger.log_template')

    tags = dict(
        h2=html(
            '<h2 style="color: #000; background-color: #f90; margin-top: 0; '
            'border-bottom: 1px solid #630">'),
        div=html('<div style="border: 2px solid #000; margin-bottom: 1em">'),
        div_inner=html('<div style="padding: 0.25em">'),
        td=html('<td style="margin-bottom: 0.25em; '
                'border-bottom: 1px solid #ddd; padding-right: 0.5em">'),
    )

    def format_html_log(self):
        """Formats this log object as HTML"""
        content_source = self.link_to(self.request.url, source=True)
        content_browse = self.link_to(self.request.url, browse=True)
        theme_browse = self.link_to(self.theme_url, browse=True)
        if edit_local_files(self.request.environ):
            ## FIXME: also test for the local-ness of the file
            edit_rules = (self.request.environ['deliverance.base_url'] +
                          '/.deliverance/edit_rules')
        else:
            edit_rules = None
        return self.log_template.substitute(
            log=self,
            middleware=self.middleware,
            unthemed_url=self._add_notheme(self.request.url),
            theme_url=self._add_notheme(self.theme_url),
            content_source=content_source,
            content_browse=content_browse,
            theme_browse=theme_browse,
            edit_rules=edit_rules,
            **self.tags)

    def _add_notheme(self, url):
        """Adds the necessary query string argument to the URL to suppress
        theming"""
        if url is None:
            return None
        if '?' in url:
            url += '&'
        else:
            url += '?'
        return url + 'deliv_notheme'

    def resolved_messages(self):
        """
        Yields a list of ``(level, level_name, context_el, rendered_message)``
        """
        for level, el, msg in self.messages:
            level_name = logging.getLevelName(level)
            yield level, level_name, el, msg

    def obj_as_html(self, el):
        """
        Returns the object formatted as HTML.  This is used to show
        the context in log messages.
        """
        ## FIXME: another magic method?
        if hasattr(el, 'log_description'):
            return el.log_description(self)
        elif isinstance(el, _Element):
            return html_quote(tostring(el))
        else:
            return html_quote(str(el))

    def color_for_level(self, level):
        """
        The HTML foreground/background colors for a given level.
        """
        return {
            logging.DEBUG: ('#666', '#fff'),
            logging.INFO: ('#333', '#fff'),
            NOTIFY: ('#000', '#fff'),
            logging.WARNING: ('#600', '#fff'),
            logging.ERROR: ('#fff', '#600'),
            logging.CRITICAL: ('#000', '#f33')
        }[level]

    def link_to(self,
                url,
                source=False,
                line=None,
                selector=None,
                browse=False):
        """
        Gives a link to the given source view (just routes to
        `deliverance.middleware.DeliveranceMiddleware.link_to`).
        """
        return self.middleware.link_to(self.request,
                                       url,
                                       source=source,
                                       line=line,
                                       selector=selector,
                                       browse=browse)
示例#25
0
import os
import re
from webob import Request, Response
from webob import exc
from tempita import HTMLTemplate

VIEW_TEMPLATE = HTMLTemplate("""\
<html>
 <head>
  <title>{{page.title}}</title>
 </head>
 <body>
<h1>{{page.title}}</h1>
{{if message}}
<div style="background-color: #99f">{{message}}</div>
{{endif}}

<div>{{page.content|html}}</div>

<hr>
<a href="{{req.url}}?action=edit">Edit</a>
 </body>
</html>
""")

EDIT_TEMPLATE = HTMLTemplate("""\
<html>
 <head>
  <title>Edit: {{page.title}}</title>
 </head>
 <body>
示例#26
0
class DeliveranceMiddleware(object):
    """
    The middleware that implements the Deliverance transformations
    """

    ## FIXME: is log_factory etc very useful?
    def __init__(self,
                 app,
                 rule_getter,
                 log_factory=SavingLogger,
                 log_factory_kw={},
                 default_theme=None):
        self.app = app
        self.rule_getter = rule_getter
        self.log_factory = log_factory
        self.log_factory_kw = log_factory_kw

        self._default_theme = default_theme

        ## FIXME: clearly, this should not be a dictionary:
        self.known_html = set()
        self.known_titles = {}

    def default_theme(self, environ):
        """
        The URI of the global default theme, if one is set, or None.

        This is a method that takes the WSGI environ so that subclasses
        can override the behavior (for example setting the default theme
        to a URI template that is interpolated on every request)
        """
        return self._default_theme

    def log_description(self, log=None):
        """The description shown in the log for this context"""
        return 'Deliverance'

    def notheme_request(self, req):
        if 'deliv_notheme' in req.GET:
            return True

    def use_internal_subrequest(self, url, orig_req, log):
        """
        Subclasses can override this method to control when
        Deliverance should make internal subrequests directly to the
        proxied application (in other words, calling the WSGI
        application that DeliveranceMiddleware is wrapping) rather
        than making an HTTP subrequest to a fully external URL.
        """
        return url.startswith(orig_req.application_url + '/')

    def __call__(self, environ, start_response):
        req = Request(environ)
        if self.notheme_request(req):
            return self.app(environ, start_response)

        req.environ['deliverance.base_url'] = req.application_url
        ## FIXME: copy_get?:
        orig_req = Request(environ.copy())
        if 'deliverance.log' in req.environ:
            log = req.environ['deliverance.log']
        else:
            log = self.log_factory(req, self, **self.log_factory_kw)
            ## FIXME: should this be put in both the orig_req and this req?
            req.environ['deliverance.log'] = log

        def resource_fetcher(url, retry_inner_if_not_200=False):
            """
            Return the Response object for the given URL
            """
            return self.get_resource(url, orig_req, log,
                                     retry_inner_if_not_200)

        if req.path_info_peek() == '.deliverance':
            req.path_info_pop()
            resp = self.internal_app(req, resource_fetcher)
            return resp(environ, start_response)
        rule_set = self.rule_getter(resource_fetcher, self.app, orig_req)
        clientside = rule_set.check_clientside(req, log)
        if clientside and req.url in self.known_html:
            if req.cookies.get('jsEnabled'):
                log.debug(self,
                          'Responding to %s with a clientside theme' % req.url)
                return self.clientside_response(req, rule_set,
                                                resource_fetcher,
                                                log)(environ, start_response)
            else:
                log.debug(
                    self,
                    'Not doing clientside theming because jsEnabled cookie not set'
                )

        head_response = None
        if req.method == "HEAD":
            # We need to copy the request instead of reusing it,
            # in case the downstream app modifies req.environ in-place
            head_req = req.copy()
            head_response = head_req.get_response(self.app)
            req.method = "GET"

        resp = req.get_response(self.app)

        ## FIXME: also XHTML?
        if resp.content_type != 'text/html':
            ## FIXME: remove from known_html?
            return resp(environ, start_response)

        # XXX: Not clear why such responses would have a content type, but
        # they sometimes do (from Zope/Plone, at least) and that then breaks
        # when trying to apply a theme.
        if resp.status_int in (301, 302, 304):
            return resp(environ, start_response)

        if resp.content_length == 0:
            return resp(environ, start_response)

        if resp.body == '':
            return resp(environ, start_response)

        if clientside and req.url not in self.known_html:
            log.debug(
                self,
                '%s would have been a clientside check; in future will be since we know it is HTML'
                % req.url)
            self.known_titles[req.url] = self._get_title(resp.body)
            self.known_html.add(req.url)
        resp = rule_set.apply_rules(req,
                                    resp,
                                    resource_fetcher,
                                    log,
                                    default_theme=self.default_theme(environ))
        if clientside:
            resp.decode_content()
            resp.body = self._substitute_jsenable(resp.body)
        resp = log.finish_request(req, resp)

        if head_response:
            head_response.headers = resp.headers
            resp = head_response

        return resp(environ, start_response)

    _title_re = re.compile(r'<title>(.*?)</title>', re.I | re.S)

    def _get_title(self, body):
        match = self._title_re.search(body)
        if match:
            return match.group(1)
        else:
            return None

    _end_head_re = re.compile(r'</head>', re.I)
    _jsenable_js = '''\
<script type="text/javascript">
document.cookie = 'jsEnabled=1; expires=__DATE__; path=/';
</script>'''
    _future_date = (datetime.datetime.now() + datetime.timedelta(days=10 * 365)
                    ).strftime('%a, %d-%b-%Y %H:%M:%S GMT')

    def _substitute_jsenable(self, body):
        match = self._end_head_re.search(body)
        if not match:
            return body
        js = self._jsenable_js.replace('__DATE__', self._future_date)
        return body[:match.start()] + js + body[match.start():]

    def clientside_response(self, req, rule_set, resource_fetcher, log):
        theme_href = rule_set.default_theme.resolve_href(req, None, log)
        theme_doc = rule_set.get_theme(theme_href, resource_fetcher, log)
        js = CLIENTSIDE_JAVASCRIPT.replace('__DELIVERANCE_URL__',
                                           req.application_url)
        theme_doc.head.insert(
            0,
            fromstring('''\
<script type="text/javascript">
%s
</script>''' % js))
        theme = tostring(theme_doc)
        ## FIXME: cache this, use the actual subresponse to get proper last-modified, etc
        title = self.known_titles.get(req.url)
        if title:
            theme = self._title_re.sub('<title>%s</title>' % title, theme)
        resp = Response(theme, conditional_response=True)
        if not resp.etag:
            resp.md5_etag()
        return resp

    def get_resource(self,
                     url,
                     orig_req,
                     log,
                     retry_inner_if_not_200=False,
                     redirections=5):
        resp = self._get_resource(url, orig_req, log, retry_inner_if_not_200)
        if not resp.status.startswith("3") or not resp.location:
            return resp
        max_redirections = redirections
        while redirections > 0:
            redirections = redirections - 1
            log.debug(
                self,
                "Request for %s returned %s; following redirect Location: %s" %
                (url, resp.status, resp.location))
            url = resp.location
            resp = self._get_resource(url, orig_req, log,
                                      retry_inner_if_not_200)
            if not resp.status.startswith("3") or not resp.location:
                return resp
        log.debug(
            self, "Max redirects (%s) reached; returning response %s from %s" %
            (max_redirections, url, resp.status))
        return resp

    def _get_resource(self, url, orig_req, log, retry_inner_if_not_200=False):
        """
        Gets the resource at the given url, using the original request
        `orig_req` as the basis for constructing the subrequest.
        Returns a `webob.Response` object.

        If `url.startswith(orig_req.application_url + '/')`, then Deliverance
        will try to fetch the resource by making a subrequest to the app that
        is being wrapped by Deliverance, instead of an external subrequest.

        This can cause problems in some setups -- see #16. To work around
        this, if `retry_inner_if_not_200` is True, then, in the situation
        described above, non-200 responses from the inner app will be tossed
        out, and the request will be retried as an external http request.
        Currently this is used only by RuleSet.get_theme
        """
        assert url is not None
        if url.lower().startswith('file:'):
            if not display_local_files(orig_req):
                ## FIXME: not sure if this applies generally; some
                ## calls to get_resource might be because of a more
                ## valid subrequest than displaying a file
                return exc.HTTPForbidden(
                    "You cannot access file: URLs (like %r)" % url)
            filename = url_to_filename(url)
            if not os.path.exists(filename):
                return exc.HTTPNotFound("The file %r was not found" % filename)
            if os.path.isdir(filename):
                return exc.HTTPForbidden(
                    "You cannot display a directory (%r)" % filename)
            subresp = Response()
            type, dummy = mimetypes.guess_type(filename)
            if not type:
                type = 'application/octet-stream'
            subresp.content_type = type
            ## FIXME: reading the whole thing obviously ain't great:
            f = open(filename, 'rb')
            subresp.body = f.read()
            f.close()
            return subresp

        elif self.use_internal_subrequest(url, orig_req, log):
            subreq = orig_req.copy_get()
            subreq.environ[
                'deliverance.subrequest_original_environ'] = orig_req.environ
            new_path_info = url[len(orig_req.application_url):]
            query_string = ''
            if '?' in new_path_info:
                new_path_info, query_string = new_path_info.split('?', 1)
            new_path_info = urllib.parse.unquote(new_path_info)
            assert new_path_info.startswith('/')
            subreq.path_info = new_path_info
            subreq.query_string = query_string
            subresp = subreq.get_response(self.app)
            ## FIXME: error if not HTML?
            ## FIXME: handle redirects?
            ## FIXME: handle non-200?
            log.debug(self, 'Internal request for %s: %s content-type: %s',
                      url, subresp.status, subresp.content_type)

            if not retry_inner_if_not_200:
                return subresp

            if subresp.status_int == 200 or subresp.status.startswith("3"):
                return subresp
            elif 'x-deliverance-theme-subrequest' in orig_req.headers:
                log.debug(
                    self, 'Internal request for %s was not 200 OK; '
                    'returning it anyway.' % url)
                return subresp
            else:
                log.debug(
                    self,
                    'Internal request for %s was not 200 OK; retrying as external request.'
                    % url)

        ## FIXME: pluggable subrequest handler?
        subreq = self.build_external_subrequest(url, orig_req, log)
        subresp = subreq.get_response(proxy_exact_request)
        log.debug(self, 'External request for %s: %s content-type: %s', url,
                  subresp.status, subresp.content_type)
        return subresp

    def build_external_subrequest(self, url, orig_req, log):
        """
        Returns a webob.Request to be used when Deliverance is getting
        a resource via an external subrequest (as opposed to a file://
        URL or an internal subrequest to the application being wrapped
        by Deliverance)

        The method returns a webob.Request object; the default
        implementation returns a blank Request with only the header
        ``x-deliverance-theme-subrequest`` set.  Subclasses can
        override this behavior, e.g. to preserve certain headers from
        the original request into subrequests.

        ``url``:
          The URL of the resource to be fetched

        ``orig_req``:
          The original request received by Deliverance

        ``log``:
          The logging object
        """
        subreq = Request.blank(url)
        subreq.headers['x-deliverance-theme-subrequest'] = "1"
        return subreq

    def link_to(self,
                req,
                url,
                source=False,
                line=None,
                selector=None,
                browse=False):
        """
        Creates a link to the given url for debugging purposes.

        ``source=True``: 
            link to the highlighted source for the file.

        ``line=#``:
            link to the specific line number

        ``selector="css/xpath"``: 
            highlight the element that matches that css/xpath selector

        ``browse=True``:
            link to a display that lets you see ids and classes in the
            document
        """
        base = req.environ['deliverance.base_url']
        base += '/.deliverance/view'
        source = int(bool(source))
        args = {'url': url}
        if source:
            args['source'] = '1'
        if line:
            args['line'] = str(line)
        if selector:
            args['selector'] = selector
        if browse:
            args['browse'] = '1'
        url = base + '?' + urllib.parse.urlencode(args)
        if selector:
            url += '#deliverance-selection'
        if line:
            url += '#code-%s' % line
        return url

    def internal_app(self, req, resource_fetcher):
        """
        Handles all internal (``/.deliverance``) requests.
        """
        segment = req.path_info_peek()
        method = 'action_%s' % segment
        method = getattr(self, method, None)
        if not display_logging(req) and not getattr(method, 'exposed', False):
            return exc.HTTPForbidden("Logging is not enabled for you")
        req.path_info_pop()
        if not method:
            return exc.HTTPNotFound('There is no %r action' % segment)
        try:
            return method(req, resource_fetcher)
        except exc.HTTPException as e:
            return e

    def action_media(self, req, resource_fetcher):
        """
        Serves up media from the ``deliverance/media`` directory.
        """
        ## FIXME: I'm not using this currently, because the Javascript
        ## didn't work.  Dunno why.
        from paste.urlparser import StaticURLParser
        app = StaticURLParser(os.path.join(os.path.dirname(__file__), 'media'))
        ## FIXME: need to pop some segments from the req?
        req.path_info_pop()
        resp = req.get_response(app)
        if resp.content_type == 'application/x-javascript':
            resp.content_type = 'application/javascript'
        return resp

    def action_view(self, req, resource_fetcher):
        """
        Views files; ``.link_to()`` creates links that go to this
        method.
        """
        url = req.GET['url']
        source = int(req.GET.get('source', '0'))
        browse = int(req.GET.get('browse', '0'))
        selector = req.GET.get('selector', '')
        subresp = resource_fetcher(url)
        if source:
            return self.view_source(req, subresp, url)
        elif browse:
            return self.view_browse(req, subresp, url)
        elif selector:
            return self.view_selection(req, subresp, url)
        else:
            return exc.HTTPBadRequest(
                "You must have a query variable source, browse, or selector")

    def action_edit_rules(self, req, resource_fetcher):
        if not edit_local_files(req.environ):
            return exc.HTTPForbidden('Editing is forbidden')
        rules = self.rule_getter(resource_fetcher, self.app, req)
        file_url = rules.source_location
        if not file_url.startswith('file:'):
            return exc.HTTPForbidden(
                'The rule location (%s) is not a local file' % file_url)
        filename = url_to_filename(file_url)
        app = Editor(filename=filename,
                     force_syntax='delivxml',
                     title='rule file %s' % os.path.basename(filename))
        return app

    def view_source(self, req, resp, url):
        """
        View the highlighted source (from `action_view`).
        """
        content_type = resp.content_type
        if content_type.startswith('application/xml'):
            lexer = XmlLexer()
        elif content_type == 'text/html':
            lexer = HtmlLexer()
        else:
            ## FIXME: what then?
            lexer = HtmlLexer()
        text = pygments_highlight(
            resp.body, lexer,
            HtmlFormatter(full=True, linenos=True, lineanchors='code'))
        return Response(text)

    def view_browse(self, req, resp, url):
        """
        View the id/class browser (from `action_view`)
        """
        import re
        body = resp.body
        f = open(os.path.join(os.path.dirname(__file__), 'media',
                              'browser.js'))
        content = f.read()
        f.close()
        extra_head = '''
        <!-- Added by Deliverance for browsing: -->
        <script src="http://www.google.com/jsapi"></script>
        <script>
        %s
        </script>
        <style type="text/css">
          .deliverance-highlight {
            border: 5px dotted #f00;
          }
        </style>
        <base href="%s">
        <!-- Begin original page -->
        ''' % (content, posixpath.dirname(req.GET['url']) + '/')
        match = re.search(r'<head>', body, re.I)
        if match:
            body = body[:match.end()] + extra_head + body[match.end():]
        else:
            body = extra_head + body
        extra_body = '''
        <div style="display: block; color: #000; background-color: #dfd; font-family: sans-serif; font-size: 100%; border-bottom: 2px dotted #f00" id="deliverance-browser">
        <span style="float: right"><button onclick="window.close()">close</button></span>
        View by id/class: <select onchange="deliveranceChangeId()" name="deliverance-ids" id="deliverance-ids"></select>
        </div>'''
        match = re.search('<body.*?>', body, re.I)
        if match:
            body = body[:match.end()] + extra_body + body[match.end():]
        else:
            body = extra_body + body
        return Response(body)

    def view_selection(self, req, resp, url):
        """
        View the highlighted selector (from `action_view`)
        """
        from deliverance.selector import Selector
        doc = document_fromstring(resp.body)
        el = Element('base')
        el.set('href', posixpath.dirname(url) + '/')
        doc.head.insert(0, el)
        selector = Selector.parse(req.GET['selector'])
        dummy_type, elements, dummy_attributes = selector(doc)
        if not elements:
            template = self._not_found_template
        else:
            template = self._found_template
        all_elements = []
        els_in_head = False
        for index, el in enumerate(elements):
            el_in_head = self._el_in_head(el)
            if el_in_head:
                els_in_head = True
            anchor = 'deliverance-selection'
            if index:
                anchor += '-%s' % index
            if el.get('id'):
                anchor = el.get('id')
            ## FIXME: is a <a name> better?
            if not el_in_head:
                el.set('id', anchor)
            else:
                anchor = None
            ## FIXME: add :target CSS rule
            ## FIXME: or better, some Javascript
            all_elements.append((anchor, el))
            if not el_in_head:
                style = el.get('style', '')
                if style:
                    style += '; '
                style += '/* deliverance */ border: 2px dotted #f00'
                el.set('style', style)
            else:
                el.set('DELIVERANCE-MATCH', '1')

        def highlight(html_code):
            """Highlights the given code (for use in the template)"""
            if isinstance(html_code, _Element):
                html_code = tostring(html_code)
            return html(
                pygments_highlight(html_code, HtmlLexer(),
                                   HtmlFormatter(noclasses=True)))

        def format_tag(tag):
            """Highlights the lxml HTML tag"""
            return highlight(tostring(tag).split('>')[0] + '>')

        def wrap_html(html, width=100):
            if isinstance(html, _Element):
                html = tostring(html)
            lines = html.splitlines()
            new_lines = []

            def wrap_html_line(line):
                if len(line) <= width:
                    return [line]
                match_trail = re.search(r'^[^<]*</.*?>', line, re.S)
                if match_trail:
                    result = [match_trail.group(0)]
                    result.extend(wrap_html_line(line[match_trail.end():]))
                    return result
                match1 = re.search(r'^[^<]*<[^>]*>', line, re.S)
                match2 = re.search(r'<[^>]*>[^<>]*$', line, re.S)
                if not match1 or not match2:
                    return [line]
                result = [match1.group(0)]
                result.extend(wrap_html_line(
                    line[match1.end():match2.start()]))
                result.append(match2.group(0))
                return result

            for line in lines:
                new_lines.extend(wrap_html_line(line))
            return '\n'.join(new_lines)

        def mark_deliv_match(highlighted_text):
            result = re.sub(
                r'(?:<[^/][^>]*>)*&lt;.*?DELIVERANCE-MATCH=.*?&gt;(?:</[^>]*>)*',
                lambda match: r'<b style="background-color: #ff8">%s</b>' %
                match.group(0), str(highlighted_text), re.S)
            return html(result)

        text = template.substitute(base_url=url,
                                   els_in_head=els_in_head,
                                   doc=doc,
                                   elements=all_elements,
                                   selector=selector,
                                   format_tag=format_tag,
                                   highlight=highlight,
                                   wrap_html=wrap_html,
                                   mark_deliv_match=mark_deliv_match)
        message = fromstring(
            self._message_template.substitute(message=text, url=url))
        if doc.body.text:
            message.tail = doc.body.text
            doc.body.text = ''
        doc.body.insert(0, message)
        text = tostring(doc)
        return Response(text)

    def _el_in_head(self, el):
        """True if the given element is in the HTML ``<head>``"""
        while el is not None:
            if el.tag == 'head':
                return True
            el = el.getparent()
        return False

    _not_found_template = HTMLTemplate(
        '''\
    There were no elements that matched the selector <code>{{selector}}</code>
    ''', 'deliverance.middleware.DeliveranceMiddleware._not_found_template')

    _found_template = HTMLTemplate(
        '''\
    {{if len(elements) == 1}}
      One element matched the selector <code>{{selector}}</code>;
      {{if elements[0][0]}}
        <a href="{{base_url}}#{{elements[0][0]}}">jump to element</a>
      {{else}}
        element is in head: {{highlight(elements[0][1])}}
      {{endif}}
    {{else}}
      {{len(elements)}} elements matched the selector <code>{{selector}}</code>:
      <ol>
      {{for anchor, el in elements}}
        {{if anchor}}
          <li><a href="{{base_url}}#{{anchor}}"><code>{{format_tag(el)}}</code></a></li>
        {{else}}
          <li>{{format_tag(el)}}</li>
        {{endif}}
      {{endfor}}
      </ol>
    {{endif}}
    {{if els_in_head}}
      <div style="border-top: 2px solid #000">
        <b>Elements matched in head.  Showing head:</b><br>
        <div style="margin: 1em; padding: 0.25em; background-color: #fff">
        {{mark_deliv_match(highlight(wrap_html(doc.head)))}}
        </div>
      </div>
    {{endif}}
    ''', 'deliverance.middleware.DeliveranceMiddleware._found_template')

    _message_template = HTMLTemplate(
        '''\
    <div style="color: #000; background-color: #f90; border-bottom: 2px dotted #f00; padding: 1em">
    <span style="float: right; font-size: 65%"><button onclick="window.close()">close</button></span>
    Viewing <code><a style="text-decoration: none" href="{{url}}">{{url}}</a></code><br>
    {{message|html}}
    </div>''',
        'deliverance.middleware.DeliveranceMiddleware._message_template')

    def action_subreq(self, req, resource_fetcher):
        log = req.environ['deliverance.log']
        from deliverance.log import PrintingLogger
        log = PrintingLogger(log.request, log.middleware)
        req.environ['deliverance.log'] = log
        url = req.GET['url']
        subreq = req.copy_get()
        base = req.environ['deliverance.base_url']
        assert url.startswith(
            base), 'Expected url %r to start with %r' % (url, base)
        rest = '/' + url[len(base):].lstrip('/')
        if '?' in rest:
            rest, qs = rest.split('?', 1)
        else:
            qs = ''
        subreq.script_name = urllib.parse.urlsplit(base)[2]
        subreq.path_info = rest
        subreq.query_string = qs
        resp = subreq.get_response(self.app)
        if resp.status_int == 304:
            return resp
        if resp.status_int != 200:
            assert 0, 'Failed response to request %s: %s' % (subreq.url,
                                                             resp.status)
        assert resp.content_type == 'text/html', (
            'Unexpected content-type: %s (for url %s)' %
            (resp.content_type, subreq.url))
        doc = fromstring(resp.body)
        if req.GET.get('action'):
            action = clientside_action(req.GET['action'],
                                       content_selector=req.GET['content'],
                                       theme_selector=req.GET['theme'])
            actions = action.clientside_actions(doc, log)
        else:
            rule_set = self.rule_getter(resource_fetcher, self.app, req)
            actions = rule_set.clientside_actions(subreq, resp, log)
        resp.body = simplejson.dumps(actions)
        resp.content_type = 'application/json'
        return resp

    action_subreq.exposed = True