GithubHelp home page GithubHelp logo

jcmcken / bp Goto Github PK

View Code? Open in Web Editor NEW
2.0 2.0 0.0 36 KB

bp (blueprint) is a CLI for populating Jinja2 templates from JSON config files

License: Other

Python 99.36% Makefile 0.64%

bp's Introduction

BP (Blueprints)

Intro

BP is a simple CLI and library for populating Jinja2 templates using JSON or YAML config files for context. BP also accepts context settings passed from the command line.

Tour

Basic usage:

bp <template_file> [options]

For example, suppose you have the following template called index.html:

<html>
 <head>
   <title>StartUp - {{ section|default('Home') }}</title>
 </head>
 <body>Welcome!</body>
</html>

This template can (optionally) take a context variable called section. If section is not supplied, it defaults to Home.

A demonstration:

[jcmcken@localhost ~]$ bp index.html
<html>
<head>
    <title>StartUp - Home</title>
</head>
<body>Welcome!</body>
</html>

Passing in a custom section from the command line:

[jcmcken@localhost ~]$ bp index.html -e section=Contact
<html>
<head>
    <title>StartUp - Contact</title>
</head>
<body>Welcome!</body>
</html>

Passing in the context from a JSON file:

[jcmcken@localhost ~]$ cat page.json
{
  "section": "Contact"
}
[jcmcken@localhost ~]$ bp index.html -c page.json
<html>
<head>
    <title>StartUp - Contact</title>
</head>
<body>Welcome!</body>
</html>

Passing in the context from the contents of a separate file:

[jcmcken@localhost ~]$ cat contact_section.txt
Contact
[jcmcken@localhost ~]$ bp index.html -f section=contact_section.txt
<html>
<head>
    <title>StartUp - Contact</title>
</head>
<body>Welcome!</body>
</html>

Obviously these examples are pretty contrived, but you can see how each of them might be useful. If you have "pivot" data that is very simple, but changes depending on some condition, you could use the -e/--expr option or pass in the appropriate JSON or YAML config file. On the other hand, if you have dense content (paragraphs of text, for example), you might prefer to keep that content in separate text files and just read out of those files.

Advanced Usage

While not really "advanced" per se, there's an additional feature of the -c/--context option which provides an even finer level control over contexts.

You can pass an expression of the form <key>=<filename> to -c, where <key> is the name of a variable to inject into the template context and <filename> is a serialized data structure (JSON or YAML) just like before.

Using this syntax, the template context will contain a variable <key> set equal to the data structure loaded from <filename>.

This has two useful benefits:

  • Context files that are not hashes can be named and turned into hashes. For example, if you have a JSON file with a list of data items, you can assign a name to that list using -c without having to rewrite the JSON file as a hash map.

  • You can use it to deconflict data structures with common keys. For example, if you have data about employees, salaries.json and ranks.json, but the data in each file is keyed off of employees names, e.g. { "Bob": 65000 } and { "Bob": "Engineer" } (respectively), then you can simply pass -c salaries=salaries.json and -c ranks=ranks.json to create the following merged context:

    {
      "salaries": {
        "Bob": 65000
      },
      "ranks": {
        "Bob": "Engineer"
      }
    }
    

    This means that you can (if need be) decouple your data into separate files rather than keeping very large, aggregated files.

More on Contexts

Note that the root-level data structure in the JSON file is always a hash (also called a dictionary, if you're a Python person). This is a hard requirement of the underlying templating engine. You're passing a namespace to the template -- in other words, data items are retrieved by their names. The internal structure of the hash can be arbitrarily complex, just so long as your template is expecting that structure.

If you prefer something a bit easier to read, you can use YAML files rather than JSON. To do this, just pass the -y/--yaml option flag along with the other arguments. (Remember, YAML is a superset of JSON, so passing -y will let you use either JSON or YAML).

Passing in the context from a YAML file:

[jcmcken@localhost ~]$ cat page.yaml
---
section: Contact
[jcmcken@localhost ~]$ bp index.html -c page.yaml --yaml
<html>
<head>
    <title>StartUp - Contact</title>
</head>
<body>Welcome!</body>
</html>

Since bp utilizes the Jinja2 templating engine, you can also use template inheritance. To make this easier bp provides an option for adding directories to the templating environment.

For example, suppose you have a template called customized.template which inherits from templates spread across multiple directories. Just include all the directories using the -d option flag:

[jcmcken@localhost ~]$ bp customized.template -d templates/base/ -d templates/add-ons/

Without using the -d option, you'll likely get a TemplateNotFound exception for referencing a template that's not in your templating environment.

Built-In Context

For convenience, bp also includes some built-in context variables. These will automatically be injected into any templates bp renders.

  • bp_datetime: The datetime object created with datetime.datetime.now(). (You can either call {{ bp_datetime }} directly to print the full timestamp, or access the datetime attributes, e.g. {{ bp_datetime.year }}).

    Note: When using the -p/--print-context option, bp_datetime will be printed as an ISO formatted timestamp (since datetime.datetime objects are not JSON-serializable)

  • bp_euser: The current effective user.

  • bp_fqdn: The fully-qualified domain name of the current host

  • bp_hostname: The short hostname of the current host

  • bp_user: The current login user.

Glueing your Blueprints Together

Shell Scripts

The simplest way to glue together your templates is to write a shell script. For example:

#!/bin/bash

DEPLOY="/var/www/html"

bp index.html -f intro=content/index/intro.txt >> $DEPLOY/index.html
bp contact.html -c contacts.json >> $DEPLOY/contacts.html
bp about.html -f founder_txt=content/about/founder.txt \
              -f employees=content/about/employees.txt >> $DEPLOY/about.html

Using the API

bp now has a very simple API you can use to generate templates programmatically in Python. This comes in the form of the bp.Blueprint class. Like the CLI, you pass in a template file and (optionally) a set of directories to add to the template environment. Unlike the CLI, the Blueprint class just takes a dictionary for its context (there's no expression or file parsing currently).

Here's a simple example:

from bp import Blueprint

bp = Blueprint(
    template_file='template.html',
    template_dirs = ['extra_templates/'],
    context={"foo":"bar"},
)

print bp.render()

bp's People

Contributors

jcmcken avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

bp's Issues

Add in-template exception capability

Add a function to the set of built-in context variables (say bp_raise) that fatally stops template rendering if encountered. Hook it up to the bp CLI utility to make the output look nice.

Add CLI option to prompt for missing information

A simple implementation would only support string values (i.e. wouldnt support pulling context from JSON or ENV). This can be used to inject sensitive data like passwords.

E.g.

Given some-template-file:

password: {{ whatever }}
$ bp --prompt some-template-file > some-config
Please specify `whatever':  some-value
$ cat some-config
password: some-value

bp CLI tool can't correctly handle Unicode characters

E.g.

Traceback (most recent call last):
  File "/bin/bp", line 6, in <module>
    main()
  File "/usr/lib/python2.7/site-packages/bp/cli.py", line 149, in main
    sys.stdout.write(rendered + '\n')
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2013' in position 4509: ordinal not in range(128)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.