Skip to content

Instantly share code, notes, and snippets.

@meyer
Last active August 8, 2016 02:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save meyer/4679035 to your computer and use it in GitHub Desktop.
Save meyer/4679035 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import mimetypes, sys
import datetime
from os import curdir, sep
from os.path import splitext
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import codecs
try:
from jinja2 import Template, Environment, FileSystemLoader, nodes
from jinja2.ext import Extension
except ImportError:
print "Jinja template engine is not installed. Fix this with `pip install jinja2`"
exit(1)
DEBUG = True
TEMPLATE_DEBUG = True
jinja_env = Environment(extensions=[])
def do_indent_tabs(s, width=1, indentfirst=False, usetabs=False):
"""
Yoinked from Jinja2 source. thx babes.
"""
tab = u'\t'
if usetabs == False:
tab = ' '
indention = tab * width
rv = (u'\n' + indention).join(s.splitlines())
if indentfirst:
rv = indention + rv
return rv
jinja_globals = {}
jinja_env.loader = FileSystemLoader('.')
jinja_env.filters['indent'] = do_indent_tabs
server_port = 8080
# Could come in handy.
jinja_globals["current_year"] = datetime.datetime.now().year
jinja_globals["current_datestamp"] = datetime.datetime.now()
jinja_env.globals.update(jinja_globals)
class JinjaHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
path = self.path
if path.endswith('/'):
path += 'index.html'
path = _path = path.strip('/')
_path = list(path.rpartition('/')) # I LOVE YOU RPARTITION
save_as_file = False
if (_path[2].endswith('.html') or _path[2].endswith('.xml')) and not _path[2].startswith('_'):
_path[2] = '_' + _path[2]
save_as_file = True
_path = ''.join(_path)
# Open the _source file
source_file = codecs.open(curdir + sep + _path, "r")
self.send_response(200)
self.send_header('Content-type', mimetypes.guess_type(path)[0])
self.end_headers()
jinja_env.globals.update({"path":path})
if( save_as_file ):
template = jinja_env.from_string(source_file.read().decode('utf8')).render().encode('utf-8')
# Non-ASCII decoration. FIGHT ME.
# template += ("\n\n"
# "<!-- ┌──────────────────────────────────────────────────────┐ -->\n"
# "<!-- │ Rendered with serve.py on %s │ -->\n"
# "<!-- └──────────────────────────────────────────────────────┘ -->\n") % datetime.datetime.now()
self.wfile.write( template )
destination_file = open( curdir + sep + path, 'w' )
destination_file.write(template)
destination_file.close()
else:
self.wfile.write(source_file.read())
source_file.close()
return
except IOError, e:
import traceback, os.path
top = traceback.extract_stack()[-1]
self.wfile.write(
"<code>Error: %s<br>Details: %s</code>" %
(
type(e).__name__,
# os.path.basename(top[0]),
# str(top[1]),
e
)
)
return
# self.send_error(404,'File Not Found: %s' % self.path)
if __name__ == '__main__':
if (len(sys.argv) > 1):
try:
sys.argv[1] = int( sys.argv[1] )
server_port = sys.argv[1]
except:
print "Invalid port number:", sys.argv[1]
exit(1)
try:
httpd = HTTPServer(('',server_port), JinjaHandler)
print 'Server started on port %d, press Ctrl-C to stop' % server_port
httpd.serve_forever()
except KeyboardInterrupt:
print "\nShutting down..."
httpd.socket.close()
@meyer
Copy link
Author

meyer commented Jan 31, 2013

WAT

Serve your current directory using the built-in Python server! Use Jinja tags in your flat HTML files for greater justice! serve.py compiles underscore-prefixed HTML/XML files into flat HTML/XML files in the same directory.

Close your eyes and imagine this with me (have someone read this to you so you can keep your eyes closed).

Your current directory has a file called _home.html. Run serve.py in this directory. Visit http://localhost:8080/home.html. home.html is crunched down and saved to that directory. Jinja tags are crunched down to regular ol’ HTML.

BONUSES

  • Making a Pinterest clone? Need to repeat the same chunk of code 60 times? Wrap one instance in a for tag! Something like {% for number in range(0,60) %}.
  • Current page URL stuff? Easy (kind of). class="{% if path == "index.html" %}current{% endif %} homepage"

BUT HOW

Open Terminal!

run easy_install pip!

run pip install jinja2!

Drop serve.py into a folder on your path, mark as executable, and run it in whatever directory you want to serve at localhost:8080! Optionally, you can specify a port number if you want to use something besides 8080.

AND FINALLY

Think it’s useful? Tell me! Think it isn’t useful? Tell me! http://twitter.com/meyer

PYTHON PURISTS: Don’t crucify me! I know it requires installing jinja2 into your global site-packages folder. My Python skills are… eeeeh. Make it better!

DESIGNERS: This might be overkill for you. If you’re the more gooey type, try the Most Excellent Hammer for Mac. It’s worth your Hard Earned Cash. http://hammerformac.com

@agusmakmun
Copy link

agusmakmun commented Apr 22, 2016

Thanks so much for this tutorial 👍 , btw can you give me a simply how to add the context?
Example:

template = jinja_env.from_string(source_file.read().decode('utf8')).render().encode('utf-8')
self.wfile.write( template, {'awesome': 'This value of awesome'} ) #it will be an error because `template` is string, how to add it?

and then in the template:

{% if awesome %}
    {{ awesome }}
{% endif %}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment