jp (output): template output first draft:
template output use the new template renderer and data_objects module in backend tools.
Options can be specified: template to give a direct path to template, browser to display result directly, inline-css to include css in the HTML page.
Default template can be specified in command's TEMPLATE attribute, and a template_data_mapping method is called if it exists to map data to what is expected by the template.
This commit is contained in:
parent
c4c57e7d42
commit
8579722d09
2 changed files with 118 additions and 7 deletions
|
|
@ -22,13 +22,13 @@ from sat_frontends.quick_frontend import constants
|
|||
|
||||
class Const(constants.Const):
|
||||
|
||||
APP_NAME = "jp"
|
||||
PLUGIN_CMD = "commands"
|
||||
PLUGIN_OUTPUT = "outputs"
|
||||
OUTPUT_TEXT = 'text' # blob of unicode text
|
||||
OUTPUT_DICT = 'dict' # simple key/value dictionary
|
||||
OUTPUT_LIST = 'list'
|
||||
OUTPUT_COMPLEX = 'complex' # complex data (e.g. multi-level dictionary)
|
||||
APP_NAME = u"jp"
|
||||
PLUGIN_CMD = u"commands"
|
||||
PLUGIN_OUTPUT = u"outputs"
|
||||
OUTPUT_TEXT = u'text' # blob of unicode text
|
||||
OUTPUT_DICT = u'dict' # simple key/value dictionary
|
||||
OUTPUT_LIST = u'list'
|
||||
OUTPUT_COMPLEX = u'complex' # complex data (e.g. multi-level dictionary)
|
||||
OUTPUT_TYPES = (OUTPUT_TEXT, OUTPUT_DICT, OUTPUT_LIST, OUTPUT_COMPLEX)
|
||||
|
||||
# exit codes
|
||||
|
|
|
|||
111
frontends/src/jp/output_template.py
Normal file
111
frontends/src/jp/output_template.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#! /usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# jp: a SàT command line tool
|
||||
# Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org)
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Standard outputs"""
|
||||
|
||||
|
||||
from sat_frontends.jp.constants import Const as C
|
||||
from sat.core.i18n import _
|
||||
from sat.tools.common import template
|
||||
import webbrowser
|
||||
import tempfile
|
||||
import os.path
|
||||
|
||||
__outputs__ = ["Template"]
|
||||
TEMPLATE = u'template'
|
||||
OPTIONS = {u'template', u'browser', u'inline-css'}
|
||||
|
||||
|
||||
class Template(object):
|
||||
"""outputs data using SàT templates"""
|
||||
|
||||
def __init__(self, jp):
|
||||
self.host = jp
|
||||
jp.register_output(C.OUTPUT_COMPLEX, TEMPLATE, self.render)
|
||||
self.renderer = template.Renderer(jp)
|
||||
|
||||
def parse_options(self, options):
|
||||
options_dict = {}
|
||||
for option in options:
|
||||
try:
|
||||
key, value = option.split(u'=', 1)
|
||||
except ValueError:
|
||||
key, value = option, None
|
||||
options_dict[key.strip()] = value.strip() if value is not None else None
|
||||
return options_dict
|
||||
|
||||
def render(self, data):
|
||||
"""render output data using requested template
|
||||
|
||||
template to render the data can be either command's TEMPLATE or
|
||||
template output_option requested by user.
|
||||
@param data(dict): data is a dict which map from variable name to use in template
|
||||
to the variable itself.
|
||||
command's template_data_mapping attribute will be used if it exists to convert
|
||||
data to a dict usable by the template.
|
||||
"""
|
||||
cmd = self.host.command
|
||||
options = self.parse_options(cmd.args.output_opts)
|
||||
if not OPTIONS.issuperset(options):
|
||||
self.host.disp(u"The following output options are invalid: {invalid_options}".format(
|
||||
invalid_options = u', '.join(set(options).difference(OPTIONS))),
|
||||
error=True)
|
||||
self.host.quit(C.EXIT_BAD_ARG)
|
||||
try:
|
||||
template_path = cmd.TEMPLATE
|
||||
except AttributeError:
|
||||
if not 'template' in cmd.args.output_opts:
|
||||
self.host.disp(u'no default template set for this command, '
|
||||
u'you need to specify a template using --oo template=[path/to/template.html',
|
||||
error=True)
|
||||
self.host.quit(C.EXIT_BAD_ARG)
|
||||
try:
|
||||
template_path = options['template']
|
||||
except KeyError:
|
||||
# template is not specified, we use default one
|
||||
pass
|
||||
if template_path is None:
|
||||
self.host.disp(u"Can't parse template, please check its syntax",
|
||||
error=True)
|
||||
self.host.quit(C.EXIT_BAD_ARG)
|
||||
|
||||
try:
|
||||
mapping_cb = cmd.template_data_mapping
|
||||
except AttributeError:
|
||||
kwargs = data
|
||||
else:
|
||||
kwargs = mapping_cb(data)
|
||||
|
||||
css_inline = u'inline-css' in options
|
||||
rendered = self.renderer.render(template_path, css_inline=css_inline, **kwargs)
|
||||
|
||||
if 'browser' in options:
|
||||
template_name = os.path.basename(template_path)
|
||||
tmp_dir = tempfile.mkdtemp()
|
||||
self.host.disp(_(u"Browser opening requested.\nTemporary files are put in the following directory, "
|
||||
u"you'll have to delete it yourself once finished viewing: {}").format(tmp_dir))
|
||||
tmp_file = os.path.join(tmp_dir, template_name)
|
||||
with open(tmp_file, 'w') as f:
|
||||
f.write(rendered.encode('utf-8'))
|
||||
static_dir = self.renderer.getStaticDir(template_path)
|
||||
if os.path.exists(static_dir):
|
||||
import shutil
|
||||
shutil.copytree(static_dir, os.path.join(tmp_dir, u'static'))
|
||||
webbrowser.open(tmp_file)
|
||||
else:
|
||||
self.host.disp(rendered)
|
||||
Loading…
Reference in a new issue