Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Adding a CLI for Jinja2 #129

Closed
wants to merge 2 commits into from

3 participants

@mattrobenolt

Allows compiling templates via the command line by taking data input
from either json, yaml, ini, or a querystring source.

Data can be read in from a file or piped in through stdin.

See __doc__ for examples on usage.

I am 100% open to critiques or adjustments that need to be made to
comply with library conformity. :)

@mattrobenolt mattrobenolt Adding a CLI for Jinja2
Allows compiling templates via the command line by taking data input
from either json, yaml, ini, or a querystring source.

Data can be read in from a file or piped in through stdin.

See __doc__ for examples on usage.

I am 100% open to critiques or adjustments that need to be made to
comply with library conformity. :)
04bdf45
@mattrobenolt

Also to note, I added in quickly Python 3 support, but I haven't tested that yet.

@heat

I like it. Thank mattrobenolt, This is very useful for me.

@mitsuhiko
Owner

Closing this for the time being. This would require some iteration in a separate package first and then we can bundle it. Not sold on the exact behavior of it.

@mitsuhiko mitsuhiko closed this
@mattrobenolt

@mitsuhiko FWIW, a long time ago, I did pull this out into it's own package. :)

https://github.com/mattrobenolt/jinja2-cli

What about the behavior were you not a fan of?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 23, 2012
  1. @mattrobenolt

    Adding a CLI for Jinja2

    mattrobenolt authored
    Allows compiling templates via the command line by taking data input
    from either json, yaml, ini, or a querystring source.
    
    Data can be read in from a file or piped in through stdin.
    
    See __doc__ for examples on usage.
    
    I am 100% open to critiques or adjustments that need to be made to
    comply with library conformity. :)
  2. @mattrobenolt

    Hello. :)

    mattrobenolt authored
This page is out of date. Refresh to see the latest.
Showing with 153 additions and 4 deletions.
  1. +1 −0  AUTHORS
  2. +144 −0 jinja2/cli.py
  3. +8 −4 setup.py
View
1  AUTHORS
@@ -17,6 +17,7 @@ Contributors:
- Cameron Knight
- Lawrence Journal-World.
- David Cramer
+- Matt Robenolt
Patches and suggestions:
View
144 jinja2/cli.py
@@ -0,0 +1,144 @@
+"""
+jinja2
+======
+A CLI interface to jinja2.
+
+$ jinja2 helloworld.tmpl data.json --format=json
+$ cat data.json | jinja2 helloworld.tmpl
+$ curl -s http://httpbin.org/ip | jinja2 helloip.tmpl
+$ curl -s http://httpbin.org/ip | jinja2 helloip.tmpl > helloip.html
+"""
+
+from __future__ import absolute_import
+
+
+class InvalidDataFormat(Exception): pass
+class InvalidInputData(Exception): pass
+class MalformedJSON(InvalidInputData): pass
+class MalformedINI(InvalidInputData): pass
+class MalformedYAML(InvalidInputData): pass
+class MalformedQuerystring(InvalidInputData): pass
+
+
+# Global list of available format parsers on your system
+# mapped to the callable/Exception to parse a string into a dict
+formats = {}
+
+# json - simplejson or packaged json as a fallback
+try:
+ import simplejson
+ formats['json'] = (simplejson.loads, simplejson.decoder.JSONDecodeError, MalformedJSON)
+except ImportError:
+ try:
+ import json
+ formats['json'] = (json.loads, ValueError, MalformedJSON)
+ except ImportError:
+ pass
+
+
+# ini - Nobody likes you.
+try:
+ # Python 2
+ import ConfigParser
+except ImportError:
+ # Python 3
+ import configparser as ConfigParser
+
+def _parse_ini(data):
+ import StringIO
+ class MyConfigParser(ConfigParser.ConfigParser):
+ def as_dict(self):
+ d = dict(self._sections)
+ for k in d:
+ d[k] = dict(self._defaults, **d[k])
+ d[k].pop('__name__', None)
+ return d
+ p = MyConfigParser()
+ p.readfp(StringIO.StringIO(data))
+ return p.as_dict()
+formats['ini'] = (_parse_ini, ConfigParser.Error, MalformedINI)
+
+
+# yaml - with PyYAML
+try:
+ import yaml
+ formats['yaml'] = (yaml.load, yaml.YAMLError, MalformedYAML)
+except ImportError:
+ pass
+
+
+# querystring - querystring parsing
+def _parse_qs(data):
+ """ Extend urlparse to allow objects in dot syntax.
+
+ >>> _parse_qs('user.first_name=Matt&user.last_name=Robenolt')
+ {'user': {'first_name': 'Matt', 'last_name': 'Robenolt'}}
+ """
+ try:
+ import urlparse
+ except ImportError:
+ import urllib.parse as urlparse
+ dict_ = {}
+ for k, v in urlparse.parse_qs(data).items():
+ v = map(lambda x: x.strip(), v)
+ v = v[0] if len(v) == 1 else v
+ if '.' in k:
+ pieces = k.split('.')
+ cur = dict_
+ for idx, piece in enumerate(pieces):
+ if piece not in cur:
+ cur[piece] = {}
+ if idx == len(pieces) - 1:
+ cur[piece] = v
+ cur = cur[piece]
+ else:
+ dict_[k] = v
+ return dict_
+formats['querystring'] = (_parse_qs, Exception, MalformedQuerystring)
+
+
+import os
+import sys
+from optparse import OptionParser
+
+from jinja2 import Environment, FileSystemLoader
+
+
+def cli(opts, args):
+ if args[1] == '-':
+ data = sys.stdin.read()
+ else:
+ data = open(os.path.join(os.getcwd(), os.path.expanduser(args[1]))).read()
+
+ try:
+ data = formats[opts.format][0](data)
+ except formats[opts.format][1]:
+ raise formats[opts.format][2](u'%s ...' % data[:60])
+ sys.exit(1)
+
+ env = Environment(loader=FileSystemLoader(os.getcwd()))
+ sys.stdout.write(env.get_template(args[0]).render(data))
+ sys.exit(0)
+
+
+def main():
+ default_format = 'json'
+ if default_format not in formats:
+ default_format = sorted(formats.keys())[0]
+
+ parser = OptionParser(usage="usage: %prog [options] <input template> <input data>")
+ parser.add_option('--format', help='Format of input variables: %s' % ', '.join(formats.keys()), dest='format', action='store', default=default_format)
+ opts, args = parser.parse_args()
+
+ if len(args) == 0:
+ parser.print_help()
+ sys.exit(1)
+
+ # Without the second argv, assume they want to read from stdin
+ if len(args) == 1:
+ args.append('-')
+
+ if opts.format not in formats:
+ raise InvalidDataFormat(opts.format)
+
+ cli(opts, args)
View
12 setup.py
@@ -101,10 +101,14 @@
extras_require={'i18n': ['Babel>=0.8']},
test_suite='jinja2.testsuite.suite',
include_package_data=True,
- entry_points="""
- [babel.extractors]
- jinja2 = jinja2.ext:babel_extract[i18n]
- """,
+ entry_points={
+ 'babel.extractors': [
+ 'jinja2 = jinja2.ext:babel_extract[i18n]',
+ ],
+ 'console_scripts': [
+ 'jinja2 = jinja2.cli:main'
+ ],
+ },
features={'debugsupport': debugsupport},
**extra
)
Something went wrong with that request. Please try again.