This commit is contained in:
Kovid Goyal 2019-09-10 18:47:30 +05:30
commit 976ee75b7b
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
14 changed files with 178 additions and 165 deletions

View File

@ -1,6 +1,8 @@
from __future__ import print_function
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
''' Code to manage ebook library'''
@ -64,7 +66,7 @@ def generate_test_db(library_path, # {{{
t = time.time() - start
print('\nGenerated', num_of_records, 'records in:', t, 'seconds')
print('Time per record:', t/float(num_of_records))
print('Time per record:', t/num_of_records)
# }}}

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
@ -466,7 +466,7 @@ class ResultCache(SearchQueryParser): # {{{
cast = lambda x: int(x)
elif dt == 'rating':
cast = lambda x: 0 if x is None else int(x)
adjust = lambda x: x/2
adjust = lambda x: x//2
elif dt in ('float', 'composite'):
cast = lambda x : float(x)
else: # count operation
@ -851,7 +851,7 @@ class ResultCache(SearchQueryParser): # {{{
def _build_restriction_string(self, restriction):
if self.base_restriction:
if restriction:
return u'(%s) and (%s)' % (self.base_restriction, restriction)
return '(%s) and (%s)' % (self.base_restriction, restriction)
else:
return self.base_restriction
else:
@ -867,7 +867,7 @@ class ResultCache(SearchQueryParser): # {{{
else:
q = query
if search_restriction:
q = u'(%s) and (%s)' % (search_restriction, query)
q = '(%s) and (%s)' % (search_restriction, query)
if not q:
if set_restriction_count:
self.search_restriction_book_count = len(self._map)
@ -924,7 +924,7 @@ class ResultCache(SearchQueryParser): # {{{
'''
if not hasattr(id_dict, 'items'):
# Simple list. Make it a dict of string 'true'
self.marked_ids_dict = dict.fromkeys(id_dict, u'true')
self.marked_ids_dict = dict.fromkeys(id_dict, 'true')
else:
# Ensure that all the items in the dict are text
self.marked_ids_dict = dict(zip(iter(id_dict), map(unicode_type,
@ -1214,7 +1214,7 @@ class SortKeyGenerator(object):
else:
if self.library_order:
try:
lang = record[self.lang_idx].partition(u',')[0]
lang = record[self.lang_idx].partition(',')[0]
except (AttributeError, ValueError, KeyError,
IndexError, TypeError):
lang = None

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
@ -8,13 +9,13 @@ __docformat__ = 'restructuredtext en'
import re, codecs, os, numbers
from collections import namedtuple
from calibre import (strftime)
from calibre import strftime
from calibre.customize import CatalogPlugin
from calibre.library.catalogs import FIELDS, TEMPLATE_ALLOWED_FIELDS
from calibre.customize.conversion import DummyReporter
from calibre.constants import preferred_encoding
from calibre.ebooks.metadata import format_isbn
from polyglot.builtins import string_or_bytes, filter
from polyglot.builtins import filter, string_or_bytes, unicode_type
class BIBTEX(CatalogPlugin):
@ -126,9 +127,9 @@ class BIBTEX(CatalogPlugin):
bibtex_entry = []
if mode != "misc" and check_entry_book_valid(entry) :
bibtex_entry.append(u'@book{')
bibtex_entry.append('@book{')
elif mode != "book" :
bibtex_entry.append(u'@misc{')
bibtex_entry.append('@misc{')
else :
# case strict book
return ''
@ -137,7 +138,7 @@ class BIBTEX(CatalogPlugin):
# Citation tag
bibtex_entry.append(make_bibtex_citation(entry, template_citation,
bibtexdict))
bibtex_entry = [u' '.join(bibtex_entry)]
bibtex_entry = [' '.join(bibtex_entry)]
for field in fields:
if field.startswith('#'):
@ -161,68 +162,68 @@ class BIBTEX(CatalogPlugin):
pass
if field == 'authors' :
bibtex_entry.append(u'author = "%s"' % bibtexdict.bibtex_author_format(item))
bibtex_entry.append('author = "%s"' % bibtexdict.bibtex_author_format(item))
elif field == 'id' :
bibtex_entry.append(u'calibreid = "%s"' % int(item))
bibtex_entry.append('calibreid = "%s"' % int(item))
elif field == 'rating' :
bibtex_entry.append(u'rating = "%s"' % int(item))
bibtex_entry.append('rating = "%s"' % int(item))
elif field == 'size' :
bibtex_entry.append(u'%s = "%s octets"' % (field, int(item)))
bibtex_entry.append('%s = "%s octets"' % (field, int(item)))
elif field == 'tags' :
# A list to flatten
bibtex_entry.append(u'tags = "%s"' % bibtexdict.utf8ToBibtex(u', '.join(item)))
bibtex_entry.append('tags = "%s"' % bibtexdict.utf8ToBibtex(', '.join(item)))
elif field == 'comments' :
# \n removal
item = item.replace(u'\r\n',u' ')
item = item.replace(u'\n',u' ')
item = item.replace('\r\n', ' ')
item = item.replace('\n', ' ')
# unmatched brace removal (users should use \leftbrace or \rightbrace for single braces)
item = bibtexdict.stripUnmatchedSyntax(item, u'{', u'}')
item = bibtexdict.stripUnmatchedSyntax(item, '{', '}')
# html to text
try:
item = html2text(item)
except:
log.warn("Failed to convert comments to text")
bibtex_entry.append(u'note = "%s"' % bibtexdict.utf8ToBibtex(item))
bibtex_entry.append('note = "%s"' % bibtexdict.utf8ToBibtex(item))
elif field == 'isbn' :
# Could be 9, 10 or 13 digits
bibtex_entry.append(u'isbn = "%s"' % format_isbn(item))
bibtex_entry.append('isbn = "%s"' % format_isbn(item))
elif field == 'formats' :
# Add file path if format is selected
formats = [format.rpartition('.')[2].lower() for format in item]
bibtex_entry.append(u'formats = "%s"' % u', '.join(formats))
bibtex_entry.append('formats = "%s"' % ', '.join(formats))
if calibre_files:
files = [u':%s:%s' % (format, format.rpartition('.')[2].upper())
files = [':%s:%s' % (format, format.rpartition('.')[2].upper())
for format in item]
bibtex_entry.append(u'file = "%s"' % u', '.join(files))
bibtex_entry.append('file = "%s"' % ', '.join(files))
elif field == 'series_index' :
bibtex_entry.append(u'volume = "%s"' % int(item))
bibtex_entry.append('volume = "%s"' % int(item))
elif field == 'timestamp' :
bibtex_entry.append(u'timestamp = "%s"' % isoformat(item).partition('T')[0])
bibtex_entry.append('timestamp = "%s"' % isoformat(item).partition('T')[0])
elif field == 'pubdate' :
bibtex_entry.append(u'year = "%s"' % item.year)
bibtex_entry.append(u'month = "%s"' % bibtexdict.utf8ToBibtex(strftime("%b", item)))
bibtex_entry.append('year = "%s"' % item.year)
bibtex_entry.append('month = "%s"' % bibtexdict.utf8ToBibtex(strftime("%b", item)))
elif field.startswith('#') and isinstance(item, string_or_bytes):
bibtex_entry.append(u'custom_%s = "%s"' % (field[1:],
bibtex_entry.append('custom_%s = "%s"' % (field[1:],
bibtexdict.utf8ToBibtex(item)))
elif isinstance(item, string_or_bytes):
# elif field in ['title', 'publisher', 'cover', 'uuid', 'ondevice',
# 'author_sort', 'series', 'title_sort'] :
bibtex_entry.append(u'%s = "%s"' % (field, bibtexdict.utf8ToBibtex(item)))
bibtex_entry.append('%s = "%s"' % (field, bibtexdict.utf8ToBibtex(item)))
bibtex_entry = u',\n '.join(bibtex_entry)
bibtex_entry += u' }\n\n'
bibtex_entry = ',\n '.join(bibtex_entry)
bibtex_entry += ' }\n\n'
return bibtex_entry
@ -241,7 +242,7 @@ class BIBTEX(CatalogPlugin):
# define a function to replace the template entry by its value
def tpl_replace(objtplname) :
tpl_field = re.sub(u'[\\{\\}]', u'', objtplname.group())
tpl_field = re.sub(r'[\{\}]', '', objtplname.group())
if tpl_field in TEMPLATE_ALLOWED_FIELDS :
if tpl_field in ['pubdate', 'timestamp'] :
@ -249,26 +250,26 @@ class BIBTEX(CatalogPlugin):
elif tpl_field in ['tags', 'authors'] :
tpl_field =entry[tpl_field][0]
elif tpl_field in ['id', 'series_index'] :
tpl_field = str(entry[tpl_field])
tpl_field = unicode_type(entry[tpl_field])
else :
tpl_field = entry[tpl_field]
return ascii_text(tpl_field)
else:
return u''
return ''
if len(template_citation) >0 :
tpl_citation = bibtexclass.utf8ToBibtex(
bibtexclass.ValidateCitationKey(re.sub(u'\\{[^{}]*\\}',
bibtexclass.ValidateCitationKey(re.sub(r'\{[^{}]*\}',
tpl_replace, template_citation)))
if len(tpl_citation) >0 :
return tpl_citation
if len(entry["isbn"]) > 0 :
template_citation = u'%s' % re.sub(u'[\\D]',u'', entry["isbn"])
template_citation = '%s' % re.sub(r'[\D]','', entry["isbn"])
else :
template_citation = u'%s' % str(entry["id"])
template_citation = '%s' % unicode_type(entry["id"])
return bibtexclass.ValidateCitationKey(template_citation)
@ -394,8 +395,8 @@ class BIBTEX(CatalogPlugin):
for entry in data:
entry['ondevice'] = db.catalog_plugin_on_device_temp_mapping[entry['id']]['ondevice']
outfile.write(u'%%%Calibre catalog\n%%%{0} entries in catalog\n\n'.format(nb_entries))
outfile.write(u'@preamble{"This catalog of %d entries was generated by calibre on %s"}\n\n'
outfile.write('%%%Calibre catalog\n%%%{0} entries in catalog\n\n'.format(nb_entries))
outfile.write('@preamble{"This catalog of %d entries was generated by calibre on %s"}\n\n'
% (nb_entries, nowf().strftime("%A, %d. %B %Y %H:%M").decode(preferred_encoding)))
for entry in data:

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
@ -107,10 +108,10 @@ class CSV_XML(CatalogPlugin):
outfile = codecs.open(path_to_output, 'w', 'utf8')
# Write a UTF-8 BOM
outfile.write('\xef\xbb\xbf')
outfile.write('\ufeff')
# Output the field headers
outfile.write(u'%s\n' % u','.join(fields))
outfile.write('%s\n' % ','.join(fields))
# Output the entry fields
for entry in data:
@ -144,26 +145,26 @@ class CSV_XML(CatalogPlugin):
item = ', '.join(item)
elif field == 'isbn':
# Could be 9, 10 or 13 digits, with hyphens, possibly ending in 'X'
item = u'%s' % re.sub(r'[^\dX-]', '', item)
item = '%s' % re.sub(r'[^\dX-]', '', item)
elif fm.get(field, {}).get('datatype') == 'datetime':
item = isoformat(item, as_utc=False)
elif field == 'comments':
item = item.replace(u'\r\n', u' ')
item = item.replace(u'\n', u' ')
item = item.replace('\r\n', ' ')
item = item.replace('\n', ' ')
elif fm.get(field, {}).get('datatype', None) == 'rating' and item:
item = u'%.2g' % (item / 2.0)
item = '%.2g' % (item / 2)
# Convert HTML to markdown text
if isinstance(item, unicode_type):
opening_tag = re.search('<(\\w+)(\x20|>)', item)
opening_tag = re.search(r'<(\w+)( |>)', item)
if opening_tag:
closing_tag = re.search('<\\/%s>$' % opening_tag.group(1), item)
closing_tag = re.search(r'<\/%s>$' % opening_tag.group(1), item)
if closing_tag:
item = html2text(item)
outstr.append(u'"%s"' % unicode_type(item).replace('"', '""'))
outstr.append('"%s"' % unicode_type(item).replace('"', '""'))
outfile.write(u','.join(outstr) + u'\n')
outfile.write(','.join(outstr) + '\n')
outfile.close()
elif self.fmt == 'xml':
@ -191,7 +192,7 @@ class CSV_XML(CatalogPlugin):
if not isinstance(val, (bytes, unicode_type)):
if (fm.get(field, {}).get('datatype', None) ==
'rating' and val):
val = u'%.2g' % (val / 2.0)
val = '%.2g' % (val / 2)
val = unicode_type(val)
item = getattr(E, field)(val)
record.append(item)
@ -221,7 +222,7 @@ class CSV_XML(CatalogPlugin):
if 'series' in fields and r['series']:
record.append(E.series(r['series'],
index=str(r['series_index'])))
index=unicode_type(r['series_index'])))
if 'cover' in fields and r['cover']:
record.append(E.cover(r['cover'].replace(os.sep, '/')))
@ -235,6 +236,6 @@ class CSV_XML(CatalogPlugin):
if 'library_name' in fields:
record.append(E.library_name(current_library))
with open(path_to_output, 'w') as f:
with open(path_to_output, 'wb') as f:
f.write(etree.tostring(root, encoding='utf-8',
xml_declaration=True, pretty_print=True))

View File

@ -16,6 +16,7 @@ from calibre.library import current_library_name
from calibre.library.catalogs import AuthorSortMismatchException, EmptyCatalogException
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.localization import calibre_langcode_to_name, canonicalize_lang, get_lang
from polyglot.builtins import unicode_type
Option = namedtuple('Option', 'option, default, dest, action, help')
@ -60,7 +61,7 @@ class EPUB_MOBI(CatalogPlugin):
"Default: '%default'\n"
"Applies to: AZW3, EPUB, MOBI output formats")),
Option('--exclude-genre',
default='\\[.+\\]|^\\+$',
default=r'\[.+\]|^\+$',
dest='exclude_genre',
action=None,
help=_("Regex describing tags to exclude as genres.\n"
@ -264,7 +265,7 @@ class EPUB_MOBI(CatalogPlugin):
build_log = []
build_log.append(u"%s('%s'): Generating %s %sin %s environment, locale: '%s'" %
build_log.append("%s('%s'): Generating %s %sin %s environment, locale: '%s'" %
(self.name,
current_library_name(),
self.fmt,
@ -282,23 +283,23 @@ class EPUB_MOBI(CatalogPlugin):
if opts.connected_device['is_device_connected'] and \
opts.connected_device['kind'] == 'device':
if opts.connected_device['serial']:
build_log.append(u" connected_device: '%s' #%s%s " %
build_log.append(" connected_device: '%s' #%s%s " %
(opts.connected_device['name'],
opts.connected_device['serial'][0:4],
'x' * (len(opts.connected_device['serial']) - 4)))
for storage in opts.connected_device['storage']:
if storage:
build_log.append(u" mount point: %s" % storage)
build_log.append(" mount point: %s" % storage)
else:
build_log.append(u" connected_device: '%s'" % opts.connected_device['name'])
build_log.append(" connected_device: '%s'" % opts.connected_device['name'])
try:
for storage in opts.connected_device['storage']:
if storage:
build_log.append(u" mount point: %s" % storage)
build_log.append(" mount point: %s" % storage)
except:
build_log.append(u" (no mount points)")
build_log.append(" (no mount points)")
else:
build_log.append(u" connected_device: '%s'" % opts.connected_device['name'])
build_log.append(" connected_device: '%s'" % opts.connected_device['name'])
opts_dict = vars(opts)
if opts_dict['ids']:
@ -337,7 +338,7 @@ class EPUB_MOBI(CatalogPlugin):
sections_list.insert(0, 'Authors')
opts.generate_authors = True
opts.log(u" Sections: %s" % ', '.join(sections_list))
opts.log(" Sections: %s" % ', '.join(sections_list))
opts.section_list = sections_list
# Limit thumb_width to 1.0" - 2.0"
@ -397,7 +398,7 @@ class EPUB_MOBI(CatalogPlugin):
if opts.verbose:
log.info(" Begin catalog source generation (%s)" %
str(datetime.timedelta(seconds=int(time.time() - opts.start_time))))
unicode_type(datetime.timedelta(seconds=int(time.time() - opts.start_time))))
# Launch the Catalog builder
catalog = CatalogBuilder(db, opts, self, report_progress=notification)
@ -406,7 +407,7 @@ class EPUB_MOBI(CatalogPlugin):
catalog.build_sources()
if opts.verbose:
log.info(" Completed catalog source generation (%s)\n" %
str(datetime.timedelta(seconds=int(time.time() - opts.start_time))))
unicode_type(datetime.timedelta(seconds=int(time.time() - opts.start_time))))
except (AuthorSortMismatchException, EmptyCatalogException) as e:
log.error(" *** Terminated catalog generation: %s ***" % e)
except:
@ -499,7 +500,7 @@ class EPUB_MOBI(CatalogPlugin):
if opts.verbose:
log.info(" Catalog creation complete (%s)\n" %
str(datetime.timedelta(seconds=int(time.time() - opts.start_time))))
unicode_type(datetime.timedelta(seconds=int(time.time() - opts.start_time))))
# returns to gui2.actions.catalog:catalog_generated()
return catalog.error

View File

@ -1,8 +1,7 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2010, Greg Riker
from __future__ import print_function
from __future__ import absolute_import, division, print_function, unicode_literals
import datetime
import os
@ -44,7 +43,7 @@ from calibre.utils.localization import get_lang, lang_as_iso639_1
from calibre.utils.zipfile import ZipFile
from polyglot.builtins import unicode_type, iteritems, map, zip
NBSP = u'\u00a0'
NBSP = '\u00a0'
class Formatter(TemplateFormatter):
@ -241,7 +240,7 @@ class CatalogBuilder(object):
index = book['series_index']
integer = int(index)
fraction = index - integer
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
series_index = '%04d%s' % (integer, unicode_type('%0.4f' % fraction).lstrip('0'))
key = '%s ~%s %s' % (self._kf_author_to_author_sort(book['author']),
self.generate_sort_title(book['series']),
series_index)
@ -260,15 +259,15 @@ class CatalogBuilder(object):
(str): sort key
"""
if not book['series']:
fs = u'{:<%d}!{!s}' % longest_author_sort
fs = '{:<%d}!{!s}' % longest_author_sort
key = fs.format(capitalize(book['author_sort']),
capitalize(book['title_sort']))
else:
index = book['series_index']
integer = int(index)
fraction = index - integer
series_index = u'%04d%s' % (integer, str(u'%0.4f' % fraction).lstrip(u'0'))
fs = u'{:<%d}~{!s}{!s}' % longest_author_sort
series_index = '%04d%s' % (integer, unicode_type('%0.4f' % fraction).lstrip('0'))
fs = '{:<%d}~{!s}{!s}' % longest_author_sort
key = fs.format(capitalize(book['author_sort']),
self.generate_sort_title(book['series']),
series_index)
@ -278,7 +277,7 @@ class CatalogBuilder(object):
index = book['series_index']
integer = int(index)
fraction = index - integer
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
series_index = '%04d%s' % (integer, unicode_type('%0.4f' % fraction).lstrip('0'))
key = '%s %s' % (self.generate_sort_title(book['series']),
series_index)
return key
@ -677,9 +676,9 @@ class CatalogBuilder(object):
# Hack to force the cataloged leading letter to be
# an unadorned character if the accented version sorts before the unaccented
exceptions = {
u'Ä': u'A',
u'Ö': u'O',
u'Ü': u'U'
'Ä': 'A',
'Ö': 'O',
'Ü': 'U'
}
if key is not None:
@ -699,7 +698,7 @@ class CatalogBuilder(object):
# Hackhackhackhackhack
# icu returns bogus results with curly apostrophes, maybe others under OS X 10.6.x
# When we see the magic combo of 0/-1 for ordnum/ordlen, special case the logic
last_c = u''
last_c = ''
if ordnum == 0 and ordlen == -1:
if icu_upper(c[0]) != last_c:
last_c = icu_upper(c[0])
@ -955,7 +954,7 @@ class CatalogBuilder(object):
if is_date_undefined(record['pubdate']):
this_title['date'] = None
else:
this_title['date'] = strftime(u'%B %Y', as_local_time(record['pubdate']).timetuple())
this_title['date'] = strftime('%B %Y', as_local_time(record['pubdate']).timetuple())
this_title['timestamp'] = record['timestamp']
@ -1091,11 +1090,11 @@ class CatalogBuilder(object):
from calibre.devices.kindle.bookmark import Bookmark
from calibre.ebooks.metadata import MetaInformation
MBP_FORMATS = [u'azw', u'mobi', u'prc', u'txt']
MBP_FORMATS = ['azw', 'mobi', 'prc', 'txt']
mbp_formats = set(MBP_FORMATS)
PDR_FORMATS = [u'pdf']
PDR_FORMATS = ['pdf']
pdr_formats = set(PDR_FORMATS)
TAN_FORMATS = [u'tpz', u'azw1']
TAN_FORMATS = ['tpz', 'azw1']
tan_formats = set(TAN_FORMATS)
class BookmarkDevice(Device):
@ -1174,7 +1173,7 @@ class CatalogBuilder(object):
book['percent_read'] = min(float(100 * myBookmark.last_read / myBookmark.book_length), 100)
except:
book['percent_read'] = 0
dots = int((book['percent_read'] + 5) / 10)
dots = int((book['percent_read'] + 5) // 10)
dot_string = self.SYMBOL_PROGRESS_READ * dots
empty_dots = self.SYMBOL_PROGRESS_UNREAD * (10 - dots)
book['reading_progress'] = '%s%s' % (dot_string, empty_dots)
@ -1229,11 +1228,11 @@ class CatalogBuilder(object):
clipped to max_len
"""
normalized = massaged = re.sub('\\s', '', ascii_text(tag).lower())
if re.search('\\W', normalized):
normalized = massaged = re.sub(r'\s', '', ascii_text(tag).lower())
if re.search(r'\W', normalized):
normalized = ''
for c in massaged:
if re.search('\\W', c):
if re.search(r'\W', c):
normalized += self.generate_unicode_name(c)
else:
normalized += c
@ -1396,7 +1395,7 @@ class CatalogBuilder(object):
Return:
(str): asciized version of author
"""
return re.sub("\\W", "", ascii_text(author))
return re.sub(r"\W", "", ascii_text(author))
def generate_format_args(self, book):
""" Generate the format args for template substitution.
@ -1411,7 +1410,7 @@ class CatalogBuilder(object):
Return:
(dict): formatted args for templating
"""
series_index = str(book['series_index'])
series_index = unicode_type(book['series_index'])
if series_index.endswith('.0'):
series_index = series_index[:-2]
args = dict(
@ -1661,7 +1660,7 @@ class CatalogBuilder(object):
key=lambda x: sort_key(self._kf_books_by_author_sorter_author_sort(x, len(las))))
# Create a new month anchor
date_string = strftime(u'%B %Y', current_date.timetuple())
date_string = strftime('%B %Y', current_date.timetuple())
pIndexTag = soup.new_tag("p")
pIndexTag['class'] = "date_index"
aTag = soup.new_tag("a")
@ -1919,7 +1918,7 @@ class CatalogBuilder(object):
def _add_books_to_html_by_day(todays_list, dtc):
if len(todays_list):
# Create a new day anchor
date_string = strftime(u'%A, %B %d', current_date.timetuple())
date_string = strftime('%A, %B %d', current_date.timetuple())
pIndexTag = soup.new_tag("p")
pIndexTag['class'] = "date_index"
aTag = soup.new_tag("a")
@ -1981,7 +1980,7 @@ class CatalogBuilder(object):
ptc = 0
# Percent read
dots = int((new_entry['percent_read'] + 5) / 10)
dots = int((new_entry['percent_read'] + 5) // 10)
dot_string = self.SYMBOL_PROGRESS_READ * dots
empty_dots = self.SYMBOL_PROGRESS_UNREAD * (10 - dots)
pBookTag.insert(ptc, NavigableString('%s%s' % (dot_string, empty_dots)))
@ -2690,7 +2689,7 @@ class CatalogBuilder(object):
series_index = ''
if book['series']:
series = book['series']
series_index = str(book['series_index'])
series_index = unicode_type(book['series_index'])
if series_index.endswith('.0'):
series_index = series_index[:-2]
@ -2754,7 +2753,7 @@ class CatalogBuilder(object):
publisher = book['publisher']
# Rating
stars = int(book['rating']) / 2
stars = int(book['rating']) // 2
rating = ''
if stars:
star_string = self.SYMBOL_FULL_RATING * stars
@ -2958,10 +2957,11 @@ class CatalogBuilder(object):
font = ImageFont.truetype(default_font, 48)
text = self.opts.catalog_title.encode('utf-8')
width, height = draw.textsize(text, font=font)
left = max(int((MI_WIDTH - width) / 2.), 0)
top = max(int((MI_HEIGHT - height) / 2.), 0)
left = max(int((MI_WIDTH - width) / 2), 0)
top = max(int((MI_HEIGHT - height) / 2), 0)
draw.text((left, top), text, fill=(0, 0, 0), font=font)
img.save(open(out_path, 'wb'), 'GIF')
with open(out_path, 'wb') as f:
img.save(f, 'GIF')
def generate_ncx_header(self):
""" Generate the basic NCX file.
@ -3099,7 +3099,7 @@ class CatalogBuilder(object):
navLabelTag = ncx_soup.new_tag("navLabel")
textTag = ncx_soup.new_tag("text")
if book['series']:
series_index = str(book['series_index'])
series_index = unicode_type(book['series_index'])
if series_index.endswith('.0'):
series_index = series_index[:-2]
if self.generate_for_kindle_mobi:
@ -3693,7 +3693,7 @@ class CatalogBuilder(object):
# Add *article* entries for each populated month
# master_months_list{}: [0]:titles list [1]:date
for books_by_month in master_month_list:
datestr = strftime(u'%B %Y', books_by_month[1].timetuple())
datestr = strftime('%B %Y', books_by_month[1].timetuple())
navPointByMonthTag = ncx_soup.new_tag('navPoint')
if self.generate_for_kindle_mobi:
navPointByMonthTag['class'] = "article"
@ -3843,7 +3843,7 @@ class CatalogBuilder(object):
# Add *article* entries for each populated day
# master_day_list{}: [0]:titles list [1]:date
for books_by_day in master_day_list:
datestr = strftime(u'%A, %B %d', books_by_day[1].timetuple())
datestr = strftime('%A, %B %d', books_by_day[1].timetuple())
navPointByDayTag = ncx_soup.new_tag('navPoint')
if self.generate_for_kindle_mobi:
navPointByDayTag['class'] = "article"
@ -3994,7 +3994,7 @@ class CatalogBuilder(object):
for title in genre['books']:
titles.append(title['title'])
titles = sorted(titles, key=lambda x: (self.generate_sort_title(x), self.generate_sort_title(x)))
titles_list = self.generate_short_description(u"".join(titles), dest="description")
titles_list = self.generate_short_description("".join(titles), dest="description")
cmTag.insert(0, NavigableString(self.format_ncx_text(titles_list, dest='description')))
navPointVolumeTag.insert(3, cmTag)
@ -4204,7 +4204,7 @@ class CatalogBuilder(object):
rating = ''
try:
if 'rating' in book:
stars = int(book['rating']) / 2
stars = int(book['rating']) // 2
if stars:
star_string = self.SYMBOL_FULL_RATING * stars
empty_stars = self.SYMBOL_EMPTY_RATING * (5 - stars)
@ -4228,9 +4228,9 @@ class CatalogBuilder(object):
# Generate a legal XHTML id/href string
if self.letter_or_symbol(series) == self.SYMBOLS:
return "symbol_%s_series" % re.sub('\\W', '', series).lower()
return "symbol_%s_series" % re.sub(r'\W', '', series).lower()
else:
return "%s_series" % re.sub('\\W', '', ascii_text(series)).lower()
return "%s_series" % re.sub(r'\W', '', ascii_text(series)).lower()
def generate_short_description(self, description, dest=None):
""" Generate a truncated version of the supplied string.
@ -4311,7 +4311,7 @@ class CatalogBuilder(object):
else:
if re.match('[0-9]+', word[0]):
word = word.replace(',', '')
suffix = re.search('[\\D]', word)
suffix = re.search(r'[\D]', word)
if suffix:
word = '%10.0f%s' % (float(word[:suffix.start()]), word[suffix.start():])
else:
@ -4327,7 +4327,7 @@ class CatalogBuilder(object):
else:
if re.search('[0-9]+', word[0]):
word = word.replace(',', '')
suffix = re.search('[\\D]', word)
suffix = re.search(r'[\D]', word)
if suffix:
word = '%10.0f%s' % (float(word[:suffix.start()]), word[suffix.start():])
else:
@ -4488,7 +4488,7 @@ class CatalogBuilder(object):
Return:
(str): legal XHTML anchor string of unicode character name
"""
fullname = u''.join(unicodedata.name(unicode_type(cc)) for cc in c)
fullname = ''.join(unicodedata.name(unicode_type(cc)) for cc in c)
terms = fullname.split()
return "_".join(terms)
@ -4520,7 +4520,7 @@ class CatalogBuilder(object):
matched = list(set(record['tags']) & set(excluded_tags))
if matched:
for rule in self.opts.exclusion_rules:
if rule[1] == _('Tags') and rule[2] == str(matched[0]):
if rule[1] == _('Tags') and rule[2] == unicode_type(matched[0]):
self.opts.log.info(" - '%s' by %s (Exclusion rule '%s')" %
(record['title'], record['authors'][0], rule[0]))
@ -4807,12 +4807,12 @@ class CatalogBuilder(object):
self.progress_int = 0.01
self.reporter(self.progress_int, self.progress_string)
if self.opts.cli_environment:
log_msg = u"%3.0f%% %s" % (self.progress_int * 100, self.progress_string)
log_msg = "%3.0f%% %s" % (self.progress_int * 100, self.progress_string)
if self.opts.verbose:
log_msg += " (%s)" % str(datetime.timedelta(seconds=int(time.time() - self.opts.start_time)))
log_msg += " (%s)" % unicode_type(datetime.timedelta(seconds=int(time.time() - self.opts.start_time)))
else:
log_msg = ("%s (%s)" % (self.progress_string,
str(datetime.timedelta(seconds=int(time.time() - self.opts.start_time)))))
unicode_type(datetime.timedelta(seconds=int(time.time() - self.opts.start_time)))))
self.opts.log(log_msg)
def update_progress_micro_step(self, description, micro_step_pct):

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import absolute_import, division, print_function, unicode_literals
from __future__ import print_function
__license__ = 'GPL v3'
__copyright__ = '2010, Greg Riker'
__docformat__ = 'restructuredtext en'
@ -44,7 +44,7 @@ class NumberToText(object): # {{{
# Build the hundreds component
if hundredsComponent:
hundredsComponentString = "%s hundred" % self.hundreds[hundredsComponent/100]
hundredsComponentString = "%s hundred" % self.hundreds[hundredsComponent//100]
else:
hundredsComponentString = ""
@ -56,7 +56,7 @@ class NumberToText(object): # {{{
onesPart = ""
# Get the tens part
tensPart = self.tens[tensComponent / 10]
tensPart = self.tens[tensComponent // 10]
onesPart = self.lessThanTwenty[tensComponent % 10]
if intToTranslate % 10:
@ -90,8 +90,8 @@ class NumberToText(object): # {{{
# Special case ordinals
if re.search('[st|nd|rd|th]',self.number):
self.number = re.sub(',','',self.number)
ordinal_suffix = re.search('[\\D]', self.number)
ordinal_number = re.sub('\\D','',re.sub(',','',self.number))
ordinal_suffix = re.search(r'[\D]', self.number)
ordinal_number = re.sub(r'\D','',re.sub(',','',self.number))
if self.verbose:
self.log("Ordinal: %s" % ordinal_number)
self.number_as_float = ordinal_number
@ -155,8 +155,8 @@ class NumberToText(object): # {{{
if self.verbose:
self.log("Hybrid: %s" % self.number)
# Split the token into number/text
number_position = re.search('\\d',self.number).start()
text_position = re.search('\\D',self.number).start()
number_position = re.search(r'\d',self.number).start()
text_position = re.search(r'\D',self.number).start()
if number_position < text_position:
number = self.number[:text_position]
text = self.number[text_position:]
@ -183,8 +183,8 @@ class NumberToText(object): # {{{
self.text = "one billion"
else :
# Isolate the three-digit number groups
millionsNumber = number/10**6
thousandsNumber = (number - (millionsNumber * 10**6))/10**3
millionsNumber = number//10**6
thousandsNumber = (number - (millionsNumber * 10**6))//10**3
hundredsNumber = number - (millionsNumber * 10**6) - (thousandsNumber * 10**3)
if self.verbose:
print("Converting %s %s %s" % (millionsNumber, thousandsNumber, hundredsNumber))
@ -196,7 +196,7 @@ class NumberToText(object): # {{{
# Convert thousandsNumber
if thousandsNumber:
if number > 1099 and number < 2000:
resultString = '%s %s' % (self.lessThanTwenty[number/100],
resultString = '%s %s' % (self.lessThanTwenty[number//100],
self.stringFromInt(number % 100))
self.text = resultString.strip().capitalize()
return
@ -222,6 +222,6 @@ class NumberToText(object): # {{{
resultString = "zero"
if self.verbose:
self.log(u'resultString: %s' % resultString)
self.log('resultString: %s' % resultString)
self.text = resultString.strip().capitalize()
# }}}

View File

@ -1,9 +1,12 @@
from __future__ import print_function
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''
Backend that implements storage of ebooks in an sqlite database.
'''
import sqlite3 as sqlite
import datetime, re, sre_constants
from zlib import compress, decompress
@ -57,7 +60,7 @@ def _connect(path):
conn = sqlite.connect(path, factory=Connection, detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES)
conn.row_factory = lambda cursor, row : list(row)
conn.create_aggregate('concat', 1, Concatenate)
title_pat = re.compile('^(A|The|An)\\s+', re.IGNORECASE)
title_pat = re.compile(r'^(A|The|An)\s+', re.IGNORECASE)
def title_sort(title):
match = title_pat.search(title)

View File

@ -1,4 +1,5 @@
from __future__ import with_statement
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
@ -6,6 +7,7 @@ __docformat__ = 'restructuredtext en'
'''
The database used to store ebook metadata
'''
import os, sys, shutil, glob, time, functools, traceback, re, \
json, uuid, hashlib, copy, numbers
from collections import defaultdict, namedtuple
@ -91,7 +93,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if self._library_id_ is None:
ans = self.conn.get('SELECT uuid FROM library_id', all=False)
if ans is None:
ans = str(uuid.uuid4())
ans = unicode_type(uuid.uuid4())
self.library_id = ans
else:
self._library_id_ = ans
@ -256,11 +258,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
from calibre.library.coloring import migrate_old_rule
old_rules = []
for i in range(1, 6):
col = self.prefs.get('column_color_name_'+str(i), None)
templ = self.prefs.get('column_color_template_'+str(i), None)
col = self.prefs.get('column_color_name_'+unicode_type(i), None)
templ = self.prefs.get('column_color_template_'+unicode_type(i), None)
if col and templ:
try:
del self.prefs['column_color_name_'+str(i)]
del self.prefs['column_color_name_'+unicode_type(i)]
rules = migrate_old_rule(self.field_metadata, templ)
for templ in rules:
old_rules.append((col, templ))
@ -359,7 +361,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
''')
self.conn.execute(
'UPDATE authors SET sort=author_to_author_sort(name) WHERE sort IS NULL')
self.conn.executescript(u'''
self.conn.executescript('''
CREATE TEMP VIEW IF NOT EXISTS tag_browser_news AS SELECT DISTINCT
id,
name,
@ -372,7 +374,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
(SELECT id FROM tags WHERE name="{0}")));
'''.format(_('News')))
self.conn.executescript(u'''
self.conn.executescript('''
CREATE TEMP VIEW IF NOT EXISTS tag_browser_filtered_news AS SELECT DISTINCT
id,
name,
@ -427,7 +429,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
custom_map = self.custom_columns_in_meta()
# custom col labels are numbers (the id in the custom_columns table)
custom_cols = list(sorted(custom_map.keys()))
custom_cols = sorted(custom_map.keys())
lines.extend([custom_map[x] for x in custom_cols])
self.FIELD_MAP = {'id':0, 'title':1, 'authors':2, 'timestamp':3,
@ -450,7 +452,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# account for the series index column. Field_metadata knows that
# the series index is one larger than the series. If you change
# it here, be sure to change it there as well.
self.FIELD_MAP[str(col)+'_index'] = base = base+1
self.FIELD_MAP[unicode_type(col)+'_index'] = base = base+1
self.field_metadata.set_field_record_index(
self.custom_column_num_map[col]['label']+'_index',
base,
@ -487,7 +489,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# There is a chance that these can be duplicates of an existing
# user category. Print the exception and continue.
try:
self.field_metadata.add_user_category(label=u'@' + cat, name=cat)
self.field_metadata.add_user_category(label='@' + cat, name=cat)
except:
traceback.print_exc()
@ -1127,7 +1129,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
try:
quathors = mi.authors[:10] # Too many authors causes parsing of
# the search expression to fail
query = u' and '.join([u'author:"=%s"'%(a.replace('"', '')) for a in
query = ' and '.join(['author:"=%s"'%(a.replace('"', '')) for a in
quathors])
qauthors = mi.authors[10:]
except ValueError:
@ -1747,7 +1749,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.id = id
def __unicode_representation__(self):
return u'n=%s s=%s c=%d rt=%d rc=%d id=%s' % (
return 'n=%s s=%s c=%d rt=%d rc=%d id=%s' % (
self.n, self.s, self.c, self.rt, self.rc, self.id)
if ispy3:
@ -1977,7 +1979,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# Duplicate the build of items below to avoid using a lambda func
# in the main Tag loop. Saves a few %
if datatype == 'rating':
formatter = (lambda x:u'\u2605'*int(x/2))
formatter = (lambda x:'\u2605'*int(x//2))
avgr = lambda x: x.n
# eliminate the zero ratings line as well as count == 0
items = [v for v in tcategories[category].values() if v.c > 0 and v.n != 0]
@ -2613,7 +2615,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if commit:
self.conn.commit()
self.data.set(book_id, self.FIELD_MAP['languages'],
u','.join(final_languages), row_is_id=True)
','.join(final_languages), row_is_id=True)
if notify:
self.notify('metadata', [book_id])
return books_to_refresh
@ -2992,7 +2994,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
tags = [x.strip().replace(',', ';') for x in tags if x.strip()]
tags = [x.decode(preferred_encoding, 'replace')
if isbytestring(x) else x for x in tags]
tags = [u' '.join(x.split()) for x in tags]
tags = [' '.join(x.split()) for x in tags]
ans, seen = [], set()
for tag in tags:
if tag.lower() not in seen:
@ -3068,7 +3070,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.conn.commit()
for x in ids:
tags = u','.join(self.get_tags(x))
tags = ','.join(self.get_tags(x))
self.data.set(x, self.FIELD_MAP['tags'], tags, row_is_id=True)
if notify:
self.notify('metadata', ids)
@ -3124,7 +3126,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.dirtied({id}|books_to_refresh, commit=False)
if commit:
self.conn.commit()
tags = u','.join(self.get_tags(id))
tags = ','.join(self.get_tags(id))
self.data.set(id, self.FIELD_MAP['tags'], tags, row_is_id=True)
if notify:
self.notify('metadata', [id])
@ -3178,7 +3180,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if not isinstance(series, unicode_type):
series = series.decode(preferred_encoding, 'replace')
series = series.strip()
series = u' '.join(series.split())
series = ' '.join(series.split())
sx = self.conn.get('SELECT id,name from series WHERE name=?', (series,))
if sx:
aid, cur_name = sx[0]
@ -3517,19 +3519,18 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.set_metadata(id, mi, commit=True, ignore_errors=True)
npath = self.run_import_plugins(path, format)
format = os.path.splitext(npath)[-1].lower().replace('.', '').upper()
stream = lopen(npath, 'rb')
format = check_ebook_format(stream, format)
self.add_format(id, format, stream, index_is_id=True)
stream.close()
with lopen(npath, 'rb') as stream:
format = check_ebook_format(stream, format)
self.add_format(id, format, stream, index_is_id=True)
postimport.append((id, format))
self.conn.commit()
self.data.refresh_ids(self, ids) # Needed to update format list and size
for book_id, fmt in postimport:
run_plugins_on_postimport(self, book_id, fmt)
if duplicates:
paths = list(duplicate[0] for duplicate in duplicates)
formats = list(duplicate[1] for duplicate in duplicates)
metadata = list(duplicate[2] for duplicate in duplicates)
paths = [duplicate[0] for duplicate in duplicates]
formats = [duplicate[1] for duplicate in duplicates]
metadata = [duplicate[2] for duplicate in duplicates]
return (paths, formats, metadata), (ids if return_ids else
len(ids))
return None, (ids if return_ids else len(ids))

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
@ -217,7 +217,7 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
if hasattr(mi, 'last_modified') and hasattr(mi.last_modified, 'timetuple'):
format_args['last_modified'] = strftime(timefmt, mi.last_modified.timetuple())
format_args['id'] = str(id)
format_args['id'] = unicode_type(id)
# Now format the custom fields
custom_metadata = mi.get_all_user_metadata(make_copy=False)
for key in custom_metadata:
@ -247,7 +247,7 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
components = [x.strip() for x in components.split('/')]
components = [sanitize_func(x) for x in components if x]
if not components:
components = [str(id)]
components = [unicode_type(id)]
if to_lowercase:
components = [x.lower() for x in components]
if replace_whitespace:
@ -360,7 +360,7 @@ def do_save_book_to_disk(db, book_id, mi, plugboards,
return not formats_written, book_id, mi.title
for fmt in formats:
fmt_path = base_path+'.'+str(fmt)
fmt_path = base_path+'.'+unicode_type(fmt)
try:
db.copy_format_to(book_id, fmt, fmt_path)
formats_written = True

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import print_function, with_statement
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
@ -593,7 +593,7 @@ class SchemaUpgrade(object):
existing = frozenset(map(int, custom_recipes))
if id_ in existing:
id_ = max(existing) + 1000
id_ = str(id_)
id_ = unicode_type(id_)
fname = custom_recipe_filename(id_, title)
custom_recipes[id_] = (title, fname)
if isinstance(script, unicode_type):

View File

@ -1,4 +1,5 @@
from __future__ import print_function, with_statement
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
@ -7,6 +8,7 @@ __docformat__ = 'restructuredtext en'
Wrapper for multi-threaded access to a single sqlite database connection. Serializes
all calls.
'''
import sqlite3 as sqlite, traceback, time, uuid, os
from sqlite3 import IntegrityError, OperationalError
from threading import Thread
@ -20,7 +22,7 @@ from calibre import isbytestring, force_unicode
from calibre.constants import iswindows, DEBUG, plugins, plugins_loc
from calibre.utils.icu import sort_key
from calibre import prints
from polyglot.builtins import unicode_type, cmp
from polyglot.builtins import cmp, native_string_type, unicode_type
from polyglot import reprlib
from polyglot.queue import Queue
@ -78,7 +80,7 @@ def adapt_datetime(dt):
sqlite.register_adapter(datetime, adapt_datetime)
sqlite.register_converter('timestamp', convert_timestamp)
sqlite.register_converter(native_string_type('timestamp'), convert_timestamp)
def convert_bool(val):
@ -86,8 +88,8 @@ def convert_bool(val):
sqlite.register_adapter(bool, lambda x : 1 if x else 0)
sqlite.register_converter('bool', convert_bool)
sqlite.register_converter('BOOL', convert_bool)
sqlite.register_converter(native_string_type('bool'), convert_bool)
sqlite.register_converter(native_string_type('BOOL'), convert_bool)
class DynamicFilter(object):
@ -162,7 +164,7 @@ class IdentifiersConcat(object):
self.ans = []
def step(self, key, val):
self.ans.append(u'%s:%s'%(key, val))
self.ans.append('%s:%s'%(key, val))
def finalize(self):
try:
@ -262,15 +264,15 @@ def do_connect(path, row_factory=None):
conn.row_factory = sqlite.Row if row_factory else (lambda cursor, row : list(row))
conn.create_aggregate('concat', 1, Concatenate)
conn.create_aggregate('aum_sortconcat', 4, AumSortedConcatenate)
conn.create_collation('PYNOCASE', partial(pynocase,
conn.create_collation(native_string_type('PYNOCASE'), partial(pynocase,
encoding=encoding))
conn.create_function('title_sort', 1, title_sort)
conn.create_function('author_to_author_sort', 1,
_author_to_author_sort)
conn.create_function('uuid4', 0, lambda : str(uuid.uuid4()))
conn.create_function('uuid4', 0, lambda : unicode_type(uuid.uuid4()))
# Dummy functions for dynamically created filters
conn.create_function('books_list_filter', 1, lambda x: 1)
conn.create_collation('icucollate', icu_collator)
conn.create_collation(native_string_type('icucollate'), icu_collator)
return conn
@ -320,7 +322,7 @@ class DBThread(Thread):
break
except OperationalError as err:
# Retry if unable to open db file
e = str(err)
e = unicode_type(err)
if 'unable to open' not in e or i == 2:
if 'unable to open' in e:
prints('Unable to open database for func',