""" Make it possible to write emails using Django templates. There are a few steps involved: 1. Parse the Django template into nodes 2. Interpret ExtendsNodes and IncludeNodes 3. Return a new Django template as a string 4. Generate an lxml tree from the resulting template 5. Replace <link rel="stylesheet"> nodes with <style> tags 6. Run toronado's CSS inliner on the resulting tree 7. Output the final Django template - Replace the implementation of all nodes other than ExtendsNodes and IncludeNodes to return themselves? - Is there an API function to do (3), or does that need to be done manually? """ import os from pathlib import PurePath import re from urllib import parse from urllib.request import urlopen import django.template.base as template_base import django.template.utils as template_utils import lxml.html from django.template.base import Lexer, Parser, Template from lxml.cssselect import CSSSelector from lxml.html.builder import STYLE import toronado remap_urls = {"/static": "/static"} def remap_url(src, remap): """ If src is in a subdirectory of any of the keys in `remap`, rewrite the path to point to a local file relative to the corresponding value. """ path = PurePath(src) for url_path, file_path in remap.items(): print(url_path, file_path) try: rel_path = path.relative_to(url_path) return PurePath(file_path).joinpath(rel_path) except ValueError: continue def resolve_link_src(src, remap=remap_urls): pieces = parse.urlsplit(src) if pieces.netloc: return urlopen(src).read() file_path = remap_url(src, remap) if file_path: with open(file_path) as src_file: return src_file.read() def parsed_to_template_string(parsed): pass def expand_includes(nodelist): pass def links_to_style(tree, rewrite_src=None): """ Replace all stylesheet links in the parsed document tree `tree` with <script> tags containing the contents of the URL. """ if not rewrite_src: rewrite_src = lambda x: x for link in CSSSelector("link[rel=stylesheet]")(tree): src = rewrite_src(link.attrib["href"]) pieces = parse.urlsplit(src) if pieces.netloc: style_body = urlopen(src).read() else: with open(src) as local_styles: style_body = local_styles.read() style = STYLE(style_body.replace("\n", "")) link.replace(style) return tree def rebuild_template(template_str): nodes = Template(template_str).compile_nodelist() expanded = expand_includes(nodes) tree = lxml.html.fromstring(nodelist_to_template(expanded)) links_to_style(tree) toronado.inline(tree) return lxml.html.tostring(tree) # body = urlopen("http://localhost:4000").read() # tree = lxml.html.fromstring(body)