Browse Source

Converted to Python3

Not fully tested: base case seems to work
pull/66/head
Louis 10 years ago
parent
commit
2a3bee175e
  1. 4
      patacrep/build.py
  2. 6
      patacrep/content/__init__.py
  3. 2
      patacrep/content/cwd.py
  4. 6
      patacrep/content/section.py
  5. 8
      patacrep/content/song.py
  6. 4
      patacrep/content/songsection.py
  7. 10
      patacrep/content/sorted.py
  8. 4
      patacrep/content/tex.py
  9. 29
      patacrep/encoding.py
  10. 5
      patacrep/errors.py
  11. 2
      patacrep/files.py
  12. 33
      patacrep/index.py
  13. 2
      patacrep/latex/__init__.py
  14. 19
      patacrep/songs.py
  15. 16
      patacrep/templates.py
  16. 10
      readme.md
  17. 2
      setup.py
  18. 6
      songbook
  19. 4
      stdeb.cfg

4
patacrep/build.py

@ -57,7 +57,7 @@ class Songbook(object):
def _set_datadir(self):
"""Set the default values for datadir"""
try:
if isinstance(self.config['datadir'], basestring):
if isinstance(self.config['datadir'], str):
self.config['datadir'] = [self.config['datadir']]
except KeyError: # No datadir in the raw_songbook
self.config['datadir'] = [os.path.abspath('.')]
@ -213,7 +213,7 @@ class SongbookBuilder(object):
log = ''
line = process.stdout.readline()
while line:
log += line
log += str(line)
line = process.stdout.readline()
LOGGER.debug(log)

6
patacrep/content/__init__.py

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Content plugin management.
@ -225,11 +225,11 @@ def process_content(content, config=None):
"""
contentlist = []
plugins = load_plugins(config)
keyword_re = re.compile(ur'^ *(?P<keyword>\w*) *(\((?P<argument>.*)\))? *$')
keyword_re = re.compile(r'^ *(?P<keyword>\w*) *(\((?P<argument>.*)\))? *$')
if not content:
content = [["song"]]
for elem in content:
if isinstance(elem, basestring):
if isinstance(elem, str):
elem = ["song", elem]
if len(content) == 0:
content = ["song"]

2
patacrep/content/cwd.py

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Change base directory before importing songs."""

6
patacrep/content/section.py

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Allow LaTeX sections (starred or not) as content of a songbook."""
@ -26,9 +26,9 @@ class Section(Content):
def render(self, __context):
if self.short is None:
return ur'\{}{{{}}}'.format(self.keyword, self.name)
return r'\{}{{{}}}'.format(self.keyword, self.name)
else:
return ur'\{}[{}]{{{}}}'.format(self.keyword, self.short, self.name)
return r'\{}[{}]{{{}}}'.format(self.keyword, self.short, self.name)
#pylint: disable=unused-argument
def parse(keyword, argument, contentlist, config):

8
patacrep/content/song.py

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Plugin to include songs to the songbook."""
@ -26,15 +26,15 @@ class SongRenderer(Content, Song):
indexes = context.resolve("indexes")
if isinstance(indexes, jinja2.runtime.Undefined):
indexes = ""
return ur'\begin{songs}{%s}' % indexes
return r'\begin{songs}{%s}' % indexes
def end_block(self, __context):
"""Return the string to end a block."""
return ur'\end{songs}'
return r'\end{songs}'
def render(self, context):
"""Return the string that will render the song."""
return ur'\input{{{}}}'.format(files.path2posix(
return r'\input{{{}}}'.format(files.path2posix(
files.relpath(
self.fullpath,
os.path.dirname(context['filename'])

4
patacrep/content/songsection.py

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Allow 'songchapter' and 'songsection' as content of a songbook."""
@ -19,7 +19,7 @@ class SongSection(Content):
def render(self, __context):
"""Render this section or chapter."""
return ur'\{}{{{}}}'.format(self.keyword, self.name)
return r'\{}{{{}}}'.format(self.keyword, self.name)
#pylint: disable=unused-argument
def parse(keyword, argument, contentlist, config):

10
patacrep/content/sorted.py

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Sorted list of songs.
@ -9,9 +9,9 @@ to a songbook.
import locale
import logging
import unidecode
from patacrep import files
from patacrep import encoding
from patacrep.content import ContentError
from patacrep.content.song import OnlySongsError, process_songs
@ -27,11 +27,11 @@ def normalize_string(string):
- lower case;
- passed through locale.strxfrm().
"""
return locale.strxfrm(encoding.unidecode(string.lower().strip()))
return locale.strxfrm(unidecode.unidecode(string.lower().strip()))
def normalize_field(field):
"""Return a normalized field, it being a string or a list of strings."""
if isinstance(field, basestring):
if isinstance(field, str):
return normalize_string(field)
elif isinstance(field, list) or isinstance(field, tuple):
return [normalize_field(string) for string in field]
@ -63,7 +63,7 @@ def key_generator(sort):
files.relpath(song.fullpath),
)
)
field = u""
field = ""
songkey.append(normalize_field(field))
return songkey
return ordered_song_keys

4
patacrep/content/tex.py

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Include LaTeX raw code in the songbook."""
@ -18,7 +18,7 @@ class LaTeX(Content):
self.filename = filename
def render(self, context):
return ur'\input{{{}}}'.format(files.relpath(
return r'\input{{{}}}'.format(files.relpath(
self.filename,
os.path.dirname(context['filename']),
))

29
patacrep/encoding.py

@ -5,7 +5,6 @@
import codecs
import chardet
import logging
from unidecode import unidecode as unidecode_orig
LOGGER = logging.getLogger(__name__)
@ -17,32 +16,6 @@ def open_read(filename, mode='r'):
return codecs.open(
filename,
mode=mode,
encoding=chardet.detect(open(filename, "r").read())['encoding'],
encoding=chardet.detect(open(filename, 'rb').read())['encoding'],
errors='replace',
)
def basestring2unicode(arg):
"""Return the unicode version of the argument, guessing original encoding.
"""
if isinstance(arg, unicode):
return arg
elif isinstance(arg, basestring):
return arg.decode(
encoding=chardet.detect(arg)['encoding'],
errors='replace',
)
else:
LOGGER.warning("Cannot decode string {}. Ignored.".format(str(arg)))
return ""
def list2unicode(arg):
"""Return the unicode version of the argument, guessing original encoding.
Argument is a list of strings. If an item is of another type, it is
silently ignored (an empty string is returned).
"""
return [basestring2unicode(item) for item in arg]
def unidecode(arg):
"""Return a unicode version of a unidecoded string."""
return unicode(unidecode_orig(arg))

5
patacrep/errors.py

@ -17,10 +17,7 @@ class SBFileError(SongbookError):
self.message = message
def __str__(self):
if self.message is None:
return str(self.original)
else:
return self.message
return self.message
class TemplateError(SongbookError):
"""Error during template generation"""

2
patacrep/files.py

@ -16,7 +16,7 @@ def recursive_find(root_directory, pattern):
matches = []
with chdir(root_directory):
for root, _, filenames in os.walk(os.curdir):
for root, __ignored, filenames in os.walk(os.curdir):
for filename in fnmatch.filter(filenames, pattern):
matches.append(os.path.join(root, filename))
return matches

33
patacrep/index.py

@ -8,17 +8,18 @@ from a file generated by the latex compilation of the songbook (.sxd).
"""
import locale
import unidecode
import re
from patacrep import authors
from patacrep import encoding
from patacrep.latex import latex2unicode
EOL = u"\n"
EOL = "\n"
# Pattern set to ignore latex command in title prefix
KEYWORD_PATTERN = re.compile(ur"^%(\w+)\s?(.*)$", re.LOCALE)
FIRST_LETTER_PATTERN = re.compile(ur"^(?:\{?\\\w+\}?)*[^\w]*(\w)", re.LOCALE)
KEYWORD_PATTERN = re.compile(r"^%(\w+)\s?(.*)$", re.LOCALE)
FIRST_LETTER_PATTERN = re.compile(r"^(?:\{?\\\w+\}?)*[^\w]*(\w)", re.LOCALE)
def process_sxd(filename):
@ -77,13 +78,13 @@ class Index(object):
except AttributeError:
# classify as number all the non letter characters
letter = "0"
if re.match(ur'\d', letter):
if re.match(r'\d', letter):
letter = '0-9'
return letter.upper()
def add_keyword(self, key, word):
"""Add 'word' to self.keywords[key]."""
if not key in self.keywords.keys():
if not key in self.keywords:
self.keywords[key] = []
self.keywords[key].append(word)
@ -93,7 +94,7 @@ class Index(object):
if 'prefix' in self.keywords:
for prefix in self.keywords['prefix']:
self.prefix_patterns.append(re.compile(
ur"^({prefix})(\b|\\)(\s*.*)$".format(prefix=prefix),
r"^({prefix})(\b|\\)(\s*.*)$".format(prefix=prefix),
re.LOCALE
))
@ -107,12 +108,12 @@ class Index(object):
similar method with processing.
"""
first = self.get_first_letter(key[0])
if not first in self.data.keys():
if not first in self.data:
self.data[first] = dict()
if not key in self.data[first].keys():
if not key in self.data[first]:
self.data[first][key] = {
'sortingkey': [
encoding.unidecode(latex2unicode(item)).lower()
unidecode.unidecode(latex2unicode(item)).lower()
for item in key
],
'entries': [],
@ -150,26 +151,26 @@ class Index(object):
@staticmethod
def ref_to_str(ref):
"""Return the LaTeX code corresponding to the reference."""
return ur'\hyperlink{{{0[link]}}}{{{0[num]}}}'.format(ref)
return r'\hyperlink{{{0[link]}}}{{{0[num]}}}'.format(ref)
def key_to_str(self, key):
"""Convert the key (title or author) to the LaTeX command rendering it.
"""
if self.indextype == "AUTHOR":
return ur"\indexauthor{{{first}}}{{{last}}}".format(
return r"\indexauthor{{{first}}}{{{last}}}".format(
first=key[1],
last=key[0],
)
if self.indextype == "TITLE":
return ur"\indextitle{{{0[1]}}}{{{0[0]}}}".format(key)
return r"\indextitle{{{0[1]}}}{{{0[0]}}}".format(key)
def entry_to_str(self, key, entry):
"""Return the LaTeX code corresponding to the entry."""
return unicode(ur'\idxentry{{{0}}}{{{1}}}' + EOL).format(
return (r'\idxentry{{{0}}}{{{1}}}' + EOL).format(
self.key_to_str(key),
ur'\\'.join([self.ref_to_str(ref) for ref in entry]),
r'\\'.join([self.ref_to_str(ref) for ref in entry]),
)
def idxblock_to_str(self, letter, entries):
@ -185,10 +186,10 @@ class Index(object):
for item
in entries[key]['sortingkey']
]
string = ur'\begin{idxblock}{' + letter + '}' + EOL
string = r'\begin{idxblock}{' + letter + '}' + EOL
for key in sorted(entries, key=sortkey):
string += self.entry_to_str(key, entries[key]['entries'])
string += ur'\end{idxblock}' + EOL
string += r'\end{idxblock}' + EOL
return string
def entries_to_str(self):

2
patacrep/latex/__init__.py

@ -4,7 +4,7 @@
def latex2unicode(string):
"""Convert LaTeX string to unicode"""
return u"TODO"
return "TODO"
def parsetex(path):
"""Return a dictonary of data read from the latex file `path`.

19
patacrep/songs.py

@ -6,13 +6,9 @@ import errno
import hashlib
import logging
import os
import pickle
import re
try:
import cPickle as pickle
except ImportError:
import pickle
from patacrep.authors import processauthors
from patacrep.latex import parsetex
@ -128,7 +124,7 @@ class Song(object):
self.args = data['args']
self.subpath = subpath
self.languages = data['languages']
if "by" in self.args.keys():
if "by" in self.args:
self.authors = processauthors(
self.args["by"],
**config["_compiled_authwords"]
@ -144,14 +140,7 @@ class Song(object):
if self.datadir:
cached = {}
for attribute in self.cached_attributes:
if attribute == "args":
cached[attribute] = dict([
(key, u"{}".format(value)) # Force conversion to unicode
for (key, value)
in self.args.iteritems()
])
else:
cached[attribute] = getattr(self, attribute)
cached[attribute] = getattr(self, attribute)
pickle.dump(
cached,
open(cached_name(self.datadir, self.subpath), 'wb'),
@ -165,7 +154,7 @@ def unprefixed_title(title, prefixes):
"""Remove the first prefix of the list in the beginning of title (if any).
"""
for prefix in prefixes:
match = re.compile(ur"^(%s)\b\s*(.*)$" % prefix, re.LOCALE).match(title)
match = re.compile(r"^(%s)\b\s*(.*)$" % prefix, re.LOCALE).match(title)
if match:
return match.group(2)
return title

16
patacrep/templates.py

@ -12,15 +12,15 @@ import json
from patacrep import encoding, errors, files
_LATEX_SUBS = (
(re.compile(ur'\\'), ur'\\textbackslash'),
(re.compile(ur'([{}_#%&$])'), ur'\\\1'),
(re.compile(ur'~'), ur'\~{}'),
(re.compile(ur'\^'), ur'\^{}'),
(re.compile(ur'"'), ur"''"),
(re.compile(ur'\.\.\.+'), ur'\\ldots'),
(re.compile(r'\\'), r'\\textbackslash'),
(re.compile(r'([{}_#%&$])'), r'\\\1'),
(re.compile(r'~'), r'\~{}'),
(re.compile(r'\^'), r'\^{}'),
(re.compile(r'"'), r"''"),
(re.compile(r'\.\.\.+'), r'\\ldots'),
)
_VARIABLE_REGEXP = re.compile(ur"""
_VARIABLE_REGEXP = re.compile(r"""
\(\*\ *variables\ *\*\) # Match (* variables *)
( # Match and capture the following:
(?: # Start of non-capturing group, used to match a single character
@ -48,7 +48,7 @@ class VariablesExtension(Extension):
tags = set(['variables'])
def parse(self, parser):
parser.stream.next()
next(parser.stream)
parser.parse_statements(
end_tokens=['name:endvariables'],
drop_needle=True,

10
readme.md

@ -12,7 +12,7 @@ is precised in the header.
# Python version
Patacrep is compatible with Python 2.7 (no Python3 yet).
Patacrep is compatible with Python 3.
# Download
@ -26,7 +26,7 @@ Clone Patacrep repos:
Make sure you have [pip](https://pip.pypa.io/en/latest/) installed, and then run
> pip install -r Requirements.txt
> python setup.py install
> python3 setup.py install
# Run
@ -40,10 +40,10 @@ Look for existing songbook files in `<patadata>/books/`. For example:
# Quick and dirty deb packages
Install `python-stdeb`, then:
Install `python3-stdeb`, then:
> python setup.py --command-packages=stdeb.command bdist_deb
> sudo dpkg -i deb_dist/python-patacrep_<version>-1_all.deb
> python3 setup.py --command-packages=stdeb.command bdist_deb
> sudo dpkg -i deb_dist/python3-patacrep_<version>-1_all.deb
# Documentation

2
setup.py

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""Installation script for songbook.

6
songbook

@ -1,4 +1,4 @@
#! /usr/bin/env python2
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""Command line tool to compile songbooks using the songbook library."""
@ -92,7 +92,7 @@ def main():
locale.setlocale(locale.LC_ALL, '')
except locale.Error as error:
# Locale is not installed on user's system, or wrongly configured.
sys.stderr.write("Locale error: {}\n".format(error.message))
sys.stderr.write("Locale error: {}\n".format(str(error)))
options = argument_parser(sys.argv[1:])
@ -119,7 +119,7 @@ def main():
datadirs += [item[0] for item in options.datadir]
if 'datadir' in songbook:
# .sg file
if isinstance(songbook['datadir'], basestring):
if isinstance(songbook['datadir'], str):
songbook['datadir'] = [songbook['datadir']]
datadirs += [
os.path.join(

4
stdeb.cfg

@ -1,6 +1,6 @@
[DEFAULT]
Depends: python-jinja2, python-pkg-resources, python-chardet, python-unidecode, texlive-latex-base, texlive-latex-recommended, texlive-latex-extra, lilypond, texlive-fonts-recommended
Depends: python3-jinja2, python3-pkg-resources, python3-chardet, python3-unidecode, texlive-latex-base, texlive-latex-recommended, texlive-latex-extra, lilypond, texlive-fonts-recommended
Recommends: texlive-lang-english, texlive-lang-french, texlive-lang-portuguese, texlive-lang-spanish, texlive-fonts-extra
XS-Python-Version: >=2.7
X-Python3-Version:
Section: tex

Loading…
Cancel
Save