Browse Source

More Pylint formatting. Almost done! (#4)

pull/20/head
Louis 11 years ago
parent
commit
8e7f4a71ac
  1. 4
      readme.md
  2. 10
      songbook
  3. 2
      songbook_core/__init__.py
  4. 144
      songbook_core/authors.py
  5. 150
      songbook_core/build.py
  6. 16
      songbook_core/errors.py
  7. 4
      songbook_core/files.py
  8. 48
      songbook_core/index.py
  9. 19
      songbook_core/plastex.py
  10. 12
      songbook_core/plastex_patchedbabel.py
  11. 12
      songbook_core/plastex_songs.py
  12. 25
      songbook_core/songs.py

4
readme.md

@ -20,12 +20,12 @@ is precised in the header.
# Run # Run
> <songbook-core>/songbook.py <songbook_file.sb> > <songbook-core>/songbook <songbook_file.sb>
> <pdfreader> <songbook_file.pdf> > <pdfreader> <songbook_file.pdf>
Look for existing songbook files in <songbook-data>/books. For example: Look for existing songbook files in <songbook-data>/books. For example:
> <songbook-core>/songbook.py <songbook-data>/books/songbook_en.sb > <songbook-core>/songbook <songbook-data>/books/songbook_en.sb
> <pdfreader> songbook_en.pdf > <pdfreader> songbook_en.pdf

10
songbook.py → songbook

@ -12,9 +12,9 @@ import os.path
import textwrap import textwrap
import sys import sys
from songbook.build import buildsongbook from songbook_core.build import buildsongbook
from songbook import __VERSION__ from songbook_core import __VERSION__
from songbook import errors from songbook_core import errors
def argument_parser(args): def argument_parser(args):
@ -43,7 +43,7 @@ def main():
"""Main function:""" """Main function:"""
# Logging configuration # Logging configuration
logging.basicConfig(name = 'songbook') logging.basicConfig(name='songbook')
logger = logging.getLogger('songbook') logger = logging.getLogger('songbook')
# set script locale to match user's # set script locale to match user's
@ -72,7 +72,7 @@ def main():
else: else:
songbook['datadir'] = os.path.dirname(songbook_path) songbook['datadir'] = os.path.dirname(songbook_path)
try: try:
buildsongbook(songbook, basename, interactive = True, logger = logger) buildsongbook(songbook, basename, interactive=True, logger=logger)
except errors.SongbookError as error: except errors.SongbookError as error:
logger.error(error) logger.error(error)
sys.exit(1) sys.exit(1)

2
songbook/__init__.py → songbook_core/__init__.py

@ -1,3 +1,5 @@
"""Global variables."""
import os import os
__VERSION__ = "3.7.2" __VERSION__ = "3.7.2"

144
songbook/authors.py → songbook_core/authors.py

@ -52,43 +52,15 @@ def split_sep_author(string, sep):
authors.append(string) authors.append(string)
return authors return authors
################################################################################
### Process authors tools.
################################################################################
def processauthors(authors_string, after=[], ignore=[], sep=[]): def processauthors_removeparen(authors_string):
r"""Return a list of authors """Remove parentheses
For example, we are processing:
# processauthors(
# "Lyrics by William Blake (from Milton, 1808),
music by Hubert Parry (1916),
and sung by The Royal\ Choir~of~Nowhere
(just here to show you how processing is done)",
# after = ["by"],
# ignore = ["anonymous"],
# sep = [re.compile('^(.*) and (.*)$')],
# )
The "authors_string" string is processed as:
1) First, parenthesis (and its content) are removed.
# "Lyrics by William Blake, music by Hubert Parry,
and sung by The Royal\ Choir~of~Nowhere"
2) String is split, separators being comma and words from "sep".
# ["Lyrics by William Blake", "music by Hubert Parry",
"sung by The Royal\ Choir~of~Nowhere"]
3) Everything before words in "after" is removed.
# ["William Blake", "Hubert Parry", "The Royal\ Choir~of~Nowhere"]
4) Strings containing words of "ignore" are dropped. See docstring of processauthors() for more information.
# ["William Blake", "Hubert Parry", The Royal\ Choir~of~Nowhere"]
5) First names are moved after last names
# ["Blake, William", "Parry, Hubert", Royal\ Choir~of~Nowhere, The"]
""" """
# Removing parentheses
opening = 0 opening = 0
dest = "" dest = ""
for char in authors_string: for char in authors_string:
@ -98,17 +70,26 @@ def processauthors(authors_string, after=[], ignore=[], sep=[]):
opening -= 1 opening -= 1
elif opening == 0: elif opening == 0:
dest += char dest += char
authors_string = dest return dest
def processauthors_split_string(authors_string, sep):
"""Split strings
# Splitting strings See docstring of processauthors() for more information.
"""
authors_list = [authors_string] authors_list = [authors_string]
for sepword in sep: for sepword in sep:
dest = [] dest = []
for author in authors_list: for author in authors_list:
dest.extend(split_sep_author(author, sepword)) dest.extend(split_sep_author(author, sepword))
authors_list = dest authors_list = dest
return authors_list
# Removing stuff before "after" def processauthors_remove_after(authors_list, after):
"""Remove stuff before "after"
See docstring of processauthors() for more information.
"""
dest = [] dest = []
for author in authors_list: for author in authors_list:
for afterword in after: for afterword in after:
@ -117,9 +98,13 @@ def processauthors(authors_string, after=[], ignore=[], sep=[]):
author = match.group(1) author = match.group(1)
break break
dest.append(author) dest.append(author)
authors_list = dest return dest
def processauthors_ignore_authors(authors_list, ignore):
"""Ignore ignored authors
# Ignoring ignored authors See docstring of processauthors() for more information.
"""
dest = [] dest = []
for author in authors_list: for author in authors_list:
ignored = False ignored = False
@ -129,13 +114,25 @@ def processauthors(authors_string, after=[], ignore=[], sep=[]):
break break
if not ignored: if not ignored:
dest.append(author) dest.append(author)
authors_list = dest return dest
# Cleaning: removing empty authors and unnecessary spaces def processauthors_clean_authors(authors_list):
authors_list = [author.lstrip() """Clean: remove empty authors and unnecessary spaces
for author in authors_list if author.lstrip()]
# Moving first names after last names See docstring of processauthors() for more information.
"""
return [
author.lstrip()
for author
in authors_list
if author.lstrip()
]
def processauthors_invert_names(authors_list):
"""Move first names after last names
See docstring of processauthors() for more information.
"""
dest = [] dest = []
for author in authors_list: for author in authors_list:
first, last = split_author_names(author) first, last = split_author_names(author)
@ -146,6 +143,61 @@ def processauthors(authors_string, after=[], ignore=[], sep=[]):
}) })
else: else:
dest.append(last.lstrip()) dest.append(last.lstrip())
authors_list = dest return dest
def processauthors(authors_string, after=None, ignore=None, sep=None):
r"""Return a list of authors
For example, we are processing:
# processauthors(
# "Lyrics by William Blake (from Milton, 1808),
music by Hubert Parry (1916),
and sung by The Royal\ Choir~of~Nowhere
(just here to show you how processing is done)",
# after = ["by"],
# ignore = ["anonymous"],
# sep = [re.compile('^(.*) and (.*)$')],
# )
The "authors_string" string is processed as:
1) First, parenthesis (and its content) are removed.
# "Lyrics by William Blake, music by Hubert Parry,
and sung by The Royal\ Choir~of~Nowhere"
2) String is split, separators being comma and words from "sep".
# ["Lyrics by William Blake", "music by Hubert Parry",
"sung by The Royal\ Choir~of~Nowhere"]
3) Everything before words in "after" is removed.
# ["William Blake", "Hubert Parry", "The Royal\ Choir~of~Nowhere"]
4) Strings containing words of "ignore" are dropped.
# ["William Blake", "Hubert Parry", The Royal\ Choir~of~Nowhere"]
5) First names are moved after last names
# ["Blake, William", "Parry, Hubert", Royal\ Choir~of~Nowhere, The"]
"""
if not sep:
sep = []
if not after:
after = []
if not ignore:
ignore = []
return processauthors_invert_names(
processauthors_clean_authors(
processauthors_ignore_authors(
processauthors_remove_after(
processauthors_split_string(
processauthors_removeparen(
authors_string
),
sep),
after),
ignore)
)
)
return authors_list

150
songbook/build.py → songbook_core/build.py

@ -10,26 +10,25 @@ import logging
import os.path import os.path
import re import re
import subprocess import subprocess
import sys
from songbook import __SHAREDIR__ from songbook_core import __SHAREDIR__
from songbook import errors from songbook_core import errors
from songbook.files import recursiveFind from songbook_core.files import recursive_find
from songbook.index import processSXD from songbook_core.index import process_sxd
from songbook.songs import Song, SongsList from songbook_core.songs import Song, SongsList
EOL = "\n" EOL = "\n"
def parseTemplate(template): def parse_template(template):
"""Return the list of parameters defined in the template.""" """Return the list of parameters defined in the template."""
embeddedJsonPattern = re.compile(r"^%%:") embedded_json_pattern = re.compile(r"^%%:")
with open(template) as template_file: with open(template) as template_file:
code = [ code = [
line[3:-1] line[3:-1]
for line for line
in template_file in template_file
if embeddedJsonPattern.match(line) if embedded_json_pattern.match(line)
] ]
data = json.loads(''.join(code)) data = json.loads(''.join(code))
@ -39,15 +38,16 @@ def parseTemplate(template):
return parameters return parameters
def toValue(parameter, data): # pylint: disable=too-many-return-statements
def to_value(parameter, data):
if "type" not in parameter: if "type" not in parameter:
return data return data
elif parameter["type"] == "stringlist": elif parameter["type"] == "stringlist":
if "join" in parameter: if "join" in parameter:
joinText = parameter["join"] join_text = parameter["join"]
else: else:
joinText = '' join_text = ''
return joinText.join(data) return join_text.join(data)
elif parameter["type"] == "color": elif parameter["type"] == "color":
return data[1:] return data[1:]
elif parameter["type"] == "font": elif parameter["type"] == "font":
@ -58,24 +58,24 @@ def toValue(parameter, data):
return data return data
elif parameter["type"] == "flag": elif parameter["type"] == "flag":
if "join" in parameter: if "join" in parameter:
joinText = parameter["join"] join_text = parameter["join"]
else: else:
joinText = '' join_text = ''
return joinText.join(data) return join_text.join(data)
def formatDeclaration(name, parameter): def format_declaration(name, parameter):
value = "" value = ""
if "default" in parameter: if "default" in parameter:
value = parameter["default"] value = parameter["default"]
return ( return (
r'\def\set@{name}#1{{\def\get{name}{{#1}}}}'.format(name=name) r'\def\set@{name}#1{{\def\get{name}{{#1}}}}'.format(name=name)
+ EOL + EOL
+ formatDefinition(name, toValue(parameter, value)) + format_definition(name, to_value(parameter, value))
) )
def formatDefinition(name, value): def format_definition(name, value):
return r'\set@{name}{{{value}}}'.format(name=name, value=value) + EOL return r'\set@{name}{{{value}}}'.format(name=name, value=value) + EOL
@ -103,9 +103,9 @@ def clean(basename):
raise errors.CleaningError(basename + ext, exception) raise errors.CleaningError(basename + ext, exception)
def makeTexFile(sb, output): def make_tex_file(songbook, output):
"""Create the LaTeX file corresponding to the .sb file given in argument.""" """Create the LaTeX file corresponding to the .sb file given in argument."""
datadir = sb['datadir'] datadir = songbook['datadir']
name = output[:-4] name = output[:-4]
template_dir = os.path.join(datadir, 'templates') template_dir = os.path.join(datadir, 'templates')
songs = [] songs = []
@ -117,33 +117,33 @@ def makeTexFile(sb, output):
authwords = {"after": ["by"], "ignore": ["unknown"], "sep": ["and"]} authwords = {"after": ["by"], "ignore": ["unknown"], "sep": ["and"]}
# parse the songbook data # parse the songbook data
if "template" in sb: if "template" in songbook:
template = sb["template"] template = songbook["template"]
del sb["template"] del songbook["template"]
else: else:
template = os.path.join(__SHAREDIR__, "templates", "default.tmpl") template = os.path.join(__SHAREDIR__, "templates", "default.tmpl")
if "songs" in sb: if "songs" in songbook:
songs = sb["songs"] songs = songbook["songs"]
del sb["songs"] del songbook["songs"]
if "titleprefixwords" in sb: if "titleprefixwords" in songbook:
prefixes = sb["titleprefixwords"] prefixes = songbook["titleprefixwords"]
for prefix in sb["titleprefixwords"]: for prefix in songbook["titleprefixwords"]:
prefixes_tex += r"\titleprefixword{%s}" % prefix + EOL prefixes_tex += r"\titleprefixword{%s}" % prefix + EOL
sb["titleprefixwords"] = prefixes_tex songbook["titleprefixwords"] = prefixes_tex
if "authwords" in sb: if "authwords" in songbook:
# Populating default value # Populating default value
for key in ["after", "sep", "ignore"]: for key in ["after", "sep", "ignore"]:
if key not in sb["authwords"]: if key not in songbook["authwords"]:
sb["authwords"][key] = authwords[key] songbook["authwords"][key] = authwords[key]
# Processing authwords values # Processing authwords values
authwords = sb["authwords"] authwords = songbook["authwords"]
for key in ["after", "sep", "ignore"]: for key in ["after", "sep", "ignore"]:
for word in authwords[key]: for word in authwords[key]:
if key == "after": if key == "after":
authwords_tex += r"\auth%sword{%s}" % ("by", word) + EOL authwords_tex += r"\auth%sword{%s}" % ("by", word) + EOL
else: else:
authwords_tex += r"\auth%sword{%s}" % (key, word) + EOL authwords_tex += r"\auth%sword{%s}" % (key, word) + EOL
sb["authwords"] = authwords_tex songbook["authwords"] = authwords_tex
if "after" in authwords: if "after" in authwords:
authwords["after"] = [re.compile(r"^.*%s\b(.*)" % after) authwords["after"] = [re.compile(r"^.*%s\b(.*)" % after)
for after in authwords["after"]] for after in authwords["after"]]
@ -152,52 +152,55 @@ def makeTexFile(sb, output):
authwords["sep"] = [re.compile(r"^(.*)%s (.*)$" % sep) authwords["sep"] = [re.compile(r"^(.*)%s (.*)$" % sep)
for sep in authwords["sep"]] for sep in authwords["sep"]]
if "lang" not in sb: if "lang" not in songbook:
sb["lang"] = "french" songbook["lang"] = "french"
if "sort" in sb: if "sort" in songbook:
sort = sb["sort"] sort = songbook["sort"]
del sb["sort"] del songbook["sort"]
else: else:
sort = [u"by", u"album", u"@title"] sort = [u"by", u"album", u"@title"]
Song.sort = sort Song.sort = sort
Song.prefixes = prefixes Song.prefixes = prefixes
Song.authwords = authwords Song.authwords = authwords
parameters = parseTemplate(os.path.join(template_dir, template)) parameters = parse_template(os.path.join(template_dir, template))
# compute songslist # compute songslist
if songs == "all": if songs == "all":
songs = [ songs = [
os.path.relpath(filename, os.path.join(datadir, 'songs')) os.path.relpath(filename, os.path.join(datadir, 'songs'))
for filename for filename
in recursiveFind(os.path.join(datadir, 'songs'), '*.sg') in recursive_find(os.path.join(datadir, 'songs'), '*.sg')
] ]
songslist = SongsList(datadir, sb["lang"]) songslist = SongsList(datadir, songbook["lang"])
songslist.append_list(songs) songslist.append_list(songs)
sb["languages"] = ",".join(songslist.languages()) songbook["languages"] = ",".join(songslist.languages())
# output relevant fields # output relevant fields
out = codecs.open(output, 'w', 'utf-8') out = codecs.open(output, 'w', 'utf-8')
out.write('%% This file has been automatically generated, do not edit!\n') out.write('%% This file has been automatically generated, do not edit!\n')
out.write(r'\makeatletter' + EOL) out.write(r'\makeatletter' + EOL)
# output automatic parameters # output automatic parameters
out.write(formatDeclaration("name", {"default": name})) out.write(format_declaration("name", {"default": name}))
out.write(formatDeclaration("songslist", {"type": "stringlist"})) out.write(format_declaration("songslist", {"type": "stringlist"}))
# output template parameter command # output template parameter command
for name, parameter in parameters.iteritems(): for name, parameter in parameters.iteritems():
out.write(formatDeclaration(name, parameter)) out.write(format_declaration(name, parameter))
# output template parameter values # output template parameter values
for name, value in sb.iteritems(): for name, value in songbook.iteritems():
if name in parameters: if name in parameters:
out.write(formatDefinition(name, toValue(parameters[name], value))) out.write(format_definition(
name,
to_value(parameters[name], value),
))
if len(songs) > 0: if len(songs) > 0:
out.write(formatDefinition('songslist', songslist.latex())) out.write(format_definition('songslist', songslist.latex()))
out.write(r'\makeatother' + EOL) out.write(r'\makeatother' + EOL)
# output template # output template
commentPattern = re.compile(r"^\s*%") comment_pattern = re.compile(r"^\s*%")
with codecs.open( with codecs.open(
os.path.join(template_dir, template), 'r', 'utf-8' os.path.join(template_dir, template), 'r', 'utf-8'
) as template_file: ) as template_file:
@ -205,7 +208,7 @@ def makeTexFile(sb, output):
line line
for line for line
in template_file in template_file
if not commentPattern.match(line) if not comment_pattern.match(line)
] ]
for index, line in enumerate(content): for index, line in enumerate(content):
@ -225,24 +228,35 @@ def makeTexFile(sb, output):
out.write(u''.join(content)) out.write(u''.join(content))
out.close() out.close()
def buildsongbook(sb, basename, interactive = False, logger = logging.getLogger()): def buildsongbook(
songbook,
basename,
interactive=False,
logger=logging.getLogger()
):
"""Build a songbook """Build a songbook
Arguments: Arguments:
- sb: Python representation of the .sb songbook configuration file. - songbook: Python representation of the .sb songbook configuration file.
- basename: basename of the songbook to be built. - basename: basename of the songbook to be built.
- interactive: in False, do not expect anything from stdin. - interactive: in False, do not expect anything from stdin.
""" """
texFile = basename + ".tex" tex_file = basename + ".tex"
# Make TeX file # Make TeX file
makeTexFile(sb, texFile) make_tex_file(songbook, tex_file)
if not 'TEXINPUTS' in os.environ.keys(): if not 'TEXINPUTS' in os.environ.keys():
os.environ['TEXINPUTS'] = '' os.environ['TEXINPUTS'] = ''
os.environ['TEXINPUTS'] += os.pathsep + os.path.join(__SHAREDIR__, 'latex') os.environ['TEXINPUTS'] += os.pathsep + os.path.join(
os.environ['TEXINPUTS'] += os.pathsep + os.path.join(sb['datadir'], 'latex') __SHAREDIR__,
'latex',
)
os.environ['TEXINPUTS'] += os.pathsep + os.path.join(
songbook['datadir'],
'latex',
)
# pdflatex options # pdflatex options
pdflatex_options = [] pdflatex_options = []
@ -251,20 +265,20 @@ def buildsongbook(sb, basename, interactive = False, logger = logging.getLogger(
pdflatex_options.append("-halt-on-error") pdflatex_options.append("-halt-on-error")
# First pdflatex pass # First pdflatex pass
if subprocess.call(["pdflatex"] + pdflatex_options + [texFile]): if subprocess.call(["pdflatex"] + pdflatex_options + [tex_file]):
raise errors.LatexCompilationError(basename) raise errors.LatexCompilationError(basename)
# Make index # Make index
sxdFiles = glob.glob("%s_*.sxd" % basename) sxd_files = glob.glob("%s_*.sxd" % basename)
for sxdFile in sxdFiles: for sxd_file in sxd_files:
logger.info("processing " + sxdFile) logger.info("processing " + sxd_file)
idx = processSXD(sxdFile) idx = process_sxd(sxd_file)
indexFile = open(sxdFile[:-3] + "sbx", "w") index_file = open(sxd_file[:-3] + "sbx", "w")
indexFile.write(idx.entriesToStr().encode('utf8')) index_file.write(idx.entries_to_str().encode('utf8'))
indexFile.close() index_file.close()
# Second pdflatex pass # Second pdflatex pass
if subprocess.call(["pdflatex"] + pdflatex_options + [texFile]): if subprocess.call(["pdflatex"] + pdflatex_options + [tex_file]):
raise errors.LatexCompilationError(basename) raise errors.LatexCompilationError(basename)
# Cleaning # Cleaning

16
songbook/errors.py → songbook_core/errors.py

@ -4,23 +4,35 @@
"""Songbook exceptions and errors.""" """Songbook exceptions and errors."""
class SongbookError(Exception): class SongbookError(Exception):
"""Generic songbook error.
Songbook errors should inherit from this one.
"""
pass pass
class LatexCompilationError(SongbookError): class LatexCompilationError(SongbookError):
"""Error during LaTeX compilation.""" """Error during LaTeX compilation."""
def __init__(self, basename): def __init__(self, basename):
super(LatexCompilationError, self).__init__()
self.basename = basename self.basename = basename
def __str__(self): def __str__(self):
return """Error while pdfLaTeX compilation of "{basename}.tex" (see {basename}.log for more information).""".format(basename = self.basename) return (
"""Error while pdfLaTeX compilation of "{basename}.tex"
(see {basename}.log for more information)."""
).format(basename=self.basename)
class CleaningError(SongbookError): class CleaningError(SongbookError):
"""Error during cleaning of LaTeX auxiliary files.""" """Error during cleaning of LaTeX auxiliary files."""
def __init__(self, filename, exception): def __init__(self, filename, exception):
super(CleaningError, self).__init__()
self.filename = filename self.filename = filename
self.exception = exception self.exception = exception
def __str__(self): def __str__(self):
return """Error while removing "{filename}": {exception}.""".format(filename = self.filename, exception = str(self.exception)) return """Error while removing "{filename}": {exception}.""".format(
filename=self.filename,
exception=str(self.exception)
)

4
songbook/files.py → songbook_core/files.py

@ -7,13 +7,13 @@
import fnmatch import fnmatch
import os import os
def recursiveFind(root_directory, pattern): def recursive_find(root_directory, pattern):
"""Recursively find files matching a pattern, from a root_directory. """Recursively find files matching a pattern, from a root_directory.
Return a list of files matching the pattern. Return a list of files matching the pattern.
""" """
matches = [] matches = []
for root, dirnames, filenames in os.walk(root_directory): for root, _, filenames in os.walk(root_directory):
for filename in fnmatch.filter(filenames, pattern): for filename in fnmatch.filter(filenames, pattern):
matches.append(os.path.join(root, filename)) matches.append(os.path.join(root, filename))
return matches return matches

48
songbook/index.py → songbook_core/index.py

@ -13,14 +13,14 @@ import locale
import re import re
import sys import sys
from songbook.authors import processauthors from songbook_core.authors import processauthors
from songbook.plastex import simpleparse from songbook_core.plastex import simpleparse
EOL = "\n" EOL = "\n"
# Pattern set to ignore latex command in title prefix # Pattern set to ignore latex command in title prefix
keywordPattern = re.compile(r"^%(\w+)\s?(.*)$") KEYWORD_PATTERN = re.compile(r"^%(\w+)\s?(.*)$")
firstLetterPattern = re.compile(r"^(?:\{?\\\w+\}?)*[^\w]*(\w)") FIRST_LETTER_PATTERN = re.compile(r"^(?:\{?\\\w+\}?)*[^\w]*(\w)")
def sortkey(value): def sortkey(value):
@ -32,7 +32,7 @@ def sortkey(value):
return locale.strxfrm(unidecode(simpleparse(value).replace(' ', 'A'))) return locale.strxfrm(unidecode(simpleparse(value).replace(' ', 'A')))
def processSXD(filename): def process_sxd(filename):
"""Parse sxd file. """Parse sxd file.
Return an Index object. Return an Index object.
@ -47,11 +47,11 @@ def processSXD(filename):
idx = Index(data[0]) idx = Index(data[0])
while len(data) > i and data[i].startswith('%'): while len(data) > i and data[i].startswith('%'):
keywords = keywordPattern.match(data[i]).groups() keywords = KEYWORD_PATTERN.match(data[i]).groups()
idx.keyword(keywords[0], keywords[1]) idx.keyword(keywords[0], keywords[1])
i += 1 i += 1
idx.compileKeywords() idx.compile_keywords()
for i in range(i, len(data), 3): for i in range(i, len(data), 3):
entry = data[i:i + 3] entry = data[i:i + 3]
idx.add(entry[0], entry[1], entry[2]) idx.add(entry[0], entry[1], entry[2])
@ -59,7 +59,7 @@ def processSXD(filename):
return idx return idx
class Index: class Index(object):
"""Title, author or scripture Index representation.""" """Title, author or scripture Index representation."""
def __init__(self, indextype): def __init__(self, indextype):
@ -76,9 +76,10 @@ class Index:
else: else:
self.indextype = "" self.indextype = ""
def filter(self, key): @staticmethod
letter = firstLetterPattern.match(key).group(1) def filter(key):
if re.match('\d', letter): letter = FIRST_LETTER_PATTERN.match(key).group(1)
if re.match(r'\d', letter):
letter = '0-9' letter = '0-9'
return (letter.upper(), key) return (letter.upper(), key)
@ -87,7 +88,7 @@ class Index:
self.keywords[key] = [] self.keywords[key] = []
self.keywords[key].append(word) self.keywords[key].append(word)
def compileKeywords(self): def compile_keywords(self):
if self.indextype == "TITLE": if self.indextype == "TITLE":
if 'prefix' in self.keywords: if 'prefix' in self.keywords:
for prefix in self.keywords['prefix']: for prefix in self.keywords['prefix']:
@ -146,27 +147,34 @@ class Index:
**self.authwords): **self.authwords):
self._raw_add(author, number, link) self._raw_add(author, number, link)
def refToStr(self, ref): @staticmethod
def ref_to_str(ref):
if sys.version_info >= (2, 6): if sys.version_info >= (2, 6):
return r'\hyperlink{{{0[link]}}}{{{0[num]}}}'.format(ref) return r'\hyperlink{{{0[link]}}}{{{0[num]}}}'.format(ref)
else: else:
return r'\hyperlink{%(link)s}{%(num)s}' % ref return r'\hyperlink{%(link)s}{%(num)s}' % ref
def entryToStr(self, key, entry): def entry_to_str(self, key, entry):
if sys.version_info >= (2, 6): if sys.version_info >= (2, 6):
return unicode(r'\idxentry{{{0}}}{{{1}}}' + EOL).format(key, r'\\'.join(map(self.refToStr, entry))) return unicode(r'\idxentry{{{0}}}{{{1}}}' + EOL).format(
key,
r'\\'.join([self.ref_to_str(ref) for ref in entry]),
)
else: else:
return unicode(r'\idxentry{%s}{%s}' + EOL) % (key, r'\\'.join(map(self.refToStr, entry))) return unicode(r'\idxentry{%s}{%s}' + EOL) % (
key,
r'\\'.join([self.ref_to_str(ref) for ref in entry]),
)
def idxBlockToStr(self, letter, entries): def idxblock_to_str(self, letter, entries):
string = r'\begin{idxblock}{' + letter + '}' + EOL string = r'\begin{idxblock}{' + letter + '}' + EOL
for key in sorted(entries.keys(), key=sortkey): for key in sorted(entries.keys(), key=sortkey):
string += self.entryToStr(key, entries[key]) string += self.entry_to_str(key, entries[key])
string += r'\end{idxblock}' + EOL string += r'\end{idxblock}' + EOL
return string return string
def entriesToStr(self): def entries_to_str(self):
string = "" string = ""
for letter in sorted(self.data.keys()): for letter in sorted(self.data.keys()):
string += self.idxBlockToStr(letter, self.data[letter]) string += self.idxblock_to_str(letter, self.data[letter])
return string return string

19
songbook/plastex.py → songbook_core/plastex.py

@ -12,7 +12,7 @@ import os
import sys import sys
def processUnbreakableSpace(node): def process_unbr_spaces(node):
r"""Replace '~' and '\ ' in node by nodes that r"""Replace '~' and '\ ' in node by nodes that
will be rendered as unbreakable space. will be rendered as unbreakable space.
@ -22,7 +22,7 @@ def processUnbreakableSpace(node):
(type(node) == Sentences.NoLineBreak and node.source == '~ ')): (type(node) == Sentences.NoLineBreak and node.source == '~ ')):
node.unicode = unichr(160) node.unicode = unichr(160)
for child in node.childNodes: for child in node.childNodes:
processUnbreakableSpace(child) process_unbr_spaces(child)
return node return node
@ -33,28 +33,31 @@ def simpleparse(text):
tex = TeX() tex = TeX()
tex.input(text.decode('utf8')) tex.input(text.decode('utf8'))
doc = tex.parse() doc = tex.parse()
return processUnbreakableSpace(doc.textContent) return process_unbr_spaces(doc.textContent)
class SongParser: class SongParser(object):
"""Analyseur syntaxique de fichiers .sg""" """Analyseur syntaxique de fichiers .sg"""
def __init__(self):
pass
@staticmethod @staticmethod
def _create_TeX(): def create_tex():
"""Create a TeX object, ready to parse a tex file.""" """Create a TeX object, ready to parse a tex file."""
tex = TeX() tex = TeX()
tex.disableLogging() tex.disableLogging()
tex.ownerDocument.context.loadBaseMacros() tex.ownerDocument.context.loadBaseMacros()
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))
tex.ownerDocument.context.loadPackage(tex, "plastex-patchedbabel") tex.ownerDocument.context.loadPackage(tex, "plastex_patchedbabel")
tex.ownerDocument.context.loadPackage(tex, "plastex-songs") tex.ownerDocument.context.loadPackage(tex, "plastex_songs")
sys.path.pop() sys.path.pop()
return tex return tex
@classmethod @classmethod
def parse(cls, filename): def parse(cls, filename):
"""Parse a TeX file, and return its plasTeX representation.""" """Parse a TeX file, and return its plasTeX representation."""
tex = cls._create_TeX() tex = cls.create_tex()
tex.input(codecs.open(filename, 'r+', 'utf-8', 'replace')) tex.input(codecs.open(filename, 'r+', 'utf-8', 'replace'))
return tex.parse() return tex.parse()

12
songbook/plastex-patchedbabel.py → songbook_core/plastex_patchedbabel.py

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Patch pour le paquet Babel de PlasTeX r"""Patch pour le paquet Babel de PlasTeX
Un bug dans PlasTeX intervient lorsqu'on essaye d'analyser une commande LaTeX Un bug dans PlasTeX intervient lorsqu'on essaye d'analyser une commande LaTeX
\selectlanguage{}, que nous voulons utiliser ici. Un patch a été proposé aux \selectlanguage{}, que nous voulons utiliser ici. Un patch a été proposé aux
@ -27,8 +27,8 @@ trop gros.
> Traceback (most recent call last): > Traceback (most recent call last):
> [...] > [...]
> File "/usr/lib/pymodules/python2.7/plasTeX/Packages/babel.py", line 18, in invoke > File "/usr/lib/pymodules/python2.7/plasTeX/Packages/babel.py", line 18, in
> context.loadLanguage(self.attributes['lang'], self.ownerDocument) > invoke context.loadLanguage(self.attributes['lang'], self.ownerDocument)
> NameError: global name 'context' is not defined > NameError: global name 'context' is not defined
3 bis) Si elle n'apparait pas : youpi ! Supprimez ce fichier ! 3 bis) Si elle n'apparait pas : youpi ! Supprimez ce fichier !
@ -42,6 +42,7 @@ Louis <spalax(at)gresille.org>
from plasTeX import Command from plasTeX import Command
# pylint: disable=invalid-name,too-many-public-methods
class selectlanguage(Command): class selectlanguage(Command):
"""Patch of vanilla selectlanguage class. """Patch of vanilla selectlanguage class.
@ -50,5 +51,8 @@ class selectlanguage(Command):
def invoke(self, tex): def invoke(self, tex):
res = Command.invoke(self, tex) res = Command.invoke(self, tex)
self.ownerDocument.context.loadLanguage(self.attributes['lang'], self.ownerDocument) self.ownerDocument.context.loadLanguage( # pylint: disable=no-member
self.attributes['lang'],
self.ownerDocument
)
return res return res

12
songbook/plastex-songs.py → songbook_core/plastex_songs.py

@ -6,7 +6,7 @@
import plasTeX import plasTeX
from songbook.plastex import processUnbreakableSpace from songbook_core.plastex import process_unbr_spaces
def split_linebreak(texlist): def split_linebreak(texlist):
@ -18,7 +18,8 @@ def split_linebreak(texlist):
Alternative name\\ Alternative name\\
Another alternative name Another alternative name
This function takes the object representation of a list of titles, and return a list of titles. This function takes the object representation of a list of titles, and
return a list of titles.
""" """
return_list = [] return_list = []
current = [] current = []
@ -27,13 +28,14 @@ def split_linebreak(texlist):
return_list.append(current) return_list.append(current)
current = [] current = []
else: else:
current.append(processUnbreakableSpace(token).textContent.encode('utf-8')) current.append(
process_unbr_spaces(token).textContent.encode('utf-8'))
if current: if current:
return_list.append(current) return_list.append(current)
return return_list return return_list
class beginsong(plasTeX.Command): class beginsong(plasTeX.Command): # pylint: disable=invalid-name,too-many-public-methods
"""Class parsing the LaTeX song environment.""" """Class parsing the LaTeX song environment."""
args = '{titles}[ args:dict ]' args = '{titles}[ args:dict ]'
@ -53,7 +55,7 @@ class beginsong(plasTeX.Command):
args = {} args = {}
for (key, val) in self.attributes['args'].iteritems(): for (key, val) in self.attributes['args'].iteritems():
if isinstance(val, plasTeX.DOM.Element): if isinstance(val, plasTeX.DOM.Element):
args[key] = processUnbreakableSpace(val).textContent.encode('utf-8') args[key] = process_unbr_spaces(val).textContent.encode('utf-8')
elif isinstance(val, unicode): elif isinstance(val, unicode):
args[key] = val.encode('utf-8') args[key] = val.encode('utf-8')
elif isinstance(val, str): elif isinstance(val, str):

25
songbook/songs.py → songbook_core/songs.py

@ -9,11 +9,12 @@ import locale
import os.path import os.path
import re import re
from songbook.authors import processauthors from songbook_core.authors import processauthors
from songbook.plastex import parsetex from songbook_core.plastex import parsetex
class Song: # pylint: disable=too-few-public-methods
class Song(object):
"""Song management""" """Song management"""
#: Ordre de tri #: Ordre de tri
@ -25,12 +26,16 @@ class Song:
def __init__(self, path, languages, titles, args): def __init__(self, path, languages, titles, args):
self.titles = titles self.titles = titles
self.normalized_titles = [locale.strxfrm( self.normalized_titles = [
unprefixed_title(unidecode(unicode(title, "utf-8")), locale.strxfrm(
self.prefixes unprefixed_title(
) unidecode(unicode(title, "utf-8")),
) self.prefixes
for title in titles] )
)
for title
in titles
]
self.args = args self.args = args
self.path = path self.path = path
self.languages = languages self.languages = languages
@ -80,7 +85,7 @@ def unprefixed_title(title, prefixes):
return title return title
class SongsList: class SongsList(object):
"""Manipulation et traitement de liste de chansons""" """Manipulation et traitement de liste de chansons"""
def __init__(self, library, language): def __init__(self, library, language):
Loading…
Cancel
Save