From 86dd4d014b1296a0b4399723d88845f4ff5f0070 Mon Sep 17 00:00:00 2001 From: Oliverpool Date: Fri, 18 Dec 2015 08:48:38 +0100 Subject: [PATCH] Use yaml in tex templates --- patacrep/build.py | 5 +-- patacrep/data/templates/default.tex | 37 ++++++++--------- patacrep/data/templates/songs.tex | 47 ---------------------- patacrep/templates.py | 62 +++++++++++++---------------- patacrep/utils.py | 14 +++++-- 5 files changed, 58 insertions(+), 107 deletions(-) diff --git a/patacrep/build.py b/patacrep/build.py index 71d8742f..ce08e767 100644 --- a/patacrep/build.py +++ b/patacrep/build.py @@ -81,9 +81,8 @@ class Songbook(object): config['book']['lang'], config['book']['encoding'], ) - # todo: better management of template variables - #config.update(renderer.get_variables()) - #config.update(self.config) + + self.config['template'] = renderer.get_all_variables(self.config.get('template', {})) config['_compiled_authwords'] = authors.compile_authwords( copy.deepcopy(config['authors']) diff --git a/patacrep/data/templates/default.tex b/patacrep/data/templates/default.tex index a6febbee..f85cbb22 100644 --- a/patacrep/data/templates/default.tex +++ b/patacrep/data/templates/default.tex @@ -19,26 +19,23 @@ %!- https://github.com/patacrep/ (* variables *) -{ -"classoptions": {"description": {"en": "LaTeX class options", "fr": "Options de la classe LaTeX"}, - "type": "flag", - "join": ",", - "mandatory": true, - "default": {"default":[]} - }, -"title": {"description": {"en": "Title", "fr": "Titre"}, - "default": {"en": "Guitar songbook", "fr": "Recueil de chansons pour guitare"}, - "mandatory":true - }, -"author": {"description": {"en": "Author", "fr": "Auteur"}, - "default": {"en": "The Patacrep Team", "fr": "L'équipe Patacrep"}, - "mandatory":true - }, -"notenamesout": {"description": {"en": "Note names. Can be 'solfedge' (Do, Re, Mi...) or 'alphascale' (A, B, C...).", - "fr": "Nom des notes : 'solfedge' (Do, Ré, Mi...) ou 'alphascale' (A, B, C...)."}, - "default": {"default": "alphascale", "fr": "solfedge"} - } -} +schema: + type: //rec + required: + title: + _description: _("Title") + type: //str + author: + _description: _("Author") + type: //str + optional: + classoptions: + _description: _("LaTeX class options") + type: //arr + contents: //str +default: + title: "Guitar songook" + author: "The Patacrep Team" (* endvariables -*) (*- extends "songs.tex" -*) diff --git a/patacrep/data/templates/songs.tex b/patacrep/data/templates/songs.tex index b2f71e6a..94846f0d 100644 --- a/patacrep/data/templates/songs.tex +++ b/patacrep/data/templates/songs.tex @@ -18,53 +18,6 @@ %!- The latest version of this program can be obtained from %!- https://github.com/patacrep/ -(* variables *) -{ -"instruments": {"description": {"en": "Instruments", "fr": "Instruments"}, - "type": "flag", - "values": {"guitar": {"en": "Guitare", "fr": "Guitare"}, - "ukulele": {"en": "Ukulele", "fr": "Ukulele"} - }, - "join": ",", - "mandatory": true, - "default": {"default":["guitar"]} - }, -"bookoptions": {"description": {"en": "Options", "fr": "Options"}, - "type": "flag", - "values": {"diagram": {"en": "Chords diagrams", "fr": "Diagrammes d'accords"}, - "importantdiagramonly": {"en": "Only importants diagrames", "fr": "Diagrammes importants uniquement"}, - "lilypond": {"en": "Lilypond music sheets", "fr": "Partitions lilypond"}, - "pictures": {"en": "Cover pictures", "fr": "Couvertures d'albums"}, - "tabs": {"en": "Tablatures", "fr": "Tablatures"}, - "repeatchords": {"en": "Repeat chords", "fr": "Répéter les accords"}, - "onesongperpage": {"en": "One song per page", "fr": "Une chanson par page"} - }, - "join": ",", - "mandatory": true, - "default": {"default":["diagram","pictures"]} - }, -"booktype": {"description": {"en": "Type", "fr": "Type"}, - "type": "enum", - "values": {"chorded": {"en": "With guitar chords", "fr": "Avec accords de guitare" }, - "lyric": {"en": "Lyrics only", "fr": "Paroles uniquement"} - }, - "default": {"default":"chorded"}, - "mandatory": true - }, -"lang": {"description": {"en": "Language", "fr": "Langue"}, - "default": {"en": "en", "fr": "fr"} - }, -"titleprefixwords": {"description": {"en": "Ignore some words in the beginning of song titles", - "fr": "Ignore des mots dans le classement des chansons"}, - "default": {"default": []} - }, -"authwords": {"description": {"en": "Set of options to process author string (LaTeX commands authsepword, authignoreword, authbyword)", - "fr": "Options pour traiter les noms d'auteurs (commandes LaTeX authsepword, authignoreword, authbyword)"}, - "default": {"default": {}} - } -} -(* endvariables -*) - (*- extends "layout.tex" -*) (* block songbookpackages *) diff --git a/patacrep/templates.py b/patacrep/templates.py index fc24c91a..ebca05f9 100644 --- a/patacrep/templates.py +++ b/patacrep/templates.py @@ -1,14 +1,15 @@ """Template for .tex generation settings and utilities""" import re -import json + +import yaml from jinja2 import Environment, FileSystemLoader, ChoiceLoader, \ TemplateNotFound, nodes from jinja2.ext import Extension from jinja2.meta import find_referenced_templates as find_templates -from patacrep import errors, files +from patacrep import errors, files, utils, Rx from patacrep.latex import lang2babel import patacrep.encoding @@ -131,37 +132,28 @@ class TexBookRenderer(Renderer): ), ) - def get_variables(self): - '''Get and return a dictionary with the default values - for all the variables + def get_all_variables(self, user_config): + ''' + Validate template variables (and set defaults when needed) ''' data = self.get_template_variables(self.template) variables = dict() for name, param in data.items(): - variables[name] = self._get_default(param) + template_config = user_config.get(name, {}) + variables[name] = self._get_variables(param, template_config) return variables - def _get_default(self, parameter): + def _get_variables(self, parameter, user_config): '''Get the default value for the parameter, according to the language. ''' - default = None - try: - default = parameter['default'] - except KeyError: - return None - - if self.lang in default: - variable = default[self.lang] - elif "default" in default: - variable = default["default"] - elif "en" in default: - variable = default["en"] - elif len(default): - variable = default.popitem()[1] - else: - variable = None - - return variable + schema = parameter.get('schema', {}).copy() + schema = utils.remove_keys(schema, ['_description']) + + data = utils.DictOfDict(parameter.get('default', {})) + data.update(user_config) + + utils.validate_yaml_schema(data, schema) + return data def get_template_variables(self, template, skip=None): """Parse the template to extract the variables as a dictionary. @@ -177,16 +169,18 @@ class TexBookRenderer(Renderer): skip = [] variables = {} (current, templates) = self.parse_template(template) + if current: + variables[template.name] = current + for subtemplate in templates: if subtemplate in skip: continue - variables.update( - self.get_template_variables( + subtemplate = self.jinjaenv.get_template(subtemplate) + variables.update(self.get_template_variables( subtemplate, skip + templates ) - ) - variables.update(current) + ) return variables def parse_template(self, template): @@ -213,17 +207,17 @@ class TexBookRenderer(Renderer): if match: for var in match: try: - subvariables.update(json.loads(var)) + subvariables.update(yaml.load(var)) except ValueError as exception: raise errors.TemplateError( exception, ( - "Error while parsing json in file " - "{filename}. The json string was:" - "\n'''\n{jsonstring}\n'''" + "Error while parsing yaml in file " + "{filename}. The yaml string was:" + "\n'''\n{yamlstring}\n'''" ).format( filename=templatename, - jsonstring=var, + yamlstring=var, ) ) diff --git a/patacrep/utils.py b/patacrep/utils.py index e4b607b4..bcdb04e0 100644 --- a/patacrep/utils.py +++ b/patacrep/utils.py @@ -99,7 +99,6 @@ def remove_keys(data, keys=None, recursive=True): def validate_config_schema(config): """ Check that the songbook config respects the excepted songbook schema - """ data = config.copy() @@ -108,11 +107,20 @@ def validate_config_schema(config): with encoding.open_read(schema_path) as schema_file: schema_struct = yaml.load(schema_file) schema_struct = remove_keys(schema_struct, ['_description']) - schema = rx_checker.make_schema(schema_struct) + validate_yaml_schema(data, schema_struct) + +def validate_yaml_schema(data, schema): + """ + Check that the data respects the schema + """ + rx_checker = Rx.Factory({"register_core_types": True}) + schema = rx_checker.make_schema(schema) + + if not isinstance(data, dict): + data = dict(data) try: schema.validate(data) except Rx.SchemaMismatch as exception: msg = 'Could not parse songbook file:\n' + str(exception) raise errors.SBFileError(msg) - return True