Permalink
Browse files

Code refactoring

Changes based mostly on complaints from Pylint. I'm telling myself it's
good practice.
  • Loading branch information...
1 parent cb5974a commit 6117fe8a6075d81b7a0bd0cd0df018559d61b1fb @chipotle committed Jan 24, 2012
Showing with 91 additions and 90 deletions.
  1. +13 −6 bin/bbind
  2. +78 −84 bookbind/bookbind.py
View
@@ -1,12 +1,19 @@
#!/usr/bin/env python
+"""Bookbind command line caller."""
import sys
from bookbind import bookbind
def print_help():
- print "Bookbind {}\n".format(bookbind.__VERSION__)
- print "Usage: {} directory\n".format(sys.argv[0])
- print "Create an ePub file from a directory of contents and a YAML manifest file."
- print "Consult the documentation for specifics."
+ """Print help."""
+ help_text = """
+Bookbind {}
+
+Usage {} directory
+
+Create an EPUB file from a directory of contents and a YAML manifest file.
+Consult the documentation for specifics.
+"""
+ print help_text.format(bookbind.__VERSION__, sys.argv[0])
if __name__ == '__main__':
@@ -19,6 +26,6 @@ if __name__ == '__main__':
binder = bookbind.Binder(source_dir, '~/.bookbindrc')
binder.load_manifest()
binder.make_book()
- except bookbind.BinderError as e:
- print e
+ except bookbind.BinderError as err:
+ print err
sys.exit(1)
View
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+"""Bookbind - EPUB creation library"""
import sys
import os
import zipfile
@@ -9,17 +10,17 @@
import yaml
from markdown import markdown, MarkdownException
from smartypants import smartyPants
-from jinja2 import Environment, FileSystemLoader, exceptions as JE
+from jinja2 import Environment, FileSystemLoader
__VERSION__ = '0.5.1'
-def manifest_required(fn):
+def manifest_required(func):
"""Decorator for functions that require the manifest to be set."""
def _wrapper(self, *args, **kwargs):
if self.manifest is None:
raise BinderError(BinderError.NO_MANIFEST_SET, 'No manifest set')
- return fn(self, *args, **kwargs)
+ return func(self, *args, **kwargs)
return _wrapper
@@ -40,6 +41,15 @@ def __str__(self):
return '[Err {}] {}'.format(self.code, self.msg)
+def make_id(fullname):
+ """Produce a simple ID from a filename. This may also be used to
+ create filenames at certain places.
+
+ """
+ filename, file_ext = os.path.splitext(fullname)
+ return filename.lower().strip()
+
+
class Binder:
"""Binder class."""
@@ -76,8 +86,13 @@ class Binder:
'.qt': 'video/quicktime',
'.webm': 'video/webm',
}
-
- DATE_FORMATS = [ '%B %Y', '%b %Y', '%B, %Y', '%b, %Y', '%Y-%b', '%Y-%m' ]
+ date_formats = [ '%B %Y', '%b %Y', '%B, %Y', '%b, %Y', '%Y-%b', '%Y-%m' ]
+ remap_values = {
+ 'author': ('creator', 'aut'),
+ 'editor': ('contributor', 'edt'),
+ 'publisher-person': ('contributor', 'pbl'),
+ 'designer': ('contributor', 'bkd')
+ }
def __init__(self, source_dir=None, config=False):
self.source_dir = source_dir
@@ -88,13 +103,14 @@ def __init__(self, source_dir=None, config=False):
def load_config(self, config_filename, silent=False):
+ """Load configuration file."""
try:
config_file = open(config_filename)
self.config = yaml.load(config_file.read())
config_file.close()
- except Exception as e:
+ except Exception as err:
if silent is False:
- raise e
+ raise err
else:
sys.exc_clear()
@@ -145,56 +161,28 @@ def generate_metadata(self):
"""Produce Dublin Core metadata elements from the manifest."""
metadata = self.manifest['metadata']
items = []
- flip = lambda x: ((x + ',').split(',')[1].rstrip() + ' ' +
- (x + ',').split(',')[0].lstrip()).strip()
if not metadata.has_key('uuid') and not metadata.has_key('isbn'):
metadata['uuid'] = uuid.uuid4().urn
if not metadata.has_key('language'):
metadata['language'] = 'en'
for elem, value in metadata.items():
attr = []
- if elem == 'author':
- self.config['author'] = value
- elem = 'creator'
- attr.append('opf:file-as="' + value + '"')
- attr.append('opf:role="aut"')
- value = flip(value)
- elif elem == 'editor':
- elem = 'contributor'
- attr.append('opf:file-as="' + value + '"')
- attr.append('opf:role="edt"')
- value = flip(value)
- elif elem == 'publisher-person':
- elem = 'contributor'
- attr.append('opf:file-as="' + value + '"')
- attr.append('opf:role="pbl"')
- value = flip(value)
- elif elem == 'designer':
- elem = 'contributor'
- attr.append('opf:file-as="' + value + '"')
- attr.append('opf:role="bkd"')
- value = flip(value)
- elif elem == 'title':
- self.config['title'] = value
- elif elem == 'uuid':
- elem = 'identifier'
- attr.append('id="bookid"')
- attr.append('opf:scheme="UUID"')
- self.config['uid'] = value
- elif elem == 'isbn':
+ if elem == 'author' or elem == 'title':
+ self.config[elem] = value
+ attr, elem, value = self.dublin_remap(attr, elem, value)
+ if elem == 'uuid' or elem == 'isbn':
elem = 'identifier'
attr.append('id="bookid"')
- attr.append('opf:scheme="ISBN"')
- if value.startswith('urn:') is False:
- value = 'urn:isbn:' + value
- value = value.translate(None, '- ')
+ attr.append('opf:scheme="' + elem.upper() + '"')
+ if elem == 'isbn':
+ value = 'urn:isbn:' + value.translate(None, '- ')
self.config['uid'] = value
elif elem == 'date':
- for format in self.DATE_FORMATS:
+ for date_fmt in self.date_formats:
new_val = None
try:
- dt = datetime.strptime(value, format)
- new_val = dt.strftime('%Y-%m')
+ stamp = datetime.strptime(value, date_fmt)
+ new_val = stamp.strftime('%Y-%m')
break
except ValueError:
pass
@@ -208,11 +196,24 @@ def generate_metadata(self):
'</dc:' + elem + '>')
if self.manifest.has_key('cover'):
name, ext = os.path.splitext(self.manifest['cover'])
- id = self.images + '_' + name
- items.append('<meta name="cover" content="' + id +'"/>')
+ img_id = self.images + '_' + name
+ items.append('<meta name="cover" content="' + img_id +'"/>')
return items
+ def dublin_remap(self, attr, elem, value):
+ """Remap bookbinder metadata to Dublin Core elements."""
+ if self.remap_values.has_key(elem):
+ flip = lambda x: ((x + ',').split(',')[1].rstrip() + ' ' +
+ (x + ',').split(',')[0].lstrip()).strip()
+ dc_element = self.remap_values[elem]
+ elem = dc_element[0]
+ attr.append('opf:file-as="' + value + '"')
+ attr.append('opf:role="' + dc_element[1] + '"')
+ value = flip(value)
+ return attr, elem, value
+
+
@manifest_required
def generate_manifest_items(self):
"""Generate items for the OPF manifest element."""
@@ -224,8 +225,8 @@ def generate_manifest_items(self):
items.append('<item id="cover" href="cover.xhtml" ' +
'media-type="application/xhtml+xml"/>')
for chapter in self.manifest['book']:
- id = self.make_id(chapter['file'])
- items.append('<item id="' + id + '" href="' + id +
+ chapter_id = make_id(chapter['file'])
+ items.append('<item id="' + chapter_id + '" href="' + chapter_id +
'.xhtml" media-type="application/xhtml+xml"/>')
items = self.add_assets(items)
return items
@@ -237,32 +238,24 @@ def add_assets(self, items):
if os.access(self.source_dir + '/' + self.styles + '/' + stylesheet,
os.R_OK) is False:
name, ext = os.path.splitext(stylesheet)
- id = (self.styles + '_' + name).lower().strip()
- items.append('<item id="' + id + '" href="' + self.styles + '/' +
- stylesheet + '" media-type="text/css"/>')
- for dir in (self.images, self.styles, self.other):
- full_dir = self.source_dir + '/' + dir
+ asset_id = (self.styles + '_' + name).lower().strip()
+ items.append('<item id="' + asset_id + '" href="' + self.styles +
+ '/' + stylesheet + '" media-type="text/css"/>')
+ for dir_name in (self.images, self.styles, self.other):
+ full_dir = self.source_dir + '/' + dir_name
if os.access(full_dir, os.R_OK):
files = os.listdir(full_dir)
- for f in files:
- name, ext = os.path.splitext(f)
+ for myfile in files:
+ name, ext = os.path.splitext(myfile)
mime_type = self.mime_map.get(ext,
'application/octet-stream')
- id = (dir + '_' + name).lower().strip()
- items.append('<item id="' + id + '" href="' + dir +
- '/' + f + '" media-type="' + mime_type + '"/>')
+ file_id = (dir_name + '_' + name).lower().strip()
+ items.append('<item id="' + file_id + '" href="' +
+ dir_name + '/' + myfile + '" media-type="' + mime_type
+ + '"/>')
return items
- def make_id(self, x):
- """Produce a simple ID from a filename. This may also be used to
- create filenames at certain places.
-
- """
- filename, file_ext = os.path.splitext(x)
- return filename.lower().strip()
-
-
@manifest_required
def generate_spine_items(self):
"""Generate the items for the OPF spine element."""
@@ -271,8 +264,8 @@ def generate_spine_items(self):
else:
items = []
for chapter in self.manifest['book']:
- id = self.make_id(chapter['file'])
- items.append('<itemref idref="' + id + '"/>')
+ chapter_id = make_id(chapter['file'])
+ items.append('<itemref idref="' + chapter_id + '"/>')
return items
@@ -294,11 +287,11 @@ def generate_navmap(self):
for chapter in self.manifest['book']:
if chapter.has_key('title') and (not chapter.has_key('linear')
or chapter['linear'] != False):
- id = self.make_id(chapter['file'])
+ chapter_id = make_id(chapter['file'])
items.append({
- 'file': id + '.xhtml',
+ 'file': chapter_id + '.xhtml',
'title': chapter['title'],
- 'id': id
+ 'id': chapter_id
})
return items
@@ -330,13 +323,13 @@ def generate_chapter(self, chapter):
try:
file_obj = open(self.source_dir + '/' + chapter['file'])
text = file_obj.read()
- except IOError as e:
- print e
+ except IOError as err:
+ print err
sys.exit(1)
try:
html = smartyPants(markdown(text))
- except MarkdownException as e:
- print "Error processing {} - {}".format(chapter['file'], e)
+ except MarkdownException as err:
+ print "Error processing {} - {}".format(chapter['file'], err)
sys.exit(1)
elif file_ext == '.xhtml':
file_obj = open(self.source_dir + '/' + chapter['file'])
@@ -381,8 +374,8 @@ def make_book(self, outfile=None):
epub.writestr('OEBPS/content.opf', self.generate_opf())
epub.writestr('OEBPS/toc.ncx', self.generate_toc())
for chapter in self.manifest['book']:
- id = self.make_id(chapter['file'])
- epub.writestr('OEBPS/' + id + '.xhtml',
+ chapter_id = make_id(chapter['file'])
+ epub.writestr('OEBPS/' + chapter_id + '.xhtml',
self.generate_chapter(chapter))
if self.manifest.has_key('cover'):
epub.writestr('OEBPS/cover.xhtml', self.generate_cover())
@@ -393,11 +386,12 @@ def make_book(self, outfile=None):
self.config['styles'] + '/' + self.manifest['stylesheet'],
'OEBPS/' + sheet
)
- for dir in (self.images, self.styles, self.other):
- full_dir = self.source_dir + '/' + dir
+ for asset_dir in (self.images, self.styles, self.other):
+ full_dir = self.source_dir + '/' + asset_dir
if os.access(full_dir, os.R_OK):
files = os.listdir(full_dir)
- for f in files:
- file_obj = open(full_dir + '/' + f)
- epub.writestr('OEBPS/' + dir + '/' + f, file_obj.read())
+ for myfile in files:
+ file_obj = open(full_dir + '/' + myfile)
+ epub.writestr('OEBPS/' + asset_dir + '/' + myfile,
+ file_obj.read())
epub.close()

0 comments on commit 6117fe8

Please sign in to comment.