Browse Source

Merge pull request #75 from patacrep/tox

Using tox for tests
pull/76/head
Luthaf 10 years ago
parent
commit
688f6c70ac
  1. 2
      .gitignore
  2. 9
      .travis.yml
  3. 13
      README.rst
  4. 2
      Requirements.txt
  5. 2
      patacrep/content/section.py
  6. 3
      patacrep/content/song.py
  7. 6
      patacrep/content/tex.py
  8. 13
      patacrep/errors.py
  9. 4
      patacrep/files.py
  10. 39
      patacrep/latex/syntax.py
  11. 27
      patacrep/songbook.py
  12. 2
      patacrep/songs/chordpro/lexer.py
  13. 38
      patacrep/songs/chordpro/syntax.py
  14. 33
      patacrep/songs/syntax.py
  15. 9
      patacrep/templates.py
  16. 5
      pylintrc
  17. 15
      tox.ini

2
.gitignore

@ -13,3 +13,5 @@ dist
*.pdf
*.pyc
*.tar.gz
.eggs
.tox

9
.travis.yml

@ -0,0 +1,9 @@
git:
depth: 1
language: python
python:
- 3.4
install:
- pip install tox
script:
- tox

13
README.rst

@ -1,6 +1,8 @@
Patacrep, a songbook compilation chain
======================================
|sources| |build| |pypi| |documentation| |license|
This package provides a compilation toolchain that produce LaTeX
songbook using the LaTeX songs package. A new LaTeX document class is
provided to allow specific customisation and new command like embedded
@ -61,3 +63,14 @@ Contact & Forums
----------------
* http://www.patacrep.com/forum
.. |documentation| image:: http://readthedocs.org/projects/patacrep/badge
:target: http://patacrep.readthedocs.org
.. |pypi| image:: https://img.shields.io/pypi/v/patacrep.svg
:target: http://pypi.python.org/pypi/patacrep
.. |license| image:: https://img.shields.io/pypi/l/patacrep.svg
:target: http://www.gnu.org/licenses/gpl-2.0.html
.. |sources| image:: https://img.shields.io/badge/sources-patacrep-brightgreen.svg
:target: http://github.com/patacrep/patacrep
.. |build| image:: https://travis-ci.org/patacrep/patacrep.svg?branch=master
:target: https://travis-ci.org/patacrep/patacrep

2
Requirements.txt

@ -1,4 +1,4 @@
ply
Jinja2==2.7.3
argparse==1.2.1
chardet==2.2.1
unidecode>=0.04.16

2
patacrep/content/section.py

@ -48,7 +48,7 @@ def parse(keyword, argument, contentlist, config):
)
if (len(contentlist) not in [1, 2]):
raise ContentError(keyword, "Section can have one or two arguments.")
return [Section(keyword, *contentlist)] #pylint: disable=star-args
return [Section(keyword, *contentlist)]
CONTENT_PLUGINS = dict([

3
patacrep/content/song.py

@ -67,7 +67,8 @@ def parse(keyword, argument, contentlist, config):
LOGGER.debug('Parsing file "{}"'.format(filename))
extension = filename.split(".")[-1]
if extension not in plugins:
LOGGER.warning((
LOGGER.warning(
(
'I do not know how to parse "{}": name does '
'not end with one of {}. Ignored.'
).format(

6
patacrep/content/tex.py

@ -48,8 +48,10 @@ def parse(keyword, argument, contentlist, config):
))
break
if not checked_file:
LOGGER.warning("{} Compilation may fail later.".format(
errors.notfound(filename, basefolders))
LOGGER.warning(
"{} Compilation may fail later.".format(
errors.notfound(filename, basefolders)
)
)
continue
filelist.append(LaTeX(checked_file))

13
patacrep/errors.py

@ -39,7 +39,8 @@ class LatexCompilationError(SongbookError):
self.basename = basename
def __str__(self):
return ("""Error while pdfLaTeX compilation of "{basename}.tex" """
return (
"""Error while pdfLaTeX compilation of "{basename}.tex" """
"""(see {basename}.log for more information)."""
).format(basename=self.basename)
@ -79,6 +80,16 @@ class UnknownStep(SongbookError):
def __str__(self):
return """Compilation step "{step}" unknown.""".format(step=self.step)
class ParsingError(SongbookError):
"""Parsing error."""
def __init__(self, message):
super().__init__(self)
self.message = message
def __str__(self):
return self.message
def notfound(filename, paths, message=None):
"""Return a string saying that file was not found in paths."""
if message is None:

4
patacrep/files.py

@ -50,7 +50,8 @@ def path2posix(string):
(head, tail) = os.path.split(string)
return posixpath.join(
path2posix(head),
tail)
tail,
)
@contextmanager
def chdir(path):
@ -87,7 +88,6 @@ def load_plugins(datadirs, root_modules, keyword):
- keys are the keywords ;
- values are functions triggered when this keyword is met.
"""
# pylint: disable=star-args
plugins = {}
directory_list = (
[

39
patacrep/latex/syntax.py

@ -3,52 +3,25 @@
import logging
import ply.yacc as yacc
from patacrep.songs.syntax import Parser
from patacrep.latex.lexer import tokens, SimpleLexer, SongLexer
from patacrep.latex import ast
from patacrep.errors import SongbookError
from patacrep.errors import ParsingError
from patacrep.latex.detex import detex
LOGGER = logging.getLogger()
class ParsingError(SongbookError):
"""Parsing error."""
def __init__(self, message):
super().__init__(self)
self.message = message
def __str__(self):
return self.message
# pylint: disable=line-too-long
class Parser:
class LatexParser(Parser):
"""LaTeX parser."""
def __init__(self, filename=None):
super().__init__()
self.tokens = tokens
self.ast = ast.AST
self.ast.init_metadata()
self.filename = filename
@staticmethod
def __find_column(token):
"""Return the column of ``token``."""
last_cr = token.lexer.lexdata.rfind('\n', 0, token.lexpos)
if last_cr < 0:
last_cr = 0
column = (token.lexpos - last_cr) + 1
return column
def p_error(self, token):
"""Manage parsing errors."""
LOGGER.error(
"Error in file {}, line {} at position {}.".format(
str(self.filename),
token.lineno,
self.__find_column(token),
)
)
@staticmethod
def p_expression(symbols):
"""expression : brackets expression
@ -238,7 +211,7 @@ def tex2plain(string):
"""Parse string and return its plain text version."""
return detex(
silent_yacc(
module=Parser(),
module=LatexParser(),
).parse(
string,
lexer=SimpleLexer().lexer,
@ -254,7 +227,7 @@ def parse_song(content, filename=None):
display error messages.
"""
return detex(
silent_yacc(module=Parser(filename)).parse(
silent_yacc(module=LatexParser(filename)).parse(
content,
lexer=SongLexer().lexer,
).metadata

27
patacrep/songbook.py

@ -41,25 +41,32 @@ def argument_parser(args):
"""Parse arguments"""
parser = argparse.ArgumentParser(description="A song book compiler")
parser.add_argument('--version', help='Show version', action='version',
version='%(prog)s ' + __version__)
parser.add_argument(
'--version', help='Show version', action='version',
version='%(prog)s ' + __version__,
)
parser.add_argument('book', nargs=1, help=textwrap.dedent("""\
Book to compile.
"""))
parser.add_argument(
'book', nargs=1, help=textwrap.dedent("Book to compile.")
)
parser.add_argument('--datadir', '-d', nargs='+', type=str, action='append',
parser.add_argument(
'--datadir', '-d', nargs='+', type=str, action='append',
help=textwrap.dedent("""\
Data location. Expected (not necessarily required)
subdirectories are 'songs', 'img', 'latex', 'templates'.
"""))
""")
)
parser.add_argument('--verbose', '-v', nargs=0, action=VerboseAction,
parser.add_argument(
'--verbose', '-v', nargs=0, action=VerboseAction,
help=textwrap.dedent("""\
Show details about the compilation process.
"""))
""")
)
parser.add_argument('--steps', '-s', nargs=1, type=str,
parser.add_argument(
'--steps', '-s', nargs=1, type=str,
action=ParseStepsAction,
help=textwrap.dedent("""\
Steps to run. Default is "{steps}".

2
patacrep/songs/chordpro/lexer.py

@ -39,7 +39,7 @@ class ChordProLexer:
t_SPACE = r'[ \t]+'
t_chord_CHORD = r'[A-G7#m]+' # TODO This can be refined
t_chord_CHORD = r'[A-G7#m]+'
t_directive_SPACE = r'[ \t]+'
t_directive_KEYWORD = r'[a-zA-Z_]+'

38
patacrep/songs/chordpro/syntax.py

@ -1,54 +1,24 @@
# -*- coding: utf-8 -*-
"""ChordPro parser"""
import logging
import ply.yacc as yacc
from patacrep.errors import SongbookError
from patacrep.songs.syntax import Parser
from patacrep.songs.chordpro import ast
from patacrep.songs.chordpro.lexer import tokens, ChordProLexer
LOGGER = logging.getLogger()
class ParsingError(SongbookError):
"""Parsing error."""
def __init__(self, message):
super().__init__(self)
self.message = message
def __str__(self):
return self.message
class Parser:
class ChordproParser(Parser):
"""ChordPro parser class"""
start = "song"
def __init__(self, filename=None):
super().__init__()
self.tokens = tokens
self.filename = filename
@staticmethod
def __find_column(token):
"""Return the column of ``token``."""
last_cr = token.lexer.lexdata.rfind('\n', 0, token.lexpos)
if last_cr < 0:
last_cr = 0
column = (token.lexpos - last_cr) + 1
return column
def p_error(self, token):
"""Manage parsing errors."""
if token:
LOGGER.error("Error in file {}, line {}:{}.".format(
str(self.filename),
token.lineno,
self.__find_column(token),
)
)
def p_song(self, symbols):
"""song : block song
| empty
@ -208,7 +178,7 @@ class Parser:
def parse_song(content, filename=None):
"""Parse song and return its metadata."""
return yacc.yacc(
module=Parser(filename),
module=ChordproParser(filename),
debug=0,
write_tables=0,
).parse(

33
patacrep/songs/syntax.py

@ -0,0 +1,33 @@
"""Generic parsing classes and methods"""
import logging
LOGGER = logging.getLogger()
class Parser:
"""Parser class"""
# pylint: disable=too-few-public-methods
def __init__(self):
self.filename = "" # Will be overloaded
@staticmethod
def __find_column(token):
"""Return the column of ``token``."""
last_cr = token.lexer.lexdata.rfind('\n', 0, token.lexpos)
if last_cr < 0:
last_cr = 0
column = (token.lexpos - last_cr) + 1
return column
def p_error(self, token):
"""Manage parsing errors."""
if token:
LOGGER.error(
"Error in file {}, line {}:{}.".format(
str(self.filename),
token.lineno,
self.__find_column(token),
)
)

9
patacrep/templates.py

@ -20,7 +20,8 @@ _LATEX_SUBS = (
(re.compile(r'\.\.\.+'), r'\\ldots'),
)
_VARIABLE_REGEXP = re.compile(r"""
_VARIABLE_REGEXP = re.compile(
r"""
\(\*\ *variables\ *\*\) # Match (* variables *)
( # Match and capture the following:
(?: # Start of non-capturing group, used to match a single character
@ -101,8 +102,10 @@ class TexBookRenderer(TexRenderer):
'''
self.lang = lang
# Load templates in filesystem ...
loaders = [FileSystemLoader(os.path.join(datadir, 'templates'))
for datadir in datadirs]
loaders = [
FileSystemLoader(os.path.join(datadir, 'templates'))
for datadir in datadirs
]
texenv = Environment(
loader=ChoiceLoader(loaders),
extensions=[VariablesExtension],

5
pylintrc

@ -0,0 +1,5 @@
[VARIABLES]
dummy-variables-rgx=_|dummy
[MESSAGES CONTROL]
disable= logging-format-interpolation

15
tox.ini

@ -0,0 +1,15 @@
# To perform those tests, install `tox` and run "tox" from this directory.
[tox]
# Uncomment to use more python versions
#envlist = py26, py27, py32, py34, lint
envlist = py34, lint
[testenv]
commands = {envpython} setup.py test
deps =
[testenv:lint]
basepython=python3.4
deps=pylint
commands=pylint patacrep --rcfile=pylintrc
Loading…
Cancel
Save