Browse Source

Validate plugin argument with a decorator

pull/190/head
Oliverpool 9 years ago
parent
commit
fbdafd0162
  1. 65
      patacrep/content/__init__.py
  2. 15
      patacrep/content/cwd.py
  3. 17
      patacrep/content/include.py
  4. 23
      patacrep/content/section.py
  5. 14
      patacrep/content/song.py
  6. 9
      patacrep/content/songsection.py
  7. 31
      patacrep/content/sorted.py
  8. 17
      patacrep/content/tex.py

65
patacrep/content/__init__.py

@ -68,7 +68,7 @@ import sys
import jinja2
import yaml
from patacrep import files, utils
from patacrep import files, Rx, utils
from patacrep.errors import SBFileError, SharedError
LOGGER = logging.getLogger(__name__)
@ -223,37 +223,31 @@ def render(context, content):
return rendered
def build_plugin_schema(plugins):
"""Builds the Rx schema for the ContentItem"""
plugin_schemas = {}
for keyword, parser in plugins.items():
subschema = getattr(parser, 'rxschema', '//any')
plugin_schemas[keyword] = yaml.load(subschema)
plugin_schema = [{
'type': '//rec',
'optional': plugin_schemas,
}]
song_schema = {
'type': '//str',
}
plugin_schema.append(song_schema)
return {
'type': '//any',
'of': plugin_schema,
}
def validate_parser_argument(raw_schema):
"""Check that the parser argument respects the schema
Will raise `SBFileError` if the schema is not respected.
"""
rx_checker = Rx.Factory({"register_core_types": True})
schema = rx_checker.make_schema(yaml.load(raw_schema))
def wrap(parse):
"""Wrap the parse function"""
def wrapped(keyword, argument, config):
"""Check the argument schema before calling the plugin parser"""
try:
schema.validate(argument)
except Rx.SchemaMismatch as exception:
msg = 'Invalid `{}` syntax:\n---\n{}---\n{}'.format(
keyword,
yaml.dump({keyword: argument}, default_flow_style=False),
str(exception)
)
raise SBFileError(msg)
return parse(keyword, argument=argument, config=config)
return wrapped
return wrap
def validate_content(content, plugins):
"""Validate the content against the Rx content schema"""
plugin_schema = build_plugin_schema(plugins)
content_schema = {
'type': '//any',
'of': [
plugin_schema,
{'type': '//arr', 'contents':plugin_schema},
#{'type': '//nil'},
]
}
utils.validate_yaml_schema(content, content_schema)
def process_content(content, config=None):
"""Process content, and return a list of ContentItem() objects.
@ -269,19 +263,14 @@ def process_content(content, config=None):
contentlist = ContentList()
plugins = config.get('_content_plugins', {})
if not content:
content = [{'song': ""}]
try:
validate_content(content, plugins)
except SBFileError as error:
contentlist.append_error(ContentError("Invalid content", str(error)))
return contentlist
content = [{'song': None}]
for elem in content:
if isinstance(elem, str):
elem = {'song': [elem]}
if isinstance(elem, dict):
for keyword, argument in elem.items():
if keyword not in plugins:
contentlist.append_error(ContentError(keyword, "Unknown content type."))
contentlist.append_error(ContentError(keyword, "Unknown content keyword."))
continue
contentlist.extend(plugins[keyword](
keyword,

15
patacrep/content/cwd.py

@ -1,9 +1,15 @@
"""Change base directory before importing songs."""
from patacrep.content import process_content
from patacrep.content import process_content, validate_parser_argument
from patacrep.songs import DataSubpath
#pylint: disable=unused-argument
@validate_parser_argument("""
type: //rec
required:
path: //str
content: //any
""")
def parse(keyword, config, argument):
"""Return a list songs, whith a different base path.
@ -33,11 +39,4 @@ def parse(keyword, config, argument):
config['_songdir'] = old_songdir
return processed_content
parse.rxschema = """
type: //rec
required:
path: //str
content: //any
"""
CONTENT_PLUGINS = {'cwd': parse}

17
patacrep/content/include.py

@ -8,7 +8,7 @@ import json
import os
import logging
from patacrep.content import process_content, ContentError, ContentList
from patacrep.content import process_content, ContentError, ContentList, validate_parser_argument
from patacrep import encoding, errors, files
LOGGER = logging.getLogger(__name__)
@ -28,6 +28,13 @@ def load_from_datadirs(path, datadirs):
)
#pylint: disable=unused-argument
@validate_parser_argument("""
type: //any
of:
- type: //str
- type: //arr
contents: //str
""")
def parse(keyword, config, argument):
"""Include an external file content.
@ -69,12 +76,4 @@ def parse(keyword, config, argument):
return new_contentlist
parse.rxschema = """
type: //any
of:
- type: //str
- type: //arr
contents: //str
"""
CONTENT_PLUGINS = {'include': parse}

23
patacrep/content/section.py

@ -1,6 +1,6 @@
"""Allow LaTeX sections (starred or not) as content of a songbook."""
from patacrep.content import ContentItem, ContentList
from patacrep.content import ContentItem, ContentList, validate_parser_argument
KEYWORDS = [
"part",
@ -29,6 +29,16 @@ class Section(ContentItem):
return r'\{}[{}]{{{}}}'.format(self.keyword, self.short, self.name)
#pylint: disable=unused-argument
@validate_parser_argument("""
type: //any
of:
- type: //str
- type: //rec
required:
name: //str
optional:
short: //str
""")
def parse(keyword, argument, config):
"""Parse the section.
@ -47,17 +57,6 @@ def parse(keyword, argument, config):
argument = {'name': argument}
return ContentList([Section(keyword, **argument)])
parse.rxschema = """
type: //any
of:
- type: //str
- type: //rec
required:
name: //str
optional:
short: //str
"""
CONTENT_PLUGINS = dict([
(word, parse)
for word

14
patacrep/content/song.py

@ -7,7 +7,7 @@ import textwrap
import jinja2
from patacrep.content import process_content
from patacrep.content import process_content, validate_parser_argument
from patacrep.content import ContentError, ContentItem, ContentList
from patacrep import files, errors
@ -58,6 +58,14 @@ class SongRenderer(ContentItem):
return self.song.fullpath < other.song.fullpath
#pylint: disable=unused-argument
@validate_parser_argument("""
type: //any
of:
- type: //nil
- type: //str
- type: //arr
contents: //str
""")
def parse(keyword, argument, config):
"""Parse data associated with keyword 'song'.
@ -121,10 +129,6 @@ def parse(keyword, argument, config):
))
return sorted(songlist)
parse.rxschema = """
type: //str
"""
CONTENT_PLUGINS = {'song': parse}

9
patacrep/content/songsection.py

@ -1,6 +1,6 @@
"""Allow 'songchapter' and 'songsection' as content of a songbook."""
from patacrep.content import ContentItem, ContentList
from patacrep.content import ContentItem, ContentList, validate_parser_argument
KEYWORDS = [
"songchapter",
@ -20,6 +20,9 @@ class SongSection(ContentItem):
return r'\{}{{{}}}'.format(self.keyword, self.name)
#pylint: disable=unused-argument
@validate_parser_argument("""
//str
""")
def parse(keyword, argument, config):
"""Parse the songsection.
@ -30,10 +33,6 @@ def parse(keyword, argument, config):
"""
return ContentList([SongSection(keyword, argument)])
parse.rxschema = """
//str
"""
CONTENT_PLUGINS = dict([
(keyword, parse)
for keyword

31
patacrep/content/sorted.py

@ -9,7 +9,7 @@ import unidecode
from patacrep import files
from patacrep.content import ContentError, EmptyContentList
from patacrep.content import process_content
from patacrep.content import process_content, validate_parser_argument
from patacrep.content.song import OnlySongsError
LOGGER = logging.getLogger(__name__)
@ -67,6 +67,20 @@ def key_generator(sort):
return ordered_song_keys
#pylint: disable=unused-argument
@validate_parser_argument("""
type: //any
of:
- type: //nil
- type: //rec
optional:
key:
type: //any
of:
- //str
- type: //arr
contents: //str
content: //any
""")
def parse(keyword, config, argument):
"""Return a sorted list of songs.
@ -94,19 +108,4 @@ def parse(keyword, config, argument):
))])
return sorted(songlist, key=key_generator(sort))
parse.rxschema = """
type: //any
of:
- type: //nil
- type: //rec
optional:
key:
type: //any
of:
- //str
- type: //arr
contents: //str
content: //any
"""
CONTENT_PLUGINS = {'sorted': parse}

17
patacrep/content/tex.py

@ -5,7 +5,7 @@ import logging
import os
from patacrep import files, errors
from patacrep.content import ContentItem, ContentList, ContentError
from patacrep.content import ContentItem, ContentList, ContentError, validate_parser_argument
LOGGER = logging.getLogger(__name__)
@ -22,6 +22,13 @@ class LaTeX(ContentItem):
)))
#pylint: disable=unused-argument
@validate_parser_argument("""
type: //any
of:
- type: //arr
contents: //str
- type: //str
""")
def parse(keyword, argument, config):
"""Parse the tex files.
@ -62,12 +69,4 @@ def parse(keyword, argument, config):
return filelist
parse.rxschema = """
type: //any
of:
- type: //arr
contents: //str
- type: //str
"""
CONTENT_PLUGINS = {'tex': parse}

Loading…
Cancel
Save