Browse Source

Errors are correctly gathered from content items

pull/176/head
Louis 9 years ago
parent
commit
1d2a285536
  1. 4
      patacrep/build.py
  2. 31
      patacrep/content/__init__.py
  3. 20
      patacrep/content/include.py
  4. 21
      patacrep/content/section.py
  5. 8
      patacrep/content/song.py
  6. 17
      patacrep/content/songsection.py
  7. 6
      patacrep/content/sorted.py
  8. 10
      patacrep/content/tex.py
  9. 8
      patacrep/latex/syntax.py

4
patacrep/build.py

@ -135,7 +135,9 @@ class Songbook:
def iter_errors(self):
"""Iterate over errors of book and book content."""
yield from self._errors
for item in self._config.get('content', list()):
content = self._config.get('content', list())
yield from content.iter_errors()
for item in content:
if not hasattr(item, "iter_errors"):
continue
yield from item.iter_errors()

31
patacrep/content/__init__.py

@ -73,7 +73,7 @@ import re
import sys
from patacrep import files
from patacrep.errors import SongbookError
from patacrep.errors import SharedError
LOGGER = logging.getLogger(__name__)
EOL = '\n'
@ -120,7 +120,7 @@ class ContentItem:
"""Return the string to end a block."""
return ""
class ContentError(SongbookError):
class ContentError(SharedError):
"""Error in a content plugin."""
def __init__(self, keyword=None, message=None):
super(ContentError, self).__init__()
@ -140,13 +140,15 @@ class ContentList:
def __init__(self, *args, **kwargs):
self._content = list(*args, **kwargs)
self.errors = []
self._errors = []
def __iter__(self):
yield from self._content
def extend(self, iterator):
return self._content.extend(iterator)
self._content.extend(iterator)
if isinstance(iterator, self.__class__):
self._errors.extend(iterator._errors)
def append(self, item):
return self._content.append(item)
@ -154,6 +156,23 @@ class ContentList:
def __len__(self):
return len(self._content)
def append_error(self, error):
LOGGER.warning(error)
self._errors.append(error)
def extend_error(self, errors):
for error in errors:
self.append_error(error)
def iter_errors(self):
yield from self._errors
class EmptyContentList(ContentList):
def __init__(self, *, errors):
super().__init__()
for error in errors:
self.append_error(error)
@jinja2.contextfunction
def render(context, content):
"""Render the content of the songbook as a LaTeX code.
@ -209,11 +228,11 @@ def process_content(content, config=None):
try:
match = keyword_re.match(elem[0]).groupdict()
except AttributeError:
contentlist.errors.append(ContentError(elem[0], "Cannot parse content type."))
contentlist.append_error(ContentError(elem[0], "Cannot parse content type."))
continue
(keyword, argument) = (match['keyword'], match['argument'])
if keyword not in plugins:
contentlist.errors.append(ContentError(keyword, "Unknown content type."))
contentlist.append_error(ContentError(keyword, "Unknown content type."))
continue
contentlist.extend(plugins[keyword](
keyword,

20
patacrep/content/include.py

@ -9,7 +9,7 @@ import os
import sys
import logging
from patacrep.content import process_content, ContentError
from patacrep.content import process_content, ContentError, ContentList
from patacrep import encoding, errors, files
LOGGER = logging.getLogger(__name__)
@ -38,10 +38,14 @@ def parse(keyword, config, argument, contentlist):
- argument: None;
- contentlist: a list of file paths to be included.
"""
new_contentlist = []
new_contentlist = ContentList()
for path in contentlist:
filepath = load_from_datadirs(path, config.get('datadir', []))
try:
filepath = load_from_datadirs(path, config.get('datadir', []))
except ContentError as error:
new_contentlist.append_error(error)
continue
content_file = None
try:
with encoding.open_read(
@ -50,12 +54,14 @@ def parse(keyword, config, argument, contentlist):
) as content_file:
new_content = json.load(content_file)
except Exception as error: # pylint: disable=broad-except
LOGGER.warning(error)
LOGGER.warning("Error while loading file '{}'.".format(filepath))
sys.exit(1)
new_contentlist.append_error(ContentError(
keyword="include",
message="Error while loading file '{}': {}".format(filepath, error),
))
continue
config["datadir"].append(os.path.abspath(os.path.dirname(filepath)))
new_contentlist += process_content(new_content, config)
new_contentlist.extend(process_content(new_content, config))
config["datadir"].pop()
return new_contentlist

21
patacrep/content/section.py

@ -1,6 +1,6 @@
"""Allow LaTeX sections (starred or not) as content of a songbook."""
from patacrep.content import ContentItem, ContentError
from patacrep.content import ContentItem, ContentError, ContentList, EmptyContentList
KEYWORDS = [
"part",
@ -41,14 +41,17 @@ def parse(keyword, argument, contentlist, config):
and long) of the section;
- config: configuration dictionary of the current songbook.
"""
if (keyword not in KEYWORDS) and (len(contentlist) != 1):
raise ContentError(
keyword,
"Starred section names must have exactly one argument."
)
if (len(contentlist) not in [1, 2]):
raise ContentError(keyword, "Section can have one or two arguments.")
return ContentList(Section(keyword, *contentlist))
try:
if (keyword not in KEYWORDS) and (len(contentlist) != 1):
raise ContentError(
keyword,
"Starred section names must have exactly one argument."
)
if (len(contentlist) not in [1, 2]):
raise ContentError(keyword, "Section can have one or two arguments.")
return ContentList([Section(keyword, *contentlist)])
except ContentError as error:
return EmptyContentList(errors=[error])
CONTENT_PLUGINS = dict([

8
patacrep/content/song.py

@ -87,14 +87,13 @@ def parse(keyword, argument, contentlist, config):
LOGGER.debug('Parsing file "{}"'.format(filename))
extension = filename.split(".")[-1]
if extension not in plugins:
LOGGER.warning(
(
songlist.append_error(ContentError(message=(
'I do not know how to parse "{}": name does '
'not end with one of {}. Ignored.'
).format(
os.path.join(songdir.datadir, filename),
", ".join(["'.{}'".format(key) for key in plugins.keys()]),
))
)))
continue
try:
renderer = SongRenderer(plugins[extension](
@ -103,8 +102,7 @@ def parse(keyword, argument, contentlist, config):
datadir=songdir.datadir,
))
except ContentError as error:
# TODO
songlist.errors.append(error)
songlist.append_error(error)
continue
songlist.append(renderer)
config["_langs"].add(renderer.song.lang)

17
patacrep/content/songsection.py

@ -1,6 +1,6 @@
"""Allow 'songchapter' and 'songsection' as content of a songbook."""
from patacrep.content import ContentItem, ContentError
from patacrep.content import ContentItem, ContentError, ContentList, EmptyContentList
KEYWORDS = [
"songchapter",
@ -29,12 +29,15 @@ def parse(keyword, argument, contentlist, config):
- contentlist: a list of one string, which is the name of the section;
- config: configuration dictionary of the current songbook.
"""
if (keyword not in KEYWORDS) and (len(contentlist) != 1):
raise ContentError(
keyword,
"Starred section names must have exactly one argument.",
)
return ContentList(SongSection(keyword, contentlist[0]))
try:
if (keyword not in KEYWORDS) and (len(contentlist) != 1):
raise ContentError(
keyword,
"Starred section names must have exactly one argument.",
)
return ContentList([SongSection(keyword, contentlist[0])])
except ContentError as error:
return EmptyContentList(errors=[error])
CONTENT_PLUGINS = dict([

6
patacrep/content/sorted.py

@ -9,7 +9,7 @@ import logging
import unidecode
from patacrep import files
from patacrep.content import ContentError
from patacrep.content import ContentError, ContentList
from patacrep.content.song import OnlySongsError, process_songs
LOGGER = logging.getLogger(__name__)
@ -85,11 +85,11 @@ def parse(keyword, config, argument, contentlist):
try:
songlist = process_songs(contentlist, config)
except OnlySongsError as error:
raise ContentError(keyword, (
return EmptyContentError(errors=[ContentError(keyword, (
"Content list of this keyword can be only songs (or content "
"that result into songs), and the following are not:" +
str(error.not_songs)
))
))])
return sorted(songlist, key=key_generator(sort))
CONTENT_PLUGINS = {'sorted': parse}

10
patacrep/content/tex.py

@ -5,7 +5,7 @@ import logging
import os
from patacrep import files, errors
from patacrep.content import ContentItem, ContentList
from patacrep.content import ContentItem, ContentList, ContentError
LOGGER = logging.getLogger(__name__)
@ -35,7 +35,7 @@ def parse(keyword, argument, contentlist, config):
LOGGER.warning(
"Useless 'tex' content: list of files to include is empty."
)
filelist = ContentList
filelist = ContentList()
basefolders = itertools.chain(
(path.fullpath for path in config['_songdir']),
files.iter_datadirs(config['datadir']),
@ -51,9 +51,9 @@ def parse(keyword, argument, contentlist, config):
))
break
if not checked_file:
LOGGER.warning(
"{} Compilation may fail later.".format(
errors.notfound(filename, basefolders)
filelist.append_error(ContentError(
keyword="tex",
message=errors.notfound(filename, basefolders),
)
)
continue

8
patacrep/latex/syntax.py

@ -131,13 +131,15 @@ class LatexParser(Parser):
"""dictionary : identifier EQUAL braces dictionary_next
| identifier EQUAL error dictionary_next
"""
symbols[0] = {}
if isinstance(symbols[3], ast.Expression):
symbols[0] = {}
symbols[0][symbols[1]] = symbols[3]
symbols[0].update(symbols[4])
else:
# TODO put error in self.errors
raise ParsingError("Do enclose arguments between braces.")
self.error(
line=symbols.lexer.lineno,
message="Argument '{}' should be enclosed between braces.".format(symbols[1]),
)
@staticmethod
def p_identifier(symbols):

Loading…
Cancel
Save