diff --git a/manual/epub.py b/manual/epub.py index f16652b56d..dd93e34817 100644 --- a/manual/epub.py +++ b/manual/epub.py @@ -15,6 +15,7 @@ from calibre.ebooks.oeb.polish.container import get_container, OEB_DOCS from calibre.ebooks.oeb.polish.check.links import check_links, UnreferencedResource from calibre.ebooks.oeb.polish.pretty import pretty_html_tree, pretty_opf from calibre.utils.imghdr import identify +from polyglot.builtins import iteritems class EPUBHelpBuilder(EpubBuilder): @@ -28,7 +29,7 @@ class EPUBHelpBuilder(EpubBuilder): def fix_epub(self, container): ' Fix all the brokenness that sphinx\'s epub builder creates ' - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS: self.workaround_ade_quirks(container, name) pretty_html_tree(container, container.parsed(name)) @@ -49,9 +50,9 @@ class EPUBHelpBuilder(EpubBuilder): def fix_opf(self, container): spine_names = {n for n, l in container.spine_names} spine = container.opf_xpath('//opf:spine')[0] - rmap = {v:k for k, v in container.manifest_id_map.iteritems()} + rmap = {v:k for k, v in iteritems(container.manifest_id_map)} # Add unreferenced text files to the spine - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS and name not in spine_names: spine_names.add(name) container.insert_into_xml(spine, spine.makeelement(OPF('itemref'), idref=rmap[name])) diff --git a/setup.cfg b/setup.cfg index af4550aa0a..2198e55434 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,6 +2,8 @@ max-line-length = 160 builtins = _,dynamic_property,__,P,I,lopen,icu_lower,icu_upper,icu_title,ngettext,connect_lambda ignore = E12,E203,E22,E231,E241,E401,E402,E731,W391,E722,E741,W504 +per-file-ignores = + src/polyglot/*:F401 [yapf] based_on_style = pep8 diff --git a/setup/browser_data.py b/setup/browser_data.py index 16b3f1fbab..7ee2e6263f 100644 --- a/setup/browser_data.py +++ b/setup/browser_data.py @@ -10,11 +10,13 @@ from datetime import datetime from setup import download_securely +from polyglot.builtins import filter + is_ci = os.environ.get('CI', '').lower() == 'true' def filter_ans(ans): - return filter(None, (x.strip() for x in ans)) + return list(filter(None, (x.strip() for x in ans))) def common_user_agents(): diff --git a/setup/plugins_mirror.py b/setup/plugins_mirror.py index 0d799cb3ab..f2424384b5 100644 --- a/setup/plugins_mirror.py +++ b/setup/plugins_mirror.py @@ -33,6 +33,7 @@ from email.utils import parsedate from functools import partial from multiprocessing.pool import ThreadPool from xml.sax.saxutils import escape, quoteattr +from polyglot.builtins import iteritems, itervalues # }}} USER_AGENT = 'calibre mirror' @@ -292,7 +293,7 @@ def get_plugin_info(raw, check_for_qt5=False): metadata = names[inits[0]] else: # Legacy plugin - for name, val in names.iteritems(): + for name, val in iteritems(names): if name.endswith('plugin.py'): metadata = val break @@ -331,7 +332,7 @@ def update_plugin_from_entry(plugin, entry): def fetch_plugin(old_index, entry): - lm_map = {plugin['thread_id']:plugin for plugin in old_index.itervalues()} + lm_map = {plugin['thread_id']:plugin for plugin in itervalues(old_index)} raw = read(entry.url) url, name = parse_plugin_zip_url(raw) if url is None: @@ -373,10 +374,10 @@ def parallel_fetch(old_index, entry): def log(*args, **kwargs): - print (*args, **kwargs) + print(*args, **kwargs) with open('log', 'a') as f: kwargs['file'] = f - print (*args, **kwargs) + print(*args, **kwargs) def atomic_write(raw, name): @@ -403,7 +404,7 @@ def fetch_plugins(old_index): log('Failed to get plugin', entry.name, 'at', datetime.utcnow().isoformat(), 'with error:') log(plugin) # Move staged files - for plugin in ans.itervalues(): + for plugin in itervalues(ans): if plugin['file'].startswith('staging_'): src = plugin['file'] plugin['file'] = src.partition('_')[-1] @@ -411,7 +412,7 @@ def fetch_plugins(old_index): raw = bz2.compress(json.dumps(ans, sort_keys=True, indent=4, separators=(',', ': '))) atomic_write(raw, PLUGINS) # Cleanup any extra .zip files - all_plugin_files = {p['file'] for p in ans.itervalues()} + all_plugin_files = {p['file'] for p in itervalues(ans)} extra = set(glob.glob('*.zip')) - all_plugin_files for x in extra: os.unlink(x) @@ -498,7 +499,7 @@ h1 { text-align: center } name, count = x return '%s%s\n' % (escape(name), count) - pstats = map(plugin_stats, sorted(stats.iteritems(), reverse=True, key=lambda x:x[1])) + pstats = map(plugin_stats, sorted(iteritems(stats), reverse=True, key=lambda x:x[1])) stats = '''\ @@ -681,7 +682,7 @@ def test_parse(): # {{{ new_entries = tuple(parse_index(raw)) for i, entry in enumerate(old_entries): if entry != new_entries[i]: - print ('The new entry: %s != %s' % (new_entries[i], entry)) + print('The new entry: %s != %s' % (new_entries[i], entry)) raise SystemExit(1) pool = ThreadPool(processes=20) urls = [e.url for e in new_entries] @@ -698,7 +699,7 @@ def test_parse(): # {{{ break new_url, aname = parse_plugin_zip_url(raw) if new_url != full_url: - print ('new url (%s): %s != %s for plugin at: %s' % (aname, new_url, full_url, url)) + print('new url (%s): %s != %s for plugin at: %s' % (aname, new_url, full_url, url)) raise SystemExit(1) # }}} diff --git a/setup/resources.py b/setup/resources.py index 7f9fc7e1db..9855dad9dc 100644 --- a/setup/resources.py +++ b/setup/resources.py @@ -64,7 +64,7 @@ class Coffee(Command): # {{{ for src in self.COFFEE_DIRS: for f in glob.glob(self.j(self.SRC, __appname__, src, '*.coffee')): - bn = os.path.basename(f).rpartition('.')[0] + bn = self.b(f).rpartition('.')[0] arcname = src.replace('/', '.') + '.' + bn + '.js' try: with open(f, 'rb') as fs: @@ -270,7 +270,7 @@ class RecentUAs(Command): # {{{ from setup.browser_data import get_data data = get_data() with open(self.UA_PATH, 'wb') as f: - f.write(json.dumps(data, indent=2)) + f.write(json.dumps(data, indent=2).encode('utf-8')) # }}} @@ -300,7 +300,7 @@ class Resources(Command): # {{{ dest = self.j(self.RESOURCES, 'scripts.calibre_msgpack') if self.newer(dest, self.j(self.SRC, 'calibre', 'linux.py')): - self.info('\tCreating ' + os.path.basename(dest)) + self.info('\tCreating ' + self.b(dest)) with open(dest, 'wb') as f: f.write(msgpack_dumps(scripts)) @@ -325,7 +325,7 @@ class Resources(Command): # {{{ with zipfile.ZipFile(dest, 'w', zipfile.ZIP_STORED) as zf: for n in sorted(files, key=self.b): with open(n, 'rb') as f: - zf.writestr(os.path.basename(n), f.read()) + zf.writestr(self.b(n), f.read()) dest = self.j(self.RESOURCES, 'ebook-convert-complete.calibre_msgpack') files = [] @@ -334,7 +334,7 @@ class Resources(Command): # {{{ if f.endswith('.py'): files.append(self.j(x[0], f)) if self.newer(dest, files): - self.info('\tCreating ' + dest) + self.info('\tCreating ' + self.b(dest)) complete = {} from calibre.ebooks.conversion.plumber import supported_input_formats complete['input_fmts'] = set(supported_input_formats()) diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py index 5f441311e4..e17ab12edb 100644 --- a/src/calibre/__init__.py +++ b/src/calibre/__init__.py @@ -4,7 +4,8 @@ __copyright__ = '2008, Kovid Goyal ' __docformat__ = 'restructuredtext en' import sys, os, re, time, random, warnings -from polyglot.builtins import builtins, codepoint_to_chr, unicode_type, range +from polyglot.builtins import (builtins, codepoint_to_chr, iteritems, + itervalues, unicode_type, range) builtins.__dict__['dynamic_property'] = lambda func: func(None) from math import floor from functools import partial @@ -706,7 +707,7 @@ def remove_bracketed_text(src, counts = Counter() buf = [] src = force_unicode(src) - rmap = dict([(v, k) for k, v in brackets.iteritems()]) + rmap = dict([(v, k) for k, v in iteritems(brackets)]) for char in src: if char in brackets: counts[char] += 1 @@ -714,7 +715,7 @@ def remove_bracketed_text(src, idx = rmap[char] if counts[idx] > 0: counts[idx] -= 1 - elif sum(counts.itervalues()) < 1: + elif sum(itervalues(counts)) < 1: buf.append(char) return u''.join(buf) diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index 2a6135fae5..15568991f7 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -212,7 +212,7 @@ class Plugin(object): # {{{ For example to load an image:: pixmap = QPixmap() - pixmap.loadFromData(self.load_resources(['images/icon.png']).itervalues().next()) + next(pixmap.loadFromData(self.load_resources(['images/icon.png']).itervalues()) icon = QIcon(pixmap) :param names: List of paths to resources in the ZIP file using / as separator diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 74a729c135..1229cbf712 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -23,6 +23,7 @@ from calibre.utils.config import (make_config_dir, Config, ConfigProxy, plugin_dir, OptionParser) from calibre.ebooks.metadata.sources.base import Source from calibre.constants import DEBUG, numeric_version +from polyglot.builtins import iteritems, itervalues builtin_names = frozenset(p.name for p in builtin_plugins) BLACKLISTED_PLUGINS = frozenset({'Marvin XD', 'iOS reader applications'}) @@ -195,7 +196,7 @@ def run_plugins_on_postimport(db, book_id, fmt): try: plugin.postimport(book_id, fmt, db) except: - print ('Running file type plugin %s failed with traceback:'% + print('Running file type plugin %s failed with traceback:'% plugin.name) traceback.print_exc() @@ -210,7 +211,7 @@ def run_plugins_on_postadd(db, book_id, fmt_map): try: plugin.postadd(book_id, fmt_map, db) except Exception: - print ('Running file type plugin %s failed with traceback:'% + print('Running file type plugin %s failed with traceback:'% plugin.name) traceback.print_exc() @@ -347,7 +348,7 @@ def reread_metadata_plugins(): return (1 if plugin.plugin_path is None else 0), plugin.name for group in (_metadata_readers, _metadata_writers): - for plugins in group.itervalues(): + for plugins in itervalues(group): if len(plugins) > 1: plugins.sort(key=key) @@ -640,7 +641,7 @@ def patch_metadata_plugins(possibly_updated_plugins): # Metadata source plugins dont use initialize() but that # might change in the future, so be safe. patches[i].initialize() - for i, pup in patches.iteritems(): + for i, pup in iteritems(patches): _initialized_plugins[i] = pup # }}} @@ -727,7 +728,7 @@ def initialize_plugins(perf=False): sys.stdout, sys.stderr = ostdout, ostderr if perf: for x in sorted(times, key=lambda x:times[x]): - print ('%50s: %.3f'%(x, times[x])) + print('%50s: %.3f'%(x, times[x])) _initialized_plugins.sort(cmp=lambda x,y:cmp(x.priority, y.priority), reverse=True) reread_filetype_plugins() reread_metadata_plugins() diff --git a/src/calibre/customize/zipplugin.py b/src/calibre/customize/zipplugin.py index 95c18da1b2..fec7842afd 100644 --- a/src/calibre/customize/zipplugin.py +++ b/src/calibre/customize/zipplugin.py @@ -2,7 +2,6 @@ # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai from __future__ import (unicode_literals, division, absolute_import, print_function) -from polyglot.builtins import map, unicode_type __license__ = 'GPL v3' __copyright__ = '2011, Kovid Goyal ' @@ -15,7 +14,8 @@ from functools import partial from calibre import as_unicode from calibre.customize import (Plugin, numeric_version, platform, InvalidPlugin, PluginNotFound) -from polyglot.builtins import string_or_bytes +from polyglot.builtins import (itervalues, iterkeys, map, + string_or_bytes, unicode_type) # PEP 302 based plugin loading mechanism, works around the bug in zipimport in # python 2.x that prevents importing from zip files in locations whose paths @@ -202,7 +202,7 @@ class PluginLoader(object): else: m = importlib.import_module(plugin_module) plugin_classes = [] - for obj in m.__dict__.itervalues(): + for obj in itervalues(m.__dict__): if isinstance(obj, type) and issubclass(obj, Plugin) and \ obj.name != 'Trivial Plugin': plugin_classes.append(obj) @@ -281,7 +281,7 @@ class PluginLoader(object): # Legacy plugins if '__init__' not in names: - for name in list(names.iterkeys()): + for name in list(iterkeys(names)): if '.' not in name and name.endswith('plugin'): names['__init__'] = names[name] break diff --git a/src/calibre/db/__init__.py b/src/calibre/db/__init__.py index 87144e4890..82ff46b5e4 100644 --- a/src/calibre/db/__init__.py +++ b/src/calibre/db/__init__.py @@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en' SPOOL_SIZE = 30*1024*1024 import numbers -from polyglot.builtins import range +from polyglot.builtins import iteritems, range def _get_next_series_num_for_list(series_indices, unwrap=True): @@ -82,7 +82,7 @@ def get_data_as_dict(self, prefix=None, authors_as_string=False, ids=None, conve 'rating', 'timestamp', 'size', 'tags', 'comments', 'series', 'series_index', 'uuid', 'pubdate', 'last_modified', 'identifiers', 'languages']).union(set(fdata)) - for x, data in fdata.iteritems(): + for x, data in iteritems(fdata): if data['datatype'] == 'series': FIELDS.add('%d_index'%x) data = [] diff --git a/src/calibre/db/adding.py b/src/calibre/db/adding.py index 44fa239ed5..febd2dda5c 100644 --- a/src/calibre/db/adding.py +++ b/src/calibre/db/adding.py @@ -8,7 +8,7 @@ __copyright__ = '2013, Kovid Goyal ' import os, time, re from collections import defaultdict -from polyglot.builtins import map, unicode_type +from polyglot.builtins import itervalues, map, unicode_type from contextlib import contextmanager from functools import partial @@ -137,7 +137,7 @@ def find_books_in_directory(dirpath, single_book_per_directory, compiled_rules=( if allow_path(path, ext, compiled_rules): formats[ext] = path if formats_ok(formats): - yield list(formats.itervalues()) + yield list(itervalues(formats)) else: books = defaultdict(dict) for path in listdir_impl(dirpath, sort_by_mtime=True): @@ -145,9 +145,9 @@ def find_books_in_directory(dirpath, single_book_per_directory, compiled_rules=( if allow_path(path, ext, compiled_rules): books[icu_lower(key) if isinstance(key, unicode_type) else key.lower()][ext] = path - for formats in books.itervalues(): + for formats in itervalues(books): if formats_ok(formats): - yield list(formats.itervalues()) + yield list(itervalues(formats)) def create_format_map(formats): diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py index e7b5b55ac4..ba9e696ce5 100644 --- a/src/calibre/db/backend.py +++ b/src/calibre/db/backend.py @@ -12,7 +12,8 @@ import os, shutil, uuid, json, glob, time, hashlib, errno, sys from functools import partial import apsw -from polyglot.builtins import unicode_type, reraise, string_or_bytes +from polyglot.builtins import (iteritems, iterkeys, itervalues, + unicode_type, reraise, string_or_bytes) from calibre import isbytestring, force_unicode, prints, as_unicode from calibre.constants import (iswindows, filesystem_encoding, @@ -46,7 +47,7 @@ from calibre.db.tables import (OneToOneTable, ManyToOneTable, ManyToManyTable, Differences in semantics from pysqlite: 1. execute/executemany operate in autocommit mode - 2. There is no fetchone() method on cursor objects, instead use next() + 2. There is no fetchone() method on cursor objects, instead use next(cursor) 3. There is no executescript ''' @@ -120,7 +121,7 @@ class DBPrefs(dict): # {{{ raw = self.to_raw(val) with self.db.conn: try: - dbraw = self.db.execute('SELECT id,val FROM preferences WHERE key=?', (key,)).next() + dbraw = next(self.db.execute('SELECT id,val FROM preferences WHERE key=?', (key,))) except StopIteration: dbraw = None if dbraw is None or dbraw[1] != raw: @@ -222,7 +223,7 @@ def SortedConcatenate(sep=','): def finalize(ctxt): if len(ctxt) == 0: return None - return sep.join(map(ctxt.get, sorted(ctxt.iterkeys()))) + return sep.join(map(ctxt.get, sorted(iterkeys(ctxt)))) return ({}, step, finalize) @@ -247,7 +248,7 @@ def AumSortedConcatenate(): ctxt[ndx] = ':::'.join((author, sort, link)) def finalize(ctxt): - keys = list(ctxt.iterkeys()) + keys = list(iterkeys(ctxt)) l = len(keys) if l == 0: return None @@ -271,7 +272,7 @@ class Connection(apsw.Connection): # {{{ self.execute('pragma cache_size=-5000') self.execute('pragma temp_store=2') - encoding = self.execute('pragma encoding').next()[0] + encoding = next(self.execute('pragma encoding'))[0] self.createcollation('PYNOCASE', partial(pynocase, encoding=encoding)) @@ -306,7 +307,7 @@ class Connection(apsw.Connection): # {{{ if kw.get('all', True): return ans.fetchall() try: - return ans.next()[0] + return next(ans)[0] except (StopIteration, IndexError): return None @@ -733,7 +734,7 @@ class DB(object): } # Create Tag Browser categories for custom columns - for k in sorted(self.custom_column_label_map.iterkeys()): + for k in sorted(iterkeys(self.custom_column_label_map)): v = self.custom_column_label_map[k] if v['normalized']: is_category = True @@ -786,10 +787,10 @@ class DB(object): 'last_modified':19, 'identifiers':20, 'languages':21, } - for k,v in self.FIELD_MAP.iteritems(): + for k,v in iteritems(self.FIELD_MAP): self.field_metadata.set_field_record_index(k, v, prefer_custom=False) - base = max(self.FIELD_MAP.itervalues()) + base = max(itervalues(self.FIELD_MAP)) for label_ in sorted(self.custom_column_label_map): data = self.custom_column_label_map[label_] @@ -875,7 +876,7 @@ class DB(object): if kw.get('all', True): return ans.fetchall() try: - return ans.next()[0] + return next(ans)[0] except (StopIteration, IndexError): return None @@ -1263,7 +1264,7 @@ class DB(object): ''' with self.conn: # Use a single transaction, to ensure nothing modifies the db while we are reading - for table in self.tables.itervalues(): + for table in itervalues(self.tables): try: table.read(self) except: @@ -1327,7 +1328,7 @@ class DB(object): def remove_formats(self, remove_map): paths = [] - for book_id, removals in remove_map.iteritems(): + for book_id, removals in iteritems(remove_map): for fmt, fname, path in removals: path = self.format_abspath(book_id, fmt, fname, path) if path is not None: @@ -1585,7 +1586,7 @@ class DB(object): if samefile(spath, tpath): # The format filenames may have changed while the folder # name remains the same - for fmt, opath in original_format_map.iteritems(): + for fmt, opath in iteritems(original_format_map): npath = format_map.get(fmt, None) if npath and os.path.abspath(npath.lower()) != os.path.abspath(opath.lower()) and samefile(opath, npath): # opath and npath are different hard links to the same file @@ -1648,7 +1649,7 @@ class DB(object): def remove_books(self, path_map, permanent=False): self.executemany( 'DELETE FROM books WHERE id=?', [(x,) for x in path_map]) - paths = {os.path.join(self.library_path, x) for x in path_map.itervalues() if x} + paths = {os.path.join(self.library_path, x) for x in itervalues(path_map) if x} paths = {x for x in paths if os.path.exists(x) and self.is_deletable(x)} if permanent: for path in paths: @@ -1663,7 +1664,7 @@ class DB(object): self.executemany( 'INSERT OR REPLACE INTO books_plugin_data (book, name, val) VALUES (?, ?, ?)', [(book_id, name, json.dumps(val, default=to_json)) - for book_id, val in val_map.iteritems()]) + for book_id, val in iteritems(val_map)]) def get_custom_book_data(self, name, book_ids, default=None): book_ids = frozenset(book_ids) @@ -1722,7 +1723,7 @@ class DB(object): def set_conversion_options(self, options, fmt): options = [(book_id, fmt.upper(), buffer(pickle_binary_string(data.encode('utf-8') if isinstance(data, unicode_type) else data))) - for book_id, data in options.iteritems()] + for book_id, data in iteritems(options)] self.executemany('INSERT OR REPLACE INTO conversion_options(book,format,data) VALUES (?,?,?)', options) def get_top_level_move_items(self, all_paths): diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index e7f1f14aa6..f04f16edeb 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -11,7 +11,7 @@ import os, traceback, random, shutil, operator from io import BytesIO from collections import defaultdict, Set, MutableSet from functools import wraps, partial -from polyglot.builtins import unicode_type, zip, string_or_bytes +from polyglot.builtins import iteritems, iterkeys, itervalues, unicode_type, zip, string_or_bytes from time import time from calibre import isbytestring, as_unicode @@ -170,7 +170,7 @@ class Cache(object): # Reconstruct the user categories, putting them into field_metadata fm = self.field_metadata fm.remove_dynamic_categories() - for user_cat in sorted(self._pref('user_categories', {}).iterkeys(), key=sort_key): + for user_cat in sorted(iterkeys(self._pref('user_categories', {})), key=sort_key): cat_name = '@' + user_cat # add the '@' to avoid name collision while cat_name: try: @@ -181,7 +181,7 @@ class Cache(object): # add grouped search term user categories muc = frozenset(self._pref('grouped_search_make_user_categories', [])) - for cat in sorted(self._pref('grouped_search_terms', {}).iterkeys(), key=sort_key): + for cat in sorted(iterkeys(self._pref('grouped_search_terms', {})), key=sort_key): if cat in muc: # There is a chance that these can be duplicates of an existing # user category. Print the exception and continue. @@ -200,7 +200,7 @@ class Cache(object): self.dirtied_cache = {x:i for i, (x,) in enumerate( self.backend.execute('SELECT book FROM metadata_dirtied'))} if self.dirtied_cache: - self.dirtied_sequence = max(self.dirtied_cache.itervalues())+1 + self.dirtied_sequence = max(itervalues(self.dirtied_cache))+1 self._initialize_dynamic_categories() @write_api @@ -213,7 +213,7 @@ class Cache(object): @write_api def clear_composite_caches(self, book_ids=None): - for field in self.composites.itervalues(): + for field in itervalues(self.composites): field.clear_caches(book_ids=book_ids) @write_api @@ -229,7 +229,7 @@ class Cache(object): def clear_caches(self, book_ids=None, template_cache=True, search_cache=True): if template_cache: self._initialize_template_cache() # Clear the formatter template cache - for field in self.fields.itervalues(): + for field in itervalues(self.fields): if hasattr(field, 'clear_caches'): field.clear_caches(book_ids=book_ids) # Clear the composite cache and ondevice caches if book_ids: @@ -247,7 +247,7 @@ class Cache(object): with self.backend.conn: # Prevent other processes, such as calibredb from interrupting the reload by locking the db self.backend.prefs.load_from_db() self._search_api.saved_searches.load_from_db() - for field in self.fields.itervalues(): + for field in itervalues(self.fields): if hasattr(field, 'table'): field.table.read(self.backend) # Reread data from metadata.db @@ -358,7 +358,7 @@ class Cache(object): self.backend.read_tables() bools_are_tristate = self.backend.prefs['bools_are_tristate'] - for field, table in self.backend.tables.iteritems(): + for field, table in iteritems(self.backend.tables): self.fields[field] = create_field(field, table, bools_are_tristate, self.backend.get_template_functions) if table.metadata['datatype'] == 'composite': @@ -368,7 +368,7 @@ class Cache(object): VirtualTable('ondevice'), bools_are_tristate, self.backend.get_template_functions) - for name, field in self.fields.iteritems(): + for name, field in iteritems(self.fields): if name[0] == '#' and name.endswith('_index'): field.series_field = self.fields[name[:-len('_index')]] self.fields[name[:-len('_index')]].index_field = field @@ -494,7 +494,7 @@ class Cache(object): return frozenset(self.fields[field].table.col_book_map) try: - return frozenset(self.fields[field].table.id_map.itervalues()) + return frozenset(itervalues(self.fields[field].table.id_map)) except AttributeError: raise ValueError('%s is not a many-one or many-many field' % field) @@ -503,7 +503,7 @@ class Cache(object): ''' Return a mapping of id to usage count for all values of the specified field, which must be a many-one or many-many field. ''' try: - return {k:len(v) for k, v in self.fields[field].table.col_book_map.iteritems()} + return {k:len(v) for k, v in iteritems(self.fields[field].table.col_book_map)} except AttributeError: raise ValueError('%s is not a many-one or many-many field' % field) @@ -528,13 +528,13 @@ class Cache(object): @read_api def get_item_id(self, field, item_name): ' Return the item id for item_name (case-insensitive) ' - rmap = {icu_lower(v) if isinstance(v, unicode_type) else v:k for k, v in self.fields[field].table.id_map.iteritems()} + rmap = {icu_lower(v) if isinstance(v, unicode_type) else v:k for k, v in iteritems(self.fields[field].table.id_map)} return rmap.get(icu_lower(item_name) if isinstance(item_name, unicode_type) else item_name, None) @read_api def get_item_ids(self, field, item_names): ' Return the item id for item_name (case-insensitive) ' - rmap = {icu_lower(v) if isinstance(v, unicode_type) else v:k for k, v in self.fields[field].table.id_map.iteritems()} + rmap = {icu_lower(v) if isinstance(v, unicode_type) else v:k for k, v in iteritems(self.fields[field].table.id_map)} return {name:rmap.get(icu_lower(name) if isinstance(name, unicode_type) else name, None) for name in item_names} @read_api @@ -1038,13 +1038,13 @@ class Cache(object): new_dirtied = book_ids - already_dirtied already_dirtied = {book_id:self.dirtied_sequence+i for i, book_id in enumerate(already_dirtied)} if already_dirtied: - self.dirtied_sequence = max(already_dirtied.itervalues()) + 1 + self.dirtied_sequence = max(itervalues(already_dirtied)) + 1 self.dirtied_cache.update(already_dirtied) if new_dirtied: self.backend.executemany('INSERT OR IGNORE INTO metadata_dirtied (book) VALUES (?)', ((x,) for x in new_dirtied)) new_dirtied = {book_id:self.dirtied_sequence+i for i, book_id in enumerate(new_dirtied)} - self.dirtied_sequence = max(new_dirtied.itervalues()) + 1 + self.dirtied_sequence = max(itervalues(new_dirtied)) + 1 self.dirtied_cache.update(new_dirtied) @write_api @@ -1075,7 +1075,7 @@ class Cache(object): if is_series: bimap, simap = {}, {} sfield = self.fields[name + '_index'] - for k, v in book_id_to_val_map.iteritems(): + for k, v in iteritems(book_id_to_val_map): if isinstance(v, string_or_bytes): v, sid = get_series_values(v) else: @@ -1117,7 +1117,7 @@ class Cache(object): @read_api def get_a_dirtied_book(self): if self.dirtied_cache: - return random.choice(tuple(self.dirtied_cache.iterkeys())) + return random.choice(tuple(iterkeys(self.dirtied_cache))) return None @read_api @@ -1220,7 +1220,7 @@ class Cache(object): QPixmap, file object or bytestring. It can also be None, in which case any existing cover is removed. ''' - for book_id, data in book_id_data_map.iteritems(): + for book_id, data in iteritems(book_id_data_map): try: path = self._field_for('path', book_id).replace('/', os.sep) except AttributeError: @@ -1231,7 +1231,7 @@ class Cache(object): for cc in self.cover_caches: cc.invalidate(book_id_data_map) return self._set_field('cover', { - book_id:(0 if data is None else 1) for book_id, data in book_id_data_map.iteritems()}) + book_id:(0 if data is None else 1) for book_id, data in iteritems(book_id_data_map)}) @write_api def add_cover_cache(self, cover_cache): @@ -1332,14 +1332,14 @@ class Cache(object): protected_set_field('identifiers', mi_idents) elif mi_idents: identifiers = self._field_for('identifiers', book_id, default_value={}) - for key, val in mi_idents.iteritems(): + for key, val in iteritems(mi_idents): if val and val.strip(): # Don't delete an existing identifier identifiers[icu_lower(key)] = val protected_set_field('identifiers', identifiers) user_mi = mi.get_all_user_metadata(make_copy=False) fm = self.field_metadata - for key in user_mi.iterkeys(): + for key in iterkeys(user_mi): if (key in fm and user_mi[key]['datatype'] == fm[key]['datatype'] and ( user_mi[key]['datatype'] != 'text' or ( user_mi[key]['is_multiple'] == fm[key]['is_multiple']))): @@ -1433,15 +1433,15 @@ class Cache(object): :param db_only: If True, only remove the record for the format from the db, do not delete the actual format file from the filesystem. ''' table = self.fields['formats'].table - formats_map = {book_id:frozenset((f or '').upper() for f in fmts) for book_id, fmts in formats_map.iteritems()} + formats_map = {book_id:frozenset((f or '').upper() for f in fmts) for book_id, fmts in iteritems(formats_map)} - for book_id, fmts in formats_map.iteritems(): + for book_id, fmts in iteritems(formats_map): for fmt in fmts: self.format_metadata_cache[book_id].pop(fmt, None) if not db_only: removes = defaultdict(set) - for book_id, fmts in formats_map.iteritems(): + for book_id, fmts in iteritems(formats_map): try: path = self._field_for('path', book_id).replace('/', os.sep) except: @@ -1458,7 +1458,7 @@ class Cache(object): size_map = table.remove_formats(formats_map, self.backend) self.fields['size'].table.update_sizes(size_map) - self._update_last_modified(tuple(formats_map.iterkeys())) + self._update_last_modified(tuple(iterkeys(formats_map))) @read_api def get_next_series_num_for(self, series, field='series', current_indices=False): @@ -1481,7 +1481,7 @@ class Cache(object): index_map = {book_id:self._fast_field_for(idf, book_id, default_value=1.0) for book_id in books} if current_indices: return index_map - series_indices = sorted(index_map.itervalues()) + series_indices = sorted(itervalues(index_map)) return _get_next_series_num_for_list(tuple(series_indices), unwrap=False) @read_api @@ -1491,7 +1491,7 @@ class Cache(object): string. ''' table = self.fields['authors'].table result = [] - rmap = {key_func(v):k for k, v in table.id_map.iteritems()} + rmap = {key_func(v):k for k, v in iteritems(table.id_map)} for aut in authors: aid = rmap.get(key_func(aut), None) result.append(author_to_author_sort(aut) if aid is None else table.asort_map[aid]) @@ -1503,10 +1503,10 @@ class Cache(object): implementation of :meth:`has_book` in a worker process without access to the db. ''' try: - return {icu_lower(title) for title in self.fields['title'].table.book_col_map.itervalues()} + return {icu_lower(title) for title in itervalues(self.fields['title'].table.book_col_map)} except TypeError: # Some non-unicode titles in the db - return {icu_lower(as_unicode(title)) for title in self.fields['title'].table.book_col_map.itervalues()} + return {icu_lower(as_unicode(title)) for title in itervalues(self.fields['title'].table.book_col_map)} @read_api def has_book(self, mi): @@ -1518,7 +1518,7 @@ class Cache(object): if isbytestring(title): title = title.decode(preferred_encoding, 'replace') q = icu_lower(title).strip() - for title in self.fields['title'].table.book_col_map.itervalues(): + for title in itervalues(self.fields['title'].table.book_col_map): if q == icu_lower(title): return True return False @@ -1599,7 +1599,7 @@ class Cache(object): duplicates.append((mi, format_map)) else: ids.append(book_id) - for fmt, stream_or_path in format_map.iteritems(): + for fmt, stream_or_path in iteritems(format_map): if self.add_format(book_id, fmt, stream_or_path, dbapi=dbapi, run_hooks=run_hooks): fmt_map[fmt.lower()] = getattr(stream_or_path, 'name', stream_or_path) or '' run_plugins_on_postadd(dbapi or self, book_id, fmt_map) @@ -1618,11 +1618,11 @@ class Cache(object): path = None path_map[book_id] = path if iswindows: - paths = (x.replace(os.sep, '/') for x in path_map.itervalues() if x) + paths = (x.replace(os.sep, '/') for x in itervalues(path_map) if x) self.backend.windows_check_if_files_in_use(paths) self.backend.remove_books(path_map, permanent=permanent) - for field in self.fields.itervalues(): + for field in itervalues(self.fields): try: table = field.table except AttributeError: @@ -1665,7 +1665,7 @@ class Cache(object): restrict_to_book_ids = frozenset(restrict_to_book_ids) id_map = {} default_process_map = {} - for old_id, new_name in item_id_to_new_name_map.iteritems(): + for old_id, new_name in iteritems(item_id_to_new_name_map): new_names = tuple(x.strip() for x in new_name.split(sv)) if sv else (new_name,) # Get a list of books in the VL with the item books_with_id = f.books_for(old_id) @@ -1720,7 +1720,7 @@ class Cache(object): raise ValueError('Cannot rename items for one-one fields: %s' % field) moved_books = set() id_map = {} - for item_id, new_name in item_id_to_new_name_map.iteritems(): + for item_id, new_name in iteritems(item_id_to_new_name_map): new_names = tuple(x.strip() for x in new_name.split(sv)) if sv else (new_name,) books, new_id = func(item_id, new_names[0], self.backend) affected_books.update(books) @@ -1735,7 +1735,7 @@ class Cache(object): if affected_books: if field == 'authors': self._set_field('author_sort', - {k:' & '.join(v) for k, v in self._author_sort_strings_for_books(affected_books).iteritems()}) + {k:' & '.join(v) for k, v in iteritems(self._author_sort_strings_for_books(affected_books))}) self._update_path(affected_books, mark_as_dirtied=False) elif change_index and hasattr(f, 'index_field') and tweaks['series_index_auto_increment'] != 'no_change': for book_id in moved_books: @@ -1835,7 +1835,7 @@ class Cache(object): insensitive). ''' - tag_map = {icu_lower(v):k for k, v in self._get_id_map('tags').iteritems()} + tag_map = {icu_lower(v):k for k, v in iteritems(self._get_id_map('tags'))} tag = icu_lower(tag.strip()) mht = icu_lower(must_have_tag.strip()) if must_have_tag else None tag_id, mht_id = tag_map.get(tag, None), tag_map.get(mht, None) @@ -1848,7 +1848,7 @@ class Cache(object): tagged_books = tagged_books.intersection(self._books_for_field('tags', mht_id)) if tagged_books: if must_have_authors is not None: - amap = {icu_lower(v):k for k, v in self._get_id_map('authors').iteritems()} + amap = {icu_lower(v):k for k, v in iteritems(self._get_id_map('authors'))} books = None for author in must_have_authors: abooks = self._books_for_field('authors', amap.get(icu_lower(author), None)) @@ -1934,7 +1934,7 @@ class Cache(object): db. See db.utils for an implementation. ''' at = self.fields['authors'].table author_map = defaultdict(set) - for aid, author in at.id_map.iteritems(): + for aid, author in iteritems(at.id_map): author_map[icu_lower(author)].add(aid) return (author_map, at.col_book_map.copy(), self.fields['title'].table.book_col_map.copy(), self.fields['languages'].book_value_map.copy()) @@ -2079,12 +2079,12 @@ class Cache(object): def virtual_libraries_for_books(self, book_ids): libraries = self._pref('virtual_libraries', {}) ans = {book_id:[] for book_id in book_ids} - for lib, expr in libraries.iteritems(): + for lib, expr in iteritems(libraries): books = self._search(expr) # We deliberately dont use book_ids as we want to use the search cache for book in book_ids: if book in books: ans[book].append(lib) - return {k:tuple(sorted(v, key=sort_key)) for k, v in ans.iteritems()} + return {k:tuple(sorted(v, key=sort_key)) for k, v in iteritems(ans)} @read_api def user_categories_for_books(self, book_ids, proxy_metadata_map=None): @@ -2101,7 +2101,7 @@ class Cache(object): for book_id in book_ids: proxy_metadata = pmm.get(book_id) or self._get_proxy_metadata(book_id) user_cat_vals = ans[book_id] = {} - for ucat, categories in user_cats.iteritems(): + for ucat, categories in iteritems(user_cats): user_cat_vals[ucat] = res = [] for name, cat, ign in categories: try: @@ -2240,15 +2240,15 @@ def import_library(library_key, importer, library_path, progress=None, abort=Non src.close() cache = Cache(DB(library_path, load_user_formatter_functions=False)) cache.init() - format_data = {int(book_id):data for book_id, data in metadata['format_data'].iteritems()} - for i, (book_id, fmt_key_map) in enumerate(format_data.iteritems()): + format_data = {int(book_id):data for book_id, data in iteritems(metadata['format_data'])} + for i, (book_id, fmt_key_map) in enumerate(iteritems(format_data)): if abort is not None and abort.is_set(): return title = cache._field_for('title', book_id) if progress is not None: progress(title, i + 1, total) cache._update_path((book_id,), mark_as_dirtied=False) - for fmt, fmtkey in fmt_key_map.iteritems(): + for fmt, fmtkey in iteritems(fmt_key_map): if fmt == '.cover': stream = importer.start_file(fmtkey, _('Cover for %s') % title) path = cache._field_for('path', book_id).replace('/', os.sep) diff --git a/src/calibre/db/categories.py b/src/calibre/db/categories.py index 0ae1cee97f..38489a40fb 100644 --- a/src/calibre/db/categories.py +++ b/src/calibre/db/categories.py @@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en' import copy from functools import partial -from polyglot.builtins import unicode_type, map +from polyglot.builtins import iteritems, iterkeys, unicode_type, map from calibre.constants import ispy3 from calibre.ebooks.metadata import author_to_author_sort @@ -75,7 +75,7 @@ class Tag(object): def find_categories(field_metadata): - for category, cat in field_metadata.iteritems(): + for category, cat in iteritems(field_metadata): if (cat['is_category'] and cat['kind'] not in {'user', 'search'}): yield (category, cat['is_multiple'].get('cache_to_list', None), False) elif (cat['datatype'] == 'composite' and @@ -215,11 +215,11 @@ def get_categories(dbcache, sort='name', book_ids=None, first_letter_sort=False) # do the verification in the category loop much faster, at the cost of # temporarily duplicating the categories lists. taglist = {} - for c, items in categories.iteritems(): + for c, items in iteritems(categories): taglist[c] = dict(map(lambda t:(icu_lower(t.name), t), items)) # Add the category values to the user categories - for user_cat in sorted(user_categories.iterkeys(), key=sort_key): + for user_cat in sorted(iterkeys(user_categories), key=sort_key): items = [] names_seen = {} user_cat_is_gst = user_cat in gst diff --git a/src/calibre/db/cli/cmd_custom_columns.py b/src/calibre/db/cli/cmd_custom_columns.py index 0e8a0b5813..b8c54bad2c 100644 --- a/src/calibre/db/cli/cmd_custom_columns.py +++ b/src/calibre/db/cli/cmd_custom_columns.py @@ -7,6 +7,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera from pprint import pformat from calibre import prints +from polyglot.builtins import iteritems readonly = True version = 0 # change this if you change signature of implementation() @@ -37,7 +38,7 @@ List available custom columns. Shows column labels and ids. def main(opts, args, dbctx): - for col, data in dbctx.run('custom_columns').iteritems(): + for col, data in iteritems(dbctx.run('custom_columns')): if opts.details: prints(col) print() diff --git a/src/calibre/db/cli/cmd_list.py b/src/calibre/db/cli/cmd_list.py index 570271c351..a6635236d4 100644 --- a/src/calibre/db/cli/cmd_list.py +++ b/src/calibre/db/cli/cmd_list.py @@ -13,6 +13,7 @@ from calibre import prints from calibre.db.cli.utils import str_width from calibre.ebooks.metadata import authors_to_string from calibre.utils.date import isoformat +from polyglot.builtins import iteritems readonly = True version = 0 # change this if you change signature of implementation() @@ -64,7 +65,7 @@ def implementation( continue if field == 'isbn': x = db.all_field_for('identifiers', book_ids, default_value={}) - data[field] = {k: v.get('isbn') or '' for k, v in x.iteritems()} + data[field] = {k: v.get('isbn') or '' for k, v in iteritems(x)} continue field = field.replace('*', '#') metadata[field] = fm[field] @@ -80,37 +81,37 @@ def implementation( def stringify(data, metadata, for_machine): - for field, m in metadata.iteritems(): + for field, m in iteritems(metadata): if field == 'authors': data[field] = { k: authors_to_string(v) - for k, v in data[field].iteritems() + for k, v in iteritems(data[field]) } else: dt = m['datatype'] if dt == 'datetime': data[field] = { k: isoformat(v, as_utc=for_machine) if v else 'None' - for k, v in data[field].iteritems() + for k, v in iteritems(data[field]) } elif not for_machine: ism = m['is_multiple'] if ism: data[field] = { k: ism['list_to_ui'].join(v) - for k, v in data[field].iteritems() + for k, v in iteritems(data[field]) } if field == 'formats': data[field] = { k: '[' + v + ']' - for k, v in data[field].iteritems() + for k, v in iteritems(data[field]) } def as_machine_data(book_ids, data, metadata): for book_id in book_ids: ans = {'id': book_id} - for field, val_map in data.iteritems(): + for field, val_map in iteritems(data): val = val_map.get(book_id) if val is not None: ans[field.replace('#', '*')] = val diff --git a/src/calibre/db/cli/cmd_saved_searches.py b/src/calibre/db/cli/cmd_saved_searches.py index fd31051782..b06585d48e 100644 --- a/src/calibre/db/cli/cmd_saved_searches.py +++ b/src/calibre/db/cli/cmd_saved_searches.py @@ -9,6 +9,7 @@ version = 0 # change this if you change signature of implementation() from calibre import prints from calibre.srv.changes import saved_searches +from polyglot.builtins import iteritems def implementation(db, notify_changes, action, *args): @@ -56,7 +57,7 @@ Syntax for removing: def main(opts, args, dbctx): args = args or ['list'] if args[0] == 'list': - for name, value in dbctx.run('saved_searches', 'list').iteritems(): + for name, value in iteritems(dbctx.run('saved_searches', 'list')): prints(_('Name:'), name) prints(_('Search string:'), value) print() diff --git a/src/calibre/db/cli/cmd_set_metadata.py b/src/calibre/db/cli/cmd_set_metadata.py index 18a09bafb9..02ac4462de 100644 --- a/src/calibre/db/cli/cmd_set_metadata.py +++ b/src/calibre/db/cli/cmd_set_metadata.py @@ -11,7 +11,7 @@ from calibre.ebooks.metadata.book.base import field_from_string from calibre.ebooks.metadata.book.serialize import read_cover from calibre.ebooks.metadata.opf import get_metadata from calibre.srv.changes import metadata -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type readonly = False version = 0 # change this if you change signature of implementation() @@ -170,7 +170,7 @@ def main(opts, args, dbctx): vals[field] = val fvals = [] for field, val in sorted( # ensure series_index fields are set last - vals.iteritems(), key=lambda k: 1 if k[0].endswith('_index') else 0): + iteritems(vals), key=lambda k: 1 if k[0].endswith('_index') else 0): if field.endswith('_index'): try: val = float(val) diff --git a/src/calibre/db/cli/tests.py b/src/calibre/db/cli/tests.py index 3c5ad650b0..1f7f960e2c 100644 --- a/src/calibre/db/cli/tests.py +++ b/src/calibre/db/cli/tests.py @@ -13,14 +13,14 @@ import csv import unittest from cStringIO import StringIO - from calibre.db.cli.cmd_check_library import _print_check_library_results +from polyglot.builtins import iteritems class Checker(object): def __init__(self, kw): - for k, v in kw.iteritems(): + for k, v in iteritems(kw): setattr(self, k, v) diff --git a/src/calibre/db/fields.py b/src/calibre/db/fields.py index 1ecf43319c..d42ab52db9 100644 --- a/src/calibre/db/fields.py +++ b/src/calibre/db/fields.py @@ -2,7 +2,6 @@ # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai from __future__ import (unicode_literals, division, absolute_import, print_function) -# from polyglot.builtins import map __license__ = 'GPL v3' __copyright__ = '2011, Kovid Goyal ' @@ -20,6 +19,7 @@ from calibre.utils.config_base import tweaks from calibre.utils.icu import sort_key from calibre.utils.date import UNDEFINED_DATE, clean_date_for_sort, parse_date from calibre.utils.localization import calibre_langcode_to_name +from polyglot.builtins import iteritems, iterkeys def bool_sort_key(bools_are_tristate): @@ -150,7 +150,7 @@ class Field(object): id_map = self.table.id_map special_sort = hasattr(self, 'category_sort_value') - for item_id, item_book_ids in self.table.col_book_map.iteritems(): + for item_id, item_book_ids in iteritems(self.table.col_book_map): if book_ids is not None: item_book_ids = item_book_ids.intersection(book_ids) if item_book_ids: @@ -184,7 +184,7 @@ class OneToOneField(Field): return {item_id} def __iter__(self): - return self.table.book_col_map.iterkeys() + return iterkeys(self.table.book_col_map) def sort_keys_for_books(self, get_metadata, lang_map): bcmg = self.table.book_col_map.get @@ -315,7 +315,7 @@ class CompositeField(OneToOneField): for v in vals: if v: val_map[v].add(book_id) - for val, book_ids in val_map.iteritems(): + for val, book_ids in iteritems(val_map): yield val, book_ids def get_composite_categories(self, tag_class, book_rating_map, book_ids, @@ -328,7 +328,7 @@ class CompositeField(OneToOneField): for val in vals: if val: id_map[val].add(book_id) - for item_id, item_book_ids in id_map.iteritems(): + for item_id, item_book_ids in iteritems(id_map): ratings = tuple(r for r in (book_rating_map.get(book_id, 0) for book_id in item_book_ids) if r > 0) avg = sum(ratings)/len(ratings) if ratings else 0 @@ -409,7 +409,7 @@ class OnDeviceField(OneToOneField): val_map = defaultdict(set) for book_id in candidates: val_map[self.for_book(book_id, default_value=default_value)].add(book_id) - for val, book_ids in val_map.iteritems(): + for val, book_ids in iteritems(val_map): yield val, book_ids @@ -456,7 +456,7 @@ class ManyToOneField(Field): return self.table.col_book_map.get(item_id, set()) def __iter__(self): - return self.table.id_map.iterkeys() + return iterkeys(self.table.id_map) def sort_keys_for_books(self, get_metadata, lang_map): sk_map = LazySortMap(self._default_sort_key, self._sort_key, self.table.id_map) @@ -466,7 +466,7 @@ class ManyToOneField(Field): def iter_searchable_values(self, get_metadata, candidates, default_value=None): cbm = self.table.col_book_map empty = set() - for item_id, val in self.table.id_map.iteritems(): + for item_id, val in iteritems(self.table.id_map): book_ids = cbm.get(item_id, empty).intersection(candidates) if book_ids: yield val, book_ids @@ -475,7 +475,7 @@ class ManyToOneField(Field): def book_value_map(self): try: return {book_id:self.table.id_map[item_id] for book_id, item_id in - self.table.book_col_map.iteritems()} + iteritems(self.table.book_col_map)} except KeyError: raise InvalidLinkTable(self.name) @@ -507,7 +507,7 @@ class ManyToManyField(Field): return self.table.col_book_map.get(item_id, set()) def __iter__(self): - return self.table.id_map.iterkeys() + return iterkeys(self.table.id_map) def sort_keys_for_books(self, get_metadata, lang_map): sk_map = LazySortMap(self._default_sort_key, self._sort_key, self.table.id_map) @@ -524,7 +524,7 @@ class ManyToManyField(Field): def iter_searchable_values(self, get_metadata, candidates, default_value=None): cbm = self.table.col_book_map empty = set() - for item_id, val in self.table.id_map.iteritems(): + for item_id, val in iteritems(self.table.id_map): book_ids = cbm.get(item_id, empty).intersection(candidates) if book_ids: yield val, book_ids @@ -534,14 +534,14 @@ class ManyToManyField(Field): cbm = self.table.book_col_map for book_id in candidates: val_map[len(cbm.get(book_id, ()))].add(book_id) - for count, book_ids in val_map.iteritems(): + for count, book_ids in iteritems(val_map): yield count, book_ids @property def book_value_map(self): try: return {book_id:tuple(self.table.id_map[item_id] for item_id in item_ids) - for book_id, item_ids in self.table.book_col_map.iteritems()} + for book_id, item_ids in iteritems(self.table.book_col_map)} except KeyError: raise InvalidLinkTable(self.name) @@ -561,7 +561,7 @@ class IdentifiersField(ManyToManyField): 'Sort by identifier keys' bcmg = self.table.book_col_map.get dv = {self._default_sort_key:None} - return lambda book_id: tuple(sorted(bcmg(book_id, dv).iterkeys())) + return lambda book_id: tuple(sorted(iterkeys(bcmg(book_id, dv)))) def iter_searchable_values(self, get_metadata, candidates, default_value=()): bcm = self.table.book_col_map @@ -573,7 +573,7 @@ class IdentifiersField(ManyToManyField): def get_categories(self, tag_class, book_rating_map, lang_map, book_ids=None): ans = [] - for id_key, item_book_ids in self.table.col_book_map.iteritems(): + for id_key, item_book_ids in iteritems(self.table.col_book_map): if book_ids is not None: item_book_ids = item_book_ids.intersection(book_ids) if item_book_ids: @@ -618,13 +618,13 @@ class FormatsField(ManyToManyField): for val in vals: val_map[val].add(book_id) - for val, book_ids in val_map.iteritems(): + for val, book_ids in iteritems(val_map): yield val, book_ids def get_categories(self, tag_class, book_rating_map, lang_map, book_ids=None): ans = [] - for fmt, item_book_ids in self.table.col_book_map.iteritems(): + for fmt, item_book_ids in iteritems(self.table.col_book_map): if book_ids is not None: item_book_ids = item_book_ids.intersection(book_ids) if item_book_ids: @@ -665,7 +665,7 @@ class SeriesField(ManyToOneField): return ssk(ts(val, order=sso, lang=lang)) sk_map = LazySeriesSortMap(self._default_sort_key, sk, self.table.id_map) bcmg = self.table.book_col_map.get - lang_map = {k:v[0] if v else None for k, v in lang_map.iteritems()} + lang_map = {k:v[0] if v else None for k, v in iteritems(lang_map)} def key(book_id): lang = lang_map.get(book_id, None) @@ -694,8 +694,8 @@ class SeriesField(ManyToOneField): sso = tweaks['title_series_sorting'] ts = title_sort empty = set() - lang_map = {k:v[0] if v else None for k, v in lang_map.iteritems()} - for item_id, val in self.table.id_map.iteritems(): + lang_map = {k:v[0] if v else None for k, v in iteritems(lang_map)} + for item_id, val in iteritems(self.table.id_map): book_ids = cbm.get(item_id, empty).intersection(candidates) if book_ids: lang_counts = Counter() @@ -712,7 +712,7 @@ class TagsField(ManyToManyField): def get_news_category(self, tag_class, book_ids=None): news_id = None ans = [] - for item_id, val in self.table.id_map.iteritems(): + for item_id, val in iteritems(self.table.id_map): if val == _('News'): news_id = item_id break @@ -724,7 +724,7 @@ class TagsField(ManyToManyField): news_books = news_books.intersection(book_ids) if not news_books: return ans - for item_id, item_book_ids in self.table.col_book_map.iteritems(): + for item_id, item_book_ids in iteritems(self.table.col_book_map): item_book_ids = item_book_ids.intersection(news_books) if item_book_ids: name = self.category_formatter(self.table.id_map[item_id]) diff --git a/src/calibre/db/lazy.py b/src/calibre/db/lazy.py index ffa71f8612..e3c5128ed4 100644 --- a/src/calibre/db/lazy.py +++ b/src/calibre/db/lazy.py @@ -15,7 +15,7 @@ from copy import deepcopy from calibre.ebooks.metadata.book.base import Metadata, SIMPLE_GET, TOP_LEVEL_IDENTIFIERS, NULL_VALUES, ALL_METADATA_FIELDS from calibre.ebooks.metadata.book.formatter import SafeFormat from calibre.utils.date import utcnow -from polyglot.builtins import unicode_type +from polyglot.builtins import iterkeys, unicode_type # Lazy format metadata retrieval {{{ ''' @@ -393,7 +393,7 @@ class ProxyMetadata(Metadata): def all_field_keys(self): um = ga(self, '_user_metadata') - return frozenset(ALL_METADATA_FIELDS.union(um.iterkeys())) + return frozenset(ALL_METADATA_FIELDS.union(iterkeys(um))) @property def _proxy_metadata(self): diff --git a/src/calibre/db/legacy.py b/src/calibre/db/legacy.py index 60b2f083d8..3eff229a68 100644 --- a/src/calibre/db/legacy.py +++ b/src/calibre/db/legacy.py @@ -7,7 +7,7 @@ __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal ' import os, traceback, types -from polyglot.builtins import zip +from polyglot.builtins import iteritems, zip from calibre import force_unicode, isbytestring from calibre.constants import preferred_encoding @@ -171,14 +171,14 @@ class LibraryDatabase(object): return not bool(self.new_api.fields['title'].table.book_col_map) def get_usage_count_by_id(self, field): - return [[k, v] for k, v in self.new_api.get_usage_count_by_id(field).iteritems()] + return [[k, v] for k, v in iteritems(self.new_api.get_usage_count_by_id(field))] def field_id_map(self, field): - return [(k, v) for k, v in self.new_api.get_id_map(field).iteritems()] + return [(k, v) for k, v in iteritems(self.new_api.get_id_map(field))] def get_custom_items_with_ids(self, label=None, num=None): try: - return [[k, v] for k, v in self.new_api.get_id_map(self.custom_field_name(label, num)).iteritems()] + return [[k, v] for k, v in iteritems(self.new_api.get_id_map(self.custom_field_name(label, num)))] except ValueError: return [] @@ -233,7 +233,7 @@ class LibraryDatabase(object): paths, formats, metadata = [], [], [] for mi, format_map in duplicates: metadata.append(mi) - for fmt, path in format_map.iteritems(): + for fmt, path in iteritems(format_map): formats.append(fmt) paths.append(path) duplicates = (paths, formats, metadata) @@ -416,7 +416,7 @@ class LibraryDatabase(object): ans = set() if title: title = icu_lower(force_unicode(title)) - for book_id, x in self.new_api.get_id_map('title').iteritems(): + for book_id, x in iteritems(self.new_api.get_id_map('title')): if icu_lower(x) == title: ans.add(book_id) if not all_matches: @@ -521,7 +521,7 @@ class LibraryDatabase(object): def delete_tags(self, tags): with self.new_api.write_lock: - tag_map = {icu_lower(v):k for k, v in self.new_api._get_id_map('tags').iteritems()} + tag_map = {icu_lower(v):k for k, v in iteritems(self.new_api._get_id_map('tags'))} tag_ids = (tag_map.get(icu_lower(tag), None) for tag in tags) tag_ids = tuple(tid for tid in tag_ids if tid is not None) if tag_ids: @@ -547,7 +547,7 @@ class LibraryDatabase(object): def format_files(self, index, index_is_id=False): book_id = index if index_is_id else self.id(index) - return [(v, k) for k, v in self.new_api.format_files(book_id).iteritems()] + return [(v, k) for k, v in iteritems(self.new_api.format_files(book_id))] def format_metadata(self, book_id, fmt, allow_cache=True, update_db=False, commit=False): return self.new_api.format_metadata(book_id, fmt, allow_cache=allow_cache, update_db=update_db) @@ -632,7 +632,7 @@ class LibraryDatabase(object): def delete_item_from_multiple(self, item, label=None, num=None): field = self.custom_field_name(label, num) existing = self.new_api.get_id_map(field) - rmap = {icu_lower(v):k for k, v in existing.iteritems()} + rmap = {icu_lower(v):k for k, v in iteritems(existing)} item_id = rmap.get(icu_lower(item), None) if item_id is None: return [] @@ -854,7 +854,7 @@ for field in ('authors', 'tags', 'publisher', 'series'): LibraryDatabase.all_formats = MT(lambda self:self.new_api.all_field_names('formats')) LibraryDatabase.all_custom = MT(lambda self, label=None, num=None:self.new_api.all_field_names(self.custom_field_name(label, num))) -for func, field in {'all_authors':'authors', 'all_titles':'title', 'all_tags2':'tags', 'all_series':'series', 'all_publishers':'publisher'}.iteritems(): +for func, field in iteritems({'all_authors':'authors', 'all_titles':'title', 'all_tags2':'tags', 'all_series':'series', 'all_publishers':'publisher'}): def getter(field): def func(self): return self.field_id_map(field) @@ -864,16 +864,16 @@ for func, field in {'all_authors':'authors', 'all_titles':'title', 'all_tags2':' LibraryDatabase.all_tags = MT(lambda self: list(self.all_tag_names())) LibraryDatabase.get_all_identifier_types = MT(lambda self: list(self.new_api.fields['identifiers'].table.all_identifier_types())) LibraryDatabase.get_authors_with_ids = MT( - lambda self: [[aid, adata['name'], adata['sort'], adata['link']] for aid, adata in self.new_api.author_data().iteritems()]) + lambda self: [[aid, adata['name'], adata['sort'], adata['link']] for aid, adata in iteritems(self.new_api.author_data())]) LibraryDatabase.get_author_id = MT( - lambda self, author: {icu_lower(v):k for k, v in self.new_api.get_id_map('authors').iteritems()}.get(icu_lower(author), None)) + lambda self, author: {icu_lower(v):k for k, v in iteritems(self.new_api.get_id_map('authors'))}.get(icu_lower(author), None)) for field in ('tags', 'series', 'publishers', 'ratings', 'languages'): def getter(field): fname = field[:-1] if field in {'publishers', 'ratings'} else field def func(self): - return [[tid, tag] for tid, tag in self.new_api.get_id_map(fname).iteritems()] + return [[tid, tag] for tid, tag in iteritems(self.new_api.get_id_map(fname))] return func setattr(LibraryDatabase, 'get_%s_with_ids' % field, MT(getter(field))) diff --git a/src/calibre/db/restore.py b/src/calibre/db/restore.py index 11526cea34..7db2ad78d1 100644 --- a/src/calibre/db/restore.py +++ b/src/calibre/db/restore.py @@ -16,6 +16,7 @@ from calibre.db.cache import Cache from calibre.constants import filesystem_encoding from calibre.utils.date import utcfromtimestamp from calibre import isbytestring, force_unicode +from polyglot.builtins import iteritems NON_EBOOK_EXTENSIONS = frozenset([ 'jpg', 'jpeg', 'gif', 'png', 'bmp', @@ -206,7 +207,7 @@ class Restore(Thread): self.mismatched_dirs.append(dirpath) alm = mi.get('author_link_map', {}) - for author, link in alm.iteritems(): + for author, link in iteritems(alm): existing_link, timestamp = self.authors_links.get(author, (None, None)) if existing_link is None or existing_link != link and timestamp < mi.timestamp: self.authors_links[author] = (link, mi.timestamp) @@ -259,7 +260,7 @@ class Restore(Thread): self.progress_callback(book['mi'].title, i+1) id_map = db.get_item_ids('authors', [author for author in self.authors_links]) - link_map = {aid:self.authors_links[name][0] for name, aid in id_map.iteritems() if aid is not None} + link_map = {aid:self.authors_links[name][0] for name, aid in iteritems(id_map) if aid is not None} if link_map: db.set_link_for_authors(link_map) db.close() diff --git a/src/calibre/db/schema_upgrades.py b/src/calibre/db/schema_upgrades.py index 7ad9d2d7c9..7b5dc28832 100644 --- a/src/calibre/db/schema_upgrades.py +++ b/src/calibre/db/schema_upgrades.py @@ -11,7 +11,7 @@ import os from calibre import prints from calibre.utils.date import isoformat, DEFAULT_DATE -from polyglot.builtins import unicode_type +from polyglot.builtins import iterkeys, itervalues, unicode_type class SchemaUpgrade(object): @@ -24,7 +24,7 @@ class SchemaUpgrade(object): # Upgrade database try: while True: - uv = self.db.execute('pragma user_version').next()[0] + uv = next(self.db.execute('pragma user_version'))[0] meth = getattr(self, 'upgrade_version_%d'%uv, None) if meth is None: break @@ -299,7 +299,7 @@ class SchemaUpgrade(object): '''.format(tn=table_name, cn=column_name, vcn=view_column_name)) self.db.execute(script) - for field in self.field_metadata.itervalues(): + for field in itervalues(self.field_metadata): if field['is_category'] and not field['is_custom'] and 'link_column' in field: table = self.db.get( 'SELECT name FROM sqlite_master WHERE type="table" AND name=?', @@ -375,7 +375,7 @@ class SchemaUpgrade(object): '''.format(lt=link_table_name, table=table_name) self.db.execute(script) - for field in self.field_metadata.itervalues(): + for field in itervalues(self.field_metadata): if field['is_category'] and not field['is_custom'] and 'link_column' in field: table = self.db.get( 'SELECT name FROM sqlite_master WHERE type="table" AND name=?', @@ -596,7 +596,7 @@ class SchemaUpgrade(object): custom_recipe_filename) bdir = os.path.dirname(custom_recipes.file_path) for id_, title, script in recipes: - existing = frozenset(map(int, custom_recipes.iterkeys())) + existing = frozenset(map(int, iterkeys(custom_recipes))) if id_ in existing: id_ = max(existing) + 1000 id_ = str(id_) diff --git a/src/calibre/db/search.py b/src/calibre/db/search.py index cc70ec4a39..b4cea09c71 100644 --- a/src/calibre/db/search.py +++ b/src/calibre/db/search.py @@ -19,7 +19,7 @@ from calibre.utils.date import parse_date, UNDEFINED_DATE, now, dt_as_local from calibre.utils.icu import primary_contains, sort_key from calibre.utils.localization import lang_map, canonicalize_lang from calibre.utils.search_query_parser import SearchQueryParser, ParseException -from polyglot.builtins import unicode_type, string_or_bytes +from polyglot.builtins import iteritems, iterkeys, unicode_type, string_or_bytes CONTAINS_MATCH = 0 EQUALS_MATCH = 1 @@ -167,7 +167,7 @@ class DateSearch(object): # {{{ matches |= book_ids return matches - for k, relop in self.operators.iteritems(): + for k, relop in iteritems(self.operators): if query.startswith(k): query = query[len(k):] break @@ -254,7 +254,7 @@ class NumericSearch(object): # {{{ else: relop = lambda x,y: x is not None else: - for k, relop in self.operators.iteritems(): + for k, relop in iteritems(self.operators): if query.startswith(k): query = query[len(k):] break @@ -372,7 +372,7 @@ class KeyPairSearch(object): # {{{ return found if valq == 'true' else candidates - found for m, book_ids in field_iter(): - for key, val in m.iteritems(): + for key, val in iteritems(m): if (keyq and not _match(keyq, (key,), keyq_mkind, use_primary_find_in_search=use_primary_find)): continue @@ -445,7 +445,7 @@ class SavedSearchQueries(object): # {{{ db._set_pref(self.opt_name, smap) def names(self): - return sorted(self.queries.iterkeys(), key=sort_key) + return sorted(iterkeys(self.queries), key=sort_key) # }}} @@ -632,7 +632,7 @@ class Parser(SearchQueryParser): # {{{ text_fields = set() field_metadata = {} - for x, fm in self.field_metadata.iteritems(): + for x, fm in iteritems(self.field_metadata): if x.startswith('@'): continue if fm['search_terms'] and x not in {'series_sort', 'id'}: @@ -670,7 +670,7 @@ class Parser(SearchQueryParser): # {{{ q = canonicalize_lang(query) if q is None: lm = lang_map() - rm = {v.lower():k for k,v in lm.iteritems()} + rm = {v.lower():k for k,v in iteritems(lm)} q = rm.get(query, query) if matchkind == CONTAINS_MATCH and q.lower() in {'true', 'false'}: @@ -799,7 +799,7 @@ class LRUCache(object): # {{{ return self.get(key) def __iter__(self): - return self.item_map.iteritems() + return iteritems(self.item_map) # }}} diff --git a/src/calibre/db/tables.py b/src/calibre/db/tables.py index 1dfd722ff0..b22b53a5b7 100644 --- a/src/calibre/db/tables.py +++ b/src/calibre/db/tables.py @@ -14,7 +14,7 @@ from collections import defaultdict from calibre.constants import plugins from calibre.utils.date import parse_date, UNDEFINED_DATE, utc_tz from calibre.ebooks.metadata import author_to_author_sort -from polyglot.builtins import range +from polyglot.builtins import iteritems, itervalues, range _c_speedup = plugins['speedup'][0].parse_date @@ -154,10 +154,10 @@ class UUIDTable(OneToOneTable): def read(self, db): OneToOneTable.read(self, db) - self.uuid_to_id_map = {v:k for k, v in self.book_col_map.iteritems()} + self.uuid_to_id_map = {v:k for k, v in iteritems(self.book_col_map)} def update_uuid_cache(self, book_id_val_map): - for book_id, uuid in book_id_val_map.iteritems(): + for book_id, uuid in iteritems(book_id_val_map): self.uuid_to_id_map.pop(self.book_col_map.get(book_id, None), None) # discard old uuid self.uuid_to_id_map[uuid] = book_id @@ -226,7 +226,7 @@ class ManyToOneTable(Table): bcm[book] = item_id def fix_link_table(self, db): - linked_item_ids = {item_id for item_id in self.book_col_map.itervalues()} + linked_item_ids = {item_id for item_id in itervalues(self.book_col_map)} extra_item_ids = linked_item_ids - set(self.id_map) if extra_item_ids: for item_id in extra_item_ids: @@ -238,10 +238,10 @@ class ManyToOneTable(Table): def fix_case_duplicates(self, db): case_map = defaultdict(set) - for item_id, val in self.id_map.iteritems(): + for item_id, val in iteritems(self.id_map): case_map[icu_lower(val)].add(item_id) - for v in case_map.itervalues(): + for v in itervalues(case_map): if len(v) > 1: main_id = min(v) v.discard(main_id) @@ -322,7 +322,7 @@ class ManyToOneTable(Table): return affected_books def rename_item(self, item_id, new_name, db): - rmap = {icu_lower(v):k for k, v in self.id_map.iteritems()} + rmap = {icu_lower(v):k for k, v in iteritems(self.id_map)} existing_item = rmap.get(icu_lower(new_name), None) table, col, lcol = self.metadata['table'], self.metadata['column'], self.metadata['link_column'] affected_books = self.col_book_map.get(item_id, set()) @@ -353,9 +353,9 @@ class RatingTable(ManyToOneTable): ManyToOneTable.read_id_maps(self, db) # Ensure there are no records with rating=0 in the table. These should # be represented as rating:None instead. - bad_ids = {item_id for item_id, rating in self.id_map.iteritems() if rating == 0} + bad_ids = {item_id for item_id, rating in iteritems(self.id_map) if rating == 0} if bad_ids: - self.id_map = {item_id:rating for item_id, rating in self.id_map.iteritems() if rating != 0} + self.id_map = {item_id:rating for item_id, rating in iteritems(self.id_map) if rating != 0} db.executemany('DELETE FROM {0} WHERE {1}=?'.format(self.link_table, self.metadata['link_column']), tuple((x,) for x in bad_ids)) db.execute('DELETE FROM {0} WHERE {1}=0'.format( @@ -382,10 +382,10 @@ class ManyToManyTable(ManyToOneTable): cbm[item_id].add(book) bcm[book].append(item_id) - self.book_col_map = {k:tuple(v) for k, v in bcm.iteritems()} + self.book_col_map = {k:tuple(v) for k, v in iteritems(bcm)} def fix_link_table(self, db): - linked_item_ids = {item_id for item_ids in self.book_col_map.itervalues() for item_id in item_ids} + linked_item_ids = {item_id for item_ids in itervalues(self.book_col_map) for item_id in item_ids} extra_item_ids = linked_item_ids - set(self.id_map) if extra_item_ids: for item_id in extra_item_ids: @@ -461,7 +461,7 @@ class ManyToManyTable(ManyToOneTable): return affected_books def rename_item(self, item_id, new_name, db): - rmap = {icu_lower(v):k for k, v in self.id_map.iteritems()} + rmap = {icu_lower(v):k for k, v in iteritems(self.id_map)} existing_item = rmap.get(icu_lower(new_name), None) table, col, lcol = self.metadata['table'], self.metadata['column'], self.metadata['link_column'] affected_books = self.col_book_map.get(item_id, set()) @@ -490,10 +490,10 @@ class ManyToManyTable(ManyToOneTable): def fix_case_duplicates(self, db): from calibre.db.write import uniq case_map = defaultdict(set) - for item_id, val in self.id_map.iteritems(): + for item_id, val in iteritems(self.id_map): case_map[icu_lower(val)].add(item_id) - for v in case_map.itervalues(): + for v in itervalues(case_map): if len(v) > 1: done_books = set() main_id = min(v) @@ -541,19 +541,19 @@ class AuthorsTable(ManyToManyTable): lm[aid] = link def set_sort_names(self, aus_map, db): - aus_map = {aid:(a or '').strip() for aid, a in aus_map.iteritems()} - aus_map = {aid:a for aid, a in aus_map.iteritems() if a != self.asort_map.get(aid, None)} + aus_map = {aid:(a or '').strip() for aid, a in iteritems(aus_map)} + aus_map = {aid:a for aid, a in iteritems(aus_map) if a != self.asort_map.get(aid, None)} self.asort_map.update(aus_map) db.executemany('UPDATE authors SET sort=? WHERE id=?', - [(v, k) for k, v in aus_map.iteritems()]) + [(v, k) for k, v in iteritems(aus_map)]) return aus_map def set_links(self, link_map, db): - link_map = {aid:(l or '').strip() for aid, l in link_map.iteritems()} - link_map = {aid:l for aid, l in link_map.iteritems() if l != self.alink_map.get(aid, None)} + link_map = {aid:(l or '').strip() for aid, l in iteritems(link_map)} + link_map = {aid:l for aid, l in iteritems(link_map) if l != self.alink_map.get(aid, None)} self.alink_map.update(link_map) db.executemany('UPDATE authors SET link=? WHERE id=?', - [(v, k) for k, v in link_map.iteritems()]) + [(v, k) for k, v in iteritems(link_map)]) return link_map def remove_books(self, book_ids, db): @@ -602,7 +602,7 @@ class FormatsTable(ManyToManyTable): fnm[book][fmt] = name sm[book][fmt] = sz - self.book_col_map = {k:tuple(sorted(v)) for k, v in bcm.iteritems()} + self.book_col_map = {k:tuple(sorted(v)) for k, v in iteritems(bcm)} def remove_books(self, book_ids, db): clean = ManyToManyTable.remove_books(self, book_ids, db) @@ -617,21 +617,21 @@ class FormatsTable(ManyToManyTable): (fname, book_id, fmt)) def remove_formats(self, formats_map, db): - for book_id, fmts in formats_map.iteritems(): + for book_id, fmts in iteritems(formats_map): self.book_col_map[book_id] = [fmt for fmt in self.book_col_map.get(book_id, []) if fmt not in fmts] for m in (self.fname_map, self.size_map): - m[book_id] = {k:v for k, v in m[book_id].iteritems() if k not in fmts} + m[book_id] = {k:v for k, v in iteritems(m[book_id]) if k not in fmts} for fmt in fmts: try: self.col_book_map[fmt].discard(book_id) except KeyError: pass db.executemany('DELETE FROM data WHERE book=? AND format=?', - [(book_id, fmt) for book_id, fmts in formats_map.iteritems() for fmt in fmts]) + [(book_id, fmt) for book_id, fmts in iteritems(formats_map) for fmt in fmts]) def zero_max(book_id): try: - return max(self.size_map[book_id].itervalues()) + return max(itervalues(self.size_map[book_id])) except ValueError: return 0 @@ -661,7 +661,7 @@ class FormatsTable(ManyToManyTable): self.size_map[book_id][fmt] = size db.execute('INSERT OR REPLACE INTO data (book,format,uncompressed_size,name) VALUES (?,?,?,?)', (book_id, fmt, size, fname)) - return max(self.size_map[book_id].itervalues()) + return max(itervalues(self.size_map[book_id])) class IdentifiersTable(ManyToManyTable): @@ -702,4 +702,4 @@ class IdentifiersTable(ManyToManyTable): raise NotImplementedError('Cannot rename identifiers') def all_identifier_types(self): - return frozenset(k for k, v in self.col_book_map.iteritems() if v) + return frozenset(k for k, v in iteritems(self.col_book_map) if v) diff --git a/src/calibre/db/tests/add_remove.py b/src/calibre/db/tests/add_remove.py index 7dee5d33ec..a39a698f8b 100644 --- a/src/calibre/db/tests/add_remove.py +++ b/src/calibre/db/tests/add_remove.py @@ -15,6 +15,7 @@ from datetime import timedelta from calibre.db.tests.base import BaseTest, IMG from calibre.ptempfile import PersistentTemporaryFile from calibre.utils.date import now, UNDEFINED_DATE +from polyglot.builtins import iteritems, itervalues def import_test(replacement_data, replacement_fmt=None): @@ -217,14 +218,14 @@ class AddRemoveTest(BaseTest): authors = cache.fields['authors'].table # Delete a single book, with no formats and check cleaning - self.assertIn(_('Unknown'), set(authors.id_map.itervalues())) + self.assertIn(_('Unknown'), set(itervalues(authors.id_map))) olen = len(authors.id_map) - item_id = {v:k for k, v in authors.id_map.iteritems()}[_('Unknown')] + item_id = {v:k for k, v in iteritems(authors.id_map)}[_('Unknown')] cache.remove_books((3,)) for c in (cache, self.init_cache()): table = c.fields['authors'].table self.assertNotIn(3, c.all_book_ids()) - self.assertNotIn(_('Unknown'), set(table.id_map.itervalues())) + self.assertNotIn(_('Unknown'), set(itervalues(table.id_map))) self.assertNotIn(item_id, table.asort_map) self.assertNotIn(item_id, table.alink_map) ae(len(table.id_map), olen-1) @@ -235,17 +236,17 @@ class AddRemoveTest(BaseTest): authorpath = os.path.dirname(bookpath) os.mkdir(os.path.join(authorpath, '.DS_Store')) open(os.path.join(authorpath, 'Thumbs.db'), 'wb').close() - item_id = {v:k for k, v in cache.fields['#series'].table.id_map.iteritems()}['My Series Two'] + item_id = {v:k for k, v in iteritems(cache.fields['#series'].table.id_map)}['My Series Two'] cache.remove_books((1,), permanent=True) for x in (fmtpath, bookpath, authorpath): af(os.path.exists(x), 'The file %s exists, when it should not' % x) for c in (cache, self.init_cache()): table = c.fields['authors'].table self.assertNotIn(1, c.all_book_ids()) - self.assertNotIn('Author Two', set(table.id_map.itervalues())) - self.assertNotIn(6, set(c.fields['rating'].table.id_map.itervalues())) - self.assertIn('A Series One', set(c.fields['series'].table.id_map.itervalues())) - self.assertNotIn('My Series Two', set(c.fields['#series'].table.id_map.itervalues())) + self.assertNotIn('Author Two', set(itervalues(table.id_map))) + self.assertNotIn(6, set(itervalues(c.fields['rating'].table.id_map))) + self.assertIn('A Series One', set(itervalues(c.fields['series'].table.id_map))) + self.assertNotIn('My Series Two', set(itervalues(c.fields['#series'].table.id_map))) self.assertNotIn(item_id, c.fields['#series'].table.col_book_map) self.assertNotIn(1, c.fields['#series'].table.book_col_map) @@ -264,7 +265,7 @@ class AddRemoveTest(BaseTest): fmtpath = cache.format_abspath(1, 'FMT1') bookpath = os.path.dirname(fmtpath) authorpath = os.path.dirname(bookpath) - item_id = {v:k for k, v in cache.fields['#series'].table.id_map.iteritems()}['My Series Two'] + item_id = {v:k for k, v in iteritems(cache.fields['#series'].table.id_map)}['My Series Two'] cache.remove_books((1,)) delete_service().wait() for x in (fmtpath, bookpath, authorpath): diff --git a/src/calibre/db/tests/filesystem.py b/src/calibre/db/tests/filesystem.py index c426f024c0..11c9fbe0d7 100644 --- a/src/calibre/db/tests/filesystem.py +++ b/src/calibre/db/tests/filesystem.py @@ -13,6 +13,7 @@ from io import BytesIO from calibre.constants import iswindows from calibre.db.tests.base import BaseTest from calibre.ptempfile import TemporaryDirectory +from polyglot.builtins import iterkeys class FilesystemTest(BaseTest): @@ -55,7 +56,7 @@ class FilesystemTest(BaseTest): cache2 = self.init_cache(cl) for c in (cache, cache2): data = self.get_filesystem_data(c, 1) - ae(set(orig_data.iterkeys()), set(data.iterkeys())) + ae(set(iterkeys(orig_data)), set(iterkeys(data))) ae(orig_data, data, 'Filesystem data does not match') ae(c.field_for('path', 1), 'Moved/Moved (1)') ae(c.field_for('path', 3), 'Moved1/Moved1 (3)') diff --git a/src/calibre/db/tests/legacy.py b/src/calibre/db/tests/legacy.py index 919f817b00..9310392882 100644 --- a/src/calibre/db/tests/legacy.py +++ b/src/calibre/db/tests/legacy.py @@ -14,7 +14,7 @@ from operator import itemgetter from calibre.library.field_metadata import fm_as_dict from calibre.db.tests.base import BaseTest -from polyglot.builtins import range +from polyglot.builtins import iteritems, iterkeys, range # Utils {{{ @@ -81,7 +81,7 @@ class LegacyTest(BaseTest): # We ignore the key rec_index, since it is not stable for # custom columns (it is created by iterating over a dict) return {k.decode('utf-8') if isinstance(k, bytes) else k:to_unicode(v) - for k, v in x.iteritems() if k != 'rec_index'} + for k, v in iteritems(x) if k != 'rec_index'} return x def get_props(db): @@ -108,7 +108,7 @@ class LegacyTest(BaseTest): 'Test the get_property interface for reading data' def get_values(db): ans = {} - for label, loc in db.FIELD_MAP.iteritems(): + for label, loc in iteritems(db.FIELD_MAP): if isinstance(label, numbers.Integral): label = '#'+db.custom_column_num_map[label]['label'] label = type('')(label) @@ -186,7 +186,7 @@ class LegacyTest(BaseTest): self.assertEqual(dict(db.prefs), dict(ndb.prefs)) - for meth, args in { + for meth, args in iteritems({ 'find_identical_books': [(Metadata('title one', ['author one']),), (Metadata('unknown'),), (Metadata('xxxx'),)], 'get_books_for_category': [('tags', newstag), ('#formats', 'FMT1')], 'get_next_series_num_for': [('A Series One',)], @@ -251,7 +251,7 @@ class LegacyTest(BaseTest): 'book_on_device_string':[(1,), (2,), (3,)], 'books_in_series_of':[(0,), (1,), (2,)], 'books_with_same_title':[(Metadata(db.title(0)),), (Metadata(db.title(1)),), (Metadata('1234'),)], - }.iteritems(): + }): fmt = lambda x: x if meth[0] in {'!', '@'}: fmt = {'!':dict, '@':frozenset}[meth[0]] @@ -277,8 +277,8 @@ class LegacyTest(BaseTest): old = db.get_data_as_dict(prefix='test-prefix') new = ndb.get_data_as_dict(prefix='test-prefix') for o, n in zip(old, new): - o = {type('')(k) if isinstance(k, bytes) else k:set(v) if isinstance(v, list) else v for k, v in o.iteritems()} - n = {k:set(v) if isinstance(v, list) else v for k, v in n.iteritems()} + o = {type('')(k) if isinstance(k, bytes) else k:set(v) if isinstance(v, list) else v for k, v in iteritems(o)} + n = {k:set(v) if isinstance(v, list) else v for k, v in iteritems(n)} self.assertEqual(o, n) ndb.search('title:Unknown') @@ -316,9 +316,9 @@ class LegacyTest(BaseTest): db = self.init_old() cache = ndb.new_api tmap = cache.get_id_map('tags') - t = next(tmap.iterkeys()) + t = next(iterkeys(tmap)) pmap = cache.get_id_map('publisher') - p = next(pmap.iterkeys()) + p = next(iterkeys(pmap)) run_funcs(self, db, ndb, ( ('delete_tag_using_id', t), ('delete_publisher_using_id', p), @@ -647,10 +647,10 @@ class LegacyTest(BaseTest): ndb = self.init_legacy(self.cloned_library) db = self.init_old(self.cloned_library) - a = {v:k for k, v in ndb.new_api.get_id_map('authors').iteritems()}['Author One'] - t = {v:k for k, v in ndb.new_api.get_id_map('tags').iteritems()}['Tag One'] - s = {v:k for k, v in ndb.new_api.get_id_map('series').iteritems()}['A Series One'] - p = {v:k for k, v in ndb.new_api.get_id_map('publisher').iteritems()}['Publisher One'] + a = {v:k for k, v in iteritems(ndb.new_api.get_id_map('authors'))}['Author One'] + t = {v:k for k, v in iteritems(ndb.new_api.get_id_map('tags'))}['Tag One'] + s = {v:k for k, v in iteritems(ndb.new_api.get_id_map('series'))}['A Series One'] + p = {v:k for k, v in iteritems(ndb.new_api.get_id_map('publisher'))}['Publisher One'] run_funcs(self, db, ndb, ( ('rename_author', a, 'Author Two'), ('rename_tag', t, 'News'), @@ -688,11 +688,11 @@ class LegacyTest(BaseTest): run_funcs(self, db, ndb, [(func, idx, label) for idx in range(3)]) # Test renaming/deleting - t = {v:k for k, v in ndb.new_api.get_id_map('#tags').iteritems()}['My Tag One'] - t2 = {v:k for k, v in ndb.new_api.get_id_map('#tags').iteritems()}['My Tag Two'] - a = {v:k for k, v in ndb.new_api.get_id_map('#authors').iteritems()}['My Author Two'] - a2 = {v:k for k, v in ndb.new_api.get_id_map('#authors').iteritems()}['Custom One'] - s = {v:k for k, v in ndb.new_api.get_id_map('#series').iteritems()}['My Series One'] + t = {v:k for k, v in iteritems(ndb.new_api.get_id_map('#tags'))}['My Tag One'] + t2 = {v:k for k, v in iteritems(ndb.new_api.get_id_map('#tags'))}['My Tag Two'] + a = {v:k for k, v in iteritems(ndb.new_api.get_id_map('#authors'))}['My Author Two'] + a2 = {v:k for k, v in iteritems(ndb.new_api.get_id_map('#authors'))}['Custom One'] + s = {v:k for k, v in iteritems(ndb.new_api.get_id_map('#series'))}['My Series One'] run_funcs(self, db, ndb, ( ('delete_custom_item_using_id', t, 'tags'), ('delete_custom_item_using_id', a, 'authors'), diff --git a/src/calibre/db/tests/reading.py b/src/calibre/db/tests/reading.py index 4c95644e1a..3b90b4d93d 100644 --- a/src/calibre/db/tests/reading.py +++ b/src/calibre/db/tests/reading.py @@ -13,7 +13,7 @@ from time import time from calibre.utils.date import utc_tz from calibre.db.tests.base import BaseTest -from polyglot.builtins import range +from polyglot.builtins import iteritems, iterkeys, itervalues, range class ReadingTest(BaseTest): @@ -116,8 +116,8 @@ class ReadingTest(BaseTest): }, } - for book_id, test in tests.iteritems(): - for field, expected_val in test.iteritems(): + for book_id, test in iteritems(tests): + for field, expected_val in iteritems(test): val = cache.field_for(field, book_id) if isinstance(val, tuple) and 'authors' not in field and 'languages' not in field: val, expected_val = set(val), set(expected_val) @@ -130,7 +130,7 @@ class ReadingTest(BaseTest): 'Test sorting' cache = self.init_cache() ae = self.assertEqual - for field, order in { + for field, order in iteritems({ 'title' : [2, 1, 3], 'authors': [2, 1, 3], 'series' : [3, 1, 2], @@ -154,7 +154,7 @@ class ReadingTest(BaseTest): '#yesno':[2, 1, 3], '#comments':[3, 2, 1], 'id': [1, 2, 3], - }.iteritems(): + }): x = list(reversed(order)) ae(order, cache.multisort([(field, True)], ids_to_sort=x), @@ -222,7 +222,7 @@ class ReadingTest(BaseTest): old_metadata = {i:old.get_metadata( i, index_is_id=True, get_cover=True, cover_as_data=True) for i in range(1, 4)} - for mi in old_metadata.itervalues(): + for mi in itervalues(old_metadata): mi.format_metadata = dict(mi.format_metadata) if mi.formats: mi.formats = tuple(mi.formats) @@ -234,7 +234,7 @@ class ReadingTest(BaseTest): new_metadata = {i:cache.get_metadata( i, get_cover=True, cover_as_data=True) for i in range(1, 4)} cache = None - for mi2, mi1 in zip(new_metadata.values(), old_metadata.values()): + for mi2, mi1 in zip(list(new_metadata.values()), list(old_metadata.values())): self.compare_metadata(mi1, mi2) # }}} @@ -262,7 +262,7 @@ class ReadingTest(BaseTest): old.conn.close() old = None cache = self.init_cache(self.library_path) - for book_id, cdata in covers.iteritems(): + for book_id, cdata in iteritems(covers): self.assertEqual(cdata, cache.cover(book_id), 'Reading of cover failed') f = cache.cover(book_id, as_file=True) self.assertEqual(cdata, f.read() if f else f, 'Reading of cover as file failed') @@ -325,7 +325,7 @@ class ReadingTest(BaseTest): old = None cache = self.init_cache(self.cloned_library) - for query, ans in oldvals.iteritems(): + for query, ans in iteritems(oldvals): nr = cache.search(query, '') self.assertEqual(ans, nr, 'Old result: %r != New result: %r for search: %s'%( @@ -407,11 +407,11 @@ class ReadingTest(BaseTest): lf = {i:set(old.formats(i, index_is_id=True).split(',')) if old.formats( i, index_is_id=True) else set() for i in ids} formats = {i:{f:old.format(i, f, index_is_id=True) for f in fmts} for - i, fmts in lf.iteritems()} + i, fmts in iteritems(lf)} old.conn.close() old = None cache = self.init_cache(self.library_path) - for book_id, fmts in lf.iteritems(): + for book_id, fmts in iteritems(lf): self.assertEqual(fmts, set(cache.formats(book_id)), 'Set of formats is not the same') for fmt in fmts: @@ -439,9 +439,9 @@ class ReadingTest(BaseTest): 'Test getting the author sort for authors from the db' cache = self.init_cache() table = cache.fields['authors'].table - table.set_sort_names({next(table.id_map.iterkeys()): 'Fake Sort'}, cache.backend) + table.set_sort_names({next(iterkeys(table.id_map)): 'Fake Sort'}, cache.backend) - authors = tuple(table.id_map.itervalues()) + authors = tuple(itervalues(table.id_map)) nval = cache.author_sort_from_authors(authors) self.assertIn('Fake Sort', nval) @@ -458,7 +458,7 @@ class ReadingTest(BaseTest): cache.set_field('series', {3:'test series'}) cache.set_field('series_index', {3:13}) table = cache.fields['series'].table - series = tuple(table.id_map.itervalues()) + series = tuple(itervalues(table.id_map)) nvals = {s:cache.get_next_series_num_for(s) for s in series} db = self.init_old() self.assertEqual({s:db.get_next_series_num_for(s) for s in series}, nvals) @@ -471,7 +471,7 @@ class ReadingTest(BaseTest): from calibre.ebooks.metadata.book.base import Metadata cache = self.init_cache() db = self.init_old() - for title in cache.fields['title'].table.book_col_map.itervalues(): + for title in itervalues(cache.fields['title'].table.book_col_map): for x in (db, cache): self.assertTrue(x.has_book(Metadata(title))) self.assertTrue(x.has_book(Metadata(title.upper()))) diff --git a/src/calibre/db/tests/writing.py b/src/calibre/db/tests/writing.py index 5806b060bd..e41b30c743 100644 --- a/src/calibre/db/tests/writing.py +++ b/src/calibre/db/tests/writing.py @@ -14,6 +14,7 @@ from io import BytesIO from calibre.ebooks.metadata import author_to_author_sort from calibre.utils.date import UNDEFINED_DATE from calibre.db.tests.base import BaseTest, IMG +from polyglot.builtins import iteritems, itervalues class WritingTest(BaseTest): @@ -166,7 +167,7 @@ class WritingTest(BaseTest): self.assertEqual(cache.set_field('#enum', {1:None}), {1}) cache2 = self.init_cache(cl) for c in (cache, cache2): - for i, val in {1:None, 2:'One', 3:'Three'}.iteritems(): + for i, val in iteritems({1:None, 2:'One', 3:'Three'}): self.assertEqual(c.field_for('#enum', i), val) del cache2 @@ -176,9 +177,9 @@ class WritingTest(BaseTest): self.assertEqual(cache.set_field('#rating', {1:None, 2:4, 3:8}), {1, 2, 3}) cache2 = self.init_cache(cl) for c in (cache, cache2): - for i, val in {1:None, 2:4, 3:2}.iteritems(): + for i, val in iteritems({1:None, 2:4, 3:2}): self.assertEqual(c.field_for('rating', i), val) - for i, val in {1:None, 2:4, 3:8}.iteritems(): + for i, val in iteritems({1:None, 2:4, 3:8}): self.assertEqual(c.field_for('#rating', i), val) del cache2 @@ -191,14 +192,14 @@ class WritingTest(BaseTest): self.assertEqual(cache.set_field('#series', {2:'Series [0]'}), {2}) cache2 = self.init_cache(cl) for c in (cache, cache2): - for i, val in {1:'A Series One', 2:'A Series One', 3:'Series'}.iteritems(): + for i, val in iteritems({1:'A Series One', 2:'A Series One', 3:'Series'}): self.assertEqual(c.field_for('series', i), val) cs_indices = {1:c.field_for('#series_index', 1), 3:c.field_for('#series_index', 3)} for i in (1, 2, 3): self.assertEqual(c.field_for('#series', i), 'Series') - for i, val in {1:2, 2:1, 3:3}.iteritems(): + for i, val in iteritems({1:2, 2:1, 3:3}): self.assertEqual(c.field_for('series_index', i), val) - for i, val in {1:cs_indices[1], 2:0, 3:cs_indices[3]}.iteritems(): + for i, val in iteritems({1:cs_indices[1], 2:0, 3:cs_indices[3]}): self.assertEqual(c.field_for('#series_index', i), val) del cache2 @@ -461,13 +462,13 @@ class WritingTest(BaseTest): tmap = cache.get_id_map('tags') self.assertEqual(cache.remove_items('tags', tmap), {1, 2}) tmap = cache.get_id_map('#tags') - t = {v:k for k, v in tmap.iteritems()}['My Tag Two'] + t = {v:k for k, v in iteritems(tmap)}['My Tag Two'] self.assertEqual(cache.remove_items('#tags', (t,)), {1, 2}) smap = cache.get_id_map('series') self.assertEqual(cache.remove_items('series', smap), {1, 2}) smap = cache.get_id_map('#series') - s = {v:k for k, v in smap.iteritems()}['My Series Two'] + s = {v:k for k, v in iteritems(smap)}['My Series Two'] self.assertEqual(cache.remove_items('#series', (s,)), {1}) for c in (cache, self.init_cache()): @@ -507,7 +508,7 @@ class WritingTest(BaseTest): for c in (cache, c2): self.assertEqual(c.field_for('tags', 1), ()) self.assertEqual(c.field_for('tags', 2), ('b', 'a')) - self.assertNotIn('c', set(c.get_id_map('tags').itervalues())) + self.assertNotIn('c', set(itervalues(c.get_id_map('tags')))) self.assertEqual(c.field_for('series', 1), None) self.assertEqual(c.field_for('series', 2), 'a') self.assertEqual(c.field_for('series_index', 1), 1.0) @@ -520,9 +521,9 @@ class WritingTest(BaseTest): cl = self.cloned_library cache = self.init_cache(cl) # Check that renaming authors updates author sort and path - a = {v:k for k, v in cache.get_id_map('authors').iteritems()}['Unknown'] + a = {v:k for k, v in iteritems(cache.get_id_map('authors'))}['Unknown'] self.assertEqual(cache.rename_items('authors', {a:'New Author'})[0], {3}) - a = {v:k for k, v in cache.get_id_map('authors').iteritems()}['Author One'] + a = {v:k for k, v in iteritems(cache.get_id_map('authors'))}['Author One'] self.assertEqual(cache.rename_items('authors', {a:'Author Two'})[0], {1, 2}) for c in (cache, self.init_cache(cl)): self.assertEqual(c.all_field_names('authors'), {'New Author', 'Author Two'}) @@ -531,7 +532,7 @@ class WritingTest(BaseTest): self.assertEqual(c.field_for('authors', 1), ('Author Two',)) self.assertEqual(c.field_for('author_sort', 1), 'Two, Author') - t = {v:k for k, v in cache.get_id_map('tags').iteritems()}['Tag One'] + t = {v:k for k, v in iteritems(cache.get_id_map('tags'))}['Tag One'] # Test case change self.assertEqual(cache.rename_items('tags', {t:'tag one'}), ({1, 2}, {t:t})) for c in (cache, self.init_cache(cl)): @@ -551,14 +552,14 @@ class WritingTest(BaseTest): self.assertEqual(set(c.field_for('tags', 1)), {'Tag Two', 'News'}) self.assertEqual(set(c.field_for('tags', 2)), {'Tag Two'}) # Test on a custom column - t = {v:k for k, v in cache.get_id_map('#tags').iteritems()}['My Tag One'] + t = {v:k for k, v in iteritems(cache.get_id_map('#tags'))}['My Tag One'] self.assertEqual(cache.rename_items('#tags', {t:'My Tag Two'})[0], {2}) for c in (cache, self.init_cache(cl)): self.assertEqual(c.all_field_names('#tags'), {'My Tag Two'}) self.assertEqual(set(c.field_for('#tags', 2)), {'My Tag Two'}) # Test a Many-one field - s = {v:k for k, v in cache.get_id_map('series').iteritems()}['A Series One'] + s = {v:k for k, v in iteritems(cache.get_id_map('series'))}['A Series One'] # Test case change self.assertEqual(cache.rename_items('series', {s:'a series one'}), ({1, 2}, {s:s})) for c in (cache, self.init_cache(cl)): @@ -574,7 +575,7 @@ class WritingTest(BaseTest): self.assertEqual(c.field_for('series', 2), 'series') self.assertEqual(c.field_for('series_index', 1), 2.0) - s = {v:k for k, v in cache.get_id_map('#series').iteritems()}['My Series One'] + s = {v:k for k, v in iteritems(cache.get_id_map('#series'))}['My Series One'] # Test custom column with rename to existing self.assertEqual(cache.rename_items('#series', {s:'My Series Two'})[0], {2}) for c in (cache, self.init_cache(cl)): @@ -585,7 +586,7 @@ class WritingTest(BaseTest): # Test renaming many-many items to multiple items cache = self.init_cache(self.cloned_library) - t = {v:k for k, v in cache.get_id_map('tags').iteritems()}['Tag One'] + t = {v:k for k, v in iteritems(cache.get_id_map('tags'))}['Tag One'] affected_books, id_map = cache.rename_items('tags', {t:'Something, Else, Entirely'}) self.assertEqual({1, 2}, affected_books) tmap = cache.get_id_map('tags') @@ -600,7 +601,7 @@ class WritingTest(BaseTest): # Test with restriction cache = self.init_cache() cache.set_field('tags', {1:'a,b,c', 2:'x,y,z', 3:'a,x,z'}) - tmap = {v:k for k, v in cache.get_id_map('tags').iteritems()} + tmap = {v:k for k, v in iteritems(cache.get_id_map('tags'))} self.assertEqual(cache.rename_items('tags', {tmap['a']:'r'}, restrict_to_book_ids=()), (set(), {})) self.assertEqual(cache.rename_items('tags', {tmap['a']:'r', tmap['b']:'q'}, restrict_to_book_ids=(1,))[0], {1}) self.assertEqual(cache.rename_items('tags', {tmap['x']:'X'}, restrict_to_book_ids=(2,))[0], {2}) @@ -657,7 +658,7 @@ class WritingTest(BaseTest): ldata = {aid:str(aid) for aid in adata} self.assertEqual({1,2,3}, cache.set_link_for_authors(ldata)) for c in (cache, self.init_cache()): - self.assertEqual(ldata, {aid:d['link'] for aid, d in c.author_data().iteritems()}) + self.assertEqual(ldata, {aid:d['link'] for aid, d in iteritems(c.author_data())}) self.assertEqual({3}, cache.set_link_for_authors({aid:'xxx' if aid == max(adata) else str(aid) for aid in adata}), 'Setting the author link to the same value as before, incorrectly marked some books as dirty') sdata = {aid:'%s, changed' % aid for aid in adata} @@ -709,7 +710,7 @@ class WritingTest(BaseTest): conn.execute('INSERT INTO tags (name) VALUES ("t")') norm = conn.last_insert_rowid() conn.execute('DELETE FROM books_tags_link') - for book_id, vals in {1:(lid, uid), 2:(uid, mid), 3:(lid, norm)}.iteritems(): + for book_id, vals in iteritems({1:(lid, uid), 2:(uid, mid), 3:(lid, norm)}): conn.executemany('INSERT INTO books_tags_link (book,tag) VALUES (?,?)', tuple((book_id, x) for x in vals)) cache.reload_from_db() diff --git a/src/calibre/db/utils.py b/src/calibre/db/utils.py index 5d02367248..d9d2b48893 100644 --- a/src/calibre/db/utils.py +++ b/src/calibre/db/utils.py @@ -9,7 +9,7 @@ __copyright__ = '2013, Kovid Goyal ' import os, errno, sys, re from locale import localeconv from collections import OrderedDict, namedtuple -from polyglot.builtins import map, unicode_type, string_or_bytes +from polyglot.builtins import iteritems, itervalues, map, unicode_type, string_or_bytes from threading import Lock from calibre import as_unicode, prints @@ -208,7 +208,7 @@ class ThumbnailCache(object): def _invalidate_sizes(self): if self.size_changed: size = self.thumbnail_size - remove = (key for key, entry in self.items.iteritems() if size != entry.thumbnail_size) + remove = (key for key, entry in iteritems(self.items) if size != entry.thumbnail_size) for key in remove: self._remove(key) self.size_changed = False @@ -365,7 +365,7 @@ class ThumbnailCache(object): pass if not hasattr(self, 'total_size'): self._load_index() - for entry in self.items.itervalues(): + for entry in itervalues(self.items): self._do_delete(entry.path) self.total_size = 0 self.items = OrderedDict() diff --git a/src/calibre/db/view.py b/src/calibre/db/view.py index fc773ac680..7fd51e783d 100644 --- a/src/calibre/db/view.py +++ b/src/calibre/db/view.py @@ -9,7 +9,8 @@ __docformat__ = 'restructuredtext en' import weakref, operator, numbers from functools import partial -from polyglot.builtins import map, unicode_type, range, zip +from polyglot.builtins import (iteritems, iterkeys, itervalues, map, + unicode_type, range, zip) from calibre.ebooks.metadata import title_sort from calibre.utils.config_base import tweaks, prefs @@ -71,7 +72,7 @@ def format_is_multiple(x, sep=',', repl=None): def format_identifiers(x): if not x: return None - return ','.join('%s:%s'%(k, v) for k, v in x.iteritems()) + return ','.join('%s:%s'%(k, v) for k, v in iteritems(x)) class View(object): @@ -88,7 +89,7 @@ class View(object): self.search_restriction_name = self.base_restriction_name = '' self._field_getters = {} self.column_count = len(cache.backend.FIELD_MAP) - for col, idx in cache.backend.FIELD_MAP.iteritems(): + for col, idx in iteritems(cache.backend.FIELD_MAP): label, fmt = col, lambda x:x func = { 'id': self._get_id, @@ -373,14 +374,14 @@ class View(object): self.marked_ids = dict.fromkeys(id_dict, u'true') else: # Ensure that all the items in the dict are text - self.marked_ids = dict(zip(id_dict.iterkeys(), map(unicode_type, - id_dict.itervalues()))) + self.marked_ids = dict(zip(iterkeys(id_dict), map(unicode_type, + itervalues(id_dict)))) # This invalidates all searches in the cache even though the cache may # be shared by multiple views. This is not ideal, but... cmids = set(self.marked_ids) self.cache.clear_search_caches(old_marked_ids | cmids) if old_marked_ids != cmids: - for funcref in self.marked_listeners.itervalues(): + for funcref in itervalues(self.marked_listeners): func = funcref() if func is not None: func(old_marked_ids, cmids) diff --git a/src/calibre/db/write.py b/src/calibre/db/write.py index 5670fff3f5..abc89e3353 100644 --- a/src/calibre/db/write.py +++ b/src/calibre/db/write.py @@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en' import re from functools import partial from datetime import datetime -from polyglot.builtins import unicode_type, zip +from polyglot.builtins import iteritems, itervalues, unicode_type, zip from calibre.constants import preferred_encoding from calibre.ebooks.metadata import author_to_author_sort, title_sort @@ -131,7 +131,7 @@ def adapt_identifiers(to_tuple, x): if not isinstance(x, dict): x = {k:v for k, v in (y.partition(':')[0::2] for y in to_tuple(x))} ans = {} - for k, v in x.iteritems(): + for k, v in iteritems(x): k, v = clean_identifier(k, v) if k and v: ans[k] = v @@ -194,7 +194,7 @@ def get_adapter(name, metadata): def one_one_in_books(book_id_val_map, db, field, *args): 'Set a one-one field in the books table' if book_id_val_map: - sequence = ((sqlite_datetime(v), k) for k, v in book_id_val_map.iteritems()) + sequence = ((sqlite_datetime(v), k) for k, v in iteritems(book_id_val_map)) db.executemany( 'UPDATE books SET %s=? WHERE id=?'%field.metadata['column'], sequence) field.table.book_col_map.update(book_id_val_map) @@ -210,23 +210,23 @@ def set_title(book_id_val_map, db, field, *args): ans = one_one_in_books(book_id_val_map, db, field, *args) # Set the title sort field field.title_sort_field.writer.set_books( - {k:title_sort(v) for k, v in book_id_val_map.iteritems()}, db) + {k:title_sort(v) for k, v in iteritems(book_id_val_map)}, db) return ans def one_one_in_other(book_id_val_map, db, field, *args): 'Set a one-one field in the non-books table, like comments' - deleted = tuple((k,) for k, v in book_id_val_map.iteritems() if v is None) + deleted = tuple((k,) for k, v in iteritems(book_id_val_map) if v is None) if deleted: db.executemany('DELETE FROM %s WHERE book=?'%field.metadata['table'], deleted) for book_id in deleted: field.table.book_col_map.pop(book_id[0], None) - updated = {k:v for k, v in book_id_val_map.iteritems() if v is not None} + updated = {k:v for k, v in iteritems(book_id_val_map) if v is not None} if updated: db.executemany('INSERT OR REPLACE INTO %s(book,%s) VALUES (?,?)'%( field.metadata['table'], field.metadata['column']), - ((k, sqlite_datetime(v)) for k, v in updated.iteritems())) + ((k, sqlite_datetime(v)) for k, v in iteritems(updated))) field.table.book_col_map.update(updated) return set(book_id_val_map) @@ -234,7 +234,7 @@ def one_one_in_other(book_id_val_map, db, field, *args): def custom_series_index(book_id_val_map, db, field, *args): series_field = field.series_field sequence = [] - for book_id, sidx in book_id_val_map.iteritems(): + for book_id, sidx in iteritems(book_id_val_map): if sidx is None: sidx = 1.0 ids = series_field.ids_for_book(book_id) @@ -285,12 +285,12 @@ def get_db_id(val, db, m, table, kmap, rid_map, allow_case_change, def change_case(case_changes, dirtied, db, table, m, is_authors=False): if is_authors: vals = ((val.replace(',', '|'), item_id) for item_id, val in - case_changes.iteritems()) + iteritems(case_changes)) else: - vals = ((val, item_id) for item_id, val in case_changes.iteritems()) + vals = ((val, item_id) for item_id, val in iteritems(case_changes)) db.executemany( 'UPDATE %s SET %s=? WHERE id=?'%(m['table'], m['column']), vals) - for item_id, val in case_changes.iteritems(): + for item_id, val in iteritems(case_changes): table.id_map[item_id] = val dirtied.update(table.col_book_map[item_id]) if is_authors: @@ -306,14 +306,14 @@ def many_one(book_id_val_map, db, field, allow_case_change, *args): # Map values to db ids, including any new values kmap = safe_lower if dt in {'text', 'series'} else lambda x:x - rid_map = {kmap(item):item_id for item_id, item in table.id_map.iteritems()} + rid_map = {kmap(item):item_id for item_id, item in iteritems(table.id_map)} if len(rid_map) != len(table.id_map): # table has some entries that differ only in case, fix it table.fix_case_duplicates(db) - rid_map = {kmap(item):item_id for item_id, item in table.id_map.iteritems()} + rid_map = {kmap(item):item_id for item_id, item in iteritems(table.id_map)} val_map = {None:None} case_changes = {} - for val in book_id_val_map.itervalues(): + for val in itervalues(book_id_val_map): if val is not None: get_db_id(val, db, m, table, kmap, rid_map, allow_case_change, case_changes, val_map) @@ -321,17 +321,17 @@ def many_one(book_id_val_map, db, field, allow_case_change, *args): if case_changes: change_case(case_changes, dirtied, db, table, m) - book_id_item_id_map = {k:val_map[v] for k, v in book_id_val_map.iteritems()} + book_id_item_id_map = {k:val_map[v] for k, v in iteritems(book_id_val_map)} # Ignore those items whose value is the same as the current value - book_id_item_id_map = {k:v for k, v in book_id_item_id_map.iteritems() + book_id_item_id_map = {k:v for k, v in iteritems(book_id_item_id_map) if v != table.book_col_map.get(k, None)} dirtied |= set(book_id_item_id_map) # Update the book->col and col->book maps deleted = set() updated = {} - for book_id, item_id in book_id_item_id_map.iteritems(): + for book_id, item_id in iteritems(book_id_item_id_map): old_item_id = table.book_col_map.get(book_id, None) if old_item_id is not None: table.col_book_map[old_item_id].discard(book_id) @@ -355,7 +355,7 @@ def many_one(book_id_val_map, db, field, allow_case_change, *args): ) db.executemany(sql.format(table.link_table, m['link_column']), ((book_id, book_id, item_id) for book_id, item_id in - updated.iteritems())) + iteritems(updated))) # Remove no longer used items remove = {item_id for item_id in table.id_map if not @@ -392,15 +392,15 @@ def many_many(book_id_val_map, db, field, allow_case_change, *args): # Map values to db ids, including any new values kmap = safe_lower if dt == 'text' else lambda x:x - rid_map = {kmap(item):item_id for item_id, item in table.id_map.iteritems()} + rid_map = {kmap(item):item_id for item_id, item in iteritems(table.id_map)} if len(rid_map) != len(table.id_map): # table has some entries that differ only in case, fix it table.fix_case_duplicates(db) - rid_map = {kmap(item):item_id for item_id, item in table.id_map.iteritems()} + rid_map = {kmap(item):item_id for item_id, item in iteritems(table.id_map)} val_map = {} case_changes = {} - book_id_val_map = {k:uniq(vals, kmap) for k, vals in book_id_val_map.iteritems()} - for vals in book_id_val_map.itervalues(): + book_id_val_map = {k:uniq(vals, kmap) for k, vals in iteritems(book_id_val_map)} + for vals in itervalues(book_id_val_map): for val in vals: get_db_id(val, db, m, table, kmap, rid_map, allow_case_change, case_changes, val_map, is_authors=is_authors) @@ -408,7 +408,7 @@ def many_many(book_id_val_map, db, field, allow_case_change, *args): if case_changes: change_case(case_changes, dirtied, db, table, m, is_authors=is_authors) if is_authors: - for item_id, val in case_changes.iteritems(): + for item_id, val in iteritems(case_changes): for book_id in table.col_book_map[item_id]: current_sort = field.db_author_sort_for_book(book_id) new_sort = field.author_sort_for_book(book_id) @@ -418,17 +418,17 @@ def many_many(book_id_val_map, db, field, allow_case_change, *args): field.author_sort_field.writer.set_books({book_id:new_sort}, db) book_id_item_id_map = {k:tuple(val_map[v] for v in vals) - for k, vals in book_id_val_map.iteritems()} + for k, vals in iteritems(book_id_val_map)} # Ignore those items whose value is the same as the current value - book_id_item_id_map = {k:v for k, v in book_id_item_id_map.iteritems() + book_id_item_id_map = {k:v for k, v in iteritems(book_id_item_id_map) if v != table.book_col_map.get(k, None)} dirtied |= set(book_id_item_id_map) # Update the book->col and col->book maps deleted = set() updated = {} - for book_id, item_ids in book_id_item_id_map.iteritems(): + for book_id, item_ids in iteritems(book_id_item_id_map): old_item_ids = table.book_col_map.get(book_id, None) if old_item_ids: for old_item_id in old_item_ids: @@ -448,7 +448,7 @@ def many_many(book_id_val_map, db, field, allow_case_change, *args): ((k,) for k in deleted)) if updated: vals = ( - (book_id, val) for book_id, vals in updated.iteritems() + (book_id, val) for book_id, vals in iteritems(updated) for val in vals ) db.executemany('DELETE FROM %s WHERE book=?'%table.link_table, @@ -481,7 +481,7 @@ def many_many(book_id_val_map, db, field, allow_case_change, *args): def identifiers(book_id_val_map, db, field, *args): # {{{ table = field.table updates = set() - for book_id, identifiers in book_id_val_map.iteritems(): + for book_id, identifiers in iteritems(book_id_val_map): if book_id not in table.book_col_map: table.book_col_map[book_id] = {} current_ids = table.book_col_map[book_id] @@ -490,7 +490,7 @@ def identifiers(book_id_val_map, db, field, *args): # {{{ table.col_book_map.get(key, set()).discard(book_id) current_ids.pop(key, None) current_ids.update(identifiers) - for key, val in identifiers.iteritems(): + for key, val in iteritems(identifiers): if key not in table.col_book_map: table.col_book_map[key] = set() table.col_book_map[key].add(book_id) @@ -538,7 +538,7 @@ class Writer(object): def set_books(self, book_id_val_map, db, allow_case_change=True): book_id_val_map = {k:self.adapter(v) for k, v in - book_id_val_map.iteritems() if self.accept_vals(v)} + iteritems(book_id_val_map) if self.accept_vals(v)} if not book_id_val_map: return set() dirtied = self.set_books_func(book_id_val_map, db, self.field, @@ -548,7 +548,7 @@ class Writer(object): def set_books_for_enum(self, book_id_val_map, db, field, allow_case_change): allowed = set(field.metadata['display']['enum_values']) - book_id_val_map = {k:v for k, v in book_id_val_map.iteritems() if v is + book_id_val_map = {k:v for k, v in iteritems(book_id_val_map) if v is None or v in allowed} if not book_id_val_map: return set() diff --git a/src/calibre/debug.py b/src/calibre/debug.py index 3b8c901377..6e67e19fce 100644 --- a/src/calibre/debug.py +++ b/src/calibre/debug.py @@ -248,7 +248,8 @@ def run_script(path, args): g = globals() g['__name__'] = '__main__' g['__file__'] = ef - execfile(ef, g) + with open(ef, 'rb') as f: + exec(compile(f.read(), ef, 'exec'), g) def inspect_mobi(path): @@ -346,7 +347,7 @@ def main(args=sys.argv): elif ext in {'mobi', 'azw', 'azw3'}: inspect_mobi(path) else: - print ('Cannot dump unknown filetype: %s' % path) + print('Cannot dump unknown filetype: %s' % path) elif len(args) >= 2 and os.path.exists(os.path.join(args[1], '__main__.py')): sys.path.insert(0, args[1]) run_script(os.path.join(args[1], '__main__.py'), args[2:]) diff --git a/src/calibre/devices/kobo/bookmark.py b/src/calibre/devices/kobo/bookmark.py index a08f5573f9..8763915ff5 100644 --- a/src/calibre/devices/kobo/bookmark.py +++ b/src/calibre/devices/kobo/bookmark.py @@ -12,6 +12,7 @@ class Bookmark(): # {{{ A simple class fetching bookmark data kobo-specific ''' + def __init__(self, db_connection, contentid, path, id, book_format, bookmark_extension): self.book_format = book_format self.bookmark_extension = bookmark_extension @@ -62,7 +63,7 @@ class Bookmark(): # {{{ kepub_chapter_data = ('{0}-%'.format(row[1]), ) cursor2.execute(kepub_chapter_query, kepub_chapter_data) try: - kepub_chapter = cursor2.next() + kepub_chapter = next(cursor2) chapter_title = kepub_chapter[0] current_chapter = kepub_chapter[1] except StopIteration: diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index c9f9f295ac..7f8223b473 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -32,7 +32,7 @@ from calibre import prints, fsync from calibre.ptempfile import PersistentTemporaryFile from calibre.constants import DEBUG from calibre.utils.config_base import prefs -from polyglot.builtins import unicode_type, string_or_bytes +from polyglot.builtins import iteritems, itervalues, unicode_type, string_or_bytes EPUB_EXT = '.epub' KEPUB_EXT = '.kepub' @@ -185,7 +185,7 @@ class KOBO(USBMS): cursor = connection.cursor() cursor.execute('SELECT version FROM dbversion') try: - result = cursor.next() + result = next(cursor) dbversion = result['version'] except StopIteration: dbversion = 0 @@ -407,7 +407,7 @@ class KOBO(USBMS): # Remove books that are no longer in the filesystem. Cache contains # indices into the booklist if book not in filesystem, None otherwise # Do the operation in reverse order so indices remain valid - for idx in sorted(bl_cache.itervalues(), reverse=True): + for idx in sorted(itervalues(bl_cache), reverse=True): if idx is not None: need_sync = True del bl[idx] @@ -572,7 +572,7 @@ class KOBO(USBMS): metadata = iter(metadata) for i, location in enumerate(locations): self.report_progress((i+1) / float(len(locations)), _('Adding books to device metadata listing...')) - info = metadata.next() + info = next(metadata) debug_print("KoboTouch::add_books_to_metadata - info=%s" % info) blist = 2 if location[1] == 'cardb' else 1 if location[1] == 'carda' else 0 @@ -790,7 +790,7 @@ class KOBO(USBMS): t = (ContentID,) cursor.execute('select DateLastRead, ReadStatus from Content where BookID is Null and ContentID = ?', t) try: - result = cursor.next() + result = next(cursor) datelastread = result['DateLastRead'] current_ReadStatus = result['ReadStatus'] except StopIteration: @@ -908,13 +908,13 @@ class KOBO(USBMS): ContentID = self.contentid_from_path(book.path, ContentType) - if category in readstatuslist.keys(): + if category in list(readstatuslist.keys()): # Manage ReadStatus self.set_readstatus(connection, ContentID, readstatuslist.get(category)) elif category == 'Shortlist' and self.dbversion >= 14: # Manage FavouritesIndex/Shortlist self.set_favouritesindex(connection, ContentID) - elif category in accessibilitylist.keys(): + elif category in list(accessibilitylist.keys()): # Do not manage the Accessibility List pass else: # No collections @@ -1020,7 +1020,7 @@ class KOBO(USBMS): t = (ContentID,) cursor.execute('select ImageId from Content where BookID is Null and ContentID = ?', t) try: - result = cursor.next() + result = next(cursor) # debug_print("ImageId: ", result[0]) ImageID = result[0] except StopIteration: @@ -1962,7 +1962,7 @@ class KOBOTOUCH(KOBO): # Remove books that are no longer in the filesystem. Cache contains # indices into the booklist if book not in filesystem, None otherwise # Do the operation in reverse order so indices remain valid - for idx in sorted(bl_cache.itervalues(), reverse=True): + for idx in sorted(itervalues(bl_cache), reverse=True): if idx is not None: if not os.path.exists(self.normalize_path(os.path.join(prefix, bl[idx].lpath))) or not bl[idx].contentID: need_sync = True @@ -2136,7 +2136,7 @@ class KOBOTOUCH(KOBO): from calibre.ebooks.oeb.base import OEB_STYLES is_dirty = False - for cssname, mt in container.mime_map.iteritems(): + for cssname, mt in iteritems(container.mime_map): if mt in OEB_STYLES: newsheet = container.parsed(cssname) oldrules = len(newsheet.cssRules) @@ -2445,7 +2445,7 @@ class KOBOTOUCH(KOBO): debug_print(' Setting bookshelf on device') self.set_bookshelf(connection, book, category) category_added = True - elif category in readstatuslist.keys(): + elif category in list(readstatuslist.keys()): debug_print("KoboTouch:update_device_database_collections - about to set_readstatus - category='%s'"%(category, )) # Manage ReadStatus self.set_readstatus(connection, book.contentID, readstatuslist.get(category)) @@ -2460,7 +2460,7 @@ class KOBOTOUCH(KOBO): debug_print(' and about to set it - %s'%book.title) self.set_favouritesindex(connection, book.contentID) category_added = True - elif category in accessibilitylist.keys(): + elif category in list(accessibilitylist.keys()): # Do not manage the Accessibility List pass @@ -2647,7 +2647,7 @@ class KOBOTOUCH(KOBO): t = (ContentID,) cursor.execute('select ImageId from Content where BookID is Null and ContentID = ?', t) try: - result = cursor.next() + result = next(cursor) ImageID = result[0] except StopIteration: ImageID = self.imageid_from_contentid(ContentID) @@ -2750,7 +2750,7 @@ class KOBOTOUCH(KOBO): cursor = connection.cursor() cursor.execute(test_query, test_values) try: - result = cursor.next() + result = next(cursor) except StopIteration: result = None @@ -2858,7 +2858,7 @@ class KOBOTOUCH(KOBO): cursor = connection.cursor() cursor.execute(test_query, test_values) try: - result = cursor.next() + result = next(cursor) except StopIteration: result = None @@ -2907,7 +2907,7 @@ class KOBOTOUCH(KOBO): cursor = connection.cursor() cursor.execute(test_query, test_values) try: - result = cursor.next() + result = next(cursor) except StopIteration: result = None diff --git a/src/calibre/devices/mtp/defaults.py b/src/calibre/devices/mtp/defaults.py index ed72ddaad1..9bcd6f2909 100644 --- a/src/calibre/devices/mtp/defaults.py +++ b/src/calibre/devices/mtp/defaults.py @@ -10,6 +10,7 @@ __docformat__ = 'restructuredtext en' import traceback, re from calibre.constants import iswindows +from polyglot.builtins import iteritems class DeviceDefaults(object): @@ -47,7 +48,7 @@ class DeviceDefaults(object): for rule in self.rules: tests = rule[0] matches = True - for k, v in tests.iteritems(): + for k, v in iteritems(tests): if k == 'vendor' and v != vid: matches = False break diff --git a/src/calibre/devices/mtp/driver.py b/src/calibre/devices/mtp/driver.py index 725f497baa..58a19b19c7 100644 --- a/src/calibre/devices/mtp/driver.py +++ b/src/calibre/devices/mtp/driver.py @@ -17,7 +17,7 @@ from calibre.devices.mtp.base import debug from calibre.devices.mtp.defaults import DeviceDefaults from calibre.ptempfile import SpooledTemporaryFile, PersistentTemporaryDirectory from calibre.utils.filenames import shorten_components_to -from polyglot.builtins import unicode_type, zip +from polyglot.builtins import iteritems, itervalues, unicode_type, zip BASE = importlib.import_module('calibre.devices.mtp.%s.driver'%( 'windows' if iswindows else 'unix')).MTP_DEVICE @@ -276,7 +276,7 @@ class MTP_DEVICE(BASE): book.path = mtp_file.mtp_id_path # Remove books in the cache that no longer exist - for idx in sorted(relpath_cache.itervalues(), reverse=True): + for idx in sorted(itervalues(relpath_cache), reverse=True): del bl[idx] need_sync = True @@ -546,7 +546,7 @@ class MTP_DEVICE(BASE): def get_user_blacklisted_devices(self): bl = frozenset(self.prefs['blacklist']) ans = {} - for dev, x in self.prefs['history'].iteritems(): + for dev, x in iteritems(self.prefs['history']): name = x[0] if dev in bl: ans[dev] = name diff --git a/src/calibre/devices/mtp/filesystem_cache.py b/src/calibre/devices/mtp/filesystem_cache.py index f5a3ef690d..1d2744ba98 100644 --- a/src/calibre/devices/mtp/filesystem_cache.py +++ b/src/calibre/devices/mtp/filesystem_cache.py @@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en' import weakref, sys, json from collections import deque from operator import attrgetter -from polyglot.builtins import map, unicode_type +from polyglot.builtins import itervalues, map, unicode_type from datetime import datetime from calibre import human_readable, prints, force_unicode @@ -201,7 +201,7 @@ class FilesystemCache(object): for entry in entries: FileOrFolder(entry, self) - for item in self.id_map.itervalues(): + for item in itervalues(self.id_map): try: p = item.parent except KeyError: @@ -227,7 +227,7 @@ class FilesystemCache(object): return e def iterebooks(self, storage_id): - for x in self.id_map.itervalues(): + for x in itervalues(self.id_map): if x.storage_id == storage_id and x.is_ebook: if x.parent_id == storage_id and x.name.lower().endswith('.txt'): continue # Ignore .txt files in the root diff --git a/src/calibre/devices/mtp/windows/driver.py b/src/calibre/devices/mtp/windows/driver.py index 23c445570b..f99a0309c6 100644 --- a/src/calibre/devices/mtp/windows/driver.py +++ b/src/calibre/devices/mtp/windows/driver.py @@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en' import time, threading, traceback from functools import wraps, partial -from polyglot.builtins import unicode_type, zip +from polyglot.builtins import iteritems, iterkeys, itervalues, unicode_type, zip from itertools import chain from calibre import as_unicode, prints, force_unicode @@ -107,7 +107,7 @@ class MTP_DEVICE(MTPDeviceBase): # Get device data for detected devices. If there is an error, we will # try again for that device the next time this method is called. - for dev in tuple(self.detected_devices.iterkeys()): + for dev in tuple(iterkeys(self.detected_devices)): data = self.detected_devices.get(dev, None) if data is None or data is False: try: @@ -130,7 +130,7 @@ class MTP_DEVICE(MTPDeviceBase): self.currently_connected_pnp_id in self.detected_devices else None) - for dev, data in self.detected_devices.iteritems(): + for dev, data in iteritems(self.detected_devices): if dev in self.blacklisted_devices or dev in self.ejected_devices: # Ignore blacklisted and ejected devices continue @@ -267,10 +267,10 @@ class MTP_DEVICE(MTPDeviceBase): self._currently_getting_sid = unicode_type(storage_id) id_map = self.dev.get_filesystem(storage_id, partial( self._filesystem_callback, {})) - for x in id_map.itervalues(): + for x in itervalues(id_map): x['storage_id'] = storage_id all_storage.append(storage) - items.append(id_map.itervalues()) + items.append(itervalues(id_map)) self._filesystem_cache = FilesystemCache(all_storage, chain(*items)) debug('Filesystem metadata loaded in %g seconds (%d objects)'%( time.time()-st, len(self._filesystem_cache))) diff --git a/src/calibre/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index 132ff00b6d..c8db25b73a 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -705,8 +705,8 @@ class XMLCache(object): child.text = '\n'+'\t'*(level+1) for gc in child: gc.tail = '\n'+'\t'*(level+1) - child.iterchildren(reversed=True).next().tail = '\n'+'\t'*level - root.iterchildren(reversed=True).next().tail = '\n'+'\t'*(level-1) + next(child.iterchildren(reversed=True)).tail = '\n'+'\t'*level + next(root.iterchildren(reversed=True)).tail = '\n'+'\t'*(level-1) def move_playlists_to_bottom(self): for root in self.record_roots.values(): @@ -799,4 +799,3 @@ class XMLCache(object): self.namespaces[i] = ns # }}} - diff --git a/src/calibre/devices/scanner.py b/src/calibre/devices/scanner.py index ca3014cda9..1eb5a24b95 100644 --- a/src/calibre/devices/scanner.py +++ b/src/calibre/devices/scanner.py @@ -13,7 +13,7 @@ from threading import Lock from calibre import prints, as_unicode from calibre.constants import (iswindows, isosx, plugins, islinux, isfreebsd, isnetbsd) -from polyglot.builtins import range +from polyglot.builtins import iterkeys, range osx_scanner = linux_scanner = freebsd_scanner = netbsd_scanner = None @@ -77,7 +77,7 @@ class LibUSBScanner(object): dev = USBDevice(*dev) dev.busnum, dev.devnum = fingerprint[:2] ans.add(dev) - extra = set(self.libusb.cache.iterkeys()) - seen + extra = set(iterkeys(self.libusb.cache)) - seen for x in extra: self.libusb.cache.pop(x, None) return ans diff --git a/src/calibre/devices/smart_device_app/driver.py b/src/calibre/devices/smart_device_app/driver.py index 7d52dc76c8..8dfe3f468e 100644 --- a/src/calibre/devices/smart_device_app/driver.py +++ b/src/calibre/devices/smart_device_app/driver.py @@ -1471,7 +1471,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin): metadata = iter(metadata) for i, infile in enumerate(files): - mdata, fname = metadata.next(), names.next() + mdata, fname = next(metadata), next(names) lpath = self._create_upload_path(mdata, fname, create_dirs=False) self._debug('lpath', lpath) if not hasattr(infile, 'read'): @@ -1497,7 +1497,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin): for i, location in enumerate(locations): self.report_progress((i + 1) / float(len(locations)), _('Adding books to device metadata listing...')) - info = metadata.next() + info = next(metadata) lpath = location[0] length = location[1] lpath = self._strip_prefix(lpath) diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py index 401728928e..a7eb0b3567 100644 --- a/src/calibre/devices/usbms/device.py +++ b/src/calibre/devices/usbms/device.py @@ -23,7 +23,7 @@ from calibre.devices.errors import DeviceError from calibre.devices.usbms.deviceconfig import DeviceConfig from calibre.constants import iswindows, islinux, isosx, isfreebsd, plugins from calibre.utils.filenames import ascii_filename as sanitize -from polyglot.builtins import string_or_bytes +from polyglot.builtins import iteritems, string_or_bytes if isosx: usbobserver, usbobserver_err = plugins['usbobserver'] @@ -404,7 +404,7 @@ class Device(DeviceConfig, DevicePlugin): bsd_drives = self.osx_bsd_names() drives = self.osx_sort_names(bsd_drives.copy()) mount_map = usbobserver.get_mounted_filesystems() - drives = {k: mount_map.get(v) for k, v in drives.iteritems()} + drives = {k: mount_map.get(v) for k, v in iteritems(drives)} if DEBUG: print() from pprint import pprint diff --git a/src/calibre/devices/usbms/driver.py b/src/calibre/devices/usbms/driver.py index 1c8e657b7d..c475800ab3 100644 --- a/src/calibre/devices/usbms/driver.py +++ b/src/calibre/devices/usbms/driver.py @@ -20,7 +20,7 @@ from calibre.devices.usbms.cli import CLI from calibre.devices.usbms.device import Device from calibre.devices.usbms.books import BookList, Book from calibre.ebooks.metadata.book.json_codec import JsonCodec -from polyglot.builtins import unicode_type, string_or_bytes +from polyglot.builtins import itervalues, unicode_type, string_or_bytes BASE_TIME = None @@ -281,7 +281,7 @@ class USBMS(CLI, Device): # Remove books that are no longer in the filesystem. Cache contains # indices into the booklist if book not in filesystem, None otherwise # Do the operation in reverse order so indices remain valid - for idx in sorted(bl_cache.itervalues(), reverse=True): + for idx in sorted(itervalues(bl_cache), reverse=True): if idx is not None: need_sync = True del bl[idx] @@ -311,7 +311,7 @@ class USBMS(CLI, Device): metadata = iter(metadata) for i, infile in enumerate(files): - mdata, fname = metadata.next(), names.next() + mdata, fname = next(metadata), next(names) filepath = self.normalize_path(self.create_upload_path(path, mdata, fname)) if not hasattr(infile, 'read'): infile = self.normalize_path(infile) @@ -350,7 +350,7 @@ class USBMS(CLI, Device): metadata = iter(metadata) for i, location in enumerate(locations): self.report_progress((i+1) / float(len(locations)), _('Adding books to device metadata listing...')) - info = metadata.next() + info = next(metadata) blist = 2 if location[1] == 'cardb' else 1 if location[1] == 'carda' else 0 # Extract the correct prefix from the pathname. To do this correctly, diff --git a/src/calibre/devices/winusb.py b/src/calibre/devices/winusb.py index 5b1a005328..0a7647cce0 100644 --- a/src/calibre/devices/winusb.py +++ b/src/calibre/devices/winusb.py @@ -15,7 +15,7 @@ from ctypes import ( ) from ctypes.wintypes import DWORD, WORD, ULONG, LPCWSTR, HWND, BOOL, LPWSTR, UINT, BYTE, HANDLE, USHORT from pprint import pprint, pformat -from polyglot.builtins import map +from polyglot.builtins import iteritems, itervalues, map from calibre import prints, as_unicode @@ -652,13 +652,13 @@ def get_volume_information(drive_letter): 'max_component_length': max_component_length.value, } - for name, num in {'FILE_CASE_PRESERVED_NAMES':0x00000002, 'FILE_CASE_SENSITIVE_SEARCH':0x00000001, 'FILE_FILE_COMPRESSION':0x00000010, + for name, num in iteritems({'FILE_CASE_PRESERVED_NAMES':0x00000002, 'FILE_CASE_SENSITIVE_SEARCH':0x00000001, 'FILE_FILE_COMPRESSION':0x00000010, 'FILE_NAMED_STREAMS':0x00040000, 'FILE_PERSISTENT_ACLS':0x00000008, 'FILE_READ_ONLY_VOLUME':0x00080000, 'FILE_SEQUENTIAL_WRITE_ONCE':0x00100000, 'FILE_SUPPORTS_ENCRYPTION':0x00020000, 'FILE_SUPPORTS_EXTENDED_ATTRIBUTES':0x00800000, 'FILE_SUPPORTS_HARD_LINKS':0x00400000, 'FILE_SUPPORTS_OBJECT_IDS':0x00010000, 'FILE_SUPPORTS_OPEN_BY_FILE_ID':0x01000000, 'FILE_SUPPORTS_REPARSE_POINTS':0x00000080, 'FILE_SUPPORTS_SPARSE_FILES':0x00000040, 'FILE_SUPPORTS_TRANSACTIONS':0x00200000, 'FILE_SUPPORTS_USN_JOURNAL':0x02000000, 'FILE_UNICODE_ON_DISK':0x00000004, 'FILE_VOLUME_IS_COMPRESSED':0x00008000, - 'FILE_VOLUME_QUOTAS':0x00000020}.iteritems(): + 'FILE_VOLUME_QUOTAS':0x00000020}): ans[name] = bool(num & flags) return ans @@ -809,7 +809,7 @@ def get_storage_number_map(drive_types=(DRIVE_REMOVABLE, DRIVE_FIXED), debug=Fal ' Get a mapping of drive letters to storage numbers for all drives on system (of the specified types) ' mask = GetLogicalDrives() type_map = {letter:GetDriveType(letter + ':' + os.sep) for i, letter in enumerate(string.ascii_uppercase) if mask & (1 << i)} - drives = (letter for letter, dt in type_map.iteritems() if dt in drive_types) + drives = (letter for letter, dt in iteritems(type_map) if dt in drive_types) ans = defaultdict(list) for letter in drives: try: @@ -819,7 +819,7 @@ def get_storage_number_map(drive_types=(DRIVE_REMOVABLE, DRIVE_FIXED), debug=Fal if debug: prints('Failed to get storage number for drive: %s with error: %s' % (letter, as_unicode(err))) continue - for val in ans.itervalues(): + for val in itervalues(ans): val.sort(key=itemgetter(0)) return dict(ans) @@ -859,7 +859,7 @@ def get_storage_number_map_alt(debug=False): if debug: prints('Failed to get storage number for drive: %s with error: %s' % (name[0], as_unicode(err))) continue - for val in ans.itervalues(): + for val in itervalues(ans): val.sort(key=itemgetter(0)) return dict(ans) diff --git a/src/calibre/ebooks/conversion/cli.py b/src/calibre/ebooks/conversion/cli.py index a1394b592b..10e9ce6b8f 100644 --- a/src/calibre/ebooks/conversion/cli.py +++ b/src/calibre/ebooks/conversion/cli.py @@ -17,6 +17,7 @@ from calibre.customize.conversion import OptionRecommendation from calibre import patheq from calibre.ebooks.conversion import ConversionUserFeedBack from calibre.utils.localization import localize_user_manual_link +from polyglot.builtins import iteritems USAGE = '%prog ' + _('''\ input_file output_file [options] @@ -254,7 +255,7 @@ def add_pipeline_options(parser, plumber): )) - for group, (desc, options) in groups.iteritems(): + for group, (desc, options) in iteritems(groups): if group: group = OptionGroup(parser, group, desc) parser.add_option_group(group) diff --git a/src/calibre/ebooks/conversion/plugins/epub_input.py b/src/calibre/ebooks/conversion/plugins/epub_input.py index a94e02150e..a72571cf12 100644 --- a/src/calibre/ebooks/conversion/plugins/epub_input.py +++ b/src/calibre/ebooks/conversion/plugins/epub_input.py @@ -18,7 +18,7 @@ def decrypt_font_data(key, data, algorithm): crypt_len = 1024 if is_adobe else 1040 crypt = bytearray(data[:crypt_len]) key = cycle(iter(bytearray(key))) - decrypt = bytes(bytearray(x^key.next() for x in crypt)) + decrypt = bytes(bytearray(x^next(key) for x in crypt)) return decrypt + data[crypt_len:] diff --git a/src/calibre/ebooks/conversion/plugins/epub_output.py b/src/calibre/ebooks/conversion/plugins/epub_output.py index 25f6c3b2aa..294c7afcfc 100644 --- a/src/calibre/ebooks/conversion/plugins/epub_output.py +++ b/src/calibre/ebooks/conversion/plugins/epub_output.py @@ -218,7 +218,7 @@ class EPUBOutput(OutputFormatPlugin): if self.oeb.toc.count() == 0: self.log.warn('This EPUB file has no Table of Contents. ' 'Creating a default TOC') - first = iter(self.oeb.spine).next() + first = next(iter(self.oeb.spine)) self.oeb.toc.add(_('Start'), first.href) from calibre.ebooks.oeb.base import OPF @@ -422,7 +422,7 @@ class EPUBOutput(OutputFormatPlugin): if br.getparent() is None: continue try: - prior = br.itersiblings(preceding=True).next() + prior = next(br.itersiblings(preceding=True)) priortag = barename(prior.tag) priortext = prior.tail except: diff --git a/src/calibre/ebooks/conversion/plugins/fb2_input.py b/src/calibre/ebooks/conversion/plugins/fb2_input.py index 879836aa85..42122d3a50 100644 --- a/src/calibre/ebooks/conversion/plugins/fb2_input.py +++ b/src/calibre/ebooks/conversion/plugins/fb2_input.py @@ -8,7 +8,7 @@ import os, re from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation from calibre import guess_type -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type FB2NS = 'http://www.gribuser.ru/xml/fictionbook/2.0' FB21NS = 'http://www.gribuser.ru/xml/fictionbook/2.1' @@ -103,7 +103,7 @@ class FB2Input(InputFormatPlugin): notes = {a.get('href')[1:]: a for a in result.xpath('//a[@link_note and @href]') if a.get('href').startswith('#')} cites = {a.get('link_cite'): a for a in result.xpath('//a[@link_cite]') if not a.get('href', '')} all_ids = {x for x in result.xpath('//*/@id')} - for cite, a in cites.iteritems(): + for cite, a in iteritems(cites): note = notes.get(cite, None) if note: c = 1 diff --git a/src/calibre/ebooks/conversion/plugins/pdf_output.py b/src/calibre/ebooks/conversion/plugins/pdf_output.py index b0b4ad6bae..ee20c0f1ac 100644 --- a/src/calibre/ebooks/conversion/plugins/pdf_output.py +++ b/src/calibre/ebooks/conversion/plugins/pdf_output.py @@ -14,7 +14,7 @@ from calibre.constants import iswindows from calibre.customize.conversion import (OutputFormatPlugin, OptionRecommendation) from calibre.ptempfile import TemporaryDirectory -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type UNITS = ['millimeter', 'centimeter', 'point', 'inch' , 'pica' , 'didot', 'cicero', 'devicepixel'] @@ -263,7 +263,7 @@ class PDFOutput(OutputFormatPlugin): self.process_fonts() if self.opts.pdf_use_document_margins and self.stored_page_margins: import json - for href, margins in self.stored_page_margins.iteritems(): + for href, margins in iteritems(self.stored_page_margins): item = oeb_book.manifest.hrefs.get(href) if item is not None: root = item.data diff --git a/src/calibre/ebooks/conversion/plugins/rtf_input.py b/src/calibre/ebooks/conversion/plugins/rtf_input.py index e38c76b2d5..98059a3eca 100644 --- a/src/calibre/ebooks/conversion/plugins/rtf_input.py +++ b/src/calibre/ebooks/conversion/plugins/rtf_input.py @@ -5,6 +5,7 @@ __copyright__ = '2008, Kovid Goyal ' import os, glob, re, textwrap from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation +from polyglot.builtins import iteritems border_style_map = { 'single' : 'solid', @@ -145,7 +146,7 @@ class RTFInput(InputFormatPlugin): def convert_images(self, imap): self.default_img = None - for count, val in imap.iteritems(): + for count, val in iteritems(imap): try: imap[count] = self.convert_image(val) except: @@ -210,7 +211,7 @@ class RTFInput(InputFormatPlugin): css += '\n'+'\n'.join(font_size_classes) css += '\n' +'\n'.join(color_classes) - for cls, val in border_styles.iteritems(): + for cls, val in iteritems(border_styles): css += '\n\n.%s {\n%s\n}'%(cls, val) with open(u'styles.css', 'ab') as f: diff --git a/src/calibre/ebooks/conversion/plugins/snb_output.py b/src/calibre/ebooks/conversion/plugins/snb_output.py index 3861286a96..00d0b0dc34 100644 --- a/src/calibre/ebooks/conversion/plugins/snb_output.py +++ b/src/calibre/ebooks/conversion/plugins/snb_output.py @@ -125,10 +125,10 @@ class SNBOutput(OutputFormatPlugin): if oeb_book.toc.count() == 0: log.warn('This SNB file has no Table of Contents. ' 'Creating a default TOC') - first = iter(oeb_book.spine).next() + first = next(iter(oeb_book.spine)) oeb_book.toc.add(_('Start page'), first.href) else: - first = iter(oeb_book.spine).next() + first = next(iter(oeb_book.spine)) if oeb_book.toc[0].href != first.href: # The pages before the fist item in toc will be stored as # "Cover Pages". diff --git a/src/calibre/ebooks/covers.py b/src/calibre/ebooks/covers.py index 035ca9ad39..a5a1c7df2d 100644 --- a/src/calibre/ebooks/covers.py +++ b/src/calibre/ebooks/covers.py @@ -10,7 +10,7 @@ import re, random, unicodedata, numbers from collections import namedtuple from contextlib import contextmanager from math import ceil, sqrt, cos, sin, atan2 -from polyglot.builtins import map, zip, string_or_bytes +from polyglot.builtins import iteritems, itervalues, map, zip, string_or_bytes from itertools import chain from PyQt5.Qt import ( @@ -282,7 +282,7 @@ def preserve_fields(obj, fields): try: yield finally: - for f, val in mem.iteritems(): + for f, val in iteritems(mem): if val is null: delattr(obj, f) else: @@ -324,10 +324,10 @@ def load_color_themes(prefs): t = default_color_themes.copy() t.update(prefs.color_themes) disabled = frozenset(prefs.disabled_color_themes) - ans = [theme_to_colors(v) for k, v in t.iteritems() if k not in disabled] + ans = [theme_to_colors(v) for k, v in iteritems(t) if k not in disabled] if not ans: # Ignore disabled and return only the builtin color themes - ans = [theme_to_colors(v) for k, v in default_color_themes.iteritems()] + ans = [theme_to_colors(v) for k, v in iteritems(default_color_themes)] return ans @@ -557,14 +557,14 @@ class Blocks(Style): def all_styles(): return set( - x.NAME for x in globals().itervalues() if + x.NAME for x in itervalues(globals()) if isinstance(x, type) and issubclass(x, Style) and x is not Style ) def load_styles(prefs, respect_disabled=True): disabled = frozenset(prefs.disabled_styles) if respect_disabled else () - ans = tuple(x for x in globals().itervalues() if + ans = tuple(x for x in itervalues(globals()) if isinstance(x, type) and issubclass(x, Style) and x is not Style and x.NAME not in disabled) if not ans and disabled: # If all styles have been disabled, ignore the disabling and return all diff --git a/src/calibre/ebooks/css_transform_rules.py b/src/calibre/ebooks/css_transform_rules.py index 58fc483047..3bd8428c2d 100644 --- a/src/calibre/ebooks/css_transform_rules.py +++ b/src/calibre/ebooks/css_transform_rules.py @@ -13,6 +13,7 @@ from css_parser.css import Property, CSSRule from calibre import force_unicode from calibre.ebooks import parse_css_length from calibre.ebooks.oeb.normalize_css import normalizers, safe_parser +from polyglot.builtins import iteritems def compile_pat(pat): @@ -44,7 +45,7 @@ class StyleDeclaration(object): yield p, None else: if p not in self.expanded_properties: - self.expanded_properties[p] = [Property(k, v, p.literalpriority) for k, v in n(p.name, p.propertyValue).iteritems()] + self.expanded_properties[p] = [Property(k, v, p.literalpriority) for k, v in iteritems(n(p.name, p.propertyValue))] for ep in self.expanded_properties[p]: yield ep, p @@ -338,7 +339,7 @@ def export_rules(serialized_rules): lines = [] for rule in serialized_rules: lines.extend('# ' + l for l in rule_to_text(rule).splitlines()) - lines.extend('%s: %s' % (k, v.replace('\n', ' ')) for k, v in rule.iteritems() if k in allowed_keys) + lines.extend('%s: %s' % (k, v.replace('\n', ' ')) for k, v in iteritems(rule) if k in allowed_keys) lines.append('') return '\n'.join(lines).encode('utf-8') diff --git a/src/calibre/ebooks/docx/block_styles.py b/src/calibre/ebooks/docx/block_styles.py index 480738fa06..05f5f54692 100644 --- a/src/calibre/ebooks/docx/block_styles.py +++ b/src/calibre/ebooks/docx/block_styles.py @@ -8,6 +8,7 @@ __copyright__ = '2013, Kovid Goyal ' import numbers from collections import OrderedDict +from polyglot.builtins import iteritems class Inherit: @@ -115,11 +116,11 @@ def read_border(parent, dest, XPath, get, border_edges=border_edges, name='pBdr' for border in XPath('./w:' + name)(parent): for edge in border_edges: - for prop, val in read_single_border(border, edge, XPath, get).iteritems(): + for prop, val in iteritems(read_single_border(border, edge, XPath, get)): if val is not None: vals[prop % edge] = val - for key, val in vals.iteritems(): + for key, val in iteritems(vals): setattr(dest, key, val) diff --git a/src/calibre/ebooks/docx/cleanup.py b/src/calibre/ebooks/docx/cleanup.py index 30fd9d25d9..6d71805fc0 100644 --- a/src/calibre/ebooks/docx/cleanup.py +++ b/src/calibre/ebooks/docx/cleanup.py @@ -7,7 +7,7 @@ __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal ' import os -from polyglot.builtins import range +from polyglot.builtins import iterkeys, itervalues, range NBSP = '\xa0' @@ -54,7 +54,7 @@ def merge_run(run): def liftable(css): # A is liftable if all its styling would work just as well if it is # specified on the parent element. - prefixes = {x.partition('-')[0] for x in css.iterkeys()} + prefixes = {x.partition('-')[0] for x in iterkeys(css)} return not (prefixes - {'text', 'font', 'letter', 'color', 'background'}) @@ -134,7 +134,7 @@ def cleanup_markup(log, root, styles, dest_dir, detect_cover, XPath): current_run = [span] # Process dir attributes - class_map = dict(styles.classes.itervalues()) + class_map = dict(itervalues(styles.classes)) parents = ('p', 'div') + tuple('h%d' % i for i in range(1, 7)) for parent in root.xpath('//*[(%s)]' % ' or '.join('name()="%s"' % t for t in parents)): # Ensure that children of rtl parents that are not rtl have an diff --git a/src/calibre/ebooks/docx/fields.py b/src/calibre/ebooks/docx/fields.py index 3d7e457019..286588371e 100644 --- a/src/calibre/ebooks/docx/fields.py +++ b/src/calibre/ebooks/docx/fields.py @@ -9,6 +9,7 @@ __copyright__ = '2013, Kovid Goyal ' import re from calibre.ebooks.docx.index import process_index, polish_index_markup +from polyglot.builtins import iteritems class Field(object): @@ -38,6 +39,7 @@ class Field(object): self.instructions = ''.join(self.buf) del self.buf + WORD, FLAG = 0, 1 scanner = re.Scanner([ (r'\\\S{1}', lambda s, t: (t, FLAG)), # A flag of the form \x @@ -76,6 +78,7 @@ def parser(name, field_map, default_field_name=None): return parse + parse_hyperlink = parser('hyperlink', 'l:anchor m:image-map n:target o:title t:target', 'url') @@ -222,7 +225,7 @@ class Fields(object): def polish_markup(self, object_map): if not self.index_fields: return - rmap = {v:k for k, v in object_map.iteritems()} + rmap = {v:k for k, v in iteritems(object_map)} for idx, blocks in self.index_fields: polish_index_markup(idx, [rmap[b] for b in blocks]) @@ -256,5 +259,6 @@ def test_parse_fields(return_tests=False): return suite unittest.TextTestRunner(verbosity=4).run(suite) + if __name__ == '__main__': test_parse_fields() diff --git a/src/calibre/ebooks/docx/fonts.py b/src/calibre/ebooks/docx/fonts.py index 0aed536cab..9532d7c078 100644 --- a/src/calibre/ebooks/docx/fonts.py +++ b/src/calibre/ebooks/docx/fonts.py @@ -14,7 +14,7 @@ from calibre.utils.filenames import ascii_filename from calibre.utils.fonts.scanner import font_scanner, NoFonts from calibre.utils.fonts.utils import panose_to_css_generic_family, is_truetype_font from calibre.utils.icu import ord_string -from polyglot.builtins import codepoint_to_chr, range +from polyglot.builtins import codepoint_to_chr, iteritems, range Embed = namedtuple('Embed', 'name key subsetted') @@ -172,7 +172,7 @@ class Fonts(object): d['font-weight'] = 'bold' if 'Italic' in variant: d['font-style'] = 'italic' - d = ['%s: %s' % (k, v) for k, v in d.iteritems()] + d = ['%s: %s' % (k, v) for k, v in iteritems(d)] d = ';\n\t'.join(d) defs.append('@font-face {\n\t%s\n}\n' % d) return '\n'.join(defs) diff --git a/src/calibre/ebooks/docx/footnotes.py b/src/calibre/ebooks/docx/footnotes.py index a078b9f57c..15f40fb092 100644 --- a/src/calibre/ebooks/docx/footnotes.py +++ b/src/calibre/ebooks/docx/footnotes.py @@ -7,6 +7,7 @@ __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal ' from collections import OrderedDict +from polyglot.builtins import iteritems class Note(object): @@ -57,10 +58,9 @@ class Footnotes(object): return None, None def __iter__(self): - for anchor, (counter, note) in self.notes.iteritems(): + for anchor, (counter, note) in iteritems(self.notes): yield anchor, counter, note @property def has_notes(self): return bool(self.notes) - diff --git a/src/calibre/ebooks/docx/images.py b/src/calibre/ebooks/docx/images.py index a3fcfc8efb..17a4bb08f0 100644 --- a/src/calibre/ebooks/docx/images.py +++ b/src/calibre/ebooks/docx/images.py @@ -15,6 +15,7 @@ from calibre.ebooks.docx.names import barename from calibre.utils.filenames import ascii_filename from calibre.utils.img import resize_to_fit, image_to_data from calibre.utils.imghdr import what +from polyglot.builtins import iteritems, itervalues class LinkedImageNotFound(ValueError): @@ -66,7 +67,7 @@ def get_image_properties(parent, XPath, get): def get_image_margins(elem): ans = {} - for w, css in {'L':'left', 'T':'top', 'R':'right', 'B':'bottom'}.iteritems(): + for w, css in iteritems({'L':'left', 'T':'top', 'R':'right', 'B':'bottom'}): val = elem.get('dist%s' % w, None) if val is not None: try: @@ -157,7 +158,7 @@ class Images(object): return raw, base def unique_name(self, base): - exists = frozenset(self.used.itervalues()) + exists = frozenset(itervalues(self.used)) c = 1 name = base while name in exists: @@ -242,7 +243,7 @@ class Images(object): ans = self.pic_to_img(pic, alt, inline, title) if ans is not None: if style: - ans.set('style', '; '.join('%s: %s' % (k, v) for k, v in style.iteritems())) + ans.set('style', '; '.join('%s: %s' % (k, v) for k, v in iteritems(style))) yield ans # Now process the floats @@ -253,7 +254,7 @@ class Images(object): ans = self.pic_to_img(pic, alt, anchor, title) if ans is not None: if style: - ans.set('style', '; '.join('%s: %s' % (k, v) for k, v in style.iteritems())) + ans.set('style', '; '.join('%s: %s' % (k, v) for k, v in iteritems(style))) yield ans def pict_to_html(self, pict, page): @@ -275,7 +276,7 @@ class Images(object): style['margin-left'] = '0' if align == 'left' else 'auto' style['margin-right'] = 'auto' if align == 'left' else '0' if style: - hr.set('style', '; '.join(('%s:%s' % (k, v) for k, v in style.iteritems()))) + hr.set('style', '; '.join(('%s:%s' % (k, v) for k, v in iteritems(style)))) yield hr for imagedata in XPath('descendant::v:imagedata[@r:id]')(pict): diff --git a/src/calibre/ebooks/docx/index.py b/src/calibre/ebooks/docx/index.py index a4e8e0ec60..38220a1c86 100644 --- a/src/calibre/ebooks/docx/index.py +++ b/src/calibre/ebooks/docx/index.py @@ -11,7 +11,7 @@ from operator import itemgetter from lxml import etree from calibre.utils.icu import partition_by_first_letter, sort_key -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type def get_applicable_xe_fields(index, xe_fields, XPath, expand): @@ -103,7 +103,7 @@ def process_index(field, index, xe_fields, log, XPath, expand): if heading_text is not None: groups = partition_by_first_letter(xe_fields, key=itemgetter('text')) items = [] - for key, fields in groups.iteritems(): + for key, fields in iteritems(groups): items.append(key), items.extend(fields) if styles: heading_style = styles[0] diff --git a/src/calibre/ebooks/docx/names.py b/src/calibre/ebooks/docx/names.py index 3db3f5e961..3238743b65 100644 --- a/src/calibre/ebooks/docx/names.py +++ b/src/calibre/ebooks/docx/names.py @@ -11,6 +11,7 @@ import re from lxml.etree import XPath as X from calibre.utils.filenames import ascii_text +from polyglot.builtins import iteritems # Names {{{ TRANSITIONAL_NAMES = { @@ -32,7 +33,7 @@ TRANSITIONAL_NAMES = { STRICT_NAMES = { k:v.replace('http://schemas.openxmlformats.org/officeDocument/2006', 'http://purl.oclc.org/ooxml/officeDocument') - for k, v in TRANSITIONAL_NAMES.iteritems() + for k, v in iteritems(TRANSITIONAL_NAMES) } TRANSITIONAL_NAMESPACES = { @@ -72,7 +73,7 @@ STRICT_NAMESPACES = { 'http://schemas.openxmlformats.org/officeDocument/2006', 'http://purl.oclc.org/ooxml/officeDocument').replace( 'http://schemas.openxmlformats.org/wordprocessingml/2006', 'http://purl.oclc.org/ooxml/wordprocessingml').replace( 'http://schemas.openxmlformats.org/drawingml/2006', 'http://purl.oclc.org/ooxml/drawingml') - for k, v in TRANSITIONAL_NAMESPACES.iteritems() + for k, v in iteritems(TRANSITIONAL_NAMESPACES) } # }}} @@ -138,7 +139,7 @@ class DOCXNamespace(object): return self.XPath('|'.join('descendant::%s' % a for a in args))(elem) def makeelement(self, root, tag, append=True, **attrs): - ans = root.makeelement(self.expand(tag), **{self.expand(k, sep='_'):v for k, v in attrs.iteritems()}) + ans = root.makeelement(self.expand(tag), **{self.expand(k, sep='_'):v for k, v in iteritems(attrs)}) if append: root.append(ans) return ans diff --git a/src/calibre/ebooks/docx/numbering.py b/src/calibre/ebooks/docx/numbering.py index a132cf2233..f2956db261 100644 --- a/src/calibre/ebooks/docx/numbering.py +++ b/src/calibre/ebooks/docx/numbering.py @@ -15,6 +15,7 @@ from lxml.html.builder import OL, UL, SPAN from calibre.ebooks.docx.block_styles import ParagraphStyle from calibre.ebooks.docx.char_styles import RunStyle, inherit from calibre.ebooks.metadata import roman +from polyglot.builtins import iteritems STYLE_MAP = { 'aiueo': 'hiragana', @@ -36,6 +37,7 @@ def alphabet(val, lower=True): x = string.ascii_lowercase if lower else string.ascii_uppercase return x[(abs(val - 1)) % len(x)] + alphabet_map = { 'lower-alpha':alphabet, 'upper-alpha':partial(alphabet, lower=False), 'lower-roman':lambda x:roman(x).lower(), 'upper-roman':roman, @@ -168,7 +170,7 @@ class NumberingDefinition(object): def copy(self): ans = NumberingDefinition(self.namespace, an_id=self.abstract_numbering_definition_id) - for l, lvl in self.levels.iteritems(): + for l, lvl in iteritems(self.levels): ans.levels[l] = lvl.copy() return ans @@ -224,7 +226,7 @@ class Numbering(object): if alvl is None: alvl = Level(self.namespace) alvl.read_from_xml(lvl, override=True) - for ilvl, so in start_overrides.iteritems(): + for ilvl, so in iteritems(start_overrides): try: nd.levels[ilvl].start = start_override except KeyError: @@ -244,22 +246,22 @@ class Numbering(object): self.instances[num_id] = create_instance(n, d) numbering_links = styles.numbering_style_links - for an_id, style_link in lazy_load.iteritems(): + for an_id, style_link in iteritems(lazy_load): num_id = numbering_links[style_link] self.definitions[an_id] = self.instances[num_id].copy() - for num_id, (an_id, n) in next_pass.iteritems(): + for num_id, (an_id, n) in iteritems(next_pass): d = self.definitions.get(an_id, None) if d is not None: self.instances[num_id] = create_instance(n, d) - for num_id, d in self.instances.iteritems(): + for num_id, d in iteritems(self.instances): self.starts[num_id] = {lvl:d.levels[lvl].start for lvl in d.levels} def get_pstyle(self, num_id, style_id): d = self.instances.get(num_id, None) if d is not None: - for ilvl, lvl in d.levels.iteritems(): + for ilvl, lvl in iteritems(d.levels): if lvl.para_link == style_id: return ilvl @@ -271,7 +273,7 @@ class Numbering(object): def update_counter(self, counter, levelnum, levels): counter[levelnum] += 1 - for ilvl, lvl in levels.iteritems(): + for ilvl, lvl in iteritems(levels): restart = lvl.restart if (restart is None and ilvl == levelnum + 1) or restart == levelnum + 1: counter[ilvl] = lvl.start diff --git a/src/calibre/ebooks/docx/styles.py b/src/calibre/ebooks/docx/styles.py index 1b1847236d..56b5b9a4e3 100644 --- a/src/calibre/ebooks/docx/styles.py +++ b/src/calibre/ebooks/docx/styles.py @@ -12,6 +12,7 @@ from collections import OrderedDict, Counter from calibre.ebooks.docx.block_styles import ParagraphStyle, inherit, twips from calibre.ebooks.docx.char_styles import RunStyle from calibre.ebooks.docx.tables import TableStyle +from polyglot.builtins import iteritems, itervalues class PageProperties(object): @@ -124,7 +125,7 @@ class Styles(object): self.default_paragraph_style = self.default_character_style = None def __iter__(self): - for s in self.id_map.itervalues(): + for s in itervalues(self.id_map): yield s def __getitem__(self, key): @@ -341,7 +342,7 @@ class Styles(object): setattr(s, prop, inherit) setattr(block_style, prop, next(iter(vals))) - for p, runs in layers.iteritems(): + for p, runs in iteritems(layers): has_links = '1' in {r.get('is-link', None) for r in runs} char_styles = [self.resolve_run(r) for r in runs] block_style = self.resolve_paragraph(p) @@ -421,7 +422,7 @@ class Styles(object): ps.pageBreakBefore = True def register(self, css, prefix): - h = hash(frozenset(css.iteritems())) + h = hash(frozenset(iteritems(css))) ans, _ = self.classes.get(h, (None, None)) if ans is None: self.counter[prefix] += 1 @@ -430,17 +431,17 @@ class Styles(object): return ans def generate_classes(self): - for bs in self.para_cache.itervalues(): + for bs in itervalues(self.para_cache): css = bs.css if css: self.register(css, 'block') - for bs in self.run_cache.itervalues(): + for bs in itervalues(self.run_cache): css = bs.css if css: self.register(css, 'text') def class_name(self, css): - h = hash(frozenset(css.iteritems())) + h = hash(frozenset(iteritems(css))) return self.classes.get(h, (None, None))[0] def generate_css(self, dest_dir, docx, notes_nopb, nosupsub): @@ -495,8 +496,8 @@ class Styles(object): prefix = ef + '\n' + prefix ans = [] - for (cls, css) in sorted(self.classes.itervalues(), key=lambda x:x[0]): - b = ('\t%s: %s;' % (k, v) for k, v in css.iteritems()) + for (cls, css) in sorted(itervalues(self.classes), key=lambda x:x[0]): + b = ('\t%s: %s;' % (k, v) for k, v in iteritems(css)) b = '\n'.join(b) ans.append('.%s {\n%s\n}\n' % (cls, b.rstrip(';'))) return prefix + '\n' + '\n'.join(ans) diff --git a/src/calibre/ebooks/docx/tables.py b/src/calibre/ebooks/docx/tables.py index b21d723ce4..a6b5f8ef69 100644 --- a/src/calibre/ebooks/docx/tables.py +++ b/src/calibre/ebooks/docx/tables.py @@ -10,7 +10,7 @@ from lxml.html.builder import TABLE, TR, TD from calibre.ebooks.docx.block_styles import inherit, read_shd as rs, read_border, binary_property, border_props, ParagraphStyle, border_to_css from calibre.ebooks.docx.char_styles import RunStyle -from polyglot.builtins import range +from polyglot.builtins import iteritems, itervalues, range # Read from XML {{{ read_shd = rs @@ -86,7 +86,7 @@ def read_spacing(parent, dest, XPath, get): def read_float(parent, dest, XPath, get): ans = inherit for x in XPath('./w:tblpPr')(parent): - ans = {k.rpartition('}')[-1]: v for k, v in x.attrib.iteritems()} + ans = {k.rpartition('}')[-1]: v for k, v in iteritems(x.attrib)} setattr(dest, 'float', ans) @@ -618,7 +618,7 @@ class Table(object): def __iter__(self): for p in self.paragraphs: yield p - for t in self.sub_tables.itervalues(): + for t in itervalues(self.sub_tables): for p in t: yield p @@ -665,7 +665,7 @@ class Table(object): table_style = self.table_style.css if table_style: table.set('class', self.styles.register(table_style, 'table')) - for elem, style in style_map.iteritems(): + for elem, style in iteritems(style_map): css = style.css if css: elem.set('class', self.styles.register(css, elem.tag)) @@ -686,7 +686,7 @@ class Tables(object): self.sub_tables |= set(self.tables[-1].sub_tables) def apply_markup(self, object_map, page_map): - rmap = {v:k for k, v in object_map.iteritems()} + rmap = {v:k for k, v in iteritems(object_map)} for table in self.tables: table.apply_markup(rmap, page_map[table.tbl]) diff --git a/src/calibre/ebooks/docx/to_html.py b/src/calibre/ebooks/docx/to_html.py index f1301f1f93..85ab2554bc 100644 --- a/src/calibre/ebooks/docx/to_html.py +++ b/src/calibre/ebooks/docx/to_html.py @@ -29,6 +29,8 @@ from calibre.ebooks.docx.fields import Fields from calibre.ebooks.docx.settings import Settings from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.utils.localization import canonicalize_lang, lang_as_iso639_1 +from polyglot.builtins import iteritems, itervalues + NBSP = '\xa0' @@ -122,7 +124,7 @@ class Convert(object): self.read_page_properties(doc) self.resolve_alternate_content(doc) self.current_rels = relationships_by_id - for wp, page_properties in self.page_map.iteritems(): + for wp, page_properties in iteritems(self.page_map): self.current_page = page_properties if wp.tag.endswith('}p'): p = self.convert_p(wp) @@ -162,7 +164,7 @@ class Convert(object): self.styles.apply_contextual_spacing(paras) self.mark_block_runs(paras) - for p, wp in self.object_map.iteritems(): + for p, wp in iteritems(self.object_map): if len(p) > 0 and not p.text and len(p[0]) > 0 and not p[0].text and p[0][0].get('class', None) == 'tab': # Paragraph uses tabs for indentation, convert to text-indent parent = p[0] @@ -192,7 +194,7 @@ class Convert(object): self.tables.apply_markup(self.object_map, self.page_map) numbered = [] - for html_obj, obj in self.object_map.iteritems(): + for html_obj, obj in iteritems(self.object_map): raw = obj.get('calibre_num_id', None) if raw is not None: lvl, num_id = raw.partition(':')[0::2] @@ -212,7 +214,7 @@ class Convert(object): self.log.debug('Converting styles to CSS') self.styles.generate_classes() - for html_obj, obj in self.object_map.iteritems(): + for html_obj, obj in iteritems(self.object_map): style = self.styles.resolve(obj) if style is not None: css = style.css @@ -220,7 +222,7 @@ class Convert(object): cls = self.styles.class_name(css) if cls: html_obj.set('class', cls) - for html_obj, css in self.framed_map.iteritems(): + for html_obj, css in iteritems(self.framed_map): cls = self.styles.class_name(css) if cls: html_obj.set('class', cls) @@ -407,13 +409,13 @@ class Convert(object): doc_anchors = frozenset(self.namespace.XPath('./w:body/w:bookmarkStart[@w:name]')(doc)) if doc_anchors: current_bm = set() - rmap = {v:k for k, v in self.object_map.iteritems()} + rmap = {v:k for k, v in iteritems(self.object_map)} for p in self.namespace.descendants(doc, 'w:p', 'w:bookmarkStart[@w:name]'): if p.tag.endswith('}p'): if current_bm and p in rmap: para = rmap[p] if 'id' not in para.attrib: - para.set('id', generate_anchor(next(iter(current_bm)), frozenset(self.anchor_map.itervalues()))) + para.set('id', generate_anchor(next(iter(current_bm)), frozenset(itervalues(self.anchor_map)))) for name in current_bm: self.anchor_map[name] = para.get('id') current_bm = set() @@ -469,10 +471,10 @@ class Convert(object): # _GoBack is a special bookmark inserted by Word 2010 for # the return to previous edit feature, we ignore it old_anchor = current_anchor - self.anchor_map[anchor] = current_anchor = generate_anchor(anchor, frozenset(self.anchor_map.itervalues())) + self.anchor_map[anchor] = current_anchor = generate_anchor(anchor, frozenset(itervalues(self.anchor_map))) if old_anchor is not None: # The previous anchor was not applied to any element - for a, t in tuple(self.anchor_map.iteritems()): + for a, t in tuple(iteritems(self.anchor_map)): if t == old_anchor: self.anchor_map[a] = current_anchor elif x.tag.endswith('}hyperlink'): @@ -480,11 +482,11 @@ class Convert(object): elif x.tag.endswith('}instrText') and x.text and x.text.strip().startswith('TOC '): old_anchor = current_anchor anchor = str(uuid.uuid4()) - self.anchor_map[anchor] = current_anchor = generate_anchor('toc', frozenset(self.anchor_map.itervalues())) + self.anchor_map[anchor] = current_anchor = generate_anchor('toc', frozenset(itervalues(self.anchor_map))) self.toc_anchor = current_anchor if old_anchor is not None: # The previous anchor was not applied to any element - for a, t in tuple(self.anchor_map.iteritems()): + for a, t in tuple(iteritems(self.anchor_map)): if t == old_anchor: self.anchor_map[a] = current_anchor if current_anchor is not None: @@ -559,7 +561,7 @@ class Convert(object): def resolve_links(self): self.resolved_link_map = {} - for hyperlink, spans in self.link_map.iteritems(): + for hyperlink, spans in iteritems(self.link_map): relationships_by_id = self.link_source_map[hyperlink] span = spans[0] if len(spans) > 1: @@ -585,7 +587,7 @@ class Convert(object): # hrefs that point nowhere give epubcheck a hernia. The element # should be styled explicitly by Word anyway. # span.set('href', '#') - rmap = {v:k for k, v in self.object_map.iteritems()} + rmap = {v:k for k, v in iteritems(self.object_map)} for hyperlink, runs in self.fields.hyperlink_fields: spans = [rmap[r] for r in runs if r in rmap] if not spans: @@ -744,7 +746,7 @@ class Convert(object): if not self.block_runs: return - rmap = {v:k for k, v in self.object_map.iteritems()} + rmap = {v:k for k, v in iteritems(self.object_map)} for border_style, blocks in self.block_runs: paras = tuple(rmap[p] for p in blocks) for p in paras: diff --git a/src/calibre/ebooks/docx/toc.py b/src/calibre/ebooks/docx/toc.py index 53caff03e9..ec40071980 100644 --- a/src/calibre/ebooks/docx/toc.py +++ b/src/calibre/ebooks/docx/toc.py @@ -13,7 +13,7 @@ from lxml.etree import tostring from calibre.ebooks.metadata.toc import TOC from calibre.ebooks.oeb.polish.toc import elem_to_toc_text -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range def from_headings(body, log, namespace): @@ -25,7 +25,7 @@ def from_headings(body, log, namespace): level_prev = {i+1:None for i in range(len(xpaths))} level_prev[0] = tocroot level_item_map = {i+1:frozenset(xp(body)) for i, xp in enumerate(xpaths)} - item_level_map = {e:i for i, elems in level_item_map.iteritems() for e in elems} + item_level_map = {e:i for i, elems in iteritems(level_item_map) for e in elems} idcount = count() diff --git a/src/calibre/ebooks/docx/writer/container.py b/src/calibre/ebooks/docx/writer/container.py index 4d45910bc7..82ae0bd8f7 100644 --- a/src/calibre/ebooks/docx/writer/container.py +++ b/src/calibre/ebooks/docx/writer/container.py @@ -19,6 +19,7 @@ from calibre.utils.date import utcnow from calibre.utils.localization import canonicalize_lang, lang_as_iso639_1 from calibre.utils.zipfile import ZipFile from calibre.ebooks.pdf.render.common import PAPER_SIZES +from polyglot.builtins import iteritems def xml2str(root, pretty_print=False, with_tail=False): @@ -55,7 +56,7 @@ def create_skeleton(opts, namespaces=None): def w(x): return '{%s}%s' % (namespaces['w'], x) - dn = {k:v for k, v in namespaces.iteritems() if k in {'w', 'r', 'm', 've', 'o', 'wp', 'w10', 'wne', 'a', 'pic'}} + dn = {k:v for k, v in iteritems(namespaces) if k in {'w', 'r', 'm', 've', 'o', 'wp', 'w10', 'wne', 'a', 'pic'}} E = ElementMaker(namespace=dn['w'], nsmap=dn) doc = E.document() body = E.body() @@ -73,7 +74,7 @@ def create_skeleton(opts, namespaces=None): E.docGrid(**{w('linePitch'):"360"}), )) - dn = {k:v for k, v in namespaces.iteritems() if k in tuple('wra') + ('wp',)} + dn = {k:v for k, v in iteritems(namespaces) if k in tuple('wra') + ('wp',)} E = ElementMaker(namespace=dn['w'], nsmap=dn) styles = E.styles( E.docDefaults( @@ -120,12 +121,12 @@ class DocumentRelationships(object): def __init__(self, namespace): self.rmap = {} self.namespace = namespace - for typ, target in { + for typ, target in iteritems({ namespace.names['STYLES']: 'styles.xml', namespace.names['NUMBERING']: 'numbering.xml', namespace.names['WEB_SETTINGS']: 'webSettings.xml', namespace.names['FONTS']: 'fontTable.xml', - }.iteritems(): + }): self.add_relationship(target, typ) def get_relationship_id(self, target, rtype, target_mode=None): @@ -145,7 +146,7 @@ class DocumentRelationships(object): namespaces = self.namespace.namespaces E = ElementMaker(namespace=namespaces['pr'], nsmap={None:namespaces['pr']}) relationships = E.Relationships() - for (target, rtype, target_mode), rid in self.rmap.iteritems(): + for (target, rtype, target_mode), rid in iteritems(self.rmap): r = E.Relationship(Id=rid, Type=rtype, Target=target) if target_mode is not None: r.set('TargetMode', target_mode) @@ -172,7 +173,7 @@ class DOCX(object): def contenttypes(self): E = ElementMaker(namespace=self.namespace.namespaces['ct'], nsmap={None:self.namespace.namespaces['ct']}) types = E.Types() - for partname, mt in { + for partname, mt in iteritems({ "/word/footnotes.xml": "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/document.xml": "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", "/word/numbering.xml": "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", @@ -184,15 +185,15 @@ class DOCX(object): "/word/webSettings.xml": "application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml", "/docProps/core.xml": "application/vnd.openxmlformats-package.core-properties+xml", "/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml", - }.iteritems(): + }): types.append(E.Override(PartName=partname, ContentType=mt)) added = {'png', 'gif', 'jpeg', 'jpg', 'svg', 'xml'} for ext in added: types.append(E.Default(Extension=ext, ContentType=guess_type('a.'+ext)[0])) - for ext, mt in { + for ext, mt in iteritems({ "rels": "application/vnd.openxmlformats-package.relationships+xml", "odttf": "application/vnd.openxmlformats-officedocument.obfuscatedFont", - }.iteritems(): + }): added.add(ext) types.append(E.Default(Extension=ext, ContentType=mt)) for fname in self.images: @@ -270,12 +271,12 @@ class DOCX(object): zf.writestr('word/fontTable.xml', xml2str(self.font_table)) zf.writestr('word/_rels/document.xml.rels', self.document_relationships.serialize()) zf.writestr('word/_rels/fontTable.xml.rels', xml2str(self.embedded_fonts)) - for fname, data_getter in self.images.iteritems(): + for fname, data_getter in iteritems(self.images): zf.writestr(fname, data_getter()) - for fname, data in self.fonts.iteritems(): + for fname, data in iteritems(self.fonts): zf.writestr(fname, data) if __name__ == '__main__': d = DOCX(None, None) - print (d.websettings) + print(d.websettings) diff --git a/src/calibre/ebooks/docx/writer/images.py b/src/calibre/ebooks/docx/writer/images.py index 94d762a4e3..6aa6ff8bbb 100644 --- a/src/calibre/ebooks/docx/writer/images.py +++ b/src/calibre/ebooks/docx/writer/images.py @@ -10,7 +10,7 @@ import os import posixpath from collections import namedtuple from functools import partial -from polyglot.builtins import map +from polyglot.builtins import iteritems, itervalues, map from lxml import etree @@ -131,7 +131,7 @@ class ImagesManager(object): if fake_margins: # DOCX does not support setting margins for inline images, so we # fake it by using effect extents to simulate margins - makeelement(parent, 'wp:effectExtent', **{k[-1].lower():v for k, v in get_image_margins(style).iteritems()}) + makeelement(parent, 'wp:effectExtent', **{k[-1].lower():v for k, v in iteritems(get_image_margins(style))}) else: makeelement(parent, 'wp:effectExtent', l='0', r='0', t='0', b='0') if floating is not None: @@ -175,7 +175,7 @@ class ImagesManager(object): return fname def serialize(self, images_map): - for img in self.images.itervalues(): + for img in itervalues(self.images): images_map['word/' + img.fname] = partial(self.get_data, img.item) def get_data(self, item): diff --git a/src/calibre/ebooks/docx/writer/lists.py b/src/calibre/ebooks/docx/writer/lists.py index c9b0d930b4..e3c0d6eec9 100644 --- a/src/calibre/ebooks/docx/writer/lists.py +++ b/src/calibre/ebooks/docx/writer/lists.py @@ -9,6 +9,8 @@ __copyright__ = '2015, Kovid Goyal ' from collections import defaultdict from operator import attrgetter +from polyglot.builtins import iteritems, itervalues + LIST_STYLES = frozenset( 'disc circle square decimal decimal-leading-zero lower-roman upper-roman' ' lower-greek lower-alpha lower-latin upper-alpha upper-latin hiragana hebrew' @@ -62,7 +64,7 @@ class NumberingDefinition(object): items_for_level = defaultdict(list) container_for_level = {} type_for_level = {} - for ilvl, items in self.level_map.iteritems(): + for ilvl, items in iteritems(self.level_map): for container, list_tag, block, list_type, tag_style in items: items_for_level[ilvl].append(list_tag) container_for_level[ilvl] = container @@ -76,7 +78,7 @@ class NumberingDefinition(object): return hash(self.levels) def link_blocks(self): - for ilvl, items in self.level_map.iteritems(): + for ilvl, items in iteritems(self.level_map): for container, list_tag, block, list_type, tag_style in items: block.numbering_id = (self.num_id + 1, ilvl) @@ -148,16 +150,16 @@ class ListsManager(object): ilvl = len(container_tags) - 1 l.level_map[ilvl].append((container_tags[0], list_tag, block, list_type, tag_style)) - [nd.finalize() for nd in lists.itervalues()] + [nd.finalize() for nd in itervalues(lists)] definitions = {} - for defn in lists.itervalues(): + for defn in itervalues(lists): try: defn = definitions[defn] except KeyError: definitions[defn] = defn defn.num_id = len(definitions) - 1 defn.link_blocks() - self.definitions = sorted(definitions.itervalues(), key=attrgetter('num_id')) + self.definitions = sorted(itervalues(definitions), key=attrgetter('num_id')) def serialize(self, parent): for defn in self.definitions: diff --git a/src/calibre/ebooks/docx/writer/styles.py b/src/calibre/ebooks/docx/writer/styles.py index fd8e4cabc9..f1c918ad6b 100644 --- a/src/calibre/ebooks/docx/writer/styles.py +++ b/src/calibre/ebooks/docx/writer/styles.py @@ -15,7 +15,7 @@ from lxml import etree from calibre.ebooks import parse_css_length from calibre.ebooks.docx.writer.utils import convert_color, int_or_zero from calibre.utils.localization import lang_as_iso639_1 -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, iterkeys, unicode_type from tinycss.css21 import CSS21Parser css_parser = CSS21Parser() @@ -158,7 +158,7 @@ class DOCXStyle(object): getattr(self, x) for x in self.ALL_PROPS)) def makeelement(self, parent, name, **attrs): - return parent.makeelement(self.w(name), **{self.w(k):v for k, v in attrs.iteritems()}) + return parent.makeelement(self.w(name), **{self.w(k):v for k, v in iteritems(attrs)}) def __hash__(self): return self._hash @@ -365,7 +365,7 @@ class DescendantTextStyle(object): p = [] def add(name, **props): - p.append((name, frozenset(props.iteritems()))) + p.append((name, frozenset(iteritems(props)))) def vals(attr): return getattr(parent_style, attr), getattr(child_style, attr) @@ -562,7 +562,7 @@ class BlockStyle(DOCXStyle): def serialize_properties(self, pPr, normal_style): makeelement, w = self.makeelement, self.w spacing = makeelement(pPr, 'spacing') - for edge, attr in {'top':'before', 'bottom':'after'}.iteritems(): + for edge, attr in iteritems({'top':'before', 'bottom':'after'}): getter = attrgetter('css_margin_' + edge) css_val, css_unit = parse_css_length(getter(self)) if css_unit in ('em', 'ex'): @@ -696,7 +696,7 @@ class StylesManager(object): counts = Counter() smap = {} - for (bs, rs), blocks in used_pairs.iteritems(): + for (bs, rs), blocks in iteritems(used_pairs): s = CombinedStyle(bs, rs, blocks, self.namespace) smap[(bs, rs)] = s counts[s] += sum(1 for b in blocks if not b.is_empty()) @@ -721,7 +721,7 @@ class StylesManager(object): heading_styles.append(style) style.id = style.name = val style.seq = i - self.combined_styles = sorted(counts.iterkeys(), key=attrgetter('seq')) + self.combined_styles = sorted(iterkeys(counts), key=attrgetter('seq')) [ls.apply() for ls in self.combined_styles] descendant_style_map = {} diff --git a/src/calibre/ebooks/docx/writer/tables.py b/src/calibre/ebooks/docx/writer/tables.py index b0ab81524a..de2d3f8382 100644 --- a/src/calibre/ebooks/docx/writer/tables.py +++ b/src/calibre/ebooks/docx/writer/tables.py @@ -10,7 +10,7 @@ from collections import namedtuple from calibre.ebooks.docx.writer.utils import convert_color from calibre.ebooks.docx.writer.styles import read_css_block_borders as rcbb, border_edges -from polyglot.builtins import range +from polyglot.builtins import iteritems, range class Dummy(object): @@ -125,7 +125,7 @@ class Cell(object): makeelement(tcPr, 'w:shd', w_val="clear", w_color="auto", w_fill=bc) b = makeelement(tcPr, 'w:tcBorders', append=False) - for edge, border in self.borders.iteritems(): + for edge, border in iteritems(self.borders): if border is not None and border.width > 0 and border.style != 'none': makeelement(b, 'w:' + edge, w_val=border.style, w_sz=str(border.width), w_color=border.color) if len(b) > 0: diff --git a/src/calibre/ebooks/epub/cfi/tests.py b/src/calibre/ebooks/epub/cfi/tests.py index 626660bd30..f6a6e2180b 100644 --- a/src/calibre/ebooks/epub/cfi/tests.py +++ b/src/calibre/ebooks/epub/cfi/tests.py @@ -10,7 +10,7 @@ import unittest, numbers from polyglot.builtins import map from calibre.ebooks.epub.cfi.parse import parser, cfi_sort_key, decode_cfi -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class Tests(unittest.TestCase): @@ -61,7 +61,7 @@ class Tests(unittest.TestCase): if after is not None: ta['after'] = after if params: - ta['params'] = {unicode_type(k):(v,) if isinstance(v, unicode_type) else v for k, v in params.iteritems()} + ta['params'] = {unicode_type(k):(v,) if isinstance(v, unicode_type) else v for k, v in iteritems(params)} if ta: step['text_assertion'] = ta return ans diff --git a/src/calibre/ebooks/epub/pages.py b/src/calibre/ebooks/epub/pages.py index d76a4a8c12..200c5e03fe 100644 --- a/src/calibre/ebooks/epub/pages.py +++ b/src/calibre/ebooks/epub/pages.py @@ -32,7 +32,7 @@ def filter_name(name): def build_name_for(expr): if not expr: counter = count(1) - return lambda elem: str(counter.next()) + return lambda elem: str(next(counter)) selector = XPath(expr, namespaces=NSMAP) def name_for(elem): @@ -55,7 +55,7 @@ def add_page_map(opfpath, opts): name = name_for(elem) id = elem.get('id', None) if id is None: - id = elem.attrib['id'] = idgen.next() + id = elem.attrib['id'] = next(idgen) href = '#'.join((item.href, id)) oeb.pages.add(name, href) writer = None # DirWriter(version='2.0', page_map=True) diff --git a/src/calibre/ebooks/lrf/html/table.py b/src/calibre/ebooks/lrf/html/table.py index 1bc14f1632..869febf632 100644 --- a/src/calibre/ebooks/lrf/html/table.py +++ b/src/calibre/ebooks/lrf/html/table.py @@ -349,7 +349,7 @@ class Table(object): nc = self.rows[r].cell_iterator() try: while True: - cell = nc.next() + cell = next(nc) cellmatrix[r][rowpos[r]] = cell rowpos[r] += cell.colspan for k in range(1, cell.rowspan): diff --git a/src/calibre/ebooks/lrf/pylrs/pylrf.py b/src/calibre/ebooks/lrf/pylrs/pylrf.py index d8f8c42ddf..a29c0139d0 100644 --- a/src/calibre/ebooks/lrf/pylrs/pylrf.py +++ b/src/calibre/ebooks/lrf/pylrs/pylrf.py @@ -10,6 +10,7 @@ import codecs import os from pylrfopt import tagListOptimizer +from polyglot.builtins import iteritems PYLRF_VERSION = "1.0" @@ -526,7 +527,7 @@ class LrfObject(object): # belongs somewhere, so here it is. # composites = {} - for name, value in tagDict.iteritems(): + for name, value in iteritems(tagDict): if name == 'rubyAlignAndAdjust': continue if name in { @@ -651,7 +652,7 @@ class LrfWriter(object): return self.sourceEncoding def toUnicode(self, string): - if type(string) is str: + if isinstance(string, str): string = string.decode(self.sourceEncoding) return string diff --git a/src/calibre/ebooks/metadata/book/base.py b/src/calibre/ebooks/metadata/book/base.py index 00f60a7298..4bb37b6c9b 100644 --- a/src/calibre/ebooks/metadata/book/base.py +++ b/src/calibre/ebooks/metadata/book/base.py @@ -14,7 +14,7 @@ from calibre.ebooks.metadata.book import (SC_COPYABLE_FIELDS, TOP_LEVEL_IDENTIFIERS, ALL_METADATA_FIELDS) from calibre.library.field_metadata import FieldMetadata from calibre.utils.icu import sort_key -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, iterkeys, unicode_type # Special sets used to optimize the performance of getting and setting # attributes on Metadata objects @@ -137,7 +137,7 @@ class Metadata(object): return object.__getattribute__(self, field) except AttributeError: pass - if field in _data['user_metadata'].iterkeys(): + if field in iterkeys(_data['user_metadata']): d = _data['user_metadata'][field] val = d['#value#'] if d['datatype'] != 'composite': @@ -180,7 +180,7 @@ class Metadata(object): if val and val.lower() != 'und': langs = [val] _data['languages'] = langs - elif field in _data['user_metadata'].iterkeys(): + elif field in iterkeys(_data['user_metadata']): _data['user_metadata'][field]['#value#'] = val _data['user_metadata'][field]['#extra#'] = extra else: @@ -190,7 +190,7 @@ class Metadata(object): self.__dict__[field] = val def __iter__(self): - return object.__getattribute__(self, '_data').iterkeys() + return iterkeys(object.__getattribute__(self, '_data')) def has_key(self, key): return key in object.__getattribute__(self, '_data') @@ -219,7 +219,7 @@ class Metadata(object): def get_extra(self, field, default=None): _data = object.__getattribute__(self, '_data') - if field in _data['user_metadata'].iterkeys(): + if field in iterkeys(_data['user_metadata']): try: return _data['user_metadata'][field]['#extra#'] except: @@ -255,7 +255,7 @@ class Metadata(object): Set all identifiers. Note that if you previously set ISBN, calling this method will delete it. ''' - cleaned = {ck(k):cv(v) for k, v in identifiers.iteritems() if k and v} + cleaned = {ck(k):cv(v) for k, v in iteritems(identifiers) if k and v} object.__getattribute__(self, '_data')['identifiers'] = cleaned def set_identifier(self, typ, val): @@ -287,14 +287,14 @@ class Metadata(object): ''' return a list of the custom fields in this book ''' - return object.__getattribute__(self, '_data')['user_metadata'].iterkeys() + return iterkeys(object.__getattribute__(self, '_data')['user_metadata']) def all_field_keys(self): ''' All field keys known by this instance, even if their value is None ''' _data = object.__getattribute__(self, '_data') - return frozenset(ALL_METADATA_FIELDS.union(_data['user_metadata'].iterkeys())) + return frozenset(ALL_METADATA_FIELDS.union(iterkeys(_data['user_metadata']))) def metadata_for_field(self, key): ''' @@ -320,7 +320,7 @@ class Metadata(object): v = self.get(attr, None) if v is not None: result[attr] = v - for attr in _data['user_metadata'].iterkeys(): + for attr in iterkeys(_data['user_metadata']): v = self.get(attr, None) if v is not None: result[attr] = v @@ -396,7 +396,7 @@ class Metadata(object): return um = {} - for key, meta in metadata.iteritems(): + for key, meta in iteritems(metadata): m = meta.copy() if '#value#' not in m: if m['datatype'] == 'text' and m['is_multiple']: @@ -576,7 +576,7 @@ class Metadata(object): if callable(getattr(other, 'get_identifiers', None)): d = self.get_identifiers() s = other.get_identifiers() - d.update([v for v in s.iteritems() if v[1] is not None]) + d.update([v for v in iteritems(s) if v[1] is not None]) self.set_identifiers(d) else: # other structure not Metadata. Copy the top-level identifiers @@ -749,7 +749,7 @@ class Metadata(object): fmt('Rights', unicode_type(self.rights)) if self.identifiers: fmt('Identifiers', u', '.join(['%s:%s'%(k, v) for k, v in - self.identifiers.iteritems()])) + iteritems(self.identifiers)])) if self.comments: fmt('Comments', self.comments) diff --git a/src/calibre/ebooks/metadata/book/json_codec.py b/src/calibre/ebooks/metadata/book/json_codec.py index 6d15eb5031..4a411b15a2 100644 --- a/src/calibre/ebooks/metadata/book/json_codec.py +++ b/src/calibre/ebooks/metadata/book/json_codec.py @@ -13,6 +13,7 @@ from calibre.ebooks.metadata.book import SERIALIZABLE_FIELDS from calibre.constants import filesystem_encoding, preferred_encoding from calibre.library.field_metadata import FieldMetadata from calibre import isbytestring +from polyglot.builtins import iteritems, itervalues # Translate datetimes to and from strings. The string form is the datetime in # UTC. The returned date is also UTC @@ -149,7 +150,7 @@ class JsonCodec(object): def encode_metadata_attr(self, book, key): if key == 'user_metadata': meta = book.get_all_user_metadata(make_copy=True) - for fm in meta.itervalues(): + for fm in itervalues(meta): if fm['datatype'] == 'datetime': fm['#value#'] = datetime_to_string(fm['#value#']) encode_is_multiple(fm) @@ -184,7 +185,7 @@ class JsonCodec(object): def raw_to_book(self, json_book, book_class, prefix): try: book = book_class(prefix, json_book.get('lpath', None)) - for key,val in json_book.iteritems(): + for key,val in iteritems(json_book): meta = self.decode_metadata(key, val) if key == 'user_metadata': book.set_all_user_metadata(meta) @@ -201,7 +202,7 @@ class JsonCodec(object): if key == 'classifiers': key = 'identifiers' if key == 'user_metadata': - for fm in value.itervalues(): + for fm in itervalues(value): if fm['datatype'] == 'datetime': fm['#value#'] = string_to_datetime(fm['#value#']) decode_is_multiple(fm) diff --git a/src/calibre/ebooks/metadata/book/serialize.py b/src/calibre/ebooks/metadata/book/serialize.py index e1a7189530..8c741cc70f 100644 --- a/src/calibre/ebooks/metadata/book/serialize.py +++ b/src/calibre/ebooks/metadata/book/serialize.py @@ -10,7 +10,7 @@ from calibre.constants import preferred_encoding from calibre.ebooks.metadata.book import SERIALIZABLE_FIELDS from calibre.ebooks.metadata.book.base import Metadata from calibre.utils.imghdr import what -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type def ensure_unicode(obj, enc=preferred_encoding): @@ -21,7 +21,7 @@ def ensure_unicode(obj, enc=preferred_encoding): if isinstance(obj, (list, tuple)): return [ensure_unicode(x) for x in obj] if isinstance(obj, dict): - return {ensure_unicode(k): ensure_unicode(v) for k, v in obj.iteritems()} + return {ensure_unicode(k): ensure_unicode(v) for k, v in iteritems(obj)} return obj @@ -63,7 +63,7 @@ def metadata_as_dict(mi, encode_cover_data=False): def metadata_from_dict(src): ans = Metadata('Unknown') - for key, value in src.iteritems(): + for key, value in iteritems(src): if key == 'user_metadata': ans.set_all_user_metadata(value) else: diff --git a/src/calibre/ebooks/metadata/cli.py b/src/calibre/ebooks/metadata/cli.py index 5a7643c946..f6ca8ae1bc 100644 --- a/src/calibre/ebooks/metadata/cli.py +++ b/src/calibre/ebooks/metadata/cli.py @@ -16,7 +16,7 @@ from calibre.ebooks.metadata import string_to_authors, authors_to_sort_string, \ from calibre.ebooks.lrf.meta import LRFMetaFile from calibre import prints from calibre.utils.date import parse_date -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type USAGE=_('%prog ebook_file [options]\n') + \ _(''' @@ -150,7 +150,7 @@ def do_set_metadata(opts, mi, stream, stream_type): if val: orig = mi.get_identifiers() orig.update(val) - val = {k:v for k, v in orig.iteritems() if k and v} + val = {k:v for k, v in iteritems(orig) if k and v} mi.set_identifiers(val) if getattr(opts, 'cover', None) is not None: diff --git a/src/calibre/ebooks/metadata/html.py b/src/calibre/ebooks/metadata/html.py index 55c3849107..9d866fac55 100644 --- a/src/calibre/ebooks/metadata/html.py +++ b/src/calibre/ebooks/metadata/html.py @@ -16,6 +16,7 @@ from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.chardet import xml_to_unicode from calibre import replace_entities, isbytestring from calibre.utils.date import parse_date, is_date_undefined +from polyglot.builtins import iteritems, itervalues def get_metadata(stream): @@ -60,16 +61,16 @@ attr_pat = r'''(?:(?P')|(?P"))(?P(?(sq)[^']+|[^"]+))(?(sq)'|")' def parse_meta_tags(src): rmap = {} - for field, names in META_NAMES.iteritems(): + for field, names in iteritems(META_NAMES): for name in names: rmap[name.lower()] = field all_names = '|'.join(rmap) ans = {} npat = r'''name\s*=\s*['"]{0,1}(?P%s)['"]{0,1}''' % all_names - cpat = 'content\s*=\s*%s' % attr_pat + cpat = r'content\s*=\s*%s' % attr_pat for pat in ( - '%s)\s*=\s*%s''' % (all_names, attr_pat), src): field = rmap[match.group('name')] diff --git a/src/calibre/ebooks/metadata/opf.py b/src/calibre/ebooks/metadata/opf.py index 90b94e727e..a27a31a951 100644 --- a/src/calibre/ebooks/metadata/opf.py +++ b/src/calibre/ebooks/metadata/opf.py @@ -11,6 +11,7 @@ from calibre.ebooks.metadata.opf2 import OPF, pretty_print from calibre.ebooks.metadata.opf3 import apply_metadata, read_metadata from calibre.ebooks.metadata.utils import parse_opf, normalize_languages, create_manifest_item, parse_opf_version from calibre.ebooks.metadata import MetaInformation +from polyglot.builtins import iteritems class DummyFile(object): @@ -61,7 +62,7 @@ def set_metadata_opf2(root, cover_prefix, mi, opf_version, else: orig = opf.get_identifiers() orig.update(mi.get_identifiers()) - opf.set_identifiers({k:v for k, v in orig.iteritems() if k and v}) + opf.set_identifiers({k:v for k, v in iteritems(orig) if k and v}) if update_timestamp and mi.timestamp is not None: opf.timestamp = mi.timestamp raster_cover = opf.raster_cover diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py index 4e5541ff1d..5468c0e72d 100644 --- a/src/calibre/ebooks/metadata/opf2.py +++ b/src/calibre/ebooks/metadata/opf2.py @@ -23,7 +23,7 @@ from calibre.utils.localization import get_lang, canonicalize_lang from calibre import prints, guess_type from calibre.utils.cleantext import clean_ascii_chars, clean_xml_chars from calibre.utils.config import tweaks -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range from polyglot.urllib import unquote, urlparse pretty_print_opf = False @@ -977,7 +977,7 @@ class OPF(object): # {{{ 'descendant::*[local-name() = "identifier" and text()]')( self.metadata): found_scheme = False - for attr, val in x.attrib.iteritems(): + for attr, val in iteritems(x.attrib): if attr.endswith('scheme'): typ = icu_lower(val) val = etree.tostring(x, with_tail=False, encoding=unicode_type, @@ -1010,7 +1010,7 @@ class OPF(object): # {{{ self.metadata): xid = x.get('id', None) is_package_identifier = uuid_id is not None and uuid_id == xid - typ = {val for attr, val in x.attrib.iteritems() if attr.endswith('scheme')} + typ = {val for attr, val in iteritems(x.attrib) if attr.endswith('scheme')} if is_package_identifier: typ = tuple(typ) if typ and typ[0].lower() in identifiers: @@ -1019,7 +1019,7 @@ class OPF(object): # {{{ if typ and not (typ & {'calibre', 'uuid'}): x.getparent().remove(x) - for typ, val in identifiers.iteritems(): + for typ, val in iteritems(identifiers): attrib = {'{%s}scheme'%self.NAMESPACES['opf']: typ.upper()} self.set_text(self.create_metadata_element( 'identifier', attrib=attrib), unicode_type(val)) @@ -1155,7 +1155,7 @@ class OPF(object): # {{{ def page_progression_direction(self): spine = self.XPath('descendant::*[re:match(name(), "spine", "i")][1]')(self.root) if spine: - for k, v in spine[0].attrib.iteritems(): + for k, v in iteritems(spine[0].attrib): if k == 'page-progression-direction' or k.endswith('}page-progression-direction'): return v @@ -1525,7 +1525,7 @@ class OPFCreator(Metadata): a(DC_ELEM('description', self.comments)) if self.publisher: a(DC_ELEM('publisher', self.publisher)) - for key, val in self.get_identifiers().iteritems(): + for key, val in iteritems(self.get_identifiers()): a(DC_ELEM('identifier', val, opf_attrs={'scheme':icu_upper(key)})) if self.rights: a(DC_ELEM('rights', self.rights)) @@ -1651,7 +1651,7 @@ def metadata_to_opf(mi, as_string=True, default_lang=None): try: elem = metadata.makeelement(tag, attrib=attrib) except ValueError: - elem = metadata.makeelement(tag, attrib={k:clean_xml_chars(v) for k, v in attrib.iteritems()}) + elem = metadata.makeelement(tag, attrib={k:clean_xml_chars(v) for k, v in iteritems(attrib)}) elem.tail = '\n'+(' '*8) if text: try: @@ -1672,7 +1672,7 @@ def metadata_to_opf(mi, as_string=True, default_lang=None): factory(DC('description'), clean_ascii_chars(mi.comments)) if mi.publisher: factory(DC('publisher'), mi.publisher) - for key, val in mi.get_identifiers().iteritems(): + for key, val in iteritems(mi.get_identifiers()): factory(DC('identifier'), val, scheme=icu_upper(key)) if mi.rights: factory(DC('rights'), mi.rights) diff --git a/src/calibre/ebooks/metadata/opf3.py b/src/calibre/ebooks/metadata/opf3.py index 8d9bfbb9b0..26cde2b802 100644 --- a/src/calibre/ebooks/metadata/opf3.py +++ b/src/calibre/ebooks/metadata/opf3.py @@ -8,7 +8,7 @@ import json import re from collections import defaultdict, namedtuple from functools import wraps -from polyglot.builtins import map +from polyglot.builtins import iteritems, map from lxml import etree @@ -190,9 +190,9 @@ def ensure_prefix(root, prefixes, prefix, value=None): if prefixes is None: prefixes = read_prefixes(root) prefixes[prefix] = value or reserved_prefixes[prefix] - prefixes = {k:v for k, v in prefixes.iteritems() if reserved_prefixes.get(k) != v} + prefixes = {k:v for k, v in iteritems(prefixes) if reserved_prefixes.get(k) != v} if prefixes: - root.set('prefix', ' '.join('%s: %s' % (k, v) for k, v in prefixes.iteritems())) + root.set('prefix', ' '.join('%s: %s' % (k, v) for k, v in iteritems(prefixes))) else: root.attrib.pop('prefix', None) @@ -299,7 +299,7 @@ def set_identifiers(root, prefixes, refines, new_identifiers, force_identifiers= remove_element(ident, refines) continue metadata = XPath('./opf:metadata')(root)[0] - for scheme, val in new_identifiers.iteritems(): + for scheme, val in iteritems(new_identifiers): ident = metadata.makeelement(DC('identifier')) ident.text = '%s:%s' % (scheme, val) if package_identifier is None: @@ -854,7 +854,7 @@ set_author_link_map = dict_writer('author_link_map') def deserialize_user_metadata(val): val = json.loads(val, object_hook=from_json) ans = {} - for name, fm in val.iteritems(): + for name, fm in iteritems(val): decode_is_multiple(fm) ans[name] = fm return ans @@ -969,7 +969,7 @@ def read_metadata(root, ver=None, return_extra_data=False): prefixes, refines = read_prefixes(root), read_refines(root) identifiers = read_identifiers(root, prefixes, refines) ids = {} - for key, vals in identifiers.iteritems(): + for key, vals in iteritems(identifiers): if key == 'calibre': ans.application_id = vals[0] elif key == 'uuid': @@ -1007,7 +1007,7 @@ def read_metadata(root, ver=None, return_extra_data=False): ans.series, ans.series_index = s, si ans.author_link_map = read_author_link_map(root, prefixes, refines) or ans.author_link_map ans.user_categories = read_user_categories(root, prefixes, refines) or ans.user_categories - for name, fm in (read_user_metadata(root, prefixes, refines) or {}).iteritems(): + for name, fm in iteritems((read_user_metadata(root, prefixes, refines) or {})): ans.set_user_metadata(name, fm) if return_extra_data: ans = ans, ver, read_raster_cover(root, prefixes, refines), first_spine_item(root, prefixes, refines) diff --git a/src/calibre/ebooks/metadata/opf_2_to_3.py b/src/calibre/ebooks/metadata/opf_2_to_3.py index 73566d8aba..da7d4a947d 100644 --- a/src/calibre/ebooks/metadata/opf_2_to_3.py +++ b/src/calibre/ebooks/metadata/opf_2_to_3.py @@ -13,6 +13,7 @@ from calibre.ebooks.metadata.opf3 import ( set_refines, set_user_metadata3 ) from calibre.ebooks.metadata.utils import parse_opf, pretty_print_opf +from polyglot.builtins import itervalues class Data(object): @@ -140,7 +141,7 @@ def upgrade_series(root, data): def upgrade_custom(root, data): m = read_user_metadata2(root, remove_tags=True) if m: - for fm in m.itervalues(): + for fm in itervalues(m): encode_is_multiple(fm) set_user_metadata3(root, data.prefixes, data.refines, m) diff --git a/src/calibre/ebooks/metadata/pdf.py b/src/calibre/ebooks/metadata/pdf.py index 01a524afcd..269e093634 100644 --- a/src/calibre/ebooks/metadata/pdf.py +++ b/src/calibre/ebooks/metadata/pdf.py @@ -12,7 +12,7 @@ from calibre.ptempfile import TemporaryDirectory from calibre.ebooks.metadata import ( MetaInformation, string_to_authors, check_isbn, check_doi) from calibre.utils.ipc.simple_worker import fork_job, WorkerError -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type def get_tools(): @@ -153,9 +153,9 @@ def get_metadata(stream, cover=True): # Look for recognizable identifiers in the info dict, if they were not # found in the XMP metadata - for scheme, check_func in {'doi':check_doi, 'isbn':check_isbn}.iteritems(): + for scheme, check_func in iteritems({'doi':check_doi, 'isbn':check_isbn}): if scheme not in mi.get_identifiers(): - for k, v in info.iteritems(): + for k, v in iteritems(info): if k != 'xmp_metadata': val = check_func(v) if val: diff --git a/src/calibre/ebooks/metadata/search_internet.py b/src/calibre/ebooks/metadata/search_internet.py index 24f54d6990..d5d9a30ebe 100644 --- a/src/calibre/ebooks/metadata/search_internet.py +++ b/src/calibre/ebooks/metadata/search_internet.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function, unicode_literals +from polyglot.builtins import iteritems from polyglot.urllib import quote_plus AUTHOR_SEARCHES = { @@ -54,7 +55,7 @@ def qquote(val): def url_for(template, data): - return template.format(**{k: qquote(v) for k, v in data.iteritems()}) + return template.format(**{k: qquote(v) for k, v in iteritems(data)}) def url_for_author_search(key, **kw): diff --git a/src/calibre/ebooks/metadata/sources/base.py b/src/calibre/ebooks/metadata/sources/base.py index 0513209277..349e104458 100644 --- a/src/calibre/ebooks/metadata/sources/base.py +++ b/src/calibre/ebooks/metadata/sources/base.py @@ -14,6 +14,7 @@ from calibre.customize import Plugin from calibre.ebooks.metadata import check_isbn from calibre.ebooks.metadata.author_mapper import cap_author_token from calibre.utils.localization import canonicalize_lang, get_lang +from polyglot.builtins import iteritems def create_log(ostream=None): @@ -65,7 +66,7 @@ class InternalMetadataCompareKeyGen(object): def __init__(self, mi, source_plugin, title, authors, identifiers): same_identifier = 2 idents = mi.get_identifiers() - for k, v in identifiers.iteritems(): + for k, v in iteritems(identifiers): if idents.get(k) == v: same_identifier = 1 break @@ -280,7 +281,7 @@ class Source(Plugin): def get_related_isbns(self, id_): with self.cache_lock: - for isbn, q in self._isbn_to_identifier_cache.iteritems(): + for isbn, q in iteritems(self._isbn_to_identifier_cache): if q == id_: yield isbn diff --git a/src/calibre/ebooks/metadata/sources/identify.py b/src/calibre/ebooks/metadata/sources/identify.py index 44cdba029b..c807d0e87a 100644 --- a/src/calibre/ebooks/metadata/sources/identify.py +++ b/src/calibre/ebooks/metadata/sources/identify.py @@ -27,7 +27,7 @@ from calibre.utils.html2text import html2text from calibre.utils.icu import lower from calibre.utils.date import UNDEFINED_DATE from calibre.utils.formatter import EvalFormatter -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, iterkeys, itervalues, unicode_type # Download worker {{{ @@ -99,7 +99,7 @@ class ISBNMerge(object): def isbn_in_pool(self, isbn): if isbn: - for isbns, pool in self.pools.iteritems(): + for isbns, pool in iteritems(self.pools): if isbn in isbns: return pool return None @@ -147,7 +147,7 @@ class ISBNMerge(object): def finalize(self): has_isbn_result = False - for results in self.pools.itervalues(): + for results in itervalues(self.pools): if results: has_isbn_result = True break @@ -192,7 +192,7 @@ class ISBNMerge(object): if len(groups) != len(self.results): self.results = [] - for rgroup in groups.itervalues(): + for rgroup in itervalues(groups): rel = [r.average_source_relevance for r in rgroup] if len(rgroup) > 1: result = self.merge(rgroup, None, do_asr=False) @@ -206,7 +206,7 @@ class ISBNMerge(object): groups, empty = {}, [] for result in self.results: key = set() - for typ, val in result.identifiers.iteritems(): + for typ, val in iteritems(result.identifiers): if typ and val: key.add((typ, val)) if key: @@ -227,7 +227,7 @@ class ISBNMerge(object): if len(groups) != len(self.results): self.results = [] - for rgroup in groups.itervalues(): + for rgroup in itervalues(groups): rel = [r.average_source_relevance for r in rgroup] if len(rgroup) > 1: result = self.merge(rgroup, None, do_asr=False) @@ -244,7 +244,7 @@ class ISBNMerge(object): def merge_isbn_results(self): self.results = [] sources = set() - for min_year, results in self.pools.itervalues(): + for min_year, results in itervalues(self.pools): if results: for r in results: sources.add(r.identify_plugin) @@ -362,7 +362,7 @@ class ISBNMerge(object): def merge_identify_results(result_map, log): isbn_merge = ISBNMerge(log) - for plugin, results in result_map.iteritems(): + for plugin, results in iteritems(result_map): for result in results: isbn_merge.add_result(result) @@ -439,12 +439,12 @@ def identify(log, abort, # {{{ pass sort_kwargs = dict(kwargs) - for k in list(sort_kwargs.iterkeys()): + for k in list(iterkeys(sort_kwargs)): if k not in ('title', 'authors', 'identifiers'): sort_kwargs.pop(k) longest, lp = -1, '' - for plugin, presults in results.iteritems(): + for plugin, presults in iteritems(results): presults.sort(key=plugin.identify_results_keygen(**sort_kwargs)) # Throw away lower priority results from the same source that have exactly the same @@ -542,7 +542,7 @@ def identify(log, abort, # {{{ def urls_from_identifiers(identifiers): # {{{ - identifiers = {k.lower():v for k, v in identifiers.iteritems()} + identifiers = {k.lower():v for k, v in iteritems(identifiers)} ans = [] keys_left = set(identifiers) @@ -553,7 +553,7 @@ def urls_from_identifiers(identifiers): # {{{ rules = msprefs['id_link_rules'] if rules: formatter = EvalFormatter() - for k, val in identifiers.iteritems(): + for k, val in iteritems(identifiers): val = val.replace('|', ',') vals = {'id':quote(val if isinstance(val, bytes) else val.encode('utf-8')).decode('ascii')} items = rules.get(k) or () @@ -592,7 +592,7 @@ def urls_from_identifiers(identifiers): # {{{ add(issn, 'issn', issn, 'https://www.worldcat.org/issn/'+issn) q = {'http', 'https', 'file'} - for k, url in identifiers.iteritems(): + for k, url in iteritems(identifiers): if url and re.match(r'ur[il]\d*$', k) is not None: url = url[:8].replace('|', ':') + url[8:].replace('|', ',') if url.partition(':')[0].lower() in q: diff --git a/src/calibre/ebooks/metadata/sources/update.py b/src/calibre/ebooks/metadata/sources/update.py index a2403d65a1..5088588647 100644 --- a/src/calibre/ebooks/metadata/sources/update.py +++ b/src/calibre/ebooks/metadata/sources/update.py @@ -17,6 +17,7 @@ from calibre.constants import DEBUG, numeric_version from calibre.ebooks.metadata.sources.base import Source from calibre.utils.config import JSONConfig from calibre.utils.https import get_https_resource_securely +from polyglot.builtins import iteritems, itervalues cache = JSONConfig('metadata-sources-cache.json') @@ -38,7 +39,7 @@ def load_plugin(src): src = src.encode('utf-8') ns = {} exec(src, ns) - for x in ns.itervalues(): + for x in itervalues(ns): if isinstance(x, type) and issubclass(x, Source) and x is not Source: return x @@ -76,7 +77,7 @@ def patch_search_engines(src): def patch_plugins(): from calibre.customize.ui import patch_metadata_plugins patches = {} - for name, val in cache.iteritems(): + for name, val in iteritems(cache): if name == 'hashes': continue if name == 'search_engines': @@ -94,7 +95,7 @@ def update_needed(): 'https://code.calibre-ebook.com/metadata-sources/hashes.json') hashes = bz2.decompress(hashes) hashes = json.loads(hashes) - for k, v in hashes.iteritems(): + for k, v in iteritems(hashes): if current_hashes.get(k) != v: needed[k] = v remove = set(current_hashes) - set(hashes) @@ -132,7 +133,7 @@ def main(report_error=prints, report_action=prints): cache.touch() return updated = {} - for name, expected_hash in needed.iteritems(): + for name, expected_hash in iteritems(needed): report_action('Updating metadata source {}...'.format(name)) try: update_plugin(name, updated, expected_hash) diff --git a/src/calibre/ebooks/metadata/sources/worker.py b/src/calibre/ebooks/metadata/sources/worker.py index 436d7014eb..cbfad164e0 100644 --- a/src/calibre/ebooks/metadata/sources/worker.py +++ b/src/calibre/ebooks/metadata/sources/worker.py @@ -18,6 +18,7 @@ from calibre.ebooks.metadata.sources.update import patch_plugins from calibre.utils.date import as_utc from calibre.utils.logging import GUILog from polyglot.queue import Empty, Queue +from polyglot.builtins import iteritems def merge_result(oldmi, newmi, ensure_fields=None): @@ -54,7 +55,7 @@ def main(do_identify, covers, metadata, ensure_fields, tdir): log = GUILog() patch_plugins() - for book_id, mi in metadata.iteritems(): + for book_id, mi in iteritems(metadata): mi = OPF(BytesIO(mi), basedir=tdir, populate_spine=False).to_book_metadata() title, authors, identifiers = mi.title, mi.authors, mi.identifiers diff --git a/src/calibre/ebooks/metadata/xmp.py b/src/calibre/ebooks/metadata/xmp.py index 82329ee335..c9d6b94491 100644 --- a/src/calibre/ebooks/metadata/xmp.py +++ b/src/calibre/ebooks/metadata/xmp.py @@ -19,7 +19,7 @@ from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.opf2 import dump_dict from calibre.utils.date import parse_date, isoformat, now from calibre.utils.localization import canonicalize_lang, lang_as_iso639_1 -from polyglot.builtins import string_or_bytes +from polyglot.builtins import iteritems, string_or_bytes _xml_declaration = re.compile(r'<\?xml[^<>]+encoding\s*=\s*[\'"](.*?)[\'"][^<>]*>', re.IGNORECASE) @@ -323,7 +323,7 @@ def metadata_from_xmp_packet(raw_bytes): identifiers[scheme] = val # Check Dublin Core for recognizable identifier types - for scheme, check_func in {'doi':check_doi, 'isbn':check_isbn}.iteritems(): + for scheme, check_func in iteritems({'doi':check_doi, 'isbn':check_isbn}): if scheme not in identifiers: val = check_func(first_simple('//dc:identifier', root)) if val: @@ -407,7 +407,7 @@ def create_identifiers(xmp, identifiers): xmp.append(xmpid) bag = xmpid.makeelement(expand('rdf:Bag')) xmpid.append(bag) - for scheme, value in identifiers.iteritems(): + for scheme, value in iteritems(identifiers): li = bag.makeelement(expand('rdf:li')) li.set(expand('rdf:parseType'), 'Resource') bag.append(li) @@ -443,7 +443,7 @@ def create_user_metadata(calibre, all_user_metadata): calibre.append(s) bag = s.makeelement(expand('rdf:Bag')) s.append(bag) - for name, fm in all_user_metadata.iteritems(): + for name, fm in iteritems(all_user_metadata): try: fm = copy.copy(fm) encode_is_multiple(fm) @@ -473,12 +473,12 @@ def metadata_to_xmp_packet(mi): dc = rdf.makeelement(expand('rdf:Description'), nsmap=nsmap('dc')) dc.set(expand('rdf:about'), '') rdf.append(dc) - for prop, tag in {'title':'dc:title', 'comments':'dc:description'}.iteritems(): + for prop, tag in iteritems({'title':'dc:title', 'comments':'dc:description'}): val = mi.get(prop) or '' create_alt_property(dc, tag, val) - for prop, (tag, ordered) in { + for prop, (tag, ordered) in iteritems({ 'authors':('dc:creator', True), 'tags':('dc:subject', False), 'publisher':('dc:publisher', False), - }.iteritems(): + }): val = mi.get(prop) or () if isinstance(val, string_or_bytes): val = [val] @@ -502,9 +502,9 @@ def metadata_to_xmp_packet(mi): identifiers = mi.get_identifiers() if identifiers: create_identifiers(xmp, identifiers) - for scheme, val in identifiers.iteritems(): + for scheme, val in iteritems(identifiers): if scheme in {'isbn', 'doi'}: - for prefix, parent in extra_ids.iteritems(): + for prefix, parent in iteritems(extra_ids): ie = parent.makeelement(expand('%s:%s'%(prefix, scheme))) ie.text = val parent.append(ie) @@ -552,7 +552,7 @@ def find_used_namespaces(elem): def find_preferred_prefix(namespace, elems): for elem in elems: - ans = {v:k for k, v in elem.nsmap.iteritems()}.get(namespace, None) + ans = {v:k for k, v in iteritems(elem.nsmap)}.get(namespace, None) if ans is not None: return ans return find_preferred_prefix(namespace, elem.iterchildren(etree.Element)) @@ -564,7 +564,7 @@ def find_nsmap(elems): used_namespaces |= find_used_namespaces(elem) ans = {} used_namespaces -= {NS_MAP['xml'], NS_MAP['x'], None, NS_MAP['rdf']} - rmap = {v:k for k, v in NS_MAP.iteritems()} + rmap = {v:k for k, v in iteritems(NS_MAP)} i = 0 for ns in used_namespaces: if ns in rmap: diff --git a/src/calibre/ebooks/mobi/debug/headers.py b/src/calibre/ebooks/mobi/debug/headers.py index 97923ab579..99e2e3a1f8 100644 --- a/src/calibre/ebooks/mobi/debug/headers.py +++ b/src/calibre/ebooks/mobi/debug/headers.py @@ -14,7 +14,7 @@ from calibre.ebooks.mobi.reader.headers import NULL_INDEX from calibre.ebooks.mobi.langcodes import main_language, sub_language from calibre.ebooks.mobi.debug import format_bytes from calibre.ebooks.mobi.utils import get_trailing_data -from polyglot.builtins import range +from polyglot.builtins import iteritems, range # PalmDB {{{ @@ -597,9 +597,9 @@ class TextRecord(object): # {{{ self.trailing_data['uncrossable_breaks'] = self.trailing_data.pop(2) self.trailing_data['raw_bytes'] = raw_trailing_bytes - for typ, val in self.trailing_data.iteritems(): + for typ, val in iteritems(self.trailing_data): if isinstance(typ, numbers.Integral): - print ('Record %d has unknown trailing data of type: %d : %r'% + print('Record %d has unknown trailing data of type: %d : %r'% (idx, typ, val)) self.idx = idx @@ -609,7 +609,7 @@ class TextRecord(object): # {{{ with open(os.path.join(folder, name+'.txt'), 'wb') as f: f.write(self.raw) with open(os.path.join(folder, name+'.trailing_data'), 'wb') as f: - for k, v in self.trailing_data.iteritems(): + for k, v in iteritems(self.trailing_data): raw = '%s : %r\n\n'%(k, v) f.write(raw.encode('utf-8')) diff --git a/src/calibre/ebooks/mobi/debug/index.py b/src/calibre/ebooks/mobi/debug/index.py index e0868b9f49..e9446f266f 100644 --- a/src/calibre/ebooks/mobi/debug/index.py +++ b/src/calibre/ebooks/mobi/debug/index.py @@ -15,7 +15,7 @@ from calibre.ebooks.mobi.reader.headers import NULL_INDEX from calibre.ebooks.mobi.reader.index import (CNCX, parse_indx_header, parse_tagx_section, parse_index_record, INDEX_HEADER_FIELDS) from calibre.ebooks.mobi.reader.ncx import (tag_fieldname_map, default_entry) -from polyglot.builtins import range +from polyglot.builtins import iteritems, iterkeys, range File = namedtuple('File', 'file_number name divtbl_count start_position length') @@ -110,13 +110,13 @@ class Index(object): if self.cncx: a('*'*10 + ' CNCX ' + '*'*10) - for offset, val in self.cncx.iteritems(): + for offset, val in iteritems(self.cncx): a('%10s: %s'%(offset, val)) ans.extend(['', '']) if self.table is not None: a('*'*10 + ' %d Index Entries '%len(self.table) + '*'*10) - for k, v in self.table.iteritems(): + for k, v in iteritems(self.table): a('%s: %r'%(k, v)) if self.records: @@ -140,11 +140,11 @@ class SKELIndex(Index): self.records = [] if self.table is not None: - for i, text in enumerate(self.table.iterkeys()): + for i, text in enumerate(iterkeys(self.table)): tag_map = self.table[text] - if set(tag_map.iterkeys()) != {1, 6}: + if set(iterkeys(tag_map)) != {1, 6}: raise ValueError('SKEL Index has unknown tags: %s'% - (set(tag_map.iterkeys())-{1,6})) + (set(iterkeys(tag_map))-{1,6})) self.records.append(File( i, # file_number text, # name @@ -161,11 +161,11 @@ class SECTIndex(Index): self.records = [] if self.table is not None: - for i, text in enumerate(self.table.iterkeys()): + for i, text in enumerate(iterkeys(self.table)): tag_map = self.table[text] - if set(tag_map.iterkeys()) != {2, 3, 4, 6}: + if set(iterkeys(tag_map)) != {2, 3, 4, 6}: raise ValueError('Chunk Index has unknown tags: %s'% - (set(tag_map.iterkeys())-{2, 3, 4, 6})) + (set(iterkeys(tag_map))-{2, 3, 4, 6})) toc_text = self.cncx[tag_map[2][0]] self.records.append(Elem( @@ -186,9 +186,9 @@ class GuideIndex(Index): self.records = [] if self.table is not None: - for i, text in enumerate(self.table.iterkeys()): + for i, text in enumerate(iterkeys(self.table)): tag_map = self.table[text] - if set(tag_map.iterkeys()) not in ({1, 6}, {1, 2, 3}): + if set(iterkeys(tag_map)) not in ({1, 6}, {1, 2, 3}): raise ValueError('Guide Index has unknown tags: %s'% tag_map) @@ -211,13 +211,13 @@ class NCXIndex(Index): NCXEntry = namedtuple('NCXEntry', 'index start length depth parent ' 'first_child last_child title pos_fid kind') - for num, x in enumerate(self.table.iteritems()): + for num, x in enumerate(iteritems(self.table)): text, tag_map = x entry = e = default_entry.copy() entry['name'] = text entry['num'] = num - for tag in tag_fieldname_map.iterkeys(): + for tag in iterkeys(tag_fieldname_map): fieldname, i = tag_fieldname_map[tag] if tag in tag_map: fieldvalue = tag_map[tag][i] @@ -226,9 +226,9 @@ class NCXIndex(Index): # offset fieldvalue = tuple(tag_map[tag]) entry[fieldname] = fieldvalue - for which, name in {3:'text', 5:'kind', 70:'description', + for which, name in iteritems({3:'text', 5:'kind', 70:'description', 71:'author', 72:'image_caption', - 73:'image_attribution'}.iteritems(): + 73:'image_attribution'}): if tag == which: entry[name] = self.cncx.get(fieldvalue, default_entry[name]) diff --git a/src/calibre/ebooks/mobi/reader/index.py b/src/calibre/ebooks/mobi/reader/index.py index 7e15c617ad..eb2ab5e31f 100644 --- a/src/calibre/ebooks/mobi/reader/index.py +++ b/src/calibre/ebooks/mobi/reader/index.py @@ -12,7 +12,7 @@ from collections import OrderedDict, namedtuple from calibre.ebooks.mobi.utils import (decint, count_set_bits, decode_string) -from polyglot.builtins import range +from polyglot.builtins import iteritems, range TagX = namedtuple('TagX', 'tag num_of_values bitmask eof') PTagX = namedtuple('PTagX', 'tag value_count value_bytes num_of_values') @@ -105,7 +105,7 @@ class CNCX(object): # {{{ except: byts = raw[pos:] r = format_bytes(byts) - print ('CNCX entry at offset %d has unknown format %s'%( + print('CNCX entry at offset %d has unknown format %s'%( pos+record_offset, r)) self.records[pos+record_offset] = r pos = len(raw) @@ -123,7 +123,7 @@ class CNCX(object): # {{{ __nonzero__ = __bool__ def iteritems(self): - return self.records.iteritems() + return iteritems(self.records) # }}} @@ -216,7 +216,7 @@ def parse_index_record(table, data, control_byte_count, tags, codec, header = parse_indx_header(data) idxt_pos = header['start'] if data[idxt_pos:idxt_pos+4] != b'IDXT': - print ('WARNING: Invalid INDX record') + print('WARNING: Invalid INDX record') entry_count = header['count'] # loop through to build up the IDXT position starts diff --git a/src/calibre/ebooks/mobi/reader/mobi6.py b/src/calibre/ebooks/mobi/reader/mobi6.py index 43d575c832..c8d247a638 100644 --- a/src/calibre/ebooks/mobi/reader/mobi6.py +++ b/src/calibre/ebooks/mobi/reader/mobi6.py @@ -23,7 +23,7 @@ from calibre.ebooks.metadata.toc import TOC from calibre.ebooks.mobi.reader.headers import BookHeader from calibre.utils.img import save_cover_data_to from calibre.utils.imghdr import what -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range class TopazError(ValueError): @@ -500,7 +500,7 @@ class MobiReader(object): try: float(sz) except ValueError: - if sz in size_map.keys(): + if sz in list(size_map.keys()): attrib['size'] = size_map[sz] elif tag.tag == 'img': recindex = None @@ -894,7 +894,7 @@ class MobiReader(object): def test_mbp_regex(): - for raw, m in { + for raw, m in iteritems({ '':'', 'yyy':' xxxyyy', ' ':'', @@ -905,7 +905,7 @@ def test_mbp_regex(): '':'', '':' sdf', 'xxx':'xxx', - }.iteritems(): + }): ans = MobiReader.PAGE_BREAK_PAT.sub(r'\1', raw) if ans != m: raise Exception('%r != %r for %r'%(ans, m, raw)) diff --git a/src/calibre/ebooks/mobi/reader/mobi8.py b/src/calibre/ebooks/mobi/reader/mobi8.py index 74b3447bd7..a1a0cfecc1 100644 --- a/src/calibre/ebooks/mobi/reader/mobi8.py +++ b/src/calibre/ebooks/mobi/reader/mobi8.py @@ -24,7 +24,7 @@ from calibre.ebooks.metadata.toc import TOC from calibre.ebooks.mobi.utils import read_font_record from calibre.ebooks.oeb.parse_utils import parse_html from calibre.ebooks.oeb.base import XPath, XHTML, xml2text -from polyglot.builtins import range, zip +from polyglot.builtins import iterkeys, range, zip from polyglot.urllib import urldefrag Part = namedtuple('Part', @@ -134,7 +134,7 @@ class Mobi8Reader(object): File = namedtuple('File', 'file_number name divtbl_count start_position length') - for i, text in enumerate(table.iterkeys()): + for i, text in enumerate(iterkeys(table)): tag_map = table[text] self.files.append(File(i, text, tag_map[1][0], tag_map[6][0], tag_map[6][1])) @@ -143,7 +143,7 @@ class Mobi8Reader(object): if self.header.dividx != NULL_INDEX: table, cncx = read_index(self.kf8_sections, self.header.dividx, self.header.codec) - for i, text in enumerate(table.iterkeys()): + for i, text in enumerate(iterkeys(table)): tag_map = table[text] toc_text = cncx[tag_map[2][0]] self.elems.append(Elem(int(text), toc_text, tag_map[3][0], @@ -156,14 +156,14 @@ class Mobi8Reader(object): Item = namedtuple('Item', 'type title pos_fid') - for i, ref_type in enumerate(table.iterkeys()): + for i, ref_type in enumerate(iterkeys(table)): tag_map = table[ref_type] # ref_type, ref_title, div/frag number title = cncx[tag_map[1][0]] fileno = None - if 3 in tag_map.keys(): + if 3 in list(tag_map.keys()): fileno = tag_map[3][0] - if 6 in tag_map.keys(): + if 6 in list(tag_map.keys()): fileno = tag_map[6] self.guide.append(Item(ref_type.decode(self.header.codec), title, fileno)) diff --git a/src/calibre/ebooks/mobi/reader/ncx.py b/src/calibre/ebooks/mobi/reader/ncx.py index c20d795c6c..cc87ea1b07 100644 --- a/src/calibre/ebooks/mobi/reader/ncx.py +++ b/src/calibre/ebooks/mobi/reader/ncx.py @@ -13,6 +13,7 @@ from calibre import replace_entities from calibre.ebooks.metadata.toc import TOC from calibre.ebooks.mobi.reader.headers import NULL_INDEX from calibre.ebooks.mobi.reader.index import read_index +from polyglot.builtins import iteritems, iterkeys tag_fieldname_map = { 1: ['pos',0], @@ -56,13 +57,13 @@ def read_ncx(sections, index, codec): if index != NULL_INDEX: table, cncx = read_index(sections, index, codec) - for num, x in enumerate(table.iteritems()): + for num, x in enumerate(iteritems(table)): text, tag_map = x entry = default_entry.copy() entry['name'] = text entry['num'] = num - for tag in tag_fieldname_map.iterkeys(): + for tag in iterkeys(tag_fieldname_map): fieldname, i = tag_fieldname_map[tag] if tag in tag_map: fieldvalue = tag_map[tag][i] @@ -71,9 +72,9 @@ def read_ncx(sections, index, codec): # offset fieldvalue = tuple(tag_map[tag]) entry[fieldname] = fieldvalue - for which, name in {3:'text', 5:'kind', 70:'description', + for which, name in iteritems({3:'text', 5:'kind', 70:'description', 71:'author', 72:'image_caption', - 73:'image_attribution'}.iteritems(): + 73:'image_attribution'}): if tag == which: entry[name] = cncx.get(fieldvalue, default_entry[name]) @@ -100,4 +101,3 @@ def build_toc(index_entries): item.play_order = i return ans - diff --git a/src/calibre/ebooks/mobi/utils.py b/src/calibre/ebooks/mobi/utils.py index bd545e5ce0..6760605650 100644 --- a/src/calibre/ebooks/mobi/utils.py +++ b/src/calibre/ebooks/mobi/utils.py @@ -14,7 +14,7 @@ from io import BytesIO from calibre.utils.img import save_cover_data_to, scale_image, image_to_data, image_from_data, resize_image from calibre.utils.imghdr import what from calibre.ebooks import normalize -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iterkeys, unicode_type, range from tinycss.color3 import parse_color_string IMAGE_MAX_SIZE = 10 * 1024 * 1024 @@ -589,7 +589,7 @@ class CNCX(object): # {{{ offset = 0 buf = BytesIO() RECORD_LIMIT = 0x10000 - 1024 # kindlegen appears to use 1024, PDB limit is 0x10000 - for key in self.strings.iterkeys(): + for key in iterkeys(self.strings): utf8 = utf8_text(key[:self.MAX_STRING_LENGTH]) l = len(utf8) sz_bytes = encint(l) diff --git a/src/calibre/ebooks/mobi/writer2/indexer.py b/src/calibre/ebooks/mobi/writer2/indexer.py index edb9abbe19..68ec0633c7 100644 --- a/src/calibre/ebooks/mobi/writer2/indexer.py +++ b/src/calibre/ebooks/mobi/writer2/indexer.py @@ -2,7 +2,6 @@ # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai from __future__ import (unicode_literals, division, absolute_import, print_function) -from polyglot.builtins import filter, map __license__ = 'GPL v3' __copyright__ = '2011, Kovid Goyal ' @@ -15,7 +14,7 @@ from collections import OrderedDict, defaultdict from calibre.ebooks.mobi.utils import (encint, encode_number_as_hex, encode_tbs, align_block, RECORD_SIZE, CNCX as CNCX_) -from polyglot.builtins import range +from polyglot.builtins import filter, iteritems, iterkeys, itervalues, map, range class CNCX(CNCX_): # {{{ @@ -109,7 +108,7 @@ class IndexEntry(object): 'author_offset': 71, } - RTAG_MAP = {v:k for k, v in TAG_VALUES.iteritems()} # noqa + RTAG_MAP = {v:k for k, v in iteritems(TAG_VALUES)} # noqa def __init__(self, offset, label_offset): self.offset, self.label_offset = offset, label_offset @@ -227,7 +226,7 @@ class SecondaryIndexEntry(IndexEntry): # The values for this index entry # I dont know what the 5 means, it is not the number of entries self.secondary = [5 if tag == min( - self.INDEX_MAP.itervalues()) else 0, 0, tag] + itervalues(self.INDEX_MAP)) else 0, 0, tag] @property def tag_nums(self): @@ -239,7 +238,7 @@ class SecondaryIndexEntry(IndexEntry): @classmethod def entries(cls): - rmap = {v:k for k,v in cls.INDEX_MAP.iteritems()} + rmap = {v:k for k,v in iteritems(cls.INDEX_MAP)} for tag in sorted(rmap, reverse=True): yield cls(rmap[tag]) @@ -284,7 +283,7 @@ class TBS(object): # {{{ for x in ('starts', 'ends', 'completes'): for idx in data[x]: depth_map[idx.depth].append(idx) - for l in depth_map.itervalues(): + for l in itervalues(depth_map): l.sort(key=lambda x:x.offset) self.periodical_tbs(data, first, depth_map) else: @@ -318,7 +317,7 @@ class TBS(object): # {{{ if first_node is not None and first_node.depth > 0: parent_section_index = (first_node.index if first_node.depth == 1 else first_node.parent_index) else: - parent_section_index = max(self.section_map.iterkeys()) + parent_section_index = max(iterkeys(self.section_map)) else: # Non terminal record @@ -455,7 +454,7 @@ class Indexer(object): # {{{ self.is_periodical else 'book')) self.is_flat_periodical = False if self.is_periodical: - periodical_node = iter(oeb.toc).next() + periodical_node = next(iter(oeb.toc)) sections = tuple(periodical_node) self.is_flat_periodical = len(sections) == 1 @@ -681,7 +680,7 @@ class Indexer(object): # {{{ # }}} def create_periodical_index(self): # {{{ - periodical_node = iter(self.oeb.toc).next() + periodical_node = next(iter(self.oeb.toc)) periodical_node_offset = self.serializer.body_start_offset periodical_node_size = (self.serializer.body_end_offset - periodical_node_offset) diff --git a/src/calibre/ebooks/mobi/writer2/main.py b/src/calibre/ebooks/mobi/writer2/main.py index 2bc19bfcdc..5edd7eebfe 100644 --- a/src/calibre/ebooks/mobi/writer2/main.py +++ b/src/calibre/ebooks/mobi/writer2/main.py @@ -19,7 +19,7 @@ from calibre.ebooks.mobi.writer2 import (PALMDOC, UNCOMPRESSED) from calibre.ebooks.mobi.utils import (encint, encode_trailing_data, align_block, detect_periodical, RECORD_SIZE, create_text_record) from calibre.ebooks.mobi.writer2.indexer import Indexer -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range # Disabled as I dont care about uncrossable breaks WRITE_UNCROSSABLE_BREAKS = False @@ -425,10 +425,10 @@ class MobiWriter(object): extra_data_flags |= 0b10 header_fields['extra_data_flags'] = extra_data_flags - for k, v in {'last_text_record':'last_text_record_idx', + for k, v in iteritems({'last_text_record':'last_text_record_idx', 'first_non_text_record':'first_non_text_record_idx', 'ncx_index':'primary_index_record_idx', - }.iteritems(): + }): header_fields[k] = getattr(self, v) if header_fields['ncx_index'] is None: header_fields['ncx_index'] = NULL_INDEX diff --git a/src/calibre/ebooks/mobi/writer2/resources.py b/src/calibre/ebooks/mobi/writer2/resources.py index ebb0d45c68..080a040102 100644 --- a/src/calibre/ebooks/mobi/writer2/resources.py +++ b/src/calibre/ebooks/mobi/writer2/resources.py @@ -16,7 +16,7 @@ from calibre.ebooks import generate_masthead from calibre.ebooks.oeb.base import OEB_RASTER_IMAGES from calibre.ptempfile import PersistentTemporaryFile from calibre.utils.imghdr import what -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type PLACEHOLDER_GIF = b'GIF89a\x01\x00\x01\x00\xf0\x00\x00\x00\x00\x00\xff\xff\xff!\xf9\x04\x01\x00\x00\x00\x00!\xfe calibre-placeholder-gif-for-azw3\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;' # noqa @@ -149,7 +149,7 @@ class Resources(object): def serialize(self, records, used_images): used_image_indices = self.used_image_indices | { - v-1 for k, v in self.item_map.iteritems() if k in used_images} + v-1 for k, v in iteritems(self.item_map) if k in used_images} for i in self.image_indices-used_image_indices: self.records[i] = PLACEHOLDER_GIF records.extend(self.records) diff --git a/src/calibre/ebooks/mobi/writer8/exth.py b/src/calibre/ebooks/mobi/writer8/exth.py index 300ccf302d..a25f1070c3 100644 --- a/src/calibre/ebooks/mobi/writer8/exth.py +++ b/src/calibre/ebooks/mobi/writer8/exth.py @@ -15,7 +15,7 @@ from calibre.constants import iswindows, isosx from calibre.ebooks.mobi.utils import (utf8_text, to_base) from calibre.utils.localization import lang_as_iso639_1 from calibre.ebooks.metadata import authors_to_sort_string -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type EXTH_CODES = { 'creator': 100, @@ -163,7 +163,7 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False, else: # Pretend to be kindlegen 1.2 vals = {204:201, 205:1, 206:2, 207:33307} - for code, val in vals.iteritems(): + for code, val in iteritems(vals): exth.write(pack(b'>III', code, 12, val)) nrecs += 1 if be_kindlegen2: diff --git a/src/calibre/ebooks/mobi/writer8/header.py b/src/calibre/ebooks/mobi/writer8/header.py index ad77196517..6ac9f42076 100644 --- a/src/calibre/ebooks/mobi/writer8/header.py +++ b/src/calibre/ebooks/mobi/writer8/header.py @@ -13,6 +13,7 @@ from collections import OrderedDict from struct import pack from calibre.ebooks.mobi.utils import align_block +from polyglot.builtins import iteritems NULL = 0xffffffff zeroes = lambda x: b'\0'*x @@ -51,18 +52,18 @@ class Header(OrderedDict): @property def dynamic_fields(self): - return tuple(k for k, v in self.iteritems() if v is None) + return tuple(k for k, v in iteritems(self) if v is None) def __call__(self, **kwargs): positions = {} - for name, val in kwargs.iteritems(): + for name, val in iteritems(kwargs): if name not in self: raise KeyError('Not a valid header field: %r'%name) self[name] = val buf = BytesIO() buf.write(bytes(self.HEADER_NAME)) - for name, val in self.iteritems(): + for name, val in iteritems(self): val = self.format_value(name, val) positions[name] = buf.tell() if val is None: @@ -72,7 +73,7 @@ class Header(OrderedDict): val = pack(b'>'+fmt, val) buf.write(val) - for pos_field, field in self.POSITIONS.iteritems(): + for pos_field, field in iteritems(self.POSITIONS): buf.seek(positions[pos_field]) buf.write(pack(b'>I', positions[field])) diff --git a/src/calibre/ebooks/mobi/writer8/main.py b/src/calibre/ebooks/mobi/writer8/main.py index d66ec8b318..d31bca8b9f 100644 --- a/src/calibre/ebooks/mobi/writer8/main.py +++ b/src/calibre/ebooks/mobi/writer8/main.py @@ -31,7 +31,7 @@ from calibre.ebooks.mobi.writer8.index import (NCXIndex, SkelIndex, from calibre.ebooks.mobi.writer8.mobi import KF8Book from calibre.ebooks.mobi.writer8.tbs import apply_trailing_byte_sequences from calibre.ebooks.mobi.writer8.toc import TOCAdder -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type XML_DOCS = OEB_DOCS | {SVG_MIME} @@ -133,7 +133,7 @@ class KF8Writer(object): if item.media_type in XML_DOCS: root = self.data(item) for tag in XPath('//h:img|//svg:image')(root): - for attr, ref in tag.attrib.iteritems(): + for attr, ref in iteritems(tag.attrib): if attr.split('}')[-1].lower() in {'src', 'href'}: tag.attrib[attr] = pointer(item, ref) @@ -206,7 +206,7 @@ class KF8Writer(object): extract(tag) inlines[raw].append(repl) - for raw, elems in inlines.iteritems(): + for raw, elems in iteritems(inlines): idx = to_ref(len(self.flows)) self.flows.append(raw) for link in elems: @@ -320,7 +320,7 @@ class KF8Writer(object): def chunk_it_up(self): placeholder_map = {} - for placeholder, x in self.link_map.iteritems(): + for placeholder, x in iteritems(self.link_map): href, frag = x aid = self.id_map.get(x, None) if aid is None: diff --git a/src/calibre/ebooks/mobi/writer8/skeleton.py b/src/calibre/ebooks/mobi/writer8/skeleton.py index fd5f943e29..418c0858fc 100644 --- a/src/calibre/ebooks/mobi/writer8/skeleton.py +++ b/src/calibre/ebooks/mobi/writer8/skeleton.py @@ -17,7 +17,7 @@ from lxml import etree from calibre.ebooks.oeb.base import XHTML_NS, extract from calibre.constants import ispy3 from calibre.ebooks.mobi.utils import to_base -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type CHUNK_SIZE = 8192 @@ -214,7 +214,7 @@ class Chunker(object): def remove_namespaces(self, root): lang = None - for attr, val in root.attrib.iteritems(): + for attr, val in iteritems(root.attrib): if attr.rpartition('}')[-1] == 'lang': lang = val @@ -248,11 +248,11 @@ class Chunker(object): tn = tag.tag if tn is not None: tn = tn.rpartition('}')[-1] - attrib = {k.rpartition('}')[-1]:v for k, v in tag.attrib.iteritems()} + attrib = {k.rpartition('}')[-1]:v for k, v in iteritems(tag.attrib)} try: elem = nroot.makeelement(tn, attrib=attrib) except ValueError: - attrib = {k:v for k, v in attrib.iteritems() if ':' not in k} + attrib = {k:v for k, v in iteritems(attrib) if ':' not in k} elem = nroot.makeelement(tn, attrib=attrib) elem.text = tag.text elem.tail = tag.tail @@ -402,7 +402,7 @@ class Chunker(object): return bytes(':off:'.join((pos, fid))) placeholder_map = {bytes(k):to_placeholder(v) for k, v in - self.placeholder_map.iteritems()} + iteritems(self.placeholder_map)} # Now update the links def sub(match): diff --git a/src/calibre/ebooks/mobi/writer8/tbs.py b/src/calibre/ebooks/mobi/writer8/tbs.py index f8becc3f8e..50a7f60a3c 100644 --- a/src/calibre/ebooks/mobi/writer8/tbs.py +++ b/src/calibre/ebooks/mobi/writer8/tbs.py @@ -23,6 +23,7 @@ from operator import attrgetter from calibre.ebooks.mobi.utils import (encode_trailing_data, encode_tbs) +from polyglot.builtins import iteritems, itervalues Entry = namedtuple('IndexEntry', 'index start length depth parent ' 'first_child last_child title action start_offset length_offset ' @@ -122,7 +123,7 @@ def encode_strands_as_sequences(strands, tbs_type=8): max_length_offset = 0 first_entry = None for strand in strands: - for entries in strand.itervalues(): + for entries in itervalues(strand): for entry in entries: if first_entry is None: first_entry = entry @@ -131,7 +132,7 @@ def encode_strands_as_sequences(strands, tbs_type=8): for strand in strands: strand_seqs = [] - for depth, entries in strand.iteritems(): + for depth, entries in iteritems(strand): extra = {} if entries[-1].action == 'spans': extra[0b1] = 0 @@ -207,9 +208,7 @@ def apply_trailing_byte_sequences(index_table, records, text_record_lengths): except NegativeStrandIndex: rmap = calculate_all_tbs(indexing_data, tbs_type=5) - for i, tbs_bytes in rmap.iteritems(): + for i, tbs_bytes in iteritems(rmap): records[i] += encode_trailing_data(tbs_bytes) return True - - diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index b6186b4fed..f5aee08109 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -20,7 +20,7 @@ from calibre.ebooks.oeb.parse_utils import (barename, XHTML_NS, RECOVER_PARSER, namespace, XHTML, parse_html, NotHTML) from calibre.utils.cleantext import clean_xml_chars from calibre.utils.short_uuid import uuid4 -from polyglot.builtins import unicode_type, string_or_bytes, range +from polyglot.builtins import iteritems, unicode_type, string_or_bytes, range from polyglot.urllib import unquote, urldefrag, urljoin, urlparse, urlunparse XML_NS = 'http://www.w3.org/XML/1998/namespace' @@ -1479,7 +1479,7 @@ class Guide(object): return self.refs.pop(type, None) def remove_by_href(self, href): - remove = [r for r, i in self.refs.iteritems() if i.href == href] + remove = [r for r, i in iteritems(self.refs) if i.href == href] for r in remove: self.remove(r) @@ -1782,7 +1782,7 @@ class PageList(object): for page in self.pages: id = page.id or uuid_id() type = page.type - value = str(values[type].next()) + value = str(next(values[type])) attrib = {'id': id, 'value': value, 'type': type, 'playOrder': '0'} if page.klass: attrib['class'] = page.klass diff --git a/src/calibre/ebooks/oeb/display/webview.py b/src/calibre/ebooks/oeb/display/webview.py index c4403e7b41..4338f69baf 100644 --- a/src/calibre/ebooks/oeb/display/webview.py +++ b/src/calibre/ebooks/oeb/display/webview.py @@ -10,6 +10,7 @@ __docformat__ = 'restructuredtext en' import re from calibre import guess_type +from polyglot.builtins import iteritems class EntityDeclarationProcessor(object): # {{{ @@ -21,7 +22,7 @@ class EntityDeclarationProcessor(object): # {{{ if len(tokens) > 1: self.declared_entities[tokens[0].strip()] = tokens[1].strip().replace('"', '') self.processed_html = html - for key, val in self.declared_entities.iteritems(): + for key, val in iteritems(self.declared_entities): self.processed_html = self.processed_html.replace('&%s;'%key, val) # }}} diff --git a/src/calibre/ebooks/oeb/normalize_css.py b/src/calibre/ebooks/oeb/normalize_css.py index 02c377974c..8672abb5cc 100644 --- a/src/calibre/ebooks/oeb/normalize_css.py +++ b/src/calibre/ebooks/oeb/normalize_css.py @@ -7,7 +7,7 @@ __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal ' import numbers -from polyglot.builtins import zip, string_or_bytes +from polyglot.builtins import iteritems, zip, string_or_bytes from functools import wraps from css_parser.css import PropertyValue @@ -140,7 +140,7 @@ def normalize_border(name, cssvalue): style = normalizers['border-' + EDGES[0]]('border-' + EDGES[0], cssvalue) vals = style.copy() for edge in EDGES[1:]: - style.update({k.replace(EDGES[0], edge):v for k, v in vals.iteritems()}) + style.update({k.replace(EDGES[0], edge):v for k, v in iteritems(vals)}) return style @@ -254,7 +254,7 @@ def condense_rule(style): if prop.name and prop.name.startswith(x): expanded[x].append(prop) break - for prefix, vals in expanded.iteritems(): + for prefix, vals in iteritems(expanded): if len(vals) > 1 and {x.priority for x in vals} == {''}: condensers[prefix[:-1]](style, vals) @@ -280,7 +280,7 @@ def test_normalization(return_tests=False): # {{{ ans.update(expected) return ans - for raw, expected in { + for raw, expected in iteritems({ 'some_font': {'font-family':'some_font'}, 'inherit':{k:'inherit' for k in font_composition}, '1.2pt/1.4 A_Font': {'font-family':'A_Font', 'font-size':'1.2pt', 'line-height':'1.4'}, 'bad font': {'font-family':'"bad font"'}, '10% serif': {'font-family':'serif', 'font-size':'10%'}, @@ -291,7 +291,7 @@ def test_normalization(return_tests=False): # {{{ {'font-family':'serif', 'font-weight':'bold', 'font-style':'italic', 'font-size':'larger', 'line-height':'normal', 'font-variant':'small-caps'}, '2em A B': {'font-family': '"A B"', 'font-size': '2em'}, - }.iteritems(): + }): val = tuple(parseStyle('font: %s' % raw, validate=False))[0].cssValue style = normalizers['font']('font', val) self.assertDictEqual(font_dict(expected), style, raw) @@ -299,7 +299,7 @@ def test_normalization(return_tests=False): # {{{ def test_border_normalization(self): def border_edge_dict(expected, edge='right'): ans = {'border-%s-%s' % (edge, x): DEFAULTS['border-%s-%s' % (edge, x)] for x in ('style', 'width', 'color')} - for x, v in expected.iteritems(): + for x, v in iteritems(expected): ans['border-%s-%s' % (edge, x)] = v return ans @@ -315,39 +315,39 @@ def test_normalization(return_tests=False): # {{{ ans['border-%s-%s' % (edge, val)] = expected return ans - for raw, expected in { + for raw, expected in iteritems({ 'solid 1px red': {'color':'red', 'width':'1px', 'style':'solid'}, '1px': {'width': '1px'}, '#aaa': {'color': '#aaa'}, '2em groove': {'width':'2em', 'style':'groove'}, - }.iteritems(): + }): for edge in EDGES: br = 'border-%s' % edge val = tuple(parseStyle('%s: %s' % (br, raw), validate=False))[0].cssValue self.assertDictEqual(border_edge_dict(expected, edge), normalizers[br](br, val)) - for raw, expected in { + for raw, expected in iteritems({ 'solid 1px red': {'color':'red', 'width':'1px', 'style':'solid'}, '1px': {'width': '1px'}, '#aaa': {'color': '#aaa'}, 'thin groove': {'width':'thin', 'style':'groove'}, - }.iteritems(): + }): val = tuple(parseStyle('%s: %s' % ('border', raw), validate=False))[0].cssValue self.assertDictEqual(border_dict(expected), normalizers['border']('border', val)) - for name, val in { + for name, val in iteritems({ 'width': '10%', 'color': 'rgb(0, 1, 1)', 'style': 'double', - }.iteritems(): + }): cval = tuple(parseStyle('border-%s: %s' % (name, val), validate=False))[0].cssValue self.assertDictEqual(border_val_dict(val, name), normalizers['border-'+name]('border-'+name, cval)) def test_edge_normalization(self): def edge_dict(prefix, expected): return {'%s-%s' % (prefix, edge) : x for edge, x in zip(EDGES, expected)} - for raw, expected in { + for raw, expected in iteritems({ '2px': ('2px', '2px', '2px', '2px'), '1em 2em': ('1em', '2em', '1em', '2em'), '1em 2em 3em': ('1em', '2em', '3em', '2em'), '1 2 3 4': ('1', '2', '3', '4'), - }.iteritems(): + }): for prefix in ('margin', 'padding'): cval = tuple(parseStyle('%s: %s' % (prefix, raw), validate=False))[0].cssValue self.assertDictEqual(edge_dict(prefix, expected), normalizers[prefix](prefix, cval)) @@ -355,14 +355,14 @@ def test_normalization(return_tests=False): # {{{ def test_list_style_normalization(self): def ls_dict(expected): ans = {'list-style-%s' % x : DEFAULTS['list-style-%s' % x] for x in ('type', 'image', 'position')} - for k, v in expected.iteritems(): + for k, v in iteritems(expected): ans['list-style-%s' % k] = v return ans - for raw, expected in { + for raw, expected in iteritems({ 'url(http://www.example.com/images/list.png)': {'image': 'url(http://www.example.com/images/list.png)'}, 'inside square': {'position':'inside', 'type':'square'}, 'upper-roman url(img) outside': {'position':'outside', 'type':'upper-roman', 'image':'url(img)'}, - }.iteritems(): + }): cval = tuple(parseStyle('list-style: %s' % raw, validate=False))[0].cssValue self.assertDictEqual(ls_dict(expected), normalizers['list-style']('list-style', cval)) @@ -382,7 +382,7 @@ def test_normalization(return_tests=False): # {{{ ae({'list-style', 'list-style-image', 'list-style-type', 'list-style-position'}, normalize_filter_css({'list-style'})) def test_edge_condensation(self): - for s, v in { + for s, v in iteritems({ (1, 1, 3) : None, (1, 2, 3, 4) : '2pt 3pt 4pt 1pt', (1, 2, 3, 2) : '2pt 3pt 2pt 1pt', @@ -391,10 +391,10 @@ def test_normalization(return_tests=False): # {{{ (1, 1, 1, 1) : '1pt', ('2%', '2%', '2%', '2%') : '2%', tuple('0 0 0 0'.split()) : '0', - }.iteritems(): + }): for prefix in ('margin', 'padding'): css = {'%s-%s' % (prefix, x) : str(y)+'pt' if isinstance(y, numbers.Number) else y for x, y in zip(('left', 'top', 'right', 'bottom'), s)} - css = '; '.join(('%s:%s' % (k, v) for k, v in css.iteritems())) + css = '; '.join(('%s:%s' % (k, v) for k, v in iteritems(css))) style = parseStyle(css) condense_rule(style) val = getattr(style.getProperty(prefix), 'value', None) diff --git a/src/calibre/ebooks/oeb/parse_utils.py b/src/calibre/ebooks/oeb/parse_utils.py index 28bb10932a..86874a93ba 100644 --- a/src/calibre/ebooks/oeb/parse_utils.py +++ b/src/calibre/ebooks/oeb/parse_utils.py @@ -14,7 +14,7 @@ from lxml import etree, html from calibre import xml_replace_entities, force_unicode from calibre.constants import filesystem_encoding from calibre.ebooks.chardet import xml_to_unicode, strip_encoding_declarations -from polyglot.builtins import unicode_type, string_or_bytes +from polyglot.builtins import iteritems, itervalues, unicode_type, string_or_bytes RECOVER_PARSER = etree.XMLParser(recover=True, no_network=True) XHTML_NS = 'http://www.w3.org/1999/xhtml' @@ -144,8 +144,8 @@ def clean_word_doc(data, log): def ensure_namespace_prefixes(node, nsmap): - namespace_uris = frozenset(nsmap.itervalues()) - fnsmap = {k:v for k, v in node.nsmap.iteritems() if v not in namespace_uris} + namespace_uris = frozenset(itervalues(nsmap)) + fnsmap = {k:v for k, v in iteritems(node.nsmap) if v not in namespace_uris} fnsmap.update(nsmap) if fnsmap != dict(node.nsmap): node = clone_element(node, nsmap=fnsmap, in_context=False) @@ -201,7 +201,7 @@ def parse_html(data, log=None, decoder=None, preprocessor=None, val = val[1:-1] user_entities[match.group(1)] = val if user_entities: - pat = re.compile(r'&(%s);'%('|'.join(user_entities.keys()))) + pat = re.compile(r'&(%s);'%('|'.join(list(user_entities.keys())))) data = pat.sub(lambda m:user_entities[m.group(1)], data) if preprocessor is not None: @@ -241,7 +241,7 @@ def parse_html(data, log=None, decoder=None, preprocessor=None, for x in data.iterdescendants(): try: x.tag = x.tag.lower() - for key, val in list(x.attrib.iteritems()): + for key, val in list(iteritems(x.attrib)): del x.attrib[key] key = key.lower() x.attrib[key] = val diff --git a/src/calibre/ebooks/oeb/polish/cascade.py b/src/calibre/ebooks/oeb/polish/cascade.py index e0f5d1602a..00fa8dd837 100644 --- a/src/calibre/ebooks/oeb/polish/cascade.py +++ b/src/calibre/ebooks/oeb/polish/cascade.py @@ -19,6 +19,7 @@ from calibre.ebooks.oeb.base import OEB_STYLES, XHTML from calibre.ebooks.oeb.normalize_css import normalizers, DEFAULTS from calibre.ebooks.oeb.stylizer import media_ok, INHERITED from tinycss.fonts3 import serialize_font_family, parse_font_family +from polyglot.builtins import iteritems, itervalues _html_css_stylesheet = None @@ -99,7 +100,7 @@ def iterdeclaration(decl): if n is None: yield p else: - for k, v in n(p.name, p.propertyValue).iteritems(): + for k, v in iteritems(n(p.name, p.propertyValue)): yield Property(k, v, p.literalpriority) @@ -156,7 +157,7 @@ def resolve_pseudo_declarations(decls): groups = defaultdict(list) for d in decls: groups[d.pseudo_element].append(d) - return {k:resolve_declarations(v) for k, v in groups.iteritems()} + return {k:resolve_declarations(v) for k, v in iteritems(groups)} def resolve_styles(container, name, select=None, sheet_callback=None): @@ -218,11 +219,11 @@ def resolve_styles(container, name, select=None, sheet_callback=None): style_map[elem].append(StyleDeclaration(Specificity(1, 0, 0, 0, 0), normalize_style_declaration(style, name), None)) for l in (style_map, pseudo_style_map): - for x in l.itervalues(): + for x in itervalues(l): x.sort(key=itemgetter(0), reverse=True) - style_map = {elem:resolve_declarations(x) for elem, x in style_map.iteritems()} - pseudo_style_map = {elem:resolve_pseudo_declarations(x) for elem, x in pseudo_style_map.iteritems()} + style_map = {elem:resolve_declarations(x) for elem, x in iteritems(style_map)} + pseudo_style_map = {elem:resolve_pseudo_declarations(x) for elem, x in iteritems(pseudo_style_map)} return partial(resolve_property, style_map), partial(resolve_pseudo_property, style_map, pseudo_style_map), select @@ -234,7 +235,7 @@ def defvals(): global _defvals if _defvals is None: u = type('') - _defvals = {k:Values(Property(k, u(val)).propertyValue) for k, val in DEFAULTS.iteritems()} + _defvals = {k:Values(Property(k, u(val)).propertyValue) for k, val in iteritems(DEFAULTS)} return _defvals diff --git a/src/calibre/ebooks/oeb/polish/check/fonts.py b/src/calibre/ebooks/oeb/polish/check/fonts.py index c8d23b0d02..667820af61 100644 --- a/src/calibre/ebooks/oeb/polish/check/fonts.py +++ b/src/calibre/ebooks/oeb/polish/check/fonts.py @@ -16,6 +16,7 @@ from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style from calibre.ebooks.oeb.polish.fonts import change_font_in_declaration from calibre.utils.fonts.utils import get_all_font_names, is_font_embeddable, UnsupportedFont from tinycss.fonts3 import parse_font_family +from polyglot.builtins import iteritems class InvalidFont(BaseError): @@ -58,7 +59,7 @@ class FontAliasing(BaseError): def __call__(self, container): changed = False - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_STYLES: sheet = container.parsed(name) if fix_sheet(sheet, self.css_name, self.font_name): @@ -85,7 +86,7 @@ class FontAliasing(BaseError): def check_fonts(container): font_map = {} errors = [] - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_FONTS: raw = container.raw_data(name) try: @@ -102,7 +103,7 @@ def check_fonts(container): errors.append(NotEmbeddable(name, fs_type)) sheets = [] - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_STYLES: try: sheets.append((name, container.parsed(name), None)) diff --git a/src/calibre/ebooks/oeb/polish/check/links.py b/src/calibre/ebooks/oeb/polish/check/links.py index b581bc6418..610585677e 100644 --- a/src/calibre/ebooks/oeb/polish/check/links.py +++ b/src/calibre/ebooks/oeb/polish/check/links.py @@ -18,7 +18,7 @@ from calibre.ebooks.oeb.polish.replace import remove_links_to from calibre.ebooks.oeb.polish.cover import get_raster_cover_name from calibre.ebooks.oeb.polish.utils import guess_type, actual_case_for_name, corrected_case_for_name from calibre.ebooks.oeb.polish.check.base import BaseError, WARN, INFO -from polyglot.builtins import map, range +from polyglot.builtins import iteritems, map, range from polyglot.urllib import urlparse from polyglot.queue import Queue, Empty @@ -132,7 +132,7 @@ class UnreferencedDoc(UnreferencedResource): def __call__(self, container): from calibre.ebooks.oeb.base import OPF - rmap = {v:k for k, v in container.manifest_id_map.iteritems()} + rmap = {v:k for k, v in iteritems(container.manifest_id_map)} if self.name in rmap: manifest_id = rmap[self.name] else: @@ -164,7 +164,7 @@ class Unmanifested(BadLink): if self.file_action == 'remove': container.remove_item(self.name) else: - rmap = {v:k for k, v in container.manifest_id_map.iteritems()} + rmap = {v:k for k, v in iteritems(container.manifest_id_map)} if self.name not in rmap: container.add_name_to_manifest(self.name) return True @@ -246,7 +246,7 @@ class MimetypeMismatch(BaseError): def check_mimetypes(container): errors = [] a = errors.append - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): gt = container.guess_type(name) if mt != gt: if mt == 'application/oebps-page-map+xml' and name.lower().endswith('.xml'): @@ -284,7 +284,7 @@ def check_link_destinations(container): dest_map = {} opf_type = guess_type('a.opf') ncx_type = guess_type('a.ncx') - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS: for a in container.parsed(name).xpath('//*[local-name()="a" and @href]'): href = a.get('href') @@ -315,7 +315,7 @@ def check_links(container): x = x[1:] return x - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS or mt in OEB_STYLES or mt in xml_types: for href, lnum, col in container.iterlinks(name): if not href: @@ -366,7 +366,7 @@ def check_links(container): cover_name = container.guide_type_map.get('cover', None) nav_items = frozenset(container.manifest_items_with_property('nav')) - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_STYLES and name not in spine_styles: a(UnreferencedResource(name)) elif mt in OEB_DOCS and name not in spine_docs and name not in nav_items: @@ -379,7 +379,7 @@ def check_links(container): continue unreferenced.add(name) - manifest_names = set(container.manifest_id_map.itervalues()) + manifest_names = set(itervalues(container.manifest_id_map)) for name in container.mime_map: if name not in manifest_names and not container.ok_to_be_unmanifested(name): a(Unmanifested(name, unreferenced=name in unreferenced)) @@ -401,7 +401,7 @@ def get_html_ids(raw_data): def check_external_links(container, progress_callback=(lambda num, total:None), check_anchors=True): progress_callback(0, 0) external_links = defaultdict(list) - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS or mt in OEB_STYLES: for href, lnum, col in container.iterlinks(name): purl = urlparse(href) @@ -411,7 +411,7 @@ def check_external_links(container, progress_callback=(lambda num, total:None), return [] items = Queue() ans = [] - tuple(map(items.put, external_links.iteritems())) + tuple(map(items.put, iteritems(external_links))) progress_callback(0, len(external_links)) done = [] downloaded_html_ids = {} diff --git a/src/calibre/ebooks/oeb/polish/check/main.py b/src/calibre/ebooks/oeb/polish/check/main.py index 66017e312e..eb9ff10571 100644 --- a/src/calibre/ebooks/oeb/polish/check/main.py +++ b/src/calibre/ebooks/oeb/polish/check/main.py @@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal ' -from polyglot.builtins import map +from polyglot.builtins import iteritems, map from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES from calibre.ebooks.oeb.polish.utils import guess_type @@ -29,7 +29,7 @@ def run_checks(container): # Check parsing xml_items, html_items, raster_images, stylesheets = [], [], [], [] - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): items = None if mt in XML_TYPES: items = xml_items diff --git a/src/calibre/ebooks/oeb/polish/check/opf.py b/src/calibre/ebooks/oeb/polish/check/opf.py index 4e9a874b41..76f8418b4e 100644 --- a/src/calibre/ebooks/oeb/polish/check/opf.py +++ b/src/calibre/ebooks/oeb/polish/check/opf.py @@ -13,6 +13,7 @@ from calibre.ebooks.oeb.polish.check.base import BaseError, WARN from calibre.ebooks.oeb.polish.toc import find_existing_nav_toc, parse_nav from calibre.ebooks.oeb.polish.utils import guess_type from calibre.ebooks.oeb.base import OPF, OPF2_NS, DC, DC11_NS, XHTML_MIME +from polyglot.builtins import iteritems class MissingSection(BaseError): @@ -315,7 +316,7 @@ def check_opf(container): dups[href].append(item.sourceline) else: seen[href] = item.sourceline - errors.extend(DuplicateHref(container.opf_name, eid, locs) for eid, locs in dups.iteritems()) + errors.extend(DuplicateHref(container.opf_name, eid, locs) for eid, locs in iteritems(dups)) seen, dups = {}, {} for item in container.opf_xpath('/opf:package/opf:spine/opf:itemref[@idref]'): @@ -326,7 +327,7 @@ def check_opf(container): dups[ref].append(item.sourceline) else: seen[ref] = item.sourceline - errors.extend(DuplicateHref(container.opf_name, eid, locs, for_spine=True) for eid, locs in dups.iteritems()) + errors.extend(DuplicateHref(container.opf_name, eid, locs, for_spine=True) for eid, locs in iteritems(dups)) spine = container.opf_xpath('/opf:package/opf:spine[@toc]') if spine: @@ -345,7 +346,7 @@ def check_opf(container): ncx = container.manifest_type_map.get(guess_type('a.ncx')) if ncx: ncx_name = ncx[0] - rmap = {v:k for k, v in container.manifest_id_map.iteritems()} + rmap = {v:k for k, v in iteritems(container.manifest_id_map)} ncx_id = rmap.get(ncx_name) if ncx_id: errors.append(MissingNCXRef(container.opf_name, spine.sourceline, ncx_id)) diff --git a/src/calibre/ebooks/oeb/polish/check/parsing.py b/src/calibre/ebooks/oeb/polish/check/parsing.py index 1ffcfd68da..1ef9fef430 100644 --- a/src/calibre/ebooks/oeb/polish/check/parsing.py +++ b/src/calibre/ebooks/oeb/polish/check/parsing.py @@ -18,7 +18,7 @@ from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style as fix_style from calibre.ebooks.oeb.polish.utils import PositionFinder, guess_type from calibre.ebooks.oeb.polish.check.base import BaseError, WARN, ERROR, INFO from calibre.ebooks.oeb.base import OEB_DOCS, XHTML_NS, urlquote, URL_SAFE, XHTML -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type HTML_ENTITTIES = frozenset(html5_entities) XML_ENTITIES = {'lt', 'gt', 'amp', 'apos', 'quot'} @@ -103,7 +103,7 @@ class NamedEntities(BaseError): changed = False from calibre.ebooks.oeb.polish.check.main import XML_TYPES check_types = XML_TYPES | OEB_DOCS - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in check_types: raw = container.raw_data(name) nraw = replace_pat.sub(lambda m:html5_entities[m.group(1)], raw) @@ -496,7 +496,7 @@ valid_id = re.compile(r'^[a-zA-Z][a-zA-Z0-9_:.-]*$') def check_ids(container): errors = [] mts = set(OEB_DOCS) | {guess_type('a.opf'), guess_type('a.ncx')} - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in mts: root = container.parsed(name) seen_ids = {} @@ -511,13 +511,13 @@ def check_ids(container): seen_ids[eid] = elem.sourceline if eid and valid_id.match(eid) is None: errors.append(InvalidId(name, elem.sourceline, eid)) - errors.extend(DuplicateId(name, eid, locs) for eid, locs in dups.iteritems()) + errors.extend(DuplicateId(name, eid, locs) for eid, locs in iteritems(dups)) return errors def check_markup(container): errors = [] - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS: lines = [] root = container.parsed(name) diff --git a/src/calibre/ebooks/oeb/polish/container.py b/src/calibre/ebooks/oeb/polish/container.py index da845d971f..ba4ce390a2 100644 --- a/src/calibre/ebooks/oeb/polish/container.py +++ b/src/calibre/ebooks/oeb/polish/container.py @@ -14,7 +14,7 @@ import time import unicodedata import uuid from collections import defaultdict -from polyglot.builtins import unicode_type, zip +from polyglot.builtins import iteritems, unicode_type, zip from io import BytesIO from itertools import count @@ -311,7 +311,7 @@ class Container(ContainerBase): # {{{ 'tweak_mode': self.tweak_mode, 'name_path_map': { name:os.path.join(dest_dir, os.path.relpath(path, self.root)) - for name, path in self.name_path_map.iteritems()} + for name, path in iteritems(self.name_path_map)} } def add_name_to_manifest(self, name, process_manifest_item=None): @@ -658,7 +658,7 @@ class Container(ContainerBase): # {{{ for item in self.opf_xpath('//opf:manifest/opf:item[@href and @media-type]'): ans[item.get('media-type').lower()].append(self.href_to_name( item.get('href'), self.opf_name)) - return {mt:tuple(v) for mt, v in ans.iteritems()} + return {mt:tuple(v) for mt, v in iteritems(ans)} def manifest_items_with_property(self, property_name): ' All manifest items that have the specified property ' @@ -676,7 +676,7 @@ class Container(ContainerBase): # {{{ predicate = predicate.__eq__ elif hasattr(predicate, '__contains__'): predicate = predicate.__contains__ - for mt, names in self.manifest_type_map.iteritems(): + for mt, names in iteritems(self.manifest_type_map): if predicate(mt): for name in names: yield name @@ -798,7 +798,7 @@ class Container(ContainerBase): # {{{ the form (name, linear). Will raise an error if one of the names is not present in the manifest. ''' imap = self.manifest_id_map - imap = {name:item_id for item_id, name in imap.iteritems()} + imap = {name:item_id for item_id, name in iteritems(imap)} items = [item for item, name, linear in self.spine_iter] tail, last_tail = (items[0].tail, items[-1].tail) if items else ('\n ', '\n ') map(self.remove_from_xml, items) @@ -1062,7 +1062,7 @@ class Container(ContainerBase): # {{{ if set(self.name_path_map) != set(other.name_path_map): return 'Set of files is not the same' mismatches = [] - for name, path in self.name_path_map.iteritems(): + for name, path in iteritems(self.name_path_map): opath = other.name_path_map[name] with lopen(path, 'rb') as f1, lopen(opath, 'rb') as f2: if f1.read() != f2.read(): @@ -1266,7 +1266,7 @@ class EpubContainer(Container): return package_id = raw_unique_identifier = idpf_key = None - for attrib, val in self.opf.attrib.iteritems(): + for attrib, val in iteritems(self.opf.attrib): if attrib.endswith('unique-identifier'): package_id = val break @@ -1295,7 +1295,7 @@ class EpubContainer(Container): self.log.exception('Failed to parse obfuscation key') key = None - for font, alg in fonts.iteritems(): + for font, alg in iteritems(fonts): tkey = key if alg == ADOBE_OBFUSCATION else idpf_key if not tkey: raise ObfuscationKeyMissing('Failed to find obfuscation key') @@ -1362,7 +1362,7 @@ class EpubContainer(Container): with lopen(join(self.root, 'mimetype'), 'wb') as f: f.write(guess_type('a.epub')) zip_rebuilder(self.root, outpath) - for name, data in restore_fonts.iteritems(): + for name, data in iteritems(restore_fonts): with self.open(name, 'wb') as f: f.write(data) @@ -1530,7 +1530,7 @@ def test_roundtrip(): ebook3 = get_container(p.name) diff = ebook3.compare_to(ebook2) if diff is not None: - print (diff) + print(diff) if __name__ == '__main__': diff --git a/src/calibre/ebooks/oeb/polish/cover.py b/src/calibre/ebooks/oeb/polish/cover.py index cb83820611..941ef71d17 100644 --- a/src/calibre/ebooks/oeb/polish/cover.py +++ b/src/calibre/ebooks/oeb/polish/cover.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python2 # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai from __future__ import (unicode_literals, division, absolute_import, print_function) @@ -12,6 +11,7 @@ import shutil, re, os from calibre.ebooks.oeb.base import OPF, OEB_DOCS, XPath, XLINK, xml2text from calibre.ebooks.oeb.polish.replace import replace_links, get_recommended_folders from calibre.utils.imghdr import identify +from polyglot.builtins import iteritems def set_azw3_cover(container, cover_path, report, options=None): @@ -135,7 +135,7 @@ def find_cover_image2(container, strict=False): # First look for a guide item with type == 'cover' guide_type_map = container.guide_type_map - for ref_type, name in guide_type_map.iteritems(): + for ref_type, name in iteritems(guide_type_map): if ref_type.lower() == 'cover' and is_raster_image(mm.get(name, None)): return name @@ -144,7 +144,7 @@ def find_cover_image2(container, strict=False): # Find the largest image from all possible guide cover items largest_cover = (None, 0) - for ref_type, name in guide_type_map.iteritems(): + for ref_type, name in iteritems(guide_type_map): if ref_type.lower() in COVER_TYPES and is_raster_image(mm.get(name, None)): path = container.name_path_map.get(name, None) if path: @@ -188,7 +188,7 @@ def get_guides(container): def mark_as_cover_epub(container, name): - mmap = {v:k for k, v in container.manifest_id_map.iteritems()} + mmap = {v:k for k, v in iteritems(container.manifest_id_map)} if name not in mmap: raise ValueError('Cannot mark %s as cover as it is not in manifest' % name) mid = mmap[name] @@ -257,7 +257,7 @@ def find_cover_page(container): mm = container.mime_map if ver.major < 3: guide_type_map = container.guide_type_map - for ref_type, name in guide_type_map.iteritems(): + for ref_type, name in iteritems(guide_type_map): if ref_type.lower() == 'cover' and mm.get(name, '').lower() in OEB_DOCS: return name else: @@ -341,7 +341,7 @@ def create_epub_cover(container, cover_path, existing_image, options=None): if existing_image: raster_cover = existing_image - manifest_id = {v:k for k, v in container.manifest_id_map.iteritems()}[existing_image] + manifest_id = {v:k for k, v in iteritems(container.manifest_id_map)}[existing_image] raster_cover_item = container.opf_xpath('//opf:manifest/*[@id="%s"]' % manifest_id)[0] else: folder = recommended_folders[cname] @@ -503,9 +503,9 @@ def set_epub_cover(container, cover_path, report, options=None): report(_('Cover updated') if updated else _('Cover inserted')) # Replace links to the old cover image/cover page - link_sub = {s:d for s, d in { + link_sub = {s:d for s, d in iteritems({ cover_page:titlepage, wrapped_image:raster_cover, - cover_image:raster_cover, extra_cover_page:titlepage}.iteritems() + cover_image:raster_cover, extra_cover_page:titlepage}) if s is not None and s != d} if link_sub: replace_links(container, link_sub, frag_map=lambda x, y:None) diff --git a/src/calibre/ebooks/oeb/polish/css.py b/src/calibre/ebooks/oeb/polish/css.py index ba92f610b1..2d52bc9af4 100644 --- a/src/calibre/ebooks/oeb/polish/css.py +++ b/src/calibre/ebooks/oeb/polish/css.py @@ -18,7 +18,7 @@ from calibre.ebooks.oeb.normalize_css import normalize_filter_css, normalizers from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style, pretty_xml_tree, serialize from calibre.utils.icu import numeric_sort_key from css_selectors import Select, SelectorError -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, itervalues, unicode_type def filter_used_rules(rules, log, select): @@ -64,7 +64,7 @@ def merge_identical_selectors(sheet): for rule in sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE): selector_map[rule.selectorText].append(rule) remove = [] - for rule_group in selector_map.itervalues(): + for rule_group in itervalues(selector_map): if len(rule_group) > 1: for i in range(1, len(rule_group)): merge_declarations(rule_group[0].style, rule_group[i].style) @@ -89,23 +89,23 @@ def remove_unused_css(container, report=None, remove_unused_classes=False, merge return container.parsed(name) except TypeError: pass - sheets = {name:safe_parse(name) for name, mt in container.mime_map.iteritems() if mt in OEB_STYLES} - sheets = {k:v for k, v in sheets.iteritems() if v is not None} + sheets = {name:safe_parse(name) for name, mt in iteritems(container.mime_map) if mt in OEB_STYLES} + sheets = {k:v for k, v in iteritems(sheets) if v is not None} num_merged = 0 if merge_rules: - for name, sheet in sheets.iteritems(): + for name, sheet in iteritems(sheets): num = merge_identical_selectors(sheet) if num: container.dirty(name) num_merged += num import_map = {name:get_imported_sheets(name, container, sheets) for name in sheets} if remove_unused_classes: - class_map = {name:{icu_lower(x) for x in classes_in_rule_list(sheet.cssRules)} for name, sheet in sheets.iteritems()} - style_rules = {name:tuple(sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE)) for name, sheet in sheets.iteritems()} + class_map = {name:{icu_lower(x) for x in classes_in_rule_list(sheet.cssRules)} for name, sheet in iteritems(sheets)} + style_rules = {name:tuple(sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE)) for name, sheet in iteritems(sheets)} num_of_removed_rules = num_of_removed_classes = 0 - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt not in OEB_DOCS: continue root = container.parsed(name) @@ -162,7 +162,7 @@ def remove_unused_css(container, report=None, remove_unused_classes=False, merge num_of_removed_classes += len(original_classes) - len(classes) container.dirty(name) - for name, sheet in sheets.iteritems(): + for name, sheet in iteritems(sheets): unused_rules = style_rules[name] if unused_rules: num_of_removed_rules += len(unused_rules) @@ -226,7 +226,7 @@ def transform_css(container, transform_sheet=None, transform_style=None, names=( if not names: types = OEB_STYLES | OEB_DOCS names = [] - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in types: names.append(name) diff --git a/src/calibre/ebooks/oeb/polish/download.py b/src/calibre/ebooks/oeb/polish/download.py index 0211b0ff0d..46fc78f22c 100644 --- a/src/calibre/ebooks/oeb/polish/download.py +++ b/src/calibre/ebooks/oeb/polish/download.py @@ -23,6 +23,7 @@ from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES, barename, iterlinks from calibre.ebooks.oeb.polish.utils import guess_type from calibre.ptempfile import TemporaryDirectory from calibre.web import get_download_filename_from_response +from polyglot.builtins import iteritems from polyglot.urllib import urlopen, urlparse @@ -43,7 +44,7 @@ def iterhtmllinks(container, name): def get_external_resources(container): ans = defaultdict(list) - for name, media_type in container.mime_map.iteritems(): + for name, media_type in iteritems(container.mime_map): if container.has_name(name) and container.exists(name): if media_type in OEB_DOCS: for el, attr, link in iterhtmllinks(container, name): @@ -185,12 +186,12 @@ def replacer(url_map): def replace_resources(container, urls, replacements): url_maps = defaultdict(dict) changed = False - for url, names in urls.iteritems(): + for url, names in iteritems(urls): replacement = replacements.get(url) if replacement is not None: for name in names: url_maps[name][url] = container.name_to_href(replacement, name) - for name, url_map in url_maps.iteritems(): + for name, url_map in iteritems(url_maps): r = replacer(url_map) container.replace_links(name, r) changed |= r.replaced diff --git a/src/calibre/ebooks/oeb/polish/embed.py b/src/calibre/ebooks/oeb/polish/embed.py index ad57d3f6ed..a815940b40 100644 --- a/src/calibre/ebooks/oeb/polish/embed.py +++ b/src/calibre/ebooks/oeb/polish/embed.py @@ -15,7 +15,7 @@ from lxml import etree from calibre import prints from calibre.ebooks.oeb.base import XHTML from calibre.utils.filenames import ascii_filename -from polyglot.builtins import string_or_bytes +from polyglot.builtins import iteritems, itervalues, string_or_bytes props = {'font-family':None, 'font-weight':'normal', 'font-style':'normal', 'font-stretch':'normal'} @@ -79,7 +79,7 @@ def filter_by_stretch(fonts, val): else: candidates = expanded or condensed distance_map = {i:abs(stretch_map[i] - val) for i in candidates} - min_dist = min(distance_map.itervalues()) + min_dist = min(itervalues(distance_map)) return [fonts[i] for i in candidates if distance_map[i] == min_dist] @@ -127,7 +127,7 @@ def filter_by_weight(fonts, val): return [fonts[rmap[400]]] candidates = below or above distance_map = {i:abs(weight_map[i] - val) for i in candidates} - min_dist = min(distance_map.itervalues()) + min_dist = min(itervalues(distance_map)) return [fonts[i] for i in candidates if distance_map[i] == min_dist] @@ -154,7 +154,7 @@ def do_embed(container, font, report): with container.open(name, 'wb') as out: out.write(data) href = container.name_to_href(name) - rule = {k:font.get(k, v) for k, v in props.iteritems()} + rule = {k:font.get(k, v) for k, v in iteritems(props)} rule['src'] = 'url(%s)' % href rule['name'] = name return rule @@ -188,7 +188,7 @@ def embed_font(container, font, all_font_rules, report, warned): else: name = rule['src'] href = container.name_to_href(name) - rule = {k:ff if k == 'font-family' else rule.get(k, v) for k, v in props.iteritems()} + rule = {k:ff if k == 'font-family' else rule.get(k, v) for k, v in iteritems(props)} rule['src'] = 'url(%s)' % href rule['name'] = name return rule @@ -199,7 +199,7 @@ def font_key(font): def embed_all_fonts(container, stats, report): - all_font_rules = tuple(stats.all_font_rules.itervalues()) + all_font_rules = tuple(itervalues(stats.all_font_rules)) warned = set() rules, nrules = [], {} modified = set() @@ -212,7 +212,7 @@ def embed_all_fonts(container, stats, report): if None in (fs, fu, fr): continue fs = {icu_lower(x) for x in fs} - for font in fu.itervalues(): + for font in itervalues(fu): if icu_lower(font['font-family']) not in fs: continue rule = matching_rule(font, fr) @@ -239,7 +239,7 @@ def embed_all_fonts(container, stats, report): # Write out CSS rules = [';\n\t'.join('%s: %s' % ( - k, '"%s"' % v if k == 'font-family' else v) for k, v in rulel.iteritems() if (k in props and props[k] != v and v != '400') or k == 'src') + k, '"%s"' % v if k == 'font-family' else v) for k, v in iteritems(rulel) if (k in props and props[k] != v and v != '400') or k == 'src') for rulel in rules] css = '\n\n'.join(['@font-face {\n\t%s\n}' % r for r in rules]) item = container.generate_item('fonts.css', id_prefix='font_embed') diff --git a/src/calibre/ebooks/oeb/polish/fonts.py b/src/calibre/ebooks/oeb/polish/fonts.py index 774cbaf00b..d6e2443e4d 100644 --- a/src/calibre/ebooks/oeb/polish/fonts.py +++ b/src/calibre/ebooks/oeb/polish/fonts.py @@ -9,6 +9,7 @@ __copyright__ = '2014, Kovid Goyal ' from calibre.ebooks.oeb.polish.container import OEB_STYLES, OEB_DOCS from calibre.ebooks.oeb.normalize_css import normalize_font from tinycss.fonts3 import parse_font_family, parse_font, serialize_font_family, serialize_font +from polyglot.builtins import iteritems def unquote(x): @@ -45,7 +46,7 @@ def font_family_data_from_sheet(sheet, families): def font_family_data(container): families = {} - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_STYLES: sheet = container.parsed(name) font_family_data_from_sheet(sheet, families) @@ -128,7 +129,7 @@ def change_font(container, old_name, new_name=None): new_name to None to remove the font family instead of changing it. ''' changed = False - for name, mt in tuple(container.mime_map.iteritems()): + for name, mt in tuple(iteritems(container.mime_map)): if mt in OEB_STYLES: sheet = container.parsed(name) if change_font_in_sheet(container, sheet, old_name, new_name, name): diff --git a/src/calibre/ebooks/oeb/polish/images.py b/src/calibre/ebooks/oeb/polish/images.py index 680fb47af0..8e42466c2b 100644 --- a/src/calibre/ebooks/oeb/polish/images.py +++ b/src/calibre/ebooks/oeb/polish/images.py @@ -9,7 +9,7 @@ from functools import partial from threading import Thread, Event from calibre import detect_ncpus, human_readable, force_unicode, filesystem_encoding -from polyglot.builtins import range +from polyglot.builtins import iteritems, range from polyglot.queue import Queue, Empty @@ -93,7 +93,7 @@ def compress_images(container, report=None, names=None, jpeg_quality=None, progr queue.join() before_total = after_total = 0 changed = False - for name, (ok, res) in results.iteritems(): + for name, (ok, res) in iteritems(results): name = force_unicode(name, filesystem_encoding) if ok: before, after = res diff --git a/src/calibre/ebooks/oeb/polish/import_book.py b/src/calibre/ebooks/oeb/polish/import_book.py index 9f9cd3152d..a35b77f49f 100644 --- a/src/calibre/ebooks/oeb/polish/import_book.py +++ b/src/calibre/ebooks/oeb/polish/import_book.py @@ -14,15 +14,16 @@ from calibre.ebooks.oeb.polish.container import Container, OEB_DOCS, OEB_STYLES from calibre.ebooks.epub import initialize_container from calibre.utils.logging import default_log +from polyglot.builtins import iteritems IMPORTABLE = {'htm', 'xhtml', 'html', 'xhtm', 'docx'} def auto_fill_manifest(container): manifest_id_map = container.manifest_id_map - manifest_name_map = {v:k for k, v in manifest_id_map.iteritems()} + manifest_name_map = {v:k for k, v in iteritems(manifest_id_map)} - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if name not in manifest_name_map and not container.ok_to_be_unmanifested(name): mitem = container.generate_item(name, unique_href=False) gname = container.href_to_name(mitem.get('href'), container.opf_name) @@ -53,7 +54,7 @@ def import_book_as_epub(srcpath, destpath, log=default_log): c = Container(tdir, pathtoopf, log) auto_fill_manifest(c) # Auto fix all HTML/CSS - for name, mt in c.mime_map.iteritems(): + for name, mt in iteritems(c.mime_map): if mt in set(OEB_DOCS) | set(OEB_STYLES): c.parsed(name) c.dirty(name) @@ -64,6 +65,6 @@ def import_book_as_epub(srcpath, destpath, log=default_log): for name in c.name_path_map: zf.writestr(name, c.raw_data(name, decode=False)) + if __name__ == '__main__': import_book_as_epub(sys.argv[-2], sys.argv[-1]) - diff --git a/src/calibre/ebooks/oeb/polish/jacket.py b/src/calibre/ebooks/oeb/polish/jacket.py index ac9cd14271..6d6cce3177 100644 --- a/src/calibre/ebooks/oeb/polish/jacket.py +++ b/src/calibre/ebooks/oeb/polish/jacket.py @@ -98,7 +98,7 @@ def add_or_replace_jacket(container): if not found: # Insert new jacket into spine index = 0 - sp = container.abspath_to_name(container.spine_items.next()) + sp = container.abspath_to_name(next(container.spine_items)) if sp == find_cover_page(container): index = 1 itemref = container.opf.makeelement(OPF('itemref'), diff --git a/src/calibre/ebooks/oeb/polish/main.py b/src/calibre/ebooks/oeb/polish/main.py index af30ac1e30..655b80b24c 100644 --- a/src/calibre/ebooks/oeb/polish/main.py +++ b/src/calibre/ebooks/oeb/polish/main.py @@ -23,6 +23,7 @@ from calibre.ebooks.oeb.polish.jacket import ( replace_jacket, add_or_replace_jacket, find_existing_jacket, remove_jacket) from calibre.ebooks.oeb.polish.css import remove_unused_css from calibre.utils.logging import Log +from polyglot.builtins import iteritems, iterkeys ALL_OPTS = { 'embed': False, @@ -131,7 +132,7 @@ def hfix(name, raw): return raw -CLI_HELP = {x:hfix(x, re.sub('<.*?>', '', y)) for x, y in HELP.iteritems()} +CLI_HELP = {x:hfix(x, re.sub('<.*?>', '', y)) for x, y in iteritems(HELP)} # }}} @@ -242,7 +243,7 @@ def polish_one(ebook, opts, report, customization=None): def polish(file_map, opts, log, report): st = time.time() - for inbook, outbook in file_map.iteritems(): + for inbook, outbook in iteritems(file_map): report(_('## Polishing: %s')%(inbook.rpartition('.')[-1].upper())) ebook = get_container(inbook, log) polish_one(ebook, opts, report) @@ -263,7 +264,7 @@ def gui_polish(data): file_map = {x:x for x in files} opts = ALL_OPTS.copy() opts.update(data) - O = namedtuple('Options', ' '.join(ALL_OPTS.iterkeys())) + O = namedtuple('Options', ' '.join(iterkeys(ALL_OPTS))) opts = O(**opts) log = Log(level=Log.DEBUG) report = [] @@ -278,7 +279,7 @@ def gui_polish(data): def tweak_polish(container, actions, customization=None): opts = ALL_OPTS.copy() opts.update(actions) - O = namedtuple('Options', ' '.join(ALL_OPTS.iterkeys())) + O = namedtuple('Options', ' '.join(iterkeys(ALL_OPTS))) opts = O(**opts) report = [] changed = polish_one(container, opts, report.append, customization=customization) @@ -331,10 +332,10 @@ def main(args=None): inbook, outbook = args popts = ALL_OPTS.copy() - for k, v in popts.iteritems(): + for k, v in iteritems(popts): popts[k] = getattr(opts, k, None) - O = namedtuple('Options', ' '.join(popts.iterkeys())) + O = namedtuple('Options', ' '.join(iterkeys(popts))) popts = O(**popts) report = [] if not tuple(filter(None, (getattr(popts, name) for name in ALL_OPTS))): diff --git a/src/calibre/ebooks/oeb/polish/pretty.py b/src/calibre/ebooks/oeb/polish/pretty.py index b5423b251a..5d90fae260 100644 --- a/src/calibre/ebooks/oeb/polish/pretty.py +++ b/src/calibre/ebooks/oeb/polish/pretty.py @@ -7,7 +7,7 @@ __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal ' import textwrap -from polyglot.builtins import map +from polyglot.builtins import iteritems, map # from lxml.etree import Element @@ -224,7 +224,7 @@ def pretty_xml(container, name, raw): def fix_all_html(container): ' Fix any parsing errors in all HTML files in the container. Fixing is done using the HTML5 parsing algorithm. ' - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS: container.parsed(name) container.dirty(name) @@ -233,7 +233,7 @@ def fix_all_html(container): def pretty_all(container): ' Pretty print all HTML/CSS/XML files in the container ' xml_types = {guess_type('a.ncx'), guess_type('a.xml'), guess_type('a.svg')} - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): prettied = False if mt in OEB_DOCS: pretty_html_tree(container, container.parsed(name)) diff --git a/src/calibre/ebooks/oeb/polish/replace.py b/src/calibre/ebooks/oeb/polish/replace.py index a04623404c..4fc7f372f7 100644 --- a/src/calibre/ebooks/oeb/polish/replace.py +++ b/src/calibre/ebooks/oeb/polish/replace.py @@ -8,7 +8,7 @@ __copyright__ = '2013, Kovid Goyal ' __docformat__ = 'restructuredtext en' import codecs, shutil, os, posixpath -from polyglot.builtins import map +from polyglot.builtins import iteritems, itervalues, map from functools import partial from collections import Counter, defaultdict @@ -118,7 +118,7 @@ def replace_links(container, link_map, frag_map=lambda name, frag:frag, replace_ :param replace_in_opf: If False, links are not replaced in the OPF file. ''' - for name, media_type in container.mime_map.iteritems(): + for name, media_type in iteritems(container.mime_map): if name == container.opf_name and not replace_in_opf: continue repl = LinkReplacer(name, container, link_map, frag_map) @@ -134,7 +134,7 @@ def replace_ids(container, id_map): ''' changed = False - for name, media_type in container.mime_map.iteritems(): + for name, media_type in iteritems(container.mime_map): repl = IdReplacer(name, container, id_map) container.replace_links(name, repl) if name == container.opf_name: @@ -186,19 +186,19 @@ def rename_files(container, file_map): :param file_map: A mapping of old canonical name to new canonical name, for example: :code:`{'text/chapter1.html': 'chapter1.html'}`. ''' - overlap = set(file_map).intersection(set(file_map.itervalues())) + overlap = set(file_map).intersection(set(itervalues(file_map))) if overlap: raise ValueError('Circular rename detected. The files %s are both rename targets and destinations' % ', '.join(overlap)) - for name, dest in file_map.iteritems(): + for name, dest in iteritems(file_map): if container.exists(dest): if name != dest and name.lower() == dest.lower(): # A case change on an OS with a case insensitive file-system. continue raise ValueError('Cannot rename {0} to {1} as {1} already exists'.format(name, dest)) - if len(tuple(file_map.itervalues())) != len(set(file_map.itervalues())): + if len(tuple(itervalues(file_map))) != len(set(itervalues(file_map))): raise ValueError('Cannot rename, the set of destination files contains duplicates') link_map = {} - for current_name, new_name in file_map.iteritems(): + for current_name, new_name in iteritems(file_map): container.rename(current_name, new_name) if new_name != container.opf_name: # OPF is handled by the container link_map[current_name] = new_name @@ -220,7 +220,7 @@ def replace_file(container, name, path, basename, force_mt=None): rename_files(container, {name:nname}) mt = force_mt or container.guess_type(nname) container.mime_map[nname] = mt - for itemid, q in container.manifest_id_map.iteritems(): + for itemid, q in iteritems(container.manifest_id_map): if q == nname: for item in container.opf_xpath('//opf:manifest/opf:item[@href and @id="%s"]' % itemid): item.set('media-type', mt) @@ -255,7 +255,7 @@ def get_recommended_folders(container, names): recommended folder is assumed to be the folder containing the OPF file. ''' from calibre.ebooks.oeb.polish.utils import guess_type counts = defaultdict(Counter) - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): folder = name.rpartition('/')[0] if '/' in name else '' counts[mt_to_category(container, mt)][folder] += 1 @@ -264,7 +264,7 @@ def get_recommended_folders(container, names): except KeyError: opf_folder = '' - recommendations = {category:counter.most_common(1)[0][0] for category, counter in counts.iteritems()} + recommendations = {category:counter.most_common(1)[0][0] for category, counter in iteritems(counts)} return {n:recommendations.get(mt_to_category(container, guess_type(os.path.basename(n))), opf_folder) for n in names} @@ -351,7 +351,7 @@ def remove_links_to(container, predicate): stylepath = XPath('//h:style') styleattrpath = XPath('//*[@style]') changed = set() - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): removed = False if mt in OEB_DOCS: root = container.parsed(name) diff --git a/src/calibre/ebooks/oeb/polish/report.py b/src/calibre/ebooks/oeb/polish/report.py index 4a954ae660..57beaf7d73 100644 --- a/src/calibre/ebooks/oeb/polish/report.py +++ b/src/calibre/ebooks/oeb/polish/report.py @@ -17,6 +17,7 @@ from calibre.ebooks.oeb.polish.spell import get_all_words, count_all_chars from calibre.utils.icu import numeric_sort_key, safe_chr from calibre.utils.imghdr import identify from css_selectors import Select, SelectorError +from polyglot.builtins import iteritems File = namedtuple('File', 'name dir basename size category') @@ -60,7 +61,7 @@ def safe_img_data(container, name, mt): def files_data(container, *args): - for name, path in container.name_path_map.iteritems(): + for name, path in iteritems(container.name_path_map): yield File(name, posixpath.dirname(name), posixpath.basename(name), safe_size(container, name), get_category(name, container.mime_map.get(name, ''))) @@ -88,7 +89,7 @@ def safe_href_to_name(container, href, base): def images_data(container, *args): image_usage = defaultdict(set) link_sources = OEB_STYLES | OEB_DOCS - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in link_sources: for href, line_number, offset in container.iterlinks(name): target = safe_href_to_name(container, href, name) @@ -98,7 +99,7 @@ def images_data(container, *args): image_usage[target].add(LinkLocation(name, line_number, href)) image_data = [] - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt.startswith('image/') and container.exists(name): image_data.append(Image(name, mt, sort_locations(container, image_usage.get(name, set())), safe_size(container, name), posixpath.basename(name), len(image_data), *safe_img_data(container, name, mt))) @@ -158,7 +159,7 @@ def links_data(container, *args): links = [] anchor_pat = XPath('//*[@id or @name]') link_pat = XPath('//h:a[@href]') - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS: root = container.parsed(name) anchor_map[name] = create_anchor_map(root, anchor_pat, name) @@ -200,7 +201,7 @@ Word = namedtuple('Word', 'id word locale usage') def words_data(container, book_locale, *args): count, words = get_all_words(container, book_locale, get_word_count=True) - return (count, tuple(Word(i, word, locale, v) for i, ((word, locale), v) in enumerate(words.iteritems()))) + return (count, tuple(Word(i, word, locale, v) for i, ((word, locale), v) in enumerate(iteritems(words)))) Char = namedtuple('Char', 'id char codepoint usage count') @@ -213,7 +214,7 @@ def chars_data(container, book_locale, *args): def sort_key(name): return nmap.get(name, len(nmap)), numeric_sort_key(name) - for i, (codepoint, usage) in enumerate(cc.chars.iteritems()): + for i, (codepoint, usage) in enumerate(iteritems(cc.chars)): yield Char(i, safe_chr(codepoint), codepoint, sorted(usage, key=sort_key), cc.counter[codepoint]) @@ -252,7 +253,7 @@ def css_data(container, book_locale, result_data, *args): spine_names = {name for name, is_linear in container.spine_names} style_path, link_path = XPath('//h:style'), XPath('//h:link/@href') - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_STYLES: importable_sheets[name] = css_rules(name, parser.parse_stylesheet(container.raw_data(name)).rules) elif mt in OEB_DOCS and name in spine_names: @@ -307,7 +308,7 @@ def css_data(container, book_locale, result_data, *args): class_map = defaultdict(lambda : defaultdict(list)) - for name, inline_sheets in html_sheets.iteritems(): + for name, inline_sheets in iteritems(html_sheets): root = container.parsed(name) cmap = defaultdict(lambda : defaultdict(list)) for elem in root.xpath('//*[@class]'): @@ -317,21 +318,21 @@ def css_data(container, book_locale, result_data, *args): for sheet in chain(sheets_for_html(name, root), inline_sheets): for rule in rules_in_sheet(sheet): rule_map[rule][name].extend(matches_for_selector(rule.selector, select, cmap, rule)) - for cls, elem_map in cmap.iteritems(): + for cls, elem_map in iteritems(cmap): class_elements = class_map[cls][name] - for elem, usage in elem_map.iteritems(): + for elem, usage in iteritems(elem_map): class_elements.append( ClassElement(name, elem.sourceline, elem.get('class'), tag_text(elem), tuple(usage))) result_data['classes'] = ans = [] - for cls, name_map in class_map.iteritems(): - la = tuple(ClassFileMatch(name, tuple(class_elements), numeric_sort_key(name)) for name, class_elements in name_map.iteritems() if class_elements) + for cls, name_map in iteritems(class_map): + la = tuple(ClassFileMatch(name, tuple(class_elements), numeric_sort_key(name)) for name, class_elements in iteritems(name_map) if class_elements) num_of_matches = sum(sum(len(ce.matched_rules) for ce in cfm.class_elements) for cfm in la) ans.append(ClassEntry(cls, num_of_matches, la, numeric_sort_key(cls))) ans = [] - for rule, loc_map in rule_map.iteritems(): - la = tuple(CSSFileMatch(name, tuple(locations), numeric_sort_key(name)) for name, locations in loc_map.iteritems() if locations) + for rule, loc_map in iteritems(rule_map): + la = tuple(CSSFileMatch(name, tuple(locations), numeric_sort_key(name)) for name, locations in iteritems(loc_map) if locations) count = sum(len(fm.locations) for fm in la) ans.append(CSSEntry(rule, count, la, numeric_sort_key(rule.selector))) diff --git a/src/calibre/ebooks/oeb/polish/spell.py b/src/calibre/ebooks/oeb/polish/spell.py index 4c9864fb2f..6d7fc5c53f 100644 --- a/src/calibre/ebooks/oeb/polish/spell.py +++ b/src/calibre/ebooks/oeb/polish/spell.py @@ -17,7 +17,7 @@ from calibre.ebooks.oeb.polish.container import OPF_NAMESPACES, get_container from calibre.ebooks.oeb.polish.parsing import parse from calibre.ebooks.oeb.polish.toc import find_existing_ncx_toc, find_existing_nav_toc from calibre.utils.icu import ord_string -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type _patterns = None @@ -144,7 +144,7 @@ def add_words_from_escaped_html(text, words, file_name, node, attr, locale): ewords[None] = 0 read_words_from_html(root, ewords, file_name, locale) words[None] += ewords.pop(None) - for k, locs in ewords.iteritems(): + for k, locs in iteritems(ewords): for loc in locs: loc.location_node, loc.node_item = node, (False, attr) words[k].extend(locs) @@ -287,7 +287,7 @@ def get_all_words(container, book_locale, get_word_count=False): elif hasattr(root, 'xpath'): read_words_from_html(root, words, file_name, book_locale) count = words.pop(None) - ans = {k:group_sort(v) for k, v in words.iteritems()} + ans = {k:group_sort(v) for k, v in iteritems(words)} if get_word_count: return count, ans return ans @@ -355,7 +355,7 @@ def replace_word(container, new_word, locations, locale, undo_cache=None): def undo_replace_word(container, undo_cache): changed = set() - for (file_name, node, is_attr, attr), text in undo_cache.iteritems(): + for (file_name, node, is_attr, attr), text in iteritems(undo_cache): node.set(attr, text) if is_attr else setattr(node, attr, text) container.replace(file_name, node.getroottree().getroot()) changed.add(file_name) diff --git a/src/calibre/ebooks/oeb/polish/split.py b/src/calibre/ebooks/oeb/polish/split.py index f06e32c37d..816ded8ba3 100644 --- a/src/calibre/ebooks/oeb/polish/split.py +++ b/src/calibre/ebooks/oeb/polish/split.py @@ -13,6 +13,7 @@ from calibre.ebooks.oeb.base import barename, XPNSMAP, XPath, OPF, XHTML, OEB_DO from calibre.ebooks.oeb.polish.errors import MalformedMarkup from calibre.ebooks.oeb.polish.toc import node_from_loc from calibre.ebooks.oeb.polish.replace import LinkRebaser +from polyglot.builtins import iteritems from polyglot.urllib import urlparse @@ -241,7 +242,7 @@ def split(container, name, loc_or_xpath, before=True, totals=None): a.set('href', '#' + purl.fragment) # Fix all links in the container that point to anchors in the bottom tree - for fname, media_type in container.mime_map.iteritems(): + for fname, media_type in iteritems(container.mime_map): if fname not in {name, bottom_name}: repl = SplitLinkReplacer(fname, anchors_in_bottom, name, bottom_name, container) container.replace_links(fname, repl) @@ -437,7 +438,7 @@ def merge_html(container, names, master): container.remove_item(name, remove_from_guide=False) # Fix all links in the container that point to merged files - for fname, media_type in container.mime_map.iteritems(): + for fname, media_type in iteritems(container.mime_map): repl = MergeLinkReplacer(fname, anchor_map, master, container) container.replace_links(fname, repl) @@ -468,7 +469,7 @@ def merge_css(container, names, master): # Remove links to merged stylesheets in the html files, replacing with a # link to the master sheet - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_DOCS: removed = False root = p(name) diff --git a/src/calibre/ebooks/oeb/polish/stats.py b/src/calibre/ebooks/oeb/polish/stats.py index 45223bc317..4adfc4c3e9 100644 --- a/src/calibre/ebooks/oeb/polish/stats.py +++ b/src/calibre/ebooks/oeb/polish/stats.py @@ -18,7 +18,7 @@ from calibre.ebooks.oeb.polish.cascade import iterrules, resolve_styles, iterdec from calibre.utils.icu import ord_string, safe_chr from polyglot.builtins import unicode_type from tinycss.fonts3 import parse_font_family -from polyglot.builtins import range +from polyglot.builtins import iteritems, itervalues, range def normalize_font_properties(font): @@ -236,7 +236,7 @@ class StatsCollector(object): return ff = [icu_lower(x) for x in font.get('font-family', ())] if ff and ff[0] not in bad_fonts: - key = frozenset(((k, ff[0] if k == 'font-family' else v) for k, v in font.iteritems() if k in font_keys)) + key = frozenset(((k, ff[0] if k == 'font-family' else v) for k, v in iteritems(font) if k in font_keys)) val = font_usage_map.get(key) if val is None: val = font_usage_map[key] = {'text': set()} @@ -301,9 +301,9 @@ class StatsCollector(object): self.font_usage_map[name] = {} self.font_spec_map[name] = set() self.get_font_usage(container, name, resolve_property, resolve_pseudo_property, font_face_rules, do_embed) - self.font_stats = {k:{safe_chr(x) for x in v} for k, v in self.font_stats.iteritems()} - for fum in self.font_usage_map.itervalues(): - for v in fum.itervalues(): + self.font_stats = {k:{safe_chr(x) for x in v} for k, v in iteritems(self.font_stats)} + for fum in itervalues(self.font_usage_map): + for v in itervalues(fum): v['text'] = {safe_chr(x) for x in v['text']} diff --git a/src/calibre/ebooks/oeb/polish/subset.py b/src/calibre/ebooks/oeb/polish/subset.py index 888e6d169c..2fddc9084b 100644 --- a/src/calibre/ebooks/oeb/polish/subset.py +++ b/src/calibre/ebooks/oeb/polish/subset.py @@ -16,6 +16,7 @@ from calibre.ebooks.oeb.polish.utils import guess_type from calibre.utils.fonts.sfnt.subset import subset from calibre.utils.fonts.sfnt.errors import UnsupportedFont from calibre.utils.fonts.utils import get_font_names +from polyglot.builtins import iteritems, itervalues def remove_font_face_rules(container, sheet, remove_names, base): @@ -35,7 +36,7 @@ def remove_font_face_rules(container, sheet, remove_names, base): def iter_subsettable_fonts(container): - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if (mt in OEB_FONTS or name.rpartition('.')[-1].lower() in {'otf', 'ttf'}) and mt != guess_type('a.woff'): yield name, mt @@ -75,8 +76,8 @@ def subset_all_fonts(container, font_stats, report): for w in warnings: container.log.warn(w) - olen = sum(old_sizes.itervalues()) - nlen = sum(new_sizes.itervalues()) + olen = sum(itervalues(old_sizes)) + nlen = sum(itervalues(new_sizes)) total_new += len(nraw) if nlen == olen: report(_('The font %s was already subset')%font_name) @@ -91,7 +92,7 @@ def subset_all_fonts(container, font_stats, report): changed = True if remove: - for name, mt in container.mime_map.iteritems(): + for name, mt in iteritems(container.mime_map): if mt in OEB_STYLES: sheet = container.parsed(name) if remove_font_face_rules(container, sheet, remove, name): diff --git a/src/calibre/ebooks/oeb/polish/tests/base.py b/src/calibre/ebooks/oeb/polish/tests/base.py index 41c0f013f6..b461a1771d 100644 --- a/src/calibre/ebooks/oeb/polish/tests/base.py +++ b/src/calibre/ebooks/oeb/polish/tests/base.py @@ -13,6 +13,7 @@ from calibre.ptempfile import TemporaryDirectory from calibre.ptempfile import PersistentTemporaryDirectory from calibre.utils.logging import DevNull import calibre.ebooks.oeb.polish.container as pc +from polyglot.builtins import iteritems def get_cache(): @@ -42,7 +43,7 @@ def build_book(src, dest, args=()): def add_resources(raw, rmap): - for placeholder, path in rmap.iteritems(): + for placeholder, path in iteritems(rmap): fname = os.path.basename(path) shutil.copy2(path, '.') raw = raw.replace(placeholder, fname) @@ -88,6 +89,7 @@ def get_split_book(fmt='epub'): os.remove(x) return ans + devnull = DevNull() @@ -110,4 +112,3 @@ class BaseTest(unittest.TestCase): dest = container.href_to_name(link, name) if dest: self.assertTrue(container.exists(dest), 'The link %s in %s does not exist' % (link, name)) - diff --git a/src/calibre/ebooks/oeb/polish/tests/cascade.py b/src/calibre/ebooks/oeb/polish/tests/cascade.py index 35a89bc580..be116a8d72 100644 --- a/src/calibre/ebooks/oeb/polish/tests/cascade.py +++ b/src/calibre/ebooks/oeb/polish/tests/cascade.py @@ -19,6 +19,7 @@ from calibre.ebooks.oeb.polish.container import ContainerBase, href_to_name from calibre.ebooks.oeb.polish.stats import StatsCollector, font_keys, normalize_font_properties, prepare_font_rule from calibre.ebooks.oeb.polish.tests.base import BaseTest from calibre.utils.logging import Log, Stream +from polyglot.builtins import iteritems class VirtualContainer(ContainerBase): @@ -155,7 +156,7 @@ class CascadeTest(BaseTest): files = {'index.html':html, 'X.otf':b'xxx', 'XB.otf': b'xbxb'} for font in fonts: styles.append('@font-face {') - for k, v in font.iteritems(): + for k, v in iteritems(font): if k == 'src': files[v] = b'xxx' v = 'url(%s)' % v @@ -186,7 +187,7 @@ class CascadeTest(BaseTest): def fkey(*args, **kw): f = font(*args, **kw) f['font-family'] = icu_lower(f['font-family'][0]) - return frozenset((k, v) for k, v in f.iteritems() if k in font_keys) + return frozenset((k, v) for k, v in iteritems(f) if k in font_keys) def fu(text, *args, **kw): key = fkey(*args, **kw) diff --git a/src/calibre/ebooks/oeb/polish/tests/container.py b/src/calibre/ebooks/oeb/polish/tests/container.py index deac24bb78..e438bd9a19 100644 --- a/src/calibre/ebooks/oeb/polish/tests/container.py +++ b/src/calibre/ebooks/oeb/polish/tests/container.py @@ -16,6 +16,7 @@ from calibre.ebooks.oeb.polish.replace import rename_files, rationalize_folders from calibre.ebooks.oeb.polish.split import split, merge from calibre.utils.filenames import nlinks_file from calibre.ptempfile import TemporaryFile, TemporaryDirectory +from polyglot.builtins import iteritems, itervalues def get_container(*args, **kwargs): @@ -38,7 +39,7 @@ class ContainerTests(BaseTest): c2 = clone_container(c1, tdir) for c in (c1, c2): - for name, path in c.name_path_map.iteritems(): + for name, path in iteritems(c.name_path_map): self.assertEqual(2, nlinks_file(path), 'The file %s is not linked' % name) for name in c1.name_path_map: @@ -178,13 +179,13 @@ class ContainerTests(BaseTest): name = 'folder/added file.html' c.add_file(name, b'xxx') self.assertEqual('xxx', c.raw_data(name)) - self.assertIn(name, set(c.manifest_id_map.itervalues())) + self.assertIn(name, set(itervalues(c.manifest_id_map))) self.assertIn(name, {x[0] for x in c.spine_names}) name = 'added.css' c.add_file(name, b'xxx') self.assertEqual('xxx', c.raw_data(name)) - self.assertIn(name, set(c.manifest_id_map.itervalues())) + self.assertIn(name, set(itervalues(c.manifest_id_map))) self.assertNotIn(name, {x[0] for x in c.spine_names}) self.assertEqual(c.make_name_unique(name), 'added-1.css') c.add_file('added-1.css', b'xxx') diff --git a/src/calibre/ebooks/oeb/polish/tests/parsing.py b/src/calibre/ebooks/oeb/polish/tests/parsing.py index 5987821a28..c60bfa1f42 100644 --- a/src/calibre/ebooks/oeb/polish/tests/parsing.py +++ b/src/calibre/ebooks/oeb/polish/tests/parsing.py @@ -15,7 +15,7 @@ from calibre.ebooks.oeb.polish.tests.base import BaseTest from calibre.ebooks.oeb.polish.parsing import parse_html5 as parse from calibre.ebooks.oeb.base import XPath, XHTML_NS, SVG_NS, XLINK_NS from calibre.ebooks.oeb.parse_utils import html5_parse -from polyglot.builtins import range +from polyglot.builtins import iteritems, range def nonvoid_cdata_elements(test, parse_function): @@ -185,7 +185,7 @@ class ParsingTests(BaseTest): for ds in (False, True): src = '\n\n

\n\n ' root = parse(src, discard_namespaces=ds) - for tag, lnum in {'html':2, 'head':3, 'body':3, 'p':3, 'svg':4, 'image':4, 'b':5}.iteritems(): + for tag, lnum in iteritems({'html':2, 'head':3, 'body':3, 'p':3, 'svg':4, 'image':4, 'b':5}): elem = root.xpath('//*[local-name()="%s"]' % tag)[0] self.assertEqual(lnum, elem.sourceline, 'Line number incorrect for %s, source: %s:' % (tag, src)) @@ -220,4 +220,4 @@ def timing(): f(raw) timings.append(monotonic() - st) avg = sum(timings)/len(timings) - print ('Average time for %s: %.2g' % (name, avg)) + print('Average time for %s: %.2g' % (name, avg)) diff --git a/src/calibre/ebooks/oeb/polish/toc.py b/src/calibre/ebooks/oeb/polish/toc.py index bcf274cf03..46b77329d2 100644 --- a/src/calibre/ebooks/oeb/polish/toc.py +++ b/src/calibre/ebooks/oeb/polish/toc.py @@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en' import re from collections import Counter, OrderedDict from functools import partial -from polyglot.builtins import map, unicode_type +from polyglot.builtins import iteritems, map, unicode_type from operator import itemgetter from lxml import etree @@ -168,7 +168,7 @@ def parse_ncx(container, ncx_name): if navmaps: process_ncx_node(container, navmaps[0], toc_root, ncx_name) toc_root.lang = toc_root.uid = None - for attr, val in root.attrib.iteritems(): + for attr, val in iteritems(root.attrib): if attr.endswith('lang'): toc_root.lang = unicode_type(val) break @@ -415,14 +415,14 @@ def from_xpaths(container, xpaths): name = container.abspath_to_name(spinepath) root = container.parsed(name) level_item_map = maps[name] = {i+1:frozenset(xp(root)) for i, xp in enumerate(xpaths)} - for lvl, elems in level_item_map.iteritems(): + for lvl, elems in iteritems(level_item_map): if elems: empty_levels.discard(lvl) # Remove empty levels from all level_maps if empty_levels: - for name, lmap in tuple(maps.iteritems()): - lmap = {lvl:items for lvl, items in lmap.iteritems() if lvl not in empty_levels} - lmap = sorted(lmap.iteritems(), key=itemgetter(0)) + for name, lmap in tuple(iteritems(maps)): + lmap = {lvl:items for lvl, items in iteritems(lmap) if lvl not in empty_levels} + lmap = sorted(iteritems(lmap), key=itemgetter(0)) lmap = {i+1:items for i, (l, items) in enumerate(lmap)} maps[name] = lmap @@ -440,9 +440,9 @@ def from_xpaths(container, xpaths): return process_node(tocroot) - for name, level_item_map in maps.iteritems(): + for name, level_item_map in iteritems(maps): root = container.parsed(name) - item_level_map = {e:i for i, elems in level_item_map.iteritems() for e in elems} + item_level_map = {e:i for i, elems in iteritems(level_item_map) for e in elems} item_dirtied = False all_ids = set(root.xpath('//*/@id')) diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index 3c6d71c1ae..4e496a7b49 100644 --- a/src/calibre/ebooks/oeb/stylizer.py +++ b/src/calibre/ebooks/oeb/stylizer.py @@ -20,7 +20,7 @@ from calibre.ebooks import unit_convert from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES, xpath, urlnormalize from calibre.ebooks.oeb.normalize_css import DEFAULTS, normalizers from css_selectors import Select, SelectorError, INAPPROPRIATE_PSEUDO_CLASSES -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type from tinycss.media3 import CSSMedia3Parser css_parser_log.setLevel(logging.WARN) @@ -753,7 +753,7 @@ class Style(object): self._get('padding-right'), base=self.parent_width) def __str__(self): - items = sorted(self._style.iteritems()) + items = sorted(iteritems(self._style)) return '; '.join("%s: %s" % (key, val) for key, val in items) def cssdict(self): @@ -762,12 +762,12 @@ class Style(object): def pseudo_classes(self, filter_css): if filter_css: css = copy.deepcopy(self._pseudo_classes) - for psel, cssdict in css.iteritems(): + for psel, cssdict in iteritems(css): for k in filter_css: cssdict.pop(k, None) else: css = self._pseudo_classes - return {k:v for k, v in css.iteritems() if v} + return {k:v for k, v in iteritems(css) if v} @property def is_hidden(self): diff --git a/src/calibre/ebooks/oeb/transforms/embed_fonts.py b/src/calibre/ebooks/oeb/transforms/embed_fonts.py index 9e669bc113..aa04c7ba62 100644 --- a/src/calibre/ebooks/oeb/transforms/embed_fonts.py +++ b/src/calibre/ebooks/oeb/transforms/embed_fonts.py @@ -18,7 +18,7 @@ from calibre.ebooks.oeb.transforms.subset import get_font_properties, find_font_ from calibre.utils.filenames import ascii_filename from calibre.utils.fonts.scanner import font_scanner, NoFonts from calibre.ebooks.oeb.polish.embed import font_key -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type def font_families_from_style(style): @@ -138,7 +138,7 @@ class EmbedFonts(object): if rule.type != rule.STYLE_RULE: continue props = {k:v for k,v in - get_font_properties(rule).iteritems() if v} + iteritems(get_font_properties(rule)) if v} if not props: continue for sel in rule.selectorList: diff --git a/src/calibre/ebooks/oeb/transforms/flatcss.py b/src/calibre/ebooks/oeb/transforms/flatcss.py index 14826539fe..a4efb4c9ac 100644 --- a/src/calibre/ebooks/oeb/transforms/flatcss.py +++ b/src/calibre/ebooks/oeb/transforms/flatcss.py @@ -21,7 +21,7 @@ from calibre.ebooks.oeb.base import (XHTML, XHTML_NS, CSS_MIME, OEB_STYLES, from calibre.ebooks.oeb.stylizer import Stylizer from calibre.utils.filenames import ascii_filename, ascii_text from calibre.utils.icu import numeric_sort_key -from polyglot.builtins import unicode_type, string_or_bytes +from polyglot.builtins import iteritems, iterkeys, unicode_type, string_or_bytes COLLAPSE = re.compile(r'[ \t\r\n\v]+') STRIPNUM = re.compile(r'[-0-9]+$') @@ -224,7 +224,7 @@ class CSSFlattener(object): def store_page_margins(self): self.opts._stored_page_margins = {} - for item, stylizer in self.stylizers.iteritems(): + for item, stylizer in iteritems(self.stylizers): margins = self.opts._stored_page_margins[item.href] = {} for prop, val in stylizer.page_rule.items(): p, w = prop.partition('-')[::2] @@ -278,7 +278,7 @@ class CSSFlattener(object): if font[k] != u'normal': cfont[k] = font[k] rule = '@font-face { %s }'%('; '.join(u'%s:%s'%(k, v) for k, v in - cfont.iteritems())) + iteritems(cfont))) rule = css_parser.parseString(rule) efi.append(rule) @@ -335,7 +335,7 @@ class CSSFlattener(object): fsize = self.context.source.fbase self.baseline_node(body, stylizer, sizes, fsize) try: - sbase = max(sizes.items(), key=operator.itemgetter(1))[0] + sbase = max(list(sizes.items()), key=operator.itemgetter(1))[0] except: sbase = 12.0 self.oeb.logger.info( @@ -538,7 +538,7 @@ class CSSFlattener(object): keep_classes = set() if cssdict: - items = sorted(cssdict.iteritems()) + items = sorted(iteritems(cssdict)) css = u';\n'.join(u'%s: %s' % (key, val) for key, val in items) classes = node.get('class', '').strip() or 'calibre' # lower() because otherwise if the document uses the same class @@ -554,8 +554,8 @@ class CSSFlattener(object): node.attrib['class'] = match keep_classes.add(match) - for psel, cssdict in pseudo_classes.iteritems(): - items = sorted(cssdict.iteritems()) + for psel, cssdict in iteritems(pseudo_classes): + items = sorted(iteritems(cssdict)) css = u';\n'.join(u'%s: %s' % (key, val) for key, val in items) pstyles = pseudo_styles[psel] if css in pstyles: @@ -656,7 +656,7 @@ class CSSFlattener(object): gc_map[css] = href ans = {} - for css, items in global_css.iteritems(): + for css, items in iteritems(global_css): for item in items: ans[item] = gc_map[css] return ans @@ -672,15 +672,15 @@ class CSSFlattener(object): body = html.find(XHTML('body')) fsize = self.context.dest.fbase self.flatten_node(body, stylizer, names, styles, pseudo_styles, fsize, item.id) - items = sorted(((key, val) for (val, key) in styles.iteritems()), key=lambda x:numeric_sort_key(x[0])) + items = sorted(((key, val) for (val, key) in iteritems(styles)), key=lambda x:numeric_sort_key(x[0])) # :hover must come after link and :active must come after :hover - psels = sorted(pseudo_styles.iterkeys(), key=lambda x : + psels = sorted(iterkeys(pseudo_styles), key=lambda x : {'hover':1, 'active':2}.get(x, 0)) for psel in psels: styles = pseudo_styles[psel] if not styles: continue - x = sorted(((k+':'+psel, v) for v, k in styles.iteritems())) + x = sorted(((k+':'+psel, v) for v, k in iteritems(styles))) items.extend(x) css = ''.join(".%s {\n%s;\n}\n\n" % (key, val) for key, val in items) diff --git a/src/calibre/ebooks/oeb/transforms/metadata.py b/src/calibre/ebooks/oeb/transforms/metadata.py index a405bd8991..e6b03f78cd 100644 --- a/src/calibre/ebooks/oeb/transforms/metadata.py +++ b/src/calibre/ebooks/oeb/transforms/metadata.py @@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en' import os, re from calibre.utils.date import isoformat, now from calibre import guess_type -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type def meta_info_to_oeb_metadata(mi, m, log, override_input_metadata=False): @@ -51,7 +51,7 @@ def meta_info_to_oeb_metadata(mi, m, log, override_input_metadata=False): m.clear('series') identifiers = mi.get_identifiers() set_isbn = False - for typ, val in identifiers.iteritems(): + for typ, val in iteritems(identifiers): has = False if typ.lower() == 'isbn': set_isbn = True diff --git a/src/calibre/ebooks/oeb/transforms/page_margin.py b/src/calibre/ebooks/oeb/transforms/page_margin.py index f56c97c155..f7fe1a0d02 100644 --- a/src/calibre/ebooks/oeb/transforms/page_margin.py +++ b/src/calibre/ebooks/oeb/transforms/page_margin.py @@ -11,6 +11,7 @@ import numbers from collections import Counter from calibre.ebooks.oeb.base import barename, XPath +from polyglot.builtins import iteritems class RemoveAdobeMargins(object): @@ -152,7 +153,7 @@ class RemoveFakeMargins(object): self.levels[level].append(p) remove = set() - for k, v in self.levels.iteritems(): + for k, v in iteritems(self.levels): num = len(v) self.log.debug('Found %d items of level:'%num, k) level = int(k.split('_')[-1]) diff --git a/src/calibre/ebooks/oeb/transforms/split.py b/src/calibre/ebooks/oeb/transforms/split.py index 0c4f6c9ae3..65fdb91698 100644 --- a/src/calibre/ebooks/oeb/transforms/split.py +++ b/src/calibre/ebooks/oeb/transforms/split.py @@ -20,7 +20,7 @@ from calibre.ebooks.epub import rules from calibre.ebooks.oeb.base import (OEB_STYLES, XPNSMAP as NAMESPACES, urldefrag, rewrite_links, urlunquote, XHTML, urlnormalize) from calibre.ebooks.oeb.polish.split import do_split -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range from css_selectors import Select, SelectorError XPath = functools.partial(_XPath, namespaces=NAMESPACES) @@ -243,7 +243,7 @@ class FlowSplitter(object): self.trees = [orig_tree] while ordered_ids: - pb_id, (pattern, before) = ordered_ids.iteritems().next() + pb_id, (pattern, before) = next(iteritems(ordered_ids)) del ordered_ids[pb_id] for i in range(len(self.trees)-1, -1, -1): tree = self.trees[i] diff --git a/src/calibre/ebooks/oeb/transforms/structure.py b/src/calibre/ebooks/oeb/transforms/structure.py index 7d11f887b1..31c95c8aa1 100644 --- a/src/calibre/ebooks/oeb/transforms/structure.py +++ b/src/calibre/ebooks/oeb/transforms/structure.py @@ -13,7 +13,7 @@ from collections import OrderedDict, Counter from calibre.ebooks.oeb.base import XPNSMAP, TOC, XHTML, xml2text, barename from calibre.ebooks import ConversionError -from polyglot.builtins import unicode_type +from polyglot.builtins import itervalues, unicode_type from polyglot.urllib import urlparse @@ -85,8 +85,8 @@ class DetectStructure(object): for item in oeb.spine: for elem in pb_xpath(item.data): try: - prev = elem.itersiblings(tag=etree.Element, - preceding=True).next() + prev = next(elem.itersiblings(tag=etree.Element, + preceding=True)) if (barename(elem.tag) in {'h1', 'h2'} and barename( prev.tag) in {'h1', 'h2'} and (not prev.tail or not prev.tail.split())): @@ -271,8 +271,8 @@ class DetectStructure(object): return [] for document in self.oeb.spine: - previous_level1 = list(added.itervalues())[-1] if added else None - previous_level2 = list(added2.itervalues())[-1] if added2 else None + previous_level1 = list(itervalues(added))[-1] if added else None + previous_level2 = list(itervalues(added2))[-1] if added2 else None level1_toc, level1_title = self.get_toc_parts_for_xpath(self.opts.level1_toc) for elem in find_matches(level1_toc, document.data): diff --git a/src/calibre/ebooks/oeb/transforms/subset.py b/src/calibre/ebooks/oeb/transforms/subset.py index 91bb5dde52..4e116ab4d4 100644 --- a/src/calibre/ebooks/oeb/transforms/subset.py +++ b/src/calibre/ebooks/oeb/transforms/subset.py @@ -11,7 +11,7 @@ from collections import defaultdict from calibre.ebooks.oeb.base import urlnormalize from calibre.utils.fonts.sfnt.subset import subset, NoGlyphs, UnsupportedFont -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, itervalues, unicode_type, range from tinycss.fonts3 import parse_font_family @@ -152,7 +152,7 @@ class SubsetFonts(object): else: fonts[item.href] = font - for font in fonts.itervalues(): + for font in itervalues(fonts): if not font['chars']: self.log('The font %s is unused. Removing it.'%font['src']) remove(font) @@ -171,8 +171,8 @@ class SubsetFonts(object): totals[1] += sz else: font['item'].data = raw - nlen = sum(new_stats.itervalues()) - olen = sum(old_stats.itervalues()) + nlen = sum(itervalues(new_stats)) + olen = sum(itervalues(old_stats)) self.log('Decreased the font %s to %.1f%% of its original size'% (font['src'], nlen/olen *100)) totals[0] += nlen @@ -208,7 +208,7 @@ class SubsetFonts(object): if rule.type != rule.STYLE_RULE: continue props = {k:v for k,v in - get_font_properties(rule).iteritems() if v} + iteritems(get_font_properties(rule)) if v} if not props: continue for sel in rule.selectorList: diff --git a/src/calibre/ebooks/pdf/reflow.py b/src/calibre/ebooks/pdf/reflow.py index bc9dd27c9e..0016dc5400 100644 --- a/src/calibre/ebooks/pdf/reflow.py +++ b/src/calibre/ebooks/pdf/reflow.py @@ -40,7 +40,7 @@ class Image(Element): def __init__(self, img, opts, log, idc): Element.__init__(self) self.opts, self.log = opts, log - self.id = idc.next() + self.id = next(idc) self.top, self.left, self.width, self.height, self.iwidth, self.iheight = \ map(float, map(img.get, ('top', 'left', 'rwidth', 'rheight', 'iwidth', 'iheight'))) @@ -61,7 +61,7 @@ class Text(Element): def __init__(self, text, font_map, opts, log, idc): Element.__init__(self) - self.id = idc.next() + self.id = next(idc) self.opts, self.log = opts, log self.font_map = font_map self.top, self.left, self.width, self.height = map(float, map(text.get, diff --git a/src/calibre/ebooks/pdf/render/common.py b/src/calibre/ebooks/pdf/render/common.py index 25313a8bc4..8c89f2589c 100644 --- a/src/calibre/ebooks/pdf/render/common.py +++ b/src/calibre/ebooks/pdf/render/common.py @@ -14,7 +14,7 @@ from binascii import hexlify from calibre.constants import plugins, ispy3 from calibre.utils.logging import default_log -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, iterkeys, unicode_type pdf_float = plugins['speedup'][0].pdf_float @@ -146,7 +146,7 @@ class Dictionary(dict): def pdf_serialize(self, stream): stream.write(b'<<' + EOL) - sorted_keys = sorted(self.iterkeys(), + sorted_keys = sorted(iterkeys(self), key=lambda x:({'Type':'1', 'Subtype':'2'}.get( x, x)+x)) for k in sorted_keys: @@ -161,7 +161,7 @@ class InlineDictionary(Dictionary): def pdf_serialize(self, stream): stream.write(b'<< ') - for k, v in self.iteritems(): + for k, v in iteritems(self): serialize(Name(k), stream) stream.write(b' ') serialize(v, stream) diff --git a/src/calibre/ebooks/pdf/render/fonts.py b/src/calibre/ebooks/pdf/render/fonts.py index 9fd6ba925a..aca2292c77 100644 --- a/src/calibre/ebooks/pdf/render/fonts.py +++ b/src/calibre/ebooks/pdf/render/fonts.py @@ -11,7 +11,7 @@ import re from itertools import groupby from operator import itemgetter from collections import Counter, OrderedDict -from polyglot.builtins import map, zip +from polyglot.builtins import iteritems, iterkeys, map, zip from calibre import as_unicode from calibre.ebooks.pdf.render.common import (Array, String, Stream, @@ -106,7 +106,7 @@ class CMap(Stream): maps.append(current_map) mapping = [] for m in maps: - meat = '\n'.join('%s %s'%(k, v) for k, v in m.iteritems()) + meat = '\n'.join('%s %s'%(k, v) for k, v in iteritems(m)) mapping.append('%d beginbfchar\n%s\nendbfchar'%(len(m), meat)) try: name = name.encode('ascii').decode('ascii') @@ -197,14 +197,14 @@ class Font(object): widths = {g:self.metrics.pdf_scale(w) for g, w in zip(glyphs, self.metrics.glyph_widths(glyphs))} counter = Counter() - for g, w in widths.iteritems(): + for g, w in iteritems(widths): counter[w] += 1 most_common = counter.most_common(1)[0][0] self.descendant_font['DW'] = most_common - widths = {g:w for g, w in widths.iteritems() if w != most_common} + widths = {g:w for g, w in iteritems(widths) if w != most_common} groups = Array() - for k, g in groupby(enumerate(widths.iterkeys()), lambda i_x:i_x[0]-i_x[1]): + for k, g in groupby(enumerate(iterkeys(widths)), lambda i_x:i_x[0]-i_x[1]): group = list(map(itemgetter(1), g)) gwidths = [widths[g] for g in group] if len(set(gwidths)) == 1 and len(group) > 1: diff --git a/src/calibre/ebooks/pdf/render/from_html.py b/src/calibre/ebooks/pdf/render/from_html.py index 0325a8db63..53c1341cb4 100644 --- a/src/calibre/ebooks/pdf/render/from_html.py +++ b/src/calibre/ebooks/pdf/render/from_html.py @@ -8,7 +8,6 @@ __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' import json, os, numbers -from polyglot.builtins import map from math import floor from collections import defaultdict @@ -25,7 +24,7 @@ from calibre.ebooks.pdf.render.common import (inch, cm, mm, pica, cicero, from calibre.ebooks.pdf.render.engine import PdfDevice from calibre.ptempfile import PersistentTemporaryFile from calibre.utils.resources import load_hyphenator_dicts -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, itervalues, map, unicode_type def get_page_size(opts, for_comic=False): # {{{ @@ -418,7 +417,7 @@ class PDFWriter(QObject): except Exception: doc_margins = None if doc_margins and isinstance(doc_margins, dict): - doc_margins = {k:float(v) for k, v in doc_margins.iteritems() if isinstance(v, numbers.Number) and k in {'right', 'top', 'left', 'bottom'}} + doc_margins = {k:float(v) for k, v in iteritems(doc_margins) if isinstance(v, numbers.Number) and k in {'right', 'top', 'left', 'bottom'}} if doc_margins: margin_top = margin_bottom = 0 page_margins = self.convert_page_margins(doc_margins) @@ -439,7 +438,7 @@ class PDFWriter(QObject): if not isinstance(amap, dict): amap = {'links':[], 'anchors':{}} # Some javascript error occurred - for val in amap['anchors'].itervalues(): + for val in itervalues(amap['anchors']): if isinstance(val, dict) and 'column' in val: val['column'] = int(val['column']) for href, val in amap['links']: diff --git a/src/calibre/ebooks/pdf/render/links.py b/src/calibre/ebooks/pdf/render/links.py index bc3751de65..d5fd908552 100644 --- a/src/calibre/ebooks/pdf/render/links.py +++ b/src/calibre/ebooks/pdf/render/links.py @@ -10,6 +10,7 @@ __docformat__ = 'restructuredtext en' import os from calibre.ebooks.pdf.render.common import Array, Name, Dictionary, String, UTF16String, current_log +from polyglot.builtins import iteritems from polyglot.urllib import unquote, urlparse @@ -45,7 +46,7 @@ class Links(object): path = os.path.normcase(os.path.abspath(base_path)) self.anchors[path] = a = {} a[None] = Destination(start_page, self.start, self.pdf.get_pageref) - for anchor, pos in anchors.iteritems(): + for anchor, pos in iteritems(anchors): a[anchor] = Destination(start_page, pos, self.pdf.get_pageref) for link in links: href, page, rect = link diff --git a/src/calibre/ebooks/readability/htmls.py b/src/calibre/ebooks/readability/htmls.py index 66a858326d..692f26c2ca 100644 --- a/src/calibre/ebooks/readability/htmls.py +++ b/src/calibre/ebooks/readability/htmls.py @@ -5,7 +5,7 @@ import lxml.html from calibre.ebooks.readability.cleaners import normalize_spaces, clean_attributes from calibre.ebooks.chardet import xml_to_unicode -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type def build_doc(page): @@ -29,7 +29,7 @@ def normalize_entities(cur_title): u'\u00BB': '"', u'"': '"', } - for c, r in entities.iteritems(): + for c, r in iteritems(entities): if c in cur_title: cur_title = cur_title.replace(c, r) diff --git a/src/calibre/ebooks/rtf2xml/add_brackets.py b/src/calibre/ebooks/rtf2xml/add_brackets.py index c3f42d30d2..0af94f6d35 100755 --- a/src/calibre/ebooks/rtf2xml/add_brackets.py +++ b/src/calibre/ebooks/rtf2xml/add_brackets.py @@ -15,6 +15,7 @@ import sys, os from calibre.ebooks.rtf2xml import copy, check_brackets from calibre.ptempfile import better_mktemp +from polyglot.builtins import iteritems class AddBrackets: @@ -161,7 +162,7 @@ class AddBrackets: self.__open_bracket = False inline_string = ''.join(['%s%s \n%s\n' @@ -121,7 +121,7 @@ def create_markdown_object(extensions): if hasattr(module, 'makeExtension'): return module.makeExtension(**configs) for name, x in vars(module).items(): - if type(x) is type and issubclass(x, Extension) and x is not Extension: + if isinstance(x, type) and issubclass(x, Extension) and x is not Extension: return x(**configs) raise ImportError('No extension class in {}'.format(ext_name)) @@ -147,7 +147,7 @@ def convert_markdown_with_metadata(txt, title='', extensions=DEFAULT_MD_EXTENSIO html = md.convert(txt) mi = Metadata(title or _('Unknown')) m = md.Meta - for k, v in {'date':'pubdate', 'summary':'comments'}.iteritems(): + for k, v in iteritems({'date':'pubdate', 'summary':'comments'}): if v not in m and k in m: m[v] = m.pop(k) for k in 'title authors series tags pubdate comments publisher rating'.split(): diff --git a/src/calibre/ebooks/unihandecode/pykakasi/j2h.py b/src/calibre/ebooks/unihandecode/pykakasi/j2h.py index d3f23f31a0..ddf0f23860 100644 --- a/src/calibre/ebooks/unihandecode/pykakasi/j2h.py +++ b/src/calibre/ebooks/unihandecode/pykakasi/j2h.py @@ -21,9 +21,11 @@ # * # */ -from calibre.ebooks.unihandecode.pykakasi.jisyo import jisyo import re +from calibre.ebooks.unihandecode.pykakasi.jisyo import jisyo +from polyglot.builtins import iteritems + class J2H (object): @@ -65,7 +67,7 @@ class J2H (object): table = self.kanwa.load_jisyo(text[0]) if table is None: return ("", 0) - for (k,v) in table.iteritems(): + for (k,v) in iteritems(table): length = len(k) if len(text) >= length: if text.startswith(k): diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 800c6df572..c6cfbea7eb 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -34,7 +34,8 @@ from calibre.utils.config import Config, ConfigProxy, JSONConfig, dynamic from calibre.utils.date import UNDEFINED_DATE from calibre.utils.file_type_icons import EXT_MAP from calibre.utils.localization import get_lang -from polyglot.builtins import unicode_type, string_or_bytes, range +from polyglot.builtins import (iteritems, itervalues, unicode_type, + string_or_bytes, range) from polyglot import queue try: @@ -569,7 +570,7 @@ class FileIconProvider(QFileIconProvider): upath, bpath = I('mimetypes'), I('mimetypes', allow_user_override=False) if upath != bpath: # User has chosen to override mimetype icons - path_map = {v:I('mimetypes/%s.png' % v) for v in set(self.ICONS.itervalues())} + path_map = {v:I('mimetypes/%s.png' % v) for v in set(itervalues(self.ICONS))} icons = self.ICONS.copy() for uicon in glob.glob(os.path.join(upath, '*.png')): ukey = os.path.basename(uicon).rpartition('.')[0].lower() @@ -577,18 +578,18 @@ class FileIconProvider(QFileIconProvider): path_map[ukey] = uicon icons[ukey] = ukey else: - path_map = {v:os.path.join(bpath, v + '.png') for v in set(self.ICONS.itervalues())} + path_map = {v:os.path.join(bpath, v + '.png') for v in set(itervalues(self.ICONS))} icons = self.ICONS - self.icons = {k:path_map[v] for k, v in icons.iteritems()} + self.icons = {k:path_map[v] for k, v in iteritems(icons)} self.icons['calibre'] = I('lt.png', allow_user_override=False) for i in ('dir', 'default', 'zero'): self.icons[i] = QIcon(self.icons[i]) def key_from_ext(self, ext): - key = ext if ext in self.icons.keys() else 'default' + key = ext if ext in list(self.icons.keys()) else 'default' if key == 'default' and ext.count('.') > 0: ext = ext.rpartition('.')[2] - key = ext if ext in self.icons.keys() else 'default' + key = ext if ext in list(self.icons.keys()) else 'default' return key def cached_icon(self, key): @@ -970,7 +971,7 @@ class Application(QApplication): def load_calibre_style(self): icon_map = self.__icon_map_memory_ = {} pcache = {} - for k, v in { + for k, v in iteritems({ 'DialogYesButton': u'ok.png', 'DialogNoButton': u'window-close.png', 'DialogCloseButton': u'window-close.png', @@ -987,7 +988,7 @@ class Application(QApplication): 'MessageBoxQuestion': u'dialog_question.png', 'BrowserReload': u'view-refresh.png', 'LineEditClearButton': u'clear_left.png', - }.iteritems(): + }): if v not in pcache: p = I(v) if isinstance(p, bytes): @@ -1099,7 +1100,7 @@ def sanitize_env_vars(): originals = {x:os.environ.get(x, '') for x in env_vars} changed = {x:False for x in env_vars} - for var, suffix in env_vars.iteritems(): + for var, suffix in iteritems(env_vars): paths = [x for x in originals[var].split(os.pathsep) if x] npaths = [] if suffix is None else [x for x in paths if x != (sys.frozen_path + suffix)] if len(npaths) < len(paths): @@ -1112,7 +1113,7 @@ def sanitize_env_vars(): try: yield finally: - for var, orig in originals.iteritems(): + for var, orig in iteritems(originals): if changed[var]: if orig: os.environ[var] = orig @@ -1321,7 +1322,7 @@ if is_running_from_develop: def event_type_name(ev_or_etype): from PyQt5.QtCore import QEvent etype = ev_or_etype.type() if isinstance(ev_or_etype, QEvent) else ev_or_etype - for name, num in vars(QEvent).iteritems(): + for name, num in iteritems(vars(QEvent)): if num == etype: return name return 'UnknownEventType' diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index 30f85adef6..92c59c3444 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -278,7 +278,7 @@ class InterfaceAction(QObject): For example to load an image:: pixmap = QPixmap() - pixmap.loadFromData(self.load_resources(['images/icon.png']).itervalues().next()) + next(pixmap.loadFromData(self.load_resources(['images/icon.png']).itervalues())) icon = QIcon(pixmap) :param names: List of paths to resources in the ZIP file using / as separator diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index 9b8575bd63..b44458a2f9 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -25,7 +25,7 @@ from calibre.gui2.actions import InterfaceAction from calibre.gui2 import question_dialog from calibre.ebooks.metadata import MetaInformation from calibre.ptempfile import PersistentTemporaryFile -from polyglot.builtins import string_or_bytes, range +from polyglot.builtins import iteritems, string_or_bytes, range def get_filters(): @@ -188,7 +188,7 @@ class AddAction(InterfaceAction): fmt_map = {os.path.splitext(fpath)[1][1:].upper():fpath for fpath in paths} for id_ in ids: - for fmt, fpath in fmt_map.iteritems(): + for fmt, fpath in iteritems(fmt_map): if fmt: db.add_format_with_hooks(id_, fmt, fpath, index_is_id=True, notify=True) diff --git a/src/calibre/gui2/actions/annotate.py b/src/calibre/gui2/actions/annotate.py index b0d00e91c6..5be9babace 100644 --- a/src/calibre/gui2/actions/annotate.py +++ b/src/calibre/gui2/actions/annotate.py @@ -12,7 +12,7 @@ from calibre.gui2 import error_dialog from calibre.gui2.actions import InterfaceAction from calibre.devices.usbms.device import Device from calibre.gui2.dialogs.progress import ProgressDialog -from polyglot.builtins import range +from polyglot.builtins import iteritems, range class Updater(QThread): # {{{ @@ -55,7 +55,7 @@ class Updater(QThread): # {{{ self.errors[id_] = traceback.format_exc() self.update_progress.emit(i) self.update_done.emit() - self.done_callback(self.annotation_map.keys(), self.errors) + self.done_callback(list(self.annotation_map.keys()), self.errors) # }}} @@ -152,7 +152,7 @@ class FetchAnnotationsAction(InterfaceAction): if errors: db = self.gui.library_view.model().db entries = [] - for id_, tb in errors.iteritems(): + for id_, tb in iteritems(errors): title = id_ if isinstance(id_, type(1)): title = db.title(id_, index_is_id=True) diff --git a/src/calibre/gui2/actions/author_mapper.py b/src/calibre/gui2/actions/author_mapper.py index 5bbd41cd47..881699246c 100644 --- a/src/calibre/gui2/actions/author_mapper.py +++ b/src/calibre/gui2/actions/author_mapper.py @@ -4,11 +4,10 @@ from __future__ import (unicode_literals, division, absolute_import, print_function) -from polyglot.builtins import map from calibre.gui2 import gprefs from calibre.gui2.actions import InterfaceAction -from polyglot.builtins import range +from polyglot.builtins import iteritems, map, range class AuthorMapAction(InterfaceAction): @@ -54,7 +53,7 @@ class AuthorMapAction(InterfaceAction): author_map = db.all_field_for('authors', book_ids) changed_author_map = {} changed_author_sort_map = {} - for book_id, authors in author_map.iteritems(): + for book_id, authors in iteritems(author_map): authors = list(authors) new_authors = map_authors(authors, rules) if authors != new_authors: diff --git a/src/calibre/gui2/actions/choose_library.py b/src/calibre/gui2/actions/choose_library.py index eb77c77610..19ccb10311 100644 --- a/src/calibre/gui2/actions/choose_library.py +++ b/src/calibre/gui2/actions/choose_library.py @@ -20,7 +20,7 @@ from calibre.utils.icu import sort_key from calibre.gui2 import (gprefs, warning_dialog, Dispatcher, error_dialog, question_dialog, info_dialog, open_local_file, choose_dir) from calibre.gui2.actions import InterfaceAction -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iterkeys, unicode_type, range def db_class(): @@ -40,7 +40,7 @@ class LibraryUsageStats(object): # {{{ # Rename the current library. Renaming of other libraries is # handled by the switch function q = os.path.basename(lp) - for loc in list(self.stats.iterkeys()): + for loc in list(iterkeys(self.stats)): bn = posixpath.basename(loc) if bn.lower() == q.lower(): self.rename(loc, lp) diff --git a/src/calibre/gui2/actions/copy_to_library.py b/src/calibre/gui2/actions/copy_to_library.py index d9cb155ca1..fa4a2635fa 100644 --- a/src/calibre/gui2/actions/copy_to_library.py +++ b/src/calibre/gui2/actions/copy_to_library.py @@ -26,7 +26,7 @@ from calibre.gui2.widgets2 import Dialog from calibre.utils.config import prefs from calibre.utils.icu import sort_key, numeric_sort_key from calibre.db.copy_to_library import copy_one_book -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, itervalues, unicode_type def ask_about_cc_mismatch(gui, db, newdb, missing_cols, incompatible_cols): # {{{ @@ -279,7 +279,7 @@ class DuplicatesQuestion(QDialog): # {{{ self.setWindowTitle(_('Duplicate books')) self.books = QListWidget(self) self.items = [] - for book_id, (title, authors) in duplicates.iteritems(): + for book_id, (title, authors) in iteritems(duplicates): i = QListWidgetItem(_('{0} by {1}').format(title, ' & '.join(authors[:3])), self.books) i.setData(Qt.UserRole, book_id) i.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) @@ -492,7 +492,7 @@ class CopyToLibraryAction(InterfaceAction): self.gui.status_bar.show_message(donemsg.format(num=len(self.worker.processed), loc=loc), 2000) if self.worker.auto_merged_ids: - books = '\n'.join(self.worker.auto_merged_ids.itervalues()) + books = '\n'.join(itervalues(self.worker.auto_merged_ids)) info_dialog(self.gui, _('Auto merged'), _('Some books were automatically merged into existing ' 'records in the target library. Click "Show ' diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 2d8ef8e9a1..90d84e7d47 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -26,7 +26,7 @@ from calibre.db.errors import NoSuchFormat from calibre.library.comments import merge_comments from calibre.ebooks.metadata.sources.prefs import msprefs from calibre.gui2.actions.show_quickview import get_quickview_action_plugin -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class EditMetadataAction(InterfaceAction): @@ -320,7 +320,7 @@ class EditMetadataAction(InterfaceAction): failed_ids |= d.rejected_ids restrict_to_failed = True nid_map = {} - for book_id, (changed, mi) in d.accepted.iteritems(): + for book_id, (changed, mi) in iteritems(d.accepted): if mi is None: # discarded continue if changed: @@ -498,7 +498,7 @@ class EditMetadataAction(InterfaceAction): 'merge_too_many_books', self.gui) def books_dropped(self, merge_map): - for dest_id, src_ids in merge_map.iteritems(): + for dest_id, src_ids in iteritems(merge_map): if not self.confirm_large_merge(len(src_ids) + 1): continue from calibre.gui2.dialogs.confirm_merge import merge_drop @@ -726,7 +726,7 @@ class EditMetadataAction(InterfaceAction): if d.result() == d.Accepted: to_rename = d.to_rename # dict of new text to old ids to_delete = d.to_delete # list of ids - for old_id, new_name in to_rename.iteritems(): + for old_id, new_name in iteritems(to_rename): model.rename_collection(old_id, new_name=unicode_type(new_name)) for item in to_delete: model.delete_collection_using_id(item) @@ -754,7 +754,7 @@ class EditMetadataAction(InterfaceAction): ''' if title is None: title = _('Applying changed metadata') - self.apply_id_map = list(id_map.iteritems()) + self.apply_id_map = list(iteritems(id_map)) self.apply_current_idx = 0 self.apply_failures = [] self.applied_ids = set() diff --git a/src/calibre/gui2/actions/polish.py b/src/calibre/gui2/actions/polish.py index 292dcf33d1..37e8dfd487 100644 --- a/src/calibre/gui2/actions/polish.py +++ b/src/calibre/gui2/actions/polish.py @@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en' import os, weakref, shutil, textwrap from collections import OrderedDict from functools import partial -from polyglot.builtins import map, unicode_type +from polyglot.builtins import iteritems, itervalues, map, unicode_type from PyQt5.Qt import (QDialog, QGridLayout, QIcon, QCheckBox, QLabel, QFrame, QApplication, QDialogButtonBox, Qt, QSize, QSpacerItem, @@ -92,7 +92,7 @@ class Polish(QDialog): # {{{ ('upgrade_book', _('&Upgrade book internals')), ]) prefs = gprefs.get('polishing_settings', {}) - for name, text in self.all_actions.iteritems(): + for name, text in iteritems(self.all_actions): count += 1 x = QCheckBox(text, self) x.setChecked(prefs.get(name, False)) @@ -241,7 +241,7 @@ class Polish(QDialog): # {{{ self.tdir = PersistentTemporaryDirectory('_queue_polish') self.jobs = [] if len(self.book_id_map) <= 5: - for i, (book_id, formats) in enumerate(self.book_id_map.iteritems()): + for i, (book_id, formats) in enumerate(iteritems(self.book_id_map)): self.do_book(i+1, book_id, formats) else: self.queue = [(i+1, id_) for i, id_ in enumerate(self.book_id_map)] @@ -452,7 +452,7 @@ class PolishAction(InterfaceAction): db = self.gui.library_view.model().db ans = (db.id(r) for r in rows) ans = self.get_supported_books(ans) - for fmts in ans.itervalues(): + for fmts in itervalues(ans): for x in fmts: if x.startswith('ORIGINAL_'): from calibre.gui2.dialogs.confirm_delete import confirm @@ -481,7 +481,7 @@ class PolishAction(InterfaceAction): ' formats. Convert to one of those formats before polishing.') %_(' or ').join(sorted(SUPPORTED)), show=True) ans = OrderedDict(ans) - for fmts in ans.itervalues(): + for fmts in itervalues(ans): for x in SUPPORTED: if ('ORIGINAL_'+x) in fmts: fmts.discard(x) diff --git a/src/calibre/gui2/actions/save_to_disk.py b/src/calibre/gui2/actions/save_to_disk.py index 6e1943ec16..0a41ed191b 100644 --- a/src/calibre/gui2/actions/save_to_disk.py +++ b/src/calibre/gui2/actions/save_to_disk.py @@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en' import os, numbers from functools import partial -from polyglot.builtins import map +from polyglot.builtins itervalues, import map from calibre.utils.config import prefs @@ -123,7 +123,7 @@ class SaveToDiskAction(InterfaceAction): def save_library_format_by_ids(self, book_ids, fmt, single_dir=True): if isinstance(book_ids, numbers.Integral): book_ids = [book_ids] - rows = list(self.gui.library_view.ids_to_rows(book_ids).itervalues()) + rows = list(itervalues(self.gui.library_view.ids_to_rows(book_ids))) rows = [self.gui.library_view.model().index(r, 0) for r in rows] self.save_to_disk(True, single_dir=single_dir, single_format=fmt, rows=rows, write_opf=False, save_cover=False) diff --git a/src/calibre/gui2/actions/sort.py b/src/calibre/gui2/actions/sort.py index 8d0159d40f..85336cdabd 100644 --- a/src/calibre/gui2/actions/sort.py +++ b/src/calibre/gui2/actions/sort.py @@ -10,6 +10,7 @@ from PyQt5.Qt import QToolButton, QAction, pyqtSignal, QIcon from calibre.gui2.actions import InterfaceAction from calibre.utils.icu import sort_key +from polyglot.builtins import iteritems class SortAction(QAction): @@ -61,7 +62,7 @@ class SortByAction(InterfaceAction): except TypeError: sort_col, order = 'date', True fm = db.field_metadata - name_map = {v:k for k, v in fm.ui_sortable_field_keys().iteritems()} + name_map = {v:k for k, v in iteritems(fm.ui_sortable_field_keys())} for name in sorted(name_map, key=sort_key): key = name_map[name] if key == 'ondevice' and self.gui.device_connected is None: diff --git a/src/calibre/gui2/actions/tag_mapper.py b/src/calibre/gui2/actions/tag_mapper.py index 9830903c09..5b4547192b 100644 --- a/src/calibre/gui2/actions/tag_mapper.py +++ b/src/calibre/gui2/actions/tag_mapper.py @@ -4,7 +4,7 @@ from __future__ import (unicode_literals, division, absolute_import, print_function) -from polyglot.builtins import map, range +from polyglot.builtins import iteritems, map, range from calibre.gui2 import gprefs from calibre.gui2.actions import InterfaceAction @@ -51,7 +51,7 @@ class TagMapAction(InterfaceAction): db = self.gui.current_db.new_api tag_map = db.all_field_for('tags', book_ids) changed_tag_map = {} - for book_id, tags in tag_map.iteritems(): + for book_id, tags in iteritems(tag_map): tags = list(tags) new_tags = map_tags(tags, rules) if tags != new_tags: diff --git a/src/calibre/gui2/actions/toc_edit.py b/src/calibre/gui2/actions/toc_edit.py index 518e98007a..25923733a6 100644 --- a/src/calibre/gui2/actions/toc_edit.py +++ b/src/calibre/gui2/actions/toc_edit.py @@ -14,7 +14,7 @@ from PyQt5.Qt import (QTimer, QDialog, QGridLayout, QCheckBox, QLabel, from calibre.gui2 import error_dialog, gprefs from calibre.gui2.actions import InterfaceAction -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type SUPPORTED = {'EPUB', 'AZW3'} @@ -130,7 +130,7 @@ class ToCEditAction(InterfaceAction): return self.get_supported_books(ans) def do_edit(self, book_id_map): - for book_id, fmts in book_id_map.iteritems(): + for book_id, fmts in iteritems(book_id_map): if len(fmts) > 1: d = ChooseFormat(fmts, self.gui) if d.exec_() != d.Accepted: diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py index 7aa6130644..0429fb0cbb 100644 --- a/src/calibre/gui2/add.py +++ b/src/calibre/gui2/add.py @@ -10,7 +10,7 @@ import shutil, os, weakref, traceback, tempfile, time from threading import Thread from collections import OrderedDict from io import BytesIO -from polyglot.builtins import map, unicode_type, string_or_bytes +from polyglot.builtins import iteritems, map, unicode_type, string_or_bytes from PyQt5.Qt import QObject, Qt, pyqtSignal @@ -435,7 +435,7 @@ class Adder(QObject): def add_formats(self, book_id, paths, mi, replace=True, is_an_add=False): fmap = {p.rpartition(os.path.extsep)[-1].lower():p for p in paths} fmt_map = {} - for fmt, path in fmap.iteritems(): + for fmt, path in iteritems(fmap): # The onimport plugins have already been run by the read metadata # worker if self.ignore_opf and fmt.lower() == 'opf': diff --git a/src/calibre/gui2/bars.py b/src/calibre/gui2/bars.py index f861c71525..82cb93c5b0 100644 --- a/src/calibre/gui2/bars.py +++ b/src/calibre/gui2/bars.py @@ -19,7 +19,7 @@ except ImportError: from calibre.constants import isosx from calibre.gui2 import gprefs, native_menubar_defaults, config from calibre.gui2.throbber import ThrobbingButton -from polyglot.builtins import unicode_type +from polyglot.builtins import itervalues, unicode_type class RevealBar(QWidget): # {{{ @@ -238,7 +238,7 @@ class ToolBar(QToolBar): # {{{ def check_iactions_for_drag(self, event, md, func): if self.added_actions: pos = event.pos() - for iac in self.gui.iactions.itervalues(): + for iac in itervalues(self.gui.iactions): if iac.accepts_drops: aa = iac.qaction w = self.widgetForAction(aa) diff --git a/src/calibre/gui2/convert/look_and_feel.py b/src/calibre/gui2/convert/look_and_feel.py index 3ab986b828..15470e3839 100644 --- a/src/calibre/gui2/convert/look_and_feel.py +++ b/src/calibre/gui2/convert/look_and_feel.py @@ -13,7 +13,7 @@ from PyQt5.Qt import Qt from calibre.gui2.convert.look_and_feel_ui import Ui_Form from calibre.gui2.convert import Widget from calibre.ebooks.conversion.config import OPTIONS -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class LookAndFeelWidget(Widget, Ui_Form): @@ -59,7 +59,7 @@ class LookAndFeelWidget(Widget, Ui_Form): return ans if g is self.opt_filter_css: ans = set() - for key, item in self.FILTER_CSS.iteritems(): + for key, item in iteritems(self.FILTER_CSS): w = getattr(self, 'filter_css_%s'%key) if w.isChecked(): ans = ans.union(item) @@ -86,7 +86,7 @@ class LookAndFeelWidget(Widget, Ui_Form): if not val: val = '' items = frozenset([x.strip().lower() for x in val.split(',')]) - for key, vals in self.FILTER_CSS.iteritems(): + for key, vals in iteritems(self.FILTER_CSS): w = getattr(self, 'filter_css_%s'%key) if not vals - items: items = items - vals diff --git a/src/calibre/gui2/convert/txt_input.py b/src/calibre/gui2/convert/txt_input.py index fff09f18fe..dc66e16278 100644 --- a/src/calibre/gui2/convert/txt_input.py +++ b/src/calibre/gui2/convert/txt_input.py @@ -10,7 +10,7 @@ from calibre.gui2.convert.txt_input_ui import Ui_Form from calibre.gui2.convert import Widget from calibre.ebooks.conversion.plugins.txt_input import MD_EXTENSIONS from calibre.ebooks.conversion.config import OPTIONS -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, itervalues, unicode_type class PluginWidget(Widget, Ui_Form): @@ -28,7 +28,7 @@ class PluginWidget(Widget, Ui_Form): for x in get_option('formatting_type').option.choices: self.opt_formatting_type.addItem(x) self.md_map = {} - for name, text in MD_EXTENSIONS.iteritems(): + for name, text in iteritems(MD_EXTENSIONS): i = QListWidgetItem('%s - %s' % (name, text), self.opt_markdown_extensions) i.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) i.setData(Qt.UserRole, name) @@ -38,7 +38,7 @@ class PluginWidget(Widget, Ui_Form): def set_value_handler(self, g, val): if g is self.opt_markdown_extensions: - for i in self.md_map.itervalues(): + for i in itervalues(self.md_map): i.setCheckState(Qt.Unchecked) for x in val.split(','): x = x.strip() @@ -49,7 +49,7 @@ class PluginWidget(Widget, Ui_Form): def get_value_handler(self, g): if g is not self.opt_markdown_extensions: return Widget.get_value_handler(self, g) - return ', '.join(unicode_type(i.data(Qt.UserRole) or '') for i in self.md_map.itervalues() if i.checkState()) + return ', '.join(unicode_type(i.data(Qt.UserRole) or '') for i in itervalues(self.md_map) if i.checkState()) def connect_gui_obj_handler(self, g, f): if g is not self.opt_markdown_extensions: diff --git a/src/calibre/gui2/covers.py b/src/calibre/gui2/covers.py index f5d4e574dc..d6103c6072 100644 --- a/src/calibre/gui2/covers.py +++ b/src/calibre/gui2/covers.py @@ -19,6 +19,7 @@ from calibre.gui2 import gprefs, error_dialog from calibre.gui2.font_family_chooser import FontFamilyChooser from calibre.utils.date import now from calibre.utils.icu import sort_key +from polyglot.builtins import iteritems, itervalues class Preview(QLabel): @@ -305,12 +306,12 @@ class CoverSettingsWidget(QWidget): if not self.for_global_prefs and lu in self.colors_map and self.colors_map[lu].checkState() == Qt.Checked: self.colors_map[lu].setSelected(True) else: - for name, li in self.colors_map.iteritems(): + for name, li in iteritems(self.colors_map): if li.checkState() == Qt.Checked: li.setSelected(True) break else: - next(self.colors_map.itervalues()).setSelected(True) + next(itervalues(self.colors_map)).setSelected(True) disabled = set(prefs['disabled_styles']) self.styles_list.clear() @@ -323,42 +324,42 @@ class CoverSettingsWidget(QWidget): if not self.for_global_prefs and lu in self.style_map and self.style_map[lu].checkState() == Qt.Checked: self.style_map[lu].setSelected(True) else: - for name, li in self.style_map.iteritems(): + for name, li in iteritems(self.style_map): if li.checkState() == Qt.Checked: li.setSelected(True) break else: - next(self.style_map.itervalues()).setSelected(True) + next(itervalues(self.style_map)).setSelected(True) @property def current_colors(self): - for name, li in self.colors_map.iteritems(): + for name, li in iteritems(self.colors_map): if li.isSelected(): return name @property def disabled_colors(self): - for name, li in self.colors_map.iteritems(): + for name, li in iteritems(self.colors_map): if li.checkState() == Qt.Unchecked: yield name @property def custom_colors(self): ans = {} - for name, li in self.colors_map.iteritems(): + for name, li in iteritems(self.colors_map): if name.startswith('#'): ans[name] = li.data(Qt.UserRole) return ans @property def current_style(self): - for name, li in self.style_map.iteritems(): + for name, li in iteritems(self.style_map): if li.isSelected(): return name @property def disabled_styles(self): - for name, li in self.style_map.iteritems(): + for name, li in iteritems(self.style_map): if li.checkState() == Qt.Unchecked: yield name @@ -386,7 +387,7 @@ class CoverSettingsWidget(QWidget): self.colors_list.insertItem(0, li) cm = OrderedDict() cm[name] = li - for k, v in self.colors_map.iteritems(): + for k, v in iteritems(self.colors_map): cm[k] = v self.colors_map = cm li.setSelected(True) @@ -502,7 +503,7 @@ class CoverSettingsWidget(QWidget): def save_as_prefs(self): with self.original_prefs: - for k, v in self.current_prefs.iteritems(): + for k, v in iteritems(self.current_prefs): self.original_prefs[k] = v diff --git a/src/calibre/gui2/css_transform_rules.py b/src/calibre/gui2/css_transform_rules.py index 361552e1e5..fefb04ba43 100644 --- a/src/calibre/gui2/css_transform_rules.py +++ b/src/calibre/gui2/css_transform_rules.py @@ -19,7 +19,7 @@ from calibre.gui2.tag_mapper import ( from calibre.gui2.widgets2 import Dialog from calibre.utils.config import JSONConfig from calibre.utils.localization import localize_user_manual_link -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class RuleEdit(QWidget): # {{{ @@ -50,7 +50,7 @@ class RuleEdit(QWidget): # {{{ 'For instance use margin-top, not margin.')) elif clause == '{match_type}': self.match_type = w = QComboBox(self) - for action, text in MATCH_TYPE_MAP.iteritems(): + for action, text in iteritems(MATCH_TYPE_MAP): w.addItem(text, action) w.currentIndexChanged.connect(self.update_state) elif clause == '{query}': @@ -70,7 +70,7 @@ class RuleEdit(QWidget): # {{{ for clause in parts: if clause == '{action}': self.action = w = QComboBox(self) - for action, text in ACTION_MAP.iteritems(): + for action, text in iteritems(ACTION_MAP): w.addItem(text, action) w.currentIndexChanged.connect(self.update_state) elif clause == '{action_data}': diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 1c73867eae..723580ba89 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -837,7 +837,7 @@ class BulkBase(Base): break ans = None if len(values) == 1: - ans = iter(values).next() + ans = next(iter(values)) if isinstance(ans, frozenset): ans = list(ans) return ans diff --git a/src/calibre/gui2/dbus_export/menu.py b/src/calibre/gui2/dbus_export/menu.py index 571fe48193..749a31bc37 100644 --- a/src/calibre/gui2/dbus_export/menu.py +++ b/src/calibre/gui2/dbus_export/menu.py @@ -16,6 +16,7 @@ from PyQt5.Qt import ( from calibre.utils.dbus_service import Object, BusName, method as dbus_method, dbus_property, signal as dbus_signal from calibre.gui2.dbus_export.utils import ( setup_for_cli_run, swap_mnemonic_char, key_sequence_to_dbus_shortcut, icon_to_dbus_menu_icon) +from polyglot.builtins import iteritems null = object() @@ -124,7 +125,7 @@ class DBusMenu(QObject): return {} ans = self._action_properties.get(action_id, PropDict()) if restrict_to: - ans = PropDict({k:v for k, v in ans.iteritems() if k in restrict_to}) + ans = PropDict({k:v for k, v in iteritems(ans) if k in restrict_to}) return ans def publish_new_menu(self, qmenu=None): @@ -195,7 +196,7 @@ class DBusMenu(QObject): removed = set(old_props) - set(new_props) if removed: removed_props.append((ac_id, dbus.Array(removed, signature='as'))) - updated = PropDict({k:v for k, v in new_props.iteritems() if v != old_props.get(k, null)}) + updated = PropDict({k:v for k, v in iteritems(new_props) if v != old_props.get(k, null)}) if updated: updated_props.append((ac_id, updated)) self.action_changes = set() diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 7414e4102f..dcc8b1a6fc 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -411,7 +411,7 @@ class DeviceManager(Thread): # {{{ do_sleep = True while True: - job = self.next() + job = next(self) if job is not None: do_sleep = False self.current_job = job @@ -1494,8 +1494,8 @@ class DeviceMixin(object): # {{{ bad, good, gf, names, remove_ids = [], [], [], [], [] for f in _files: - mi = imetadata.next() - id = ids.next() + mi = next(imetadata) + id = next(ids) if f is None: bad.append(mi.title) else: diff --git a/src/calibre/gui2/device_drivers/mtp_config.py b/src/calibre/gui2/device_drivers/mtp_config.py index ef3607fd1c..37a904402c 100644 --- a/src/calibre/gui2/device_drivers/mtp_config.py +++ b/src/calibre/gui2/device_drivers/mtp_config.py @@ -20,7 +20,7 @@ from calibre.gui2 import error_dialog from calibre.gui2.dialogs.template_dialog import TemplateDialog from calibre.utils.date import parse_date from calibre.gui2.device_drivers.mtp_folder_browser import Browser, IgnoredFolders -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range class FormatsConfig(QWidget): # {{{ @@ -177,7 +177,7 @@ class IgnoredDevices(QWidget): # {{{ l.addWidget(f) devs = [(snum, (x[0], parse_date(x[1]))) for snum, x in - devs.iteritems()] + iteritems(devs)] for dev, x in sorted(devs, key=lambda x:x[1][1], reverse=True): name = x[0] name = '%s [%s]'%(name, dev) diff --git a/src/calibre/gui2/dialogs/custom_recipes.py b/src/calibre/gui2/dialogs/custom_recipes.py index 8c0b5dea1f..7b33412c5c 100644 --- a/src/calibre/gui2/dialogs/custom_recipes.py +++ b/src/calibre/gui2/dialogs/custom_recipes.py @@ -21,7 +21,7 @@ from calibre.gui2.tweak_book.editor.text import TextEdit from calibre.utils.icu import sort_key from calibre.web.feeds.recipes.collection import get_builtin_recipe_collection, get_builtin_recipe_by_id from calibre.utils.localization import localize_user_manual_link -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range def is_basic_recipe(src): @@ -70,7 +70,7 @@ class CustomRecipeModel(QAbstractListModel): # {{{ def replace_many_by_title(self, scriptmap): script_urn_map = {} - for title, script in scriptmap.iteritems(): + for title, script in iteritems(scriptmap): urn = None for x in self.recipe_model.custom_recipe_collection: if x.get('title', False) == title: @@ -650,7 +650,7 @@ class CustomRecipes(Dialog): if replace_recipes: self.recipe_list.replace_many_by_title(replace_recipes) if failed_recipes: - det_msg = '\n'.join('%s\n%s\n' % (title, tb) for title, tb in failed_recipes.iteritems()) + det_msg = '\n'.join('%s\n%s\n' % (title, tb) for title, tb in iteritems(failed_recipes)) error_dialog(self, _('Failed to create recipes'), _( 'Failed to create some recipes, click "Show details" for details'), show=True, det_msg=det_msg) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 612c0148a1..8c53ff7c0c 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -32,7 +32,7 @@ from calibre.utils.date import qt_to_dt, internal_iso_format_string from calibre.utils.icu import capitalize, sort_key from calibre.utils.titlecase import titlecase from calibre.gui2.widgets import LineEditECM -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, itervalues, unicode_type Settings = namedtuple('Settings', 'remove_all remove add au aus do_aus rating pub do_series do_autonumber ' @@ -241,8 +241,8 @@ class MyBlockingBusy(QDialog): # {{{ def new_title(authors): ans = authors_to_string(authors) return change_title_casing(ans) if args.do_title_case else ans - new_title_map = {bid:new_title(authors) for bid, authors in authors_map.iteritems()} - new_authors_map = {bid:string_to_authors(title) for bid, title in title_map.iteritems()} + new_title_map = {bid:new_title(authors) for bid, authors in iteritems(authors_map)} + new_authors_map = {bid:string_to_authors(title) for bid, title in iteritems(title_map)} self.progress_update.emit(1) cache.set_field('authors', new_authors_map) cache.set_field('title', new_title_map) @@ -252,7 +252,7 @@ class MyBlockingBusy(QDialog): # {{{ if args.do_title_case and not args.do_swap_ta: self.progress_next_step_range.emit(0) title_map = cache.all_field_for('title', self.ids) - cache.set_field('title', {bid:change_title_casing(title) for bid, title in title_map.iteritems()}) + cache.set_field('title', {bid:change_title_casing(title) for bid, title in iteritems(title_map)}) self.progress_finished_cur_step.emit() if args.do_title_sort: @@ -392,7 +392,7 @@ class MyBlockingBusy(QDialog): # {{{ def next_series_num(bid, i): if args.do_series_restart: return sval + (i * args.series_increment) - next_num = _get_next_series_num_for_list(sorted(sval.itervalues()), unwrap=False) + next_num = _get_next_series_num_for_list(sorted(itervalues(sval)), unwrap=False) sval[bid] = next_num return next_num @@ -443,7 +443,7 @@ class MyBlockingBusy(QDialog): # {{{ if self.sr_calls: self.progress_next_step_range.emit(len(self.sr_calls)) self.progress_update.emit(0) - for field, book_id_val_map in self.sr_calls.iteritems(): + for field, book_id_val_map in iteritems(self.sr_calls): self.refresh_books.update(self.db.new_api.set_field(field, book_id_val_map)) self.progress_update.emit(1) self.progress_finished_cur_step.emit() @@ -781,7 +781,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): if id_type: val = [val.get(id_type, '')] else: - val = [u'%s:%s'%(t[0], t[1]) for t in val.iteritems()] + val = [u'%s:%s'%(t[0], t[1]) for t in iteritems(val)] if val is None: val = [] if fm['is_multiple'] else [''] elif not fm['is_multiple']: @@ -959,7 +959,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): dest_val = [dest_val.get(dst_id_type, '')] else: # convert the csp dict into a list - dest_val = [u'%s:%s'%(t[0], t[1]) for t in dest_val.iteritems()] + dest_val = [u'%s:%s'%(t[0], t[1]) for t in iteritems(dest_val)] if dest_val is None: dest_val = [] elif not isinstance(dest_val, list): @@ -1269,7 +1269,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.query_field.blockSignals(False) self.query_field.setCurrentIndex(0) - if item_name in self.queries.keys(): + if item_name in list(self.queries.keys()): del(self.queries[item_name]) self.queries.commit() @@ -1291,7 +1291,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): _("You must provide a name."), show=True) new = True name = unicode_type(name) - if name in self.queries.keys(): + if name in list(self.queries.keys()): if not question_dialog(self, _("Save search/replace"), _("That saved search/replace already exists and will be overwritten. " "Are you sure?")): diff --git a/src/calibre/gui2/dialogs/opml.py b/src/calibre/gui2/dialogs/opml.py index 7f7efc8a22..2b6bde5f3f 100644 --- a/src/calibre/gui2/dialogs/opml.py +++ b/src/calibre/gui2/dialogs/opml.py @@ -17,7 +17,7 @@ from lxml import etree from calibre.gui2 import choose_files, error_dialog from calibre.utils.icu import sort_key -from polyglot.builtins import unicode_type +from polyglot.builtins import iterkeys, unicode_type Group = namedtuple('Group', 'title feeds') @@ -49,7 +49,7 @@ def import_opml(raw, preserve_groups=True): break groups[parent].append((title, url)) - for title in sorted(groups.iterkeys(), key=sort_key): + for title in sorted(iterkeys(groups), key=sort_key): yield Group(title, uniq(groups[title], kmap=itemgetter(1))) diff --git a/src/calibre/gui2/dialogs/plugin_updater.py b/src/calibre/gui2/dialogs/plugin_updater.py index 34616b56c8..cfcddde0e1 100644 --- a/src/calibre/gui2/dialogs/plugin_updater.py +++ b/src/calibre/gui2/dialogs/plugin_updater.py @@ -24,7 +24,7 @@ from calibre.gui2 import error_dialog, question_dialog, info_dialog, open_url, g from calibre.gui2.preferences.plugins import ConfigWidget from calibre.utils.date import UNDEFINED_DATE, format_date from calibre.utils.https import get_https_resource_securely -from polyglot.builtins import unicode_type +from polyglot.builtins import itervalues, unicode_type SERVER = 'https://code.calibre-ebook.com/plugins/' INDEX_URL = '%splugins.json.bz2' % SERVER @@ -72,7 +72,7 @@ def read_available_plugins(raise_error=False): raise traceback.print_exc() return - for plugin in raw.itervalues(): + for plugin in itervalues(raw): try: display_plugin = DisplayPlugin(plugin) get_installed_plugin_status(display_plugin) diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py index 27be20cb99..67a835a1fc 100644 --- a/src/calibre/gui2/dialogs/scheduler.py +++ b/src/calibre/gui2/dialogs/scheduler.py @@ -26,7 +26,7 @@ from calibre.utils.date import utcnow from calibre.utils.network import internet_connected from calibre import force_unicode from calibre.utils.localization import get_lang, canonicalize_lang -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range def convert_day_time_schedule(val): @@ -314,7 +314,7 @@ class SchedulerDialog(QDialog): g.addWidget(spw, 2, 0, 1, 2) self.rla = la = QLabel(_("For the scheduling to work, you must leave calibre running.")) vt.addWidget(la) - for b, c in self.SCHEDULE_TYPES.iteritems(): + for b, c in iteritems(self.SCHEDULE_TYPES): b = getattr(self, b) b.toggled.connect(self.schedule_type_selected) b.setToolTip(textwrap.dedent(c.HELP)) diff --git a/src/calibre/gui2/dialogs/search.py b/src/calibre/gui2/dialogs/search.py index 1bc27dfb21..0a3ebd278a 100644 --- a/src/calibre/gui2/dialogs/search.py +++ b/src/calibre/gui2/dialogs/search.py @@ -19,7 +19,7 @@ from calibre.utils.icu import sort_key from calibre.utils.config import tweaks from calibre.utils.date import now from calibre.utils.localization import localize_user_manual_link -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range box_values = {} last_matchkind = CONTAINS_MATCH @@ -174,7 +174,7 @@ def create_date_tab(self, db): w.h1 = h = QHBoxLayout() l.addLayout(h) self.date_field = df = add(_("&Search the"), QComboBox(w)) - vals = [((v['search_terms'] or [k])[0], v['name'] or k) for k, v in db.field_metadata.iteritems() if v.get('datatype', None) == 'datetime'] + vals = [((v['search_terms'] or [k])[0], v['name'] or k) for k, v in iteritems(db.field_metadata) if v.get('datatype', None) == 'datetime'] for k, v in sorted(vals, key=lambda k_v: sort_key(k_v[1])): df.addItem(v, k) h.addWidget(df) diff --git a/src/calibre/gui2/dialogs/smartdevice.py b/src/calibre/gui2/dialogs/smartdevice.py index 57b5ad55c3..324f9af2fe 100644 --- a/src/calibre/gui2/dialogs/smartdevice.py +++ b/src/calibre/gui2/dialogs/smartdevice.py @@ -10,7 +10,7 @@ from PyQt5.Qt import (QDialog, QLineEdit, Qt) from calibre.gui2 import error_dialog from calibre.gui2.dialogs.smartdevice_ui import Ui_Dialog from calibre.utils.mdns import get_all_ips -from polyglot.builtins import unicode_type +from polyglot.builtins import itervalues, unicode_type def _cmp_ipaddr(l, r): @@ -30,7 +30,7 @@ def _cmp_ipaddr(l, r): def get_all_ip_addresses(): ipaddrs = list() - for iface in get_all_ips().itervalues(): + for iface in itervalues(get_all_ips()): for addrs in iface: if 'broadcast' in addrs and addrs['addr'] != '127.0.0.1': ipaddrs.append(addrs['addr']) diff --git a/src/calibre/gui2/dialogs/tag_categories.py b/src/calibre/gui2/dialogs/tag_categories.py index 783a513bec..52756a5a8a 100644 --- a/src/calibre/gui2/dialogs/tag_categories.py +++ b/src/calibre/gui2/dialogs/tag_categories.py @@ -10,7 +10,7 @@ from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2 import error_dialog from calibre.constants import islinux from calibre.utils.icu import sort_key, strcmp -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class Item(object): @@ -69,7 +69,7 @@ class TagCategories(QDialog, Ui_TagCategories): ] category_names = ['', _('Authors'), ngettext('Series', 'Series', 2), _('Publishers'), _('Tags')] - for key,cc in self.db.custom_field_metadata().iteritems(): + for key,cc in iteritems(self.db.custom_field_metadata()): if cc['datatype'] in ['text', 'series', 'enumeration']: self.category_labels.append(key) self.category_icons.append(cc_icon) diff --git a/src/calibre/gui2/email.py b/src/calibre/gui2/email.py index f24f131923..3fcfc9696a 100644 --- a/src/calibre/gui2/email.py +++ b/src/calibre/gui2/email.py @@ -28,7 +28,7 @@ from calibre.library.save_to_disk import get_components from calibre.utils.config import tweaks, prefs from calibre.utils.icu import primary_sort_key from calibre.gui2.threaded_jobs import ThreadedJob -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, itervalues, unicode_type class Worker(Thread): @@ -321,7 +321,7 @@ class EmailMixin(object): # {{{ for to, fmts, subject in recipients: rfmts = set(fmts) - ok_ids = {book_id for book_id, bfmts in db_fmt_map.iteritems() if bfmts.intersection(rfmts)} + ok_ids = {book_id for book_id, bfmts in iteritems(db_fmt_map) if bfmts.intersection(rfmts)} convert_ids = ids - ok_ids self.send_by_mail(to, fmts, delete_from_library, subject=subject, send_ids=ok_ids, do_auto_convert=False) if not rfmts.intersection(ofmts): @@ -336,20 +336,20 @@ class EmailMixin(object): # {{{ auto_convert_map[outfmt].append((to, subject, ok_ids)) if auto_convert_map: - titles = {book_id for x in auto_convert_map.itervalues() for data in x for book_id in data[2]} + titles = {book_id for x in itervalues(auto_convert_map) for data in x for book_id in data[2]} titles = {db.title(book_id, index_is_id=True) for book_id in titles} if self.auto_convert_question( _('Auto convert the following books before sending via email?'), list(titles)): - for ofmt, data in auto_convert_map.iteritems(): + for ofmt, data in iteritems(auto_convert_map): ids = {bid for x in data for bid in x[2]} data = [(to, subject) for to, subject, x in data] self.iactions['Convert Books'].auto_convert_multiple_mail(ids, data, ofmt, delete_from_library) if bad_recipients: det_msg = [] - titles = {book_id for x in bad_recipients.itervalues() for book_id in x[0]} + titles = {book_id for x in itervalues(bad_recipients) for book_id in x[0]} titles = {book_id:db.title(book_id, index_is_id=True) for book_id in titles} - for to, (ids, nooutput) in bad_recipients.iteritems(): + for to, (ids, nooutput) in iteritems(bad_recipients): msg = _('This recipient has no valid formats defined') if nooutput else \ _('These books have no suitable input formats for conversion') det_msg.append('%s - %s' % (to, msg)) @@ -506,4 +506,4 @@ class EmailMixin(object): # {{{ if __name__ == '__main__': from PyQt5.Qt import QApplication app = QApplication([]) # noqa - print (select_recipients()) + print(select_recipients()) diff --git a/src/calibre/gui2/gestures.py b/src/calibre/gui2/gestures.py index 81afadbbd8..b841e19c98 100644 --- a/src/calibre/gui2/gestures.py +++ b/src/calibre/gui2/gestures.py @@ -12,6 +12,7 @@ from PyQt5.Qt import ( from calibre.constants import iswindows from calibre.utils.monotonic import monotonic +from polyglot.builtins import itervalues touch_supported = False if iswindows and sys.getwindowsversion()[:2] >= (6, 2): # At least windows 7 @@ -91,14 +92,14 @@ class State(QObject): else: self.check_for_holds() if Flick in self.possible_gestures: - tp = next(self.touch_points.itervalues()) + tp = next(itervalues(self.touch_points)) self.flicking.emit(tp, False) def check_for_holds(self): if not {TapAndHold} & self.possible_gestures: return now = monotonic() - tp = next(self.touch_points.itervalues()) + tp = next(itervalues(self.touch_points)) if now - tp.time_of_last_move < HOLD_THRESHOLD: return if self.hold_started: @@ -116,20 +117,20 @@ class State(QObject): def finalize(self): if Tap in self.possible_gestures: - tp = next(self.touch_points.itervalues()) + tp = next(itervalues(self.touch_points)) if tp.total_movement <= TAP_THRESHOLD: self.tapped.emit(tp) return if Flick in self.possible_gestures: - tp = next(self.touch_points.itervalues()) + tp = next(itervalues(self.touch_points)) self.flicking.emit(tp, True) if not self.hold_started: return if TapAndHold in self.possible_gestures: - tp = next(self.touch_points.itervalues()) + tp = next(itervalues(self.touch_points)) self.tap_hold_finished.emit(tp) return diff --git a/src/calibre/gui2/icon_theme.py b/src/calibre/gui2/icon_theme.py index 495a5c2969..d8d6b839bc 100644 --- a/src/calibre/gui2/icon_theme.py +++ b/src/calibre/gui2/icon_theme.py @@ -9,12 +9,9 @@ __copyright__ = '2015, Kovid Goyal ' import os, errno, json, importlib, math, httplib, bz2, shutil, sys from itertools import count from io import BytesIO -from polyglot.builtins import map from threading import Thread, Event from multiprocessing.pool import ThreadPool -from polyglot.builtins import reraise, range - from PyQt5.Qt import ( QImageReader, QFormLayout, QVBoxLayout, QSplitter, QGroupBox, QListWidget, QLineEdit, QSpinBox, QTextEdit, QSize, QListWidgetItem, QIcon, QImage, @@ -39,6 +36,7 @@ from calibre.utils.zipfile import ZipFile, ZIP_STORED from calibre.utils.filenames import atomic_rename from lzma.xz import compress, decompress from polyglot.queue import Queue, Empty +from polyglot.builtins import iteritems, iterkeys, map, range, reraise IMAGE_EXTENSIONS = {'png', 'jpg', 'jpeg'} THEME_COVER = 'icon-theme-cover.jpg' @@ -191,7 +189,7 @@ def create_cover(report, icons=(), cols=5, size=120, padding=16): def verify_theme(report): must_use_qt() report.bad = bad = {} - for name, path in report.name_map.iteritems(): + for name, path in iteritems(report.name_map): reader = QImageReader(os.path.join(report.path, path)) img = reader.read() if img.isNull(): @@ -364,7 +362,7 @@ def create_themeball(report, progress=None, abort=None): except Exception: return sys.exc_info() - errors = tuple(filter(None, pool.map(optimize, tuple(report.name_map.iterkeys())))) + errors = tuple(filter(None, pool.map(optimize, tuple(iterkeys(report.name_map))))) pool.close(), pool.join() if abort is not None and abort.is_set(): return diff --git a/src/calibre/gui2/keyboard.py b/src/calibre/gui2/keyboard.py index 5d1254bc0e..f1ce68232f 100644 --- a/src/calibre/gui2/keyboard.py +++ b/src/calibre/gui2/keyboard.py @@ -26,7 +26,7 @@ from calibre.utils.icu import sort_key, lower from calibre.gui2 import error_dialog, info_dialog from calibre.utils.search_query_parser import SearchQueryParser, ParseException from calibre.gui2.search_box import SearchBox2 -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, itervalues, unicode_type, range ROOT = QModelIndex() @@ -60,7 +60,7 @@ def finalize(shortcuts, custom_keys_map={}): # {{{ correctly for each shortcut. ''' seen, keys_map = {}, {} - for unique_name, shortcut in shortcuts.iteritems(): + for unique_name, shortcut in iteritems(shortcuts): custom_keys = custom_keys_map.get(unique_name, None) if custom_keys is None: candidates = shortcut['default_keys'] @@ -142,15 +142,15 @@ class Manager(QObject): # {{{ done unregistering. ''' self.shortcuts.pop(unique_name, None) - for group in self.groups.itervalues(): + for group in itervalues(self.groups): try: group.remove(unique_name) except ValueError: pass def finalize(self): - custom_keys_map = {un:tuple(keys) for un, keys in self.config.get( - 'map', {}).iteritems()} + custom_keys_map = {un:tuple(keys) for un, keys in iteritems(self.config.get( + 'map', {}))} self.keys_map = finalize(self.shortcuts, custom_keys_map=custom_keys_map) def replace_action(self, unique_name, new_action): @@ -198,16 +198,16 @@ class ConfigModel(SearchQueryParser, QAbstractItemModel): self.keyboard = keyboard groups = sorted(keyboard.groups, key=sort_key) shortcut_map = {k:v.copy() for k, v in - self.keyboard.shortcuts.iteritems()} - for un, s in shortcut_map.iteritems(): + iteritems(self.keyboard.shortcuts)} + for un, s in iteritems(shortcut_map): s['keys'] = tuple(self.keyboard.keys_map.get(un, ())) s['unique_name'] = un - s['group'] = [g for g, names in self.keyboard.groups.iteritems() if un in + s['group'] = [g for g, names in iteritems(self.keyboard.groups) if un in names][0] group_map = {group:sorted(names, key=lambda x: sort_key(shortcut_map[x]['name'])) for group, names in - self.keyboard.groups.iteritems()} + iteritems(self.keyboard.groups)} self.data = [Node(group_map, shortcut_map, group) for group in groups] diff --git a/src/calibre/gui2/languages.py b/src/calibre/gui2/languages.py index 1f7ce4f0fd..70c4302a9d 100644 --- a/src/calibre/gui2/languages.py +++ b/src/calibre/gui2/languages.py @@ -11,7 +11,7 @@ from calibre.gui2 import gui_prefs from calibre.gui2.complete2 import EditWithComplete from calibre.utils.localization import lang_map_for_ui from calibre.utils.icu import sort_key, lower -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, itervalues, unicode_type class LanguagesEdit(EditWithComplete): @@ -24,15 +24,15 @@ class LanguagesEdit(EditWithComplete): self.setSizeAdjustPolicy(self.AdjustToMinimumContentsLengthWithIcon) self.setMinimumContentsLength(20) self._lang_map = lang_map_for_ui() - self.names_with_commas = [x for x in self._lang_map.itervalues() if ',' in x] + self.names_with_commas = [x for x in itervalues(self._lang_map) if ',' in x] self.comma_map = {k:k.replace(',', '|') for k in self.names_with_commas} - self.comma_rmap = {v:k for k, v in self.comma_map.iteritems()} - self._rmap = {lower(v):k for k,v in self._lang_map.iteritems()} + self.comma_rmap = {v:k for k, v in iteritems(self.comma_map)} + self._rmap = {lower(v):k for k,v in iteritems(self._lang_map)} self.init_langs(db) self.item_selected.connect(self.update_recently_used) def init_langs(self, db): - self.update_items_cache(self._lang_map.itervalues()) + self.update_items_cache(itervalues(self._lang_map)) def refresh_recently_used(self): recently_used = self.prefs.get('recently_used_languages') or () @@ -55,7 +55,7 @@ class LanguagesEdit(EditWithComplete): @property def vals(self): raw = unicode_type(self.lineEdit().text()) - for k, v in self.comma_map.iteritems(): + for k, v in iteritems(self.comma_map): raw = raw.replace(k, v) parts = [x.strip() for x in raw.split(',')] return [self.comma_rmap.get(x, x) for x in parts] diff --git a/src/calibre/gui2/library/alternate_views.py b/src/calibre/gui2/library/alternate_views.py index bab59f60d1..ff46e97ba8 100644 --- a/src/calibre/gui2/library/alternate_views.py +++ b/src/calibre/gui2/library/alternate_views.py @@ -29,7 +29,7 @@ from calibre.gui2 import gprefs, config, rating_font, empty_index from calibre.gui2.gestures import GestureManager from calibre.gui2.library.caches import CoverCache, ThumbnailCache from calibre.utils.config import prefs, tweaks -from polyglot.builtins import unicode_type, range +from polyglot.builtins import itervalues, unicode_type, range from polyglot.queue import LifoQueue CM_TO_INCH = 0.393701 @@ -327,7 +327,7 @@ class AlternateViews(object): view.setFocus(Qt.OtherFocusReason) def set_database(self, db, stage=0): - for view in self.views.itervalues(): + for view in itervalues(self.views): if view is not self.main_view: view.set_database(db, stage=stage) @@ -356,7 +356,7 @@ class AlternateViews(object): self.current_view.select_rows(rows) def set_context_menu(self, menu): - for view in self.views.itervalues(): + for view in itervalues(self.views): if view is not self.main_view: view.set_context_menu(menu) @@ -957,7 +957,7 @@ class GridView(QListView): # rendered, but this is better than a deadlock join_with_timeout(self.delegate.render_queue) except RuntimeError: - print ('Cover rendering thread is stuck!') + print('Cover rendering thread is stuck!') finally: self.ignore_render_requests.clear() else: diff --git a/src/calibre/gui2/library/caches.py b/src/calibre/gui2/library/caches.py index 6f5034ef95..dd0b925003 100644 --- a/src/calibre/gui2/library/caches.py +++ b/src/calibre/gui2/library/caches.py @@ -12,6 +12,7 @@ from collections import OrderedDict from PyQt5.Qt import QImage, QPixmap from calibre.db.utils import ThumbnailCache as TC +from polyglot.builtins import interkeys, itervalues class ThumbnailCache(TC): @@ -45,7 +46,7 @@ class CoverCache(dict): def _pop(self, book_id): val = self.items.pop(book_id, None) - if type(val) is QPixmap and current_thread() is not self.gui_thread: + if isinstance(val, QPixmap) and current_thread() is not self.gui_thread: self.pixmap_staging.append(val) def __getitem__(self, key): @@ -54,7 +55,7 @@ class CoverCache(dict): self.clear_staging() ans = self.items.pop(key, False) # pop() so that item is moved to the top if ans is not False: - if type(ans) is QImage: + if isinstance(ans, QImage): # Convert to QPixmap, since rendering QPixmap is much # faster ans = QPixmap.fromImage(ans) @@ -67,12 +68,12 @@ class CoverCache(dict): self._pop(key) # pop() so that item is moved to the top self.items[key] = val if len(self.items) > self.limit: - del self.items[next(self.items.iterkeys())] + del self.items[next(iterkeys(self.items))] def clear(self): with self.lock: if current_thread() is not self.gui_thread: - pixmaps = (x for x in self.items.itervalues() if type(x) is QPixmap) + pixmaps = (x for x in itervalues(self.items) if isinstance(x, QPixmap)) self.pixmap_staging.extend(pixmaps) self.items.clear() @@ -84,8 +85,6 @@ class CoverCache(dict): self.limit = limit if len(self.items) > self.limit: extra = len(self.items) - self.limit - remove = tuple(self.iterkeys())[:extra] + remove = tuple(iterkeys(self))[:extra] for k in remove: self._pop(k) - - diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index f203a3de30..b36f91798c 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -30,7 +30,7 @@ from calibre.constants import filesystem_encoding, DEBUG, config_dir from calibre.gui2.library import DEFAULT_SORT from calibre.utils.localization import calibre_langcode_to_name from calibre.library.coloring import color_row_key -from polyglot.builtins import unicode_type, string_or_bytes, range +from polyglot.builtins import iteritems, itervalues, unicode_type, string_or_bytes, range Counts = namedtuple('Counts', 'library_total total current') @@ -307,7 +307,7 @@ class BooksModel(QAbstractTableModel): # {{{ if db: style_map = {'bold': self.bold_font, 'bi': self.bi_font, 'italic': self.italic_font} - self.styled_columns = {k: style_map.get(v, None) for k, v in db.new_api.pref('styled_columns', {}).iteritems()} + self.styled_columns = {k: style_map.get(v, None) for k, v in iteritems(db.new_api.pref('styled_columns', {}))} self.alignment_map = {} self.ids_to_highlight_set = set() self.current_highlighted_idx = None @@ -509,7 +509,7 @@ class BooksModel(QAbstractTableModel): # {{{ self._sort(label, order, reset) def sort_by_named_field(self, field, order, reset=True): - if field in self.db.field_metadata.keys(): + if field in list(self.db.field_metadata.keys()): self._sort(field, order, reset) def _sort(self, label, order, reset): @@ -879,7 +879,7 @@ class BooksModel(QAbstractTableModel): # {{{ ans += '.5' return _('%s stars') % ans return f - for f, allow_half in rating_fields.iteritems(): + for f, allow_half in iteritems(rating_fields): tc[f] = stars_tooltip(self.dc[f], allow_half) # build a index column to data converter map, to remove the string lookup in the data loop self.column_to_dc_map = [self.dc[col] for col in self.column_map] @@ -1400,7 +1400,7 @@ class DeviceBooksModel(BooksModel): # {{{ return False path = getattr(item, 'path', None) - for items in self.marked_for_deletion.itervalues(): + for items in itervalues(self.marked_for_deletion): for x in items: if x is item or (path and path == getattr(x, 'path', None)): return True diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 57c31b6c4d..a49f7c778f 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import itertools, operator from functools import partial -from polyglot.builtins import map, unicode_type, range +from polyglot.builtins import iteritems, map, unicode_type, range from collections import OrderedDict from PyQt5.Qt import ( @@ -194,7 +194,7 @@ class PreserveViewState(object): # {{{ 'vscroll', 'hscroll')} def fset(self, state): - for k, v in state.iteritems(): + for k, v in iteritems(state): setattr(self, k, v) self.__exit__() return property(fget=fget, fset=fset) @@ -465,7 +465,7 @@ class BooksView(QTableView): # {{{ ans.addSeparator() if hidden_cols: m = ans.addMenu(_('Show column')) - hcols = [(hcol, unicode_type(self.model().headerData(hidx, Qt.Horizontal, Qt.DisplayRole) or '')) for hcol, hidx in hidden_cols.iteritems()] + hcols = [(hcol, unicode_type(self.model().headerData(hidx, Qt.Horizontal, Qt.DisplayRole) or '')) for hcol, hidx in iteritems(hidden_cols)] hcols.sort(key=lambda x: primary_sort_key(x[1])) for hcol, hname in hcols: m.addAction(hname, partial(handler, action='show', column=hcol)) @@ -576,7 +576,7 @@ class BooksView(QTableView): # {{{ return for n,d in reversed(fields): - if n in self._model.db.field_metadata.keys(): + if n in list(self._model.db.field_metadata.keys()): sh.insert(0, (n, d)) sh = self.cleanup_sort_history(sh, ignore_column_map=True) self._model.sort_history = [tuple(x) for x in sh] diff --git a/src/calibre/gui2/lrf_renderer/document.py b/src/calibre/gui2/lrf_renderer/document.py index 6611eb3bc3..644f4d9e17 100644 --- a/src/calibre/gui2/lrf_renderer/document.py +++ b/src/calibre/gui2/lrf_renderer/document.py @@ -521,10 +521,9 @@ class Document(QGraphicsScene): self.next_match() def next_match(self): - page_num = self.last_search.next()[0] + page_num = next(self.last_search)[0] if self.current_page == page_num: self.update() else: self.add_to_history() self.show_page(page_num) - diff --git a/src/calibre/gui2/lrf_renderer/text.py b/src/calibre/gui2/lrf_renderer/text.py index d86a5e92b2..a8c59c7561 100644 --- a/src/calibre/gui2/lrf_renderer/text.py +++ b/src/calibre/gui2/lrf_renderer/text.py @@ -532,12 +532,12 @@ class Line(QGraphicsItem): matches = [] try: while True: - word = words.next() + word = next(words) word.highlight = False if tokens[0] in unicode_type(word.string).lower(): matches.append(word) for c in range(1, len(tokens)): - word = words.next() + word = next(words) print(tokens[c], word.string) if tokens[c] not in unicode_type(word.string): return None diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index 3dac5c5893..1bf2148fd1 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -41,7 +41,7 @@ from calibre.ptempfile import PersistentTemporaryFile, SpooledTemporaryFile from calibre.gui2.languages import LanguagesEdit as LE from calibre.db import SPOOL_SIZE from calibre.ebooks.oeb.polish.main import SUPPORTED as EDIT_SUPPORTED -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range OK_COLOR = 'rgba(0, 255, 0, 12%)' ERR_COLOR = 'rgba(255, 0, 0, 12%)' @@ -1594,7 +1594,7 @@ class IdentifiersEdit(QLineEdit, ToMetadataMixin): v = check_isbn(k) if v is not None: val[k] = v - ids = sorted(val.iteritems(), key=keygen) + ids = sorted(iteritems(val), key=keygen) txt = ', '.join(['%s:%s'%(k.lower(), vl) for k, vl in ids]) # Use selectAll + insert instead of setText so that undo works self.selectAll(), self.insert(txt.strip()) diff --git a/src/calibre/gui2/metadata/bulk_download.py b/src/calibre/gui2/metadata/bulk_download.py index e92a59b063..e2b4de5154 100644 --- a/src/calibre/gui2/metadata/bulk_download.py +++ b/src/calibre/gui2/metadata/bulk_download.py @@ -18,6 +18,7 @@ from calibre.ebooks.metadata.opf2 import metadata_to_opf from calibre.utils.ipc.simple_worker import fork_job, WorkerError from calibre.ptempfile import (PersistentTemporaryDirectory, PersistentTemporaryFile) +from polyglot.builtins import iteritems # Start download {{{ @@ -244,7 +245,7 @@ def download(all_ids, tf, db, do_identify, covers, ensure_fields, title_map[i] = metadata[i].title lm_map[i] = metadata[i].last_modified metadata = {i:metadata_to_opf(mi, default_lang='und') for i, mi in - metadata.iteritems()} + iteritems(metadata)} try: ret = fork_job('calibre.ebooks.metadata.sources.worker', 'main', (do_identify, covers, metadata, ensure_fields, tdir), diff --git a/src/calibre/gui2/metadata/config.py b/src/calibre/gui2/metadata/config.py index 1f5ae83243..fa72f7892d 100644 --- a/src/calibre/gui2/metadata/config.py +++ b/src/calibre/gui2/metadata/config.py @@ -14,7 +14,7 @@ from PyQt5.Qt import (QWidget, QGridLayout, QGroupBox, QListView, Qt, QSpinBox, from calibre.gui2.preferences.metadata_sources import FieldsModel as FM from calibre.utils.icu import sort_key -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class FieldsModel(FM): # {{{ @@ -48,7 +48,7 @@ class FieldsModel(FM): # {{{ def commit(self): ignored_fields = {x for x in self.prefs['ignore_fields'] if x not in self.overrides} - changed = {k for k, v in self.overrides.iteritems() if v == + changed = {k for k, v in iteritems(self.overrides) if v == Qt.Unchecked} self.prefs['ignore_fields'] = list(ignored_fields.union(changed)) @@ -101,7 +101,7 @@ class ConfigWidget(QWidget): widget.setChecked(bool(val)) elif opt.type == 'choices': widget = QComboBox(self) - items = list(opt.choices.iteritems()) + items = list(iteritems(opt.choices)) items.sort(key=lambda k_v: sort_key(k_v[1])) for key, label in items: widget.addItem(label, (key)) diff --git a/src/calibre/gui2/metadata/diff.py b/src/calibre/gui2/metadata/diff.py index 286feaa2fd..9f5b1fe9b6 100644 --- a/src/calibre/gui2/metadata/diff.py +++ b/src/calibre/gui2/metadata/diff.py @@ -9,7 +9,7 @@ __copyright__ = '2013, Kovid Goyal ' import os, weakref from collections import OrderedDict, namedtuple from functools import partial -from polyglot.builtins import zip, unicode_type, range +from polyglot.builtins import iteritems, itervalues, zip, unicode_type, range from PyQt5.Qt import ( QDialog, QWidget, QGridLayout, QLabel, QToolButton, QIcon, @@ -245,10 +245,10 @@ class IdentifiersEdit(LineEdit): def as_dict(self): def fget(self): parts = (x.strip() for x in self.current_val.split(',') if x.strip()) - return {k:v for k, v in {x.partition(':')[0].strip():x.partition(':')[-1].strip() for x in parts}.iteritems() if k and v} + return {k:v for k, v in iteritems({x.partition(':')[0].strip():x.partition(':')[-1].strip() for x in parts}) if k and v} def fset(self, val): - val = ('%s:%s' % (k, v) for k, v in val.iteritems()) + val = ('%s:%s' % (k, v) for k, v in iteritems(val)) self.setText(', '.join(val)) self.setCursorPosition(0) return property(fget=fget, fset=fset) @@ -519,14 +519,14 @@ class CompareSingle(QWidget): def __call__(self, oldmi, newmi): self.current_mi = newmi self.initial_vals = {} - for field, widgets in self.widgets.iteritems(): + for field, widgets in iteritems(self.widgets): widgets.old.from_mi(oldmi) widgets.new.from_mi(newmi) self.initial_vals[field] = widgets.new.current_val def apply_changes(self): changed = False - for field, widgets in self.widgets.iteritems(): + for field, widgets in iteritems(self.widgets): val = widgets.new.current_val if val != self.initial_vals[field]: widgets.new.to_mi(self.current_mi) @@ -701,6 +701,6 @@ if __name__ == '__main__': get_metadata = lambda x:map(gm, ids[x]) d = CompareMany(list(range(len(ids))), get_metadata, db.field_metadata, db=db) if d.exec_() == d.Accepted: - for changed, mi in d.accepted.itervalues(): + for changed, mi in itervalues(d.accepted): if changed and mi is not None: print(mi) diff --git a/src/calibre/gui2/metadata/single.py b/src/calibre/gui2/metadata/single.py index d1c4131302..b06fe83e41 100644 --- a/src/calibre/gui2/metadata/single.py +++ b/src/calibre/gui2/metadata/single.py @@ -31,6 +31,7 @@ from calibre.ebooks.metadata.book.base import Metadata from calibre.utils.localization import canonicalize_lang from calibre.utils.date import local_tz from calibre.library.comments import merge_comments as merge_two_comments +from polyglot.builtins import iteritems BASE_TITLE = _('Edit Metadata') fetched_fields = ('title', 'title_sort', 'authors', 'author_sort', 'series', @@ -555,7 +556,7 @@ class MetadataSingleDialogBase(QDialog): if self.metadata_before_fetch is None: return error_dialog(self, _('No downloaded metadata'), _( 'There is no downloaded metadata to undo'), show=True) - for field, val in self.metadata_before_fetch.iteritems(): + for field, val in iteritems(self.metadata_before_fetch): getattr(self, field).current_val = val self.metadata_before_fetch = None @@ -710,7 +711,7 @@ class MetadataSingleDialogBase(QDialog): self.button_box.button(self.button_box.Ok).setDefault(True) self.button_box.button(self.button_box.Ok).setFocus(Qt.OtherFocusReason) self(self.db.id(self.row_list[self.current_row])) - for w, state in self.comments_edit_state_at_apply.iteritems(): + for w, state in iteritems(self.comments_edit_state_at_apply): if state == 'code': w.tab = 'code' diff --git a/src/calibre/gui2/metadata/single_download.py b/src/calibre/gui2/metadata/single_download.py index fe51133577..5d73912cd0 100644 --- a/src/calibre/gui2/metadata/single_download.py +++ b/src/calibre/gui2/metadata/single_download.py @@ -39,7 +39,7 @@ from calibre import force_unicode from calibre.utils.config import tweaks from calibre.utils.ipc.simple_worker import fork_job, WorkerError from calibre.ptempfile import TemporaryDirectory -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, itervalues, unicode_type, range from polyglot.queue import Queue, Empty # }}} @@ -509,7 +509,7 @@ class IdentifyWidget(QWidget): # {{{ parts.append('authors:'+authors_to_string(authors)) simple_desc += _('Authors: %s ') % authors_to_string(authors) if identifiers: - x = ', '.join('%s:%s'%(k, v) for k, v in identifiers.iteritems()) + x = ', '.join('%s:%s'%(k, v) for k, v in iteritems(identifiers)) parts.append(x) if 'isbn' in identifiers: simple_desc += 'ISBN: %s' % identifiers['isbn'] @@ -689,7 +689,7 @@ class CoversModel(QAbstractListModel): # {{{ def plugin_for_index(self, index): row = index.row() if hasattr(index, 'row') else index - for k, v in self.plugin_map.iteritems(): + for k, v in iteritems(self.plugin_map): if row in v: return k @@ -750,7 +750,7 @@ class CoversModel(QAbstractListModel): # {{{ if pmap.isNull(): return self.beginInsertRows(QModelIndex(), last_row, last_row) - for rows in self.plugin_map.itervalues(): + for rows in itervalues(self.plugin_map): for i in range(len(rows)): if rows[i] >= last_row: rows[i] += 1 @@ -760,7 +760,7 @@ class CoversModel(QAbstractListModel): # {{{ else: # single cover plugin idx = None - for plugin, rows in self.plugin_map.iteritems(): + for plugin, rows in iteritems(self.plugin_map): if plugin.name == plugin_name: idx = rows[0] break diff --git a/src/calibre/gui2/open_with.py b/src/calibre/gui2/open_with.py index 725b7af0c6..9b47f6a619 100644 --- a/src/calibre/gui2/open_with.py +++ b/src/calibre/gui2/open_with.py @@ -22,7 +22,7 @@ from calibre.gui2.widgets2 import Dialog from calibre.gui2.progress_indicator import ProgressIndicator from calibre.utils.config import JSONConfig from calibre.utils.icu import numeric_sort_key as sort_key -from polyglot.builtins import string_or_bytes, range +from polyglot.builtins import iteritems, string_or_bytes, range ENTRY_ROLE = Qt.UserRole @@ -431,12 +431,12 @@ def register_keyboard_shortcuts(gui=None, finalize=False): gui = get_gui() if gui is None: return - for unique_name, action in registered_shortcuts.iteritems(): + for unique_name, action in iteritems(registered_shortcuts): gui.keyboard.unregister_shortcut(unique_name) gui.removeAction(action) registered_shortcuts.clear() - for filetype, applications in oprefs['entries'].iteritems(): + for filetype, applications in iteritems(oprefs['entries']): for application in applications: text = entry_to_icon_text(application, only_text=True) t = _('cover image') if filetype.upper() == 'COVER_IMAGE' else filetype.upper() diff --git a/src/calibre/gui2/preferences/behavior.py b/src/calibre/gui2/preferences/behavior.py index b9a1fcfd47..5acc1ffd2b 100644 --- a/src/calibre/gui2/preferences/behavior.py +++ b/src/calibre/gui2/preferences/behavior.py @@ -18,7 +18,7 @@ from calibre.ebooks import BOOK_EXTENSIONS from calibre.ebooks.oeb.iterator import is_supported from calibre.constants import iswindows from calibre.utils.icu import sort_key -from polyglot.builtins import unicode_type +from polyglot.builtins import iterkeys, unicode_type class OutputFormatSetting(Setting): @@ -50,7 +50,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): choices = [(x.upper(), x) for x in output_formats] r('output_format', prefs, choices=choices, setting=OutputFormatSetting) - restrictions = sorted(db.prefs['virtual_libraries'].iterkeys(), key=sort_key) + restrictions = sorted(iterkeys(db.prefs['virtual_libraries']), key=sort_key) choices = [('', '')] + [(x, x) for x in restrictions] # check that the virtual library still exists vls = db.prefs['virtual_lib_on_startup'] diff --git a/src/calibre/gui2/preferences/coloring.py b/src/calibre/gui2/preferences/coloring.py index ee14634c1b..16ed941465 100644 --- a/src/calibre/gui2/preferences/coloring.py +++ b/src/calibre/gui2/preferences/coloring.py @@ -26,7 +26,7 @@ from calibre.library.coloring import (Rule, conditionable_columns, displayable_columns, rule_from_template, color_row_key) from calibre.utils.localization import lang_map from calibre.utils.icu import lower -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type all_columns_string = _('All columns') @@ -172,7 +172,7 @@ class ConditionEditor(QWidget): # {{{ def current_val(self): ans = unicode_type(self.value_box.text()).strip() if self.current_col == 'languages': - rmap = {lower(v):k for k, v in lang_map().iteritems()} + rmap = {lower(v):k for k, v in iteritems(lang_map())} ans = rmap.get(lower(ans), ans) return ans @@ -1130,8 +1130,8 @@ if __name__ == '__main__': kind, col, r = d.rule print('Column to be colored:', col) - print ('Template:') - print (r.template) + print('Template:') + print(r.template) else: d = EditRules() d.resize(QSize(800, 600)) diff --git a/src/calibre/gui2/preferences/create_custom_column.py b/src/calibre/gui2/preferences/create_custom_column.py index a67fe945e7..2fc4100cbc 100644 --- a/src/calibre/gui2/preferences/create_custom_column.py +++ b/src/calibre/gui2/preferences/create_custom_column.py @@ -16,7 +16,7 @@ from PyQt5.Qt import ( ) from calibre.gui2 import error_dialog -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class CreateCustomColumn(QDialog): @@ -86,7 +86,7 @@ class CreateCustomColumn(QDialog): 'is_multiple':True }, ))) - column_types_map = {k['datatype']:idx for idx, k in column_types.iteritems()} + column_types_map = {k['datatype']:idx for idx, k in iteritems(column_types)} def __init__(self, parent, current_row, current_key, standard_colheads, standard_colnames): QDialog.__init__(self, parent) diff --git a/src/calibre/gui2/preferences/ignored_devices.py b/src/calibre/gui2/preferences/ignored_devices.py index b0ecce5bcd..1e5ecb5d24 100644 --- a/src/calibre/gui2/preferences/ignored_devices.py +++ b/src/calibre/gui2/preferences/ignored_devices.py @@ -12,7 +12,7 @@ from PyQt5.Qt import (QLabel, QVBoxLayout, QListWidget, QListWidgetItem, Qt, from calibre.customize.ui import enable_plugin from calibre.gui2.preferences import ConfigWidgetBase, test_widget -from polyglot.builtins import range +from polyglot.builtins import iteritems, range class ConfigWidget(ConfigWidgetBase): @@ -55,7 +55,7 @@ class ConfigWidget(ConfigWidgetBase): self.devices.blockSignals(True) self.devices.clear() for dev in self.gui.device_manager.devices: - for d, name in dev.get_user_blacklisted_devices().iteritems(): + for d, name in iteritems(dev.get_user_blacklisted_devices()): item = QListWidgetItem('%s [%s]'%(name, d), self.devices) item.setData(Qt.UserRole, (dev, d)) item.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable|Qt.ItemIsSelectable) @@ -87,7 +87,7 @@ class ConfigWidget(ConfigWidgetBase): if e.checkState() == Qt.Checked: devs[dev].append(uid) - for dev, bl in devs.iteritems(): + for dev, bl in iteritems(devs): dev.set_user_blacklisted_devices(bl) for i in range(self.device_plugins.count()): diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index 0ba64accf0..0fb52d9a97 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -36,7 +36,7 @@ from calibre.gui2.preferences.coloring import EditRules from calibre.gui2.library.alternate_views import auto_height, CM_TO_INCH from calibre.gui2.widgets2 import Dialog from calibre.gui2.actions.show_quickview import get_quickview_action_plugin -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class BusyCursor(object): @@ -159,7 +159,7 @@ class IdLinksEditor(Dialog): la.setWordWrap(True) l.addWidget(la) items = [] - for k, lx in msprefs['id_link_rules'].iteritems(): + for k, lx in iteritems(msprefs['id_link_rules']): for n, t in lx: items.append((k, n, t)) items.sort(key=lambda x:sort_key(x[1])) diff --git a/src/calibre/gui2/preferences/metadata_sources.py b/src/calibre/gui2/preferences/metadata_sources.py index a9ea411bcd..c6eb579ee8 100644 --- a/src/calibre/gui2/preferences/metadata_sources.py +++ b/src/calibre/gui2/preferences/metadata_sources.py @@ -18,6 +18,7 @@ from calibre.ebooks.metadata.sources.prefs import msprefs from calibre.customize.ui import (all_metadata_plugins, is_disabled, enable_plugin, disable_plugin, default_disabled_plugins) from calibre.gui2 import error_dialog, question_dialog +from polyglot.builtins import iteritems class SourcesModel(QAbstractTableModel): # {{{ @@ -117,7 +118,7 @@ class SourcesModel(QAbstractTableModel): # {{{ return Qt.ItemIsEditable | ans def commit(self): - for plugin, val in self.enabled_overrides.iteritems(): + for plugin, val in iteritems(self.enabled_overrides): if val == Qt.Checked: enable_plugin(plugin) elif val == Qt.Unchecked: @@ -125,7 +126,7 @@ class SourcesModel(QAbstractTableModel): # {{{ if self.cover_overrides: cp = msprefs['cover_priorities'] - for plugin, val in self.cover_overrides.iteritems(): + for plugin, val in iteritems(self.cover_overrides): if val == 1: cp.pop(plugin.name, None) else: @@ -235,7 +236,7 @@ class FieldsModel(QAbstractListModel): # {{{ def commit(self): ignored_fields = {x for x in msprefs['ignore_fields'] if x not in self.overrides} - changed = {k for k, v in self.overrides.iteritems() if v == + changed = {k for k, v in iteritems(self.overrides) if v == Qt.Unchecked} msprefs['ignore_fields'] = list(ignored_fields.union(changed)) @@ -251,7 +252,7 @@ class FieldsModel(QAbstractListModel): # {{{ def commit_user_defaults(self): default_ignored_fields = {x for x in msprefs['user_default_ignore_fields'] if x not in self.overrides} - changed = {k for k, v in self.overrides.iteritems() if v == + changed = {k for k, v in iteritems(self.overrides) if v == Qt.Unchecked} msprefs['user_default_ignore_fields'] = list(default_ignored_fields.union(changed)) diff --git a/src/calibre/gui2/preferences/misc.py b/src/calibre/gui2/preferences/misc.py index e6f891d75d..e7dbd1867f 100644 --- a/src/calibre/gui2/preferences/misc.py +++ b/src/calibre/gui2/preferences/misc.py @@ -11,6 +11,7 @@ from calibre.gui2.preferences import ConfigWidgetBase, test_widget, Setting from calibre.gui2.preferences.misc_ui import Ui_Form from calibre.gui2 import (config, open_local_file, gprefs) from calibre import get_proxies +from polyglot.builtins import iteritems class WorkersSetting(Setting): @@ -45,7 +46,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): txt = _('No proxies used') if proxies: lines = ['
%s: %s'%(t, p) for t, p in - proxies.iteritems()] + iteritems(proxies)] txt = _('Using proxies:') + ''.join(lines) self.proxies.setText(txt) @@ -67,8 +68,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): from calibre.utils.config import config_dir open_local_file(config_dir) + if __name__ == '__main__': from PyQt5.Qt import QApplication app = QApplication([]) test_widget('Advanced', 'Misc') - diff --git a/src/calibre/gui2/preferences/plugins.py b/src/calibre/gui2/preferences/plugins.py index 704cbc39c6..a683eccf4d 100644 --- a/src/calibre/gui2/preferences/plugins.py +++ b/src/calibre/gui2/preferences/plugins.py @@ -22,7 +22,7 @@ from calibre.gui2.dialogs.confirm_delete import confirm from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.icu import lower from calibre.constants import iswindows -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, itervalues, unicode_type class AdaptSQP(SearchQueryParser): @@ -438,12 +438,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): if previously_installed: return # If already installed in a GUI container, do nothing - for action_names in installed_actions.itervalues(): + for action_names in itervalues(installed_actions): if plugin_action.name in action_names: return allowed_locations = [(key, text) for key, text in - all_locations.iteritems() if key + iteritems(all_locations) if key not in plugin_action.dont_add_to] if not allowed_locations: return # This plugin doesn't want to live in the GUI diff --git a/src/calibre/gui2/preferences/search.py b/src/calibre/gui2/preferences/search.py index 7384075e02..e919ece61a 100644 --- a/src/calibre/gui2/preferences/search.py +++ b/src/calibre/gui2/preferences/search.py @@ -14,7 +14,7 @@ from calibre.gui2 import config, error_dialog, gprefs from calibre.utils.config import prefs from calibre.utils.icu import sort_key from calibre.library.caches import set_use_primary_find_in_search -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class ConfigWidget(ConfigWidgetBase, Ui_Form): @@ -64,7 +64,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): "a particular item, or to have hierarchical categories (categories " "that contain categories).")) self.gst = db.prefs.get('grouped_search_terms', {}).copy() - self.orig_gst_keys = self.gst.keys() + self.orig_gst_keys = list(self.gst.keys()) fl = [] for f in db.all_field_keys(): @@ -249,7 +249,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): gui.search.do_search() def clear_histories(self, *args): - for key, val in config.defaults.iteritems(): + for key, val in iteritems(config.defaults): if key.endswith('_search_history') and isinstance(val, list): config[key] = [] self.gui.search.clear_history() diff --git a/src/calibre/gui2/preferences/template_functions.py b/src/calibre/gui2/preferences/template_functions.py index e89afe0066..b8e0d49441 100644 --- a/src/calibre/gui2/preferences/template_functions.py +++ b/src/calibre/gui2/preferences/template_functions.py @@ -16,7 +16,7 @@ from calibre.gui2.widgets import PythonHighlighter from calibre.utils.formatter_functions import (formatter_functions, compile_user_function, compile_user_template_functions, load_user_template_functions) -from polyglot.builtins import unicode_type +from polyglot.builtins import iteritems, unicode_type class ConfigWidget(ConfigWidgetBase, Ui_Form): @@ -223,7 +223,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): def commit(self): # formatter_functions().reset_to_builtins() pref_value = [] - for name, cls in self.funcs.iteritems(): + for name, cls in iteritems(self.funcs): if name not in self.builtins: pref_value.append((cls.name, cls.doc, cls.arg_count, cls.program_text)) self.db.new_api.set_pref('user_template_functions', pref_value) diff --git a/src/calibre/gui2/preferences/tweaks.py b/src/calibre/gui2/preferences/tweaks.py index ecff365aaa..bec93d7226 100644 --- a/src/calibre/gui2/preferences/tweaks.py +++ b/src/calibre/gui2/preferences/tweaks.py @@ -19,7 +19,7 @@ from calibre import isbytestring from calibre.utils.icu import lower from calibre.utils.search_query_parser import (ParseException, SearchQueryParser) -from polyglot.builtins import unicode_type, range +from polyglot.builtins import iteritems, iterkeys, unicode_type, range from PyQt5.Qt import ( QAbstractListModel, Qt, QStyledItemDelegate, QStyle, QStyleOptionViewItem, @@ -96,7 +96,7 @@ class Tweak(object): # {{{ for line in self.doc.splitlines(): if line: ans.append('# ' + line) - for key, val in self.default_values.iteritems(): + for key, val in iteritems(self.default_values): val = self.custom_values.get(key, val) ans.append('%s = %r'%(key, val)) ans = '\n'.join(ans) @@ -110,7 +110,7 @@ class Tweak(object): # {{{ @property def is_customized(self): - for x, val in self.default_values.iteritems(): + for x, val in iteritems(self.default_values): if self.custom_values.get(x, val) != val: return True return False @@ -118,7 +118,7 @@ class Tweak(object): # {{{ @property def edit_text(self): ans = ['# %s'%self.name] - for x, val in self.default_values.iteritems(): + for x, val in iteritems(self.default_values): val = self.custom_values.get(x, val) ans.append('%s = %r'%(x, val)) return '\n\n'.join(ans) @@ -161,7 +161,7 @@ class Tweaks(QAbstractListModel, AdaptSQP): # {{{ if tweak.is_customized: tt = '

'+_('This tweak has been customized') tt += '

'
-                for varn, val in tweak.custom_values.iteritems():
+                for varn, val in iteritems(tweak.custom_values):
                     tt += '%s = %r\n\n'%(varn, val)
             return textwrap.fill(tt)
         if role == Qt.UserRole:
@@ -188,8 +188,8 @@ class Tweaks(QAbstractListModel, AdaptSQP):  # {{{
             pos += 1
 
         self.tweaks.sort()
-        default_keys = set(dl.iterkeys())
-        custom_keys = set(l.iterkeys())
+        default_keys = set(iterkeys(dl))
+        custom_keys = set(iterkeys(l))
 
         self.plugin_tweaks = {}
         for key in custom_keys - default_keys:
@@ -264,14 +264,14 @@ class Tweaks(QAbstractListModel, AdaptSQP):  # {{{
         if self.plugin_tweaks:
             ans.extend(['', '',
                 '# The following are tweaks for installed plugins', ''])
-            for key, val in self.plugin_tweaks.iteritems():
+            for key, val in iteritems(self.plugin_tweaks):
                 ans.extend(['%s = %r'%(key, val), '', ''])
         return '\n'.join(ans)
 
     @property
     def plugin_tweaks_string(self):
         ans = []
-        for key, val in self.plugin_tweaks.iteritems():
+        for key, val in iteritems(self.plugin_tweaks):
             ans.extend(['%s = %r'%(key, val), '', ''])
         ans = '\n'.join(ans)
         if isbytestring(ans):
diff --git a/src/calibre/gui2/save.py b/src/calibre/gui2/save.py
index d7a1553496..777e351a6d 100644
--- a/src/calibre/gui2/save.py
+++ b/src/calibre/gui2/save.py
@@ -24,7 +24,7 @@ from calibre.gui2.dialogs.progress import ProgressDialog
 from calibre.utils.formatter_functions import load_user_template_functions
 from calibre.utils.ipc.pool import Pool, Failure
 from calibre.library.save_to_disk import sanitize_args, get_path_components, find_plugboard, plugboard_save_to_disk_value
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, itervalues, unicode_type
 from polyglot.queue import Empty
 
 BookId = namedtuple('BookId', 'title authors')
@@ -33,11 +33,11 @@ BookId = namedtuple('BookId', 'title authors')
 def ensure_unique_components(data):  # {{{
     cmap = defaultdict(set)
     bid_map = {}
-    for book_id, (mi, components, fmts) in data.iteritems():
+    for book_id, (mi, components, fmts) in iteritems(data):
         cmap[tuple(components)].add(book_id)
         bid_map[book_id] = components
 
-    for book_ids in cmap.itervalues():
+    for book_ids in itervalues(cmap):
         if len(book_ids) > 1:
             for i, book_id in enumerate(sorted(book_ids)[1:]):
                 suffix = ' (%d)' % (i + 1)
@@ -151,7 +151,7 @@ class Saver(QObject):
         self.pd.max = len(self.collected_data)
         self.pd.value = 0
         if self.opts.update_metadata:
-            all_fmts = {fmt for data in self.collected_data.itervalues() for fmt in data[2]}
+            all_fmts = {fmt for data in itervalues(self.collected_data) for fmt in data[2]}
             plugboards_cache = {fmt:find_plugboard(plugboard_save_to_disk_value, fmt, self.plugboards) for fmt in all_fmts}
             self.pool = Pool(name='SaveToDisk') if self.pool is None else self.pool
             try:
@@ -334,7 +334,7 @@ class Saver(QObject):
             text = force_unicode(text)
             return '\xa0\xa0\xa0\xa0' + '\n\xa0\xa0\xa0\xa0'.join(text.splitlines())
 
-        for book_id, errors in self.errors.iteritems():
+        for book_id, errors in iteritems(self.errors):
             types = {t for t, data in errors}
             title, authors = self.book_id_data(book_id).title, authors_to_string(self.book_id_data(book_id).authors[:1])
             if report:
@@ -362,7 +362,7 @@ class Saver(QObject):
     def report(self):
         if not self.errors:
             return
-        err_types = {e[0] for errors in self.errors.itervalues() for e in errors}
+        err_types = {e[0] for errors in itervalues(self.errors) for e in errors}
         if err_types == {'metadata'}:
             msg = _('Failed to update metadata in some books, click "Show details" for more information')
             d = warning_dialog
diff --git a/src/calibre/gui2/search_restriction_mixin.py b/src/calibre/gui2/search_restriction_mixin.py
index cfb6d57409..43763975f2 100644
--- a/src/calibre/gui2/search_restriction_mixin.py
+++ b/src/calibre/gui2/search_restriction_mixin.py
@@ -255,7 +255,7 @@ class CreateVirtualLibrary(QDialog):  # {{{
                 search = ['%s:"=%s"'%(prefix, x.replace('"', '\\"')) for x in d.names]
             if search:
                 if not self.editing:
-                    self.vl_name.lineEdit().setText(d.names.next())
+                    self.vl_name.lineEdit().setText(next(d.names))
                     self.vl_name.lineEdit().setCursorPosition(0)
                 self.vl_text.setText(d.match_type.join(search))
                 self.vl_text.setCursorPosition(0)
diff --git a/src/calibre/gui2/tag_browser/model.py b/src/calibre/gui2/tag_browser/model.py
index 75ea12470e..83997a4122 100644
--- a/src/calibre/gui2/tag_browser/model.py
+++ b/src/calibre/gui2/tag_browser/model.py
@@ -2,7 +2,6 @@
 # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
 from __future__ import (unicode_literals, division, absolute_import,
                         print_function)
-from polyglot.builtins import map, unicode_type
 
 __license__   = 'GPL v3'
 __copyright__ = '2011, Kovid Goyal '
@@ -23,8 +22,8 @@ from calibre.utils.icu import sort_key, lower, strcmp, collation_order, primary_
 from calibre.library.field_metadata import category_icon_map
 from calibre.gui2.dialogs.confirm_delete import confirm
 from calibre.utils.formatter import EvalFormatter
-from polyglot.builtins import range
 from calibre.utils.serialize import json_dumps, json_loads
+from polyglot.builtins import iteritems, itervalues, map, range, unicode_type
 
 
 TAG_SEARCH_STATES = {'clear': 0, 'mark_plus': 1, 'mark_plusplus': 2,
@@ -307,7 +306,7 @@ class TagsModel(QAbstractItemModel):  # {{{
         self.node_map = {}
         self.category_nodes = []
         self.category_custom_icons = {}
-        for k, v in self.prefs['tags_browser_category_icons'].iteritems():
+        for k, v in iteritems(self.prefs['tags_browser_category_icons']):
             icon = QIcon(os.path.join(config_dir, 'tb_icons', v))
             if len(icon.availableSizes()) > 0:
                 self.category_custom_icons[k] = icon
@@ -375,7 +374,7 @@ class TagsModel(QAbstractItemModel):  # {{{
 
     def rebuild_node_tree(self, state_map={}):
         if self._build_in_progress:
-            print ('Tag browser build already in progress')
+            print('Tag browser build already in progress')
             traceback.print_stack()
             return
         # traceback.print_stack()
@@ -387,7 +386,7 @@ class TagsModel(QAbstractItemModel):  # {{{
         self._build_in_progress = False
 
     def _run_rebuild(self, state_map={}):
-        for node in self.node_map.itervalues():
+        for node in itervalues(self.node_map):
             node.break_cycles()
         del node  # Clear reference to node in the current frame
         self.node_map.clear()
@@ -475,7 +474,7 @@ class TagsModel(QAbstractItemModel):  # {{{
         intermediate_nodes = {}
 
         if data is None:
-            print ('_create_node_tree: no data!')
+            print('_create_node_tree: no data!')
             traceback.print_stack()
             return
 
@@ -1012,7 +1011,7 @@ class TagsModel(QAbstractItemModel):  # {{{
             if not isinstance(order, dict):
                 raise TypeError()
         except:
-            print ('Tweak tag_browser_category_order is not valid. Ignored')
+            print('Tweak tag_browser_category_order is not valid. Ignored')
             order = {'*': 100}
         defvalue = order.get('*', 100)
         self.row_map = sorted(self.categories, key=lambda x: order.get(x, defvalue))
@@ -1032,7 +1031,7 @@ class TagsModel(QAbstractItemModel):  # {{{
         Here to trap usages of refresh in the old architecture. Can eventually
         be removed.
         '''
-        print ('TagsModel: refresh called!')
+        print('TagsModel: refresh called!')
         traceback.print_stack()
         return False
 
@@ -1102,7 +1101,7 @@ class TagsModel(QAbstractItemModel):  # {{{
                 self.use_position_based_index_on_next_recount = True
                 return True
 
-            for c in sorted(user_cats.keys(), key=sort_key):
+            for c in sorted(list(user_cats.keys()), key=sort_key):
                 if icu_lower(c).startswith(ckey_lower):
                     if len(c) == len(ckey):
                         if strcmp(ckey, nkey) != 0 and \
diff --git a/src/calibre/gui2/tag_mapper.py b/src/calibre/gui2/tag_mapper.py
index 45af4b1211..fc05cc6468 100644
--- a/src/calibre/gui2/tag_mapper.py
+++ b/src/calibre/gui2/tag_mapper.py
@@ -20,7 +20,7 @@ from calibre.gui2.ui import get_gui
 from calibre.gui2.widgets2 import Dialog
 from calibre.utils.config import JSONConfig
 from calibre.utils.localization import localize_user_manual_link
-from polyglot.builtins import unicode_type, range
+from polyglot.builtins import iteritems, unicode_type, range
 
 tag_maps = JSONConfig('tag-map-rules')
 
@@ -85,14 +85,14 @@ class RuleEdit(QWidget):
         l.addLayout(h)
         self.action = a = QComboBox(self)
         h.addWidget(a)
-        for action, text in self.ACTION_MAP.iteritems():
+        for action, text in iteritems(self.ACTION_MAP):
             a.addItem(text, action)
         a.currentIndexChanged.connect(self.update_state)
         self.la1 = la = QLabel('\xa0' + self.SUBJECT + '\xa0')
         h.addWidget(la)
         self.match_type = q = QComboBox(self)
         h.addWidget(q)
-        for action, text in self.MATCH_TYPE_MAP.iteritems():
+        for action, text in iteritems(self.MATCH_TYPE_MAP):
             q.addItem(text, action)
         q.currentIndexChanged.connect(self.update_state)
         self.la2 = la = QLabel(':\xa0')
@@ -452,13 +452,13 @@ class SaveLoadMixin(object):
     def build_load_menu(self):
         self.load_menu.clear()
         if len(self.PREFS_OBJECT):
-            for name, rules in self.PREFS_OBJECT.iteritems():
+            for name, rules in iteritems(self.PREFS_OBJECT):
                 ac = self.load_menu.addAction(name)
                 ac.setObjectName(name)
                 connect_lambda(ac.triggered, self, lambda self: self.load_ruleset(self.sender().objectName()))
             self.load_menu.addSeparator()
             m = self.load_menu.addMenu(_('Delete saved rulesets'))
-            for name, rules in self.PREFS_OBJECT.iteritems():
+            for name, rules in iteritems(self.PREFS_OBJECT):
                 ac = m.addAction(name)
                 ac.setObjectName(name)
                 connect_lambda(ac.triggered, self, lambda self: self.delete_ruleset(self.sender().objectName()))
diff --git a/src/calibre/gui2/toc/main.py b/src/calibre/gui2/toc/main.py
index ba23176964..a4e8cf7be1 100644
--- a/src/calibre/gui2/toc/main.py
+++ b/src/calibre/gui2/toc/main.py
@@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en'
 import sys, os, textwrap
 from threading import Thread
 from functools import partial
-from polyglot.builtins import map, unicode_type, range
+from polyglot.builtins import iteritems, map, unicode_type, range
 
 from PyQt5.Qt import (QPushButton, QFrame, QMenu, QInputDialog, QCheckBox,
     QDialog, QVBoxLayout, QDialogButtonBox, QSize, QStackedWidget, QWidget,
@@ -469,7 +469,7 @@ class TreeWidget(QTreeWidget):  # {{{
             # For order to be be preserved when moving by drag and drop, we
             # have to ensure that selectedIndexes returns an ordered list of
             # indexes.
-            sort_map = {self.indexFromItem(item):i for i, item in enumerate(self.iteritems())}
+            sort_map = {self.indexFromItem(item):i for i, item in enumerate(iteritems(self))}
             ans = sorted(ans, key=lambda x:sort_map.get(x, -1))
         return ans
 
@@ -615,7 +615,7 @@ class TreeWidget(QTreeWidget):  # {{{
 
     def bulk_rename(self):
         from calibre.gui2.tweak_book.file_list import get_bulk_rename_settings
-        sort_map = {item:i for i, item in enumerate(self.iteritems())}
+        sort_map = {item:i for i, item in enumerate(iteritems(self))}
         items = sorted(self.selectedItems(), key=lambda x:sort_map.get(x, -1))
         settings = get_bulk_rename_settings(self, len(items), prefix=_('Chapter '), msg=_(
             'All selected items will be renamed to the form prefix-number'), sanitize=lambda x:x, leading_zeros=False)
@@ -784,7 +784,7 @@ class TOCView(QWidget):  # {{{
         found = True
         while found:
             found = False
-            for item in self.iteritems():
+            for item in iteritems(self):
                 if item.childCount() > 0:
                     self._flatten_item(item)
                     found = True
diff --git a/src/calibre/gui2/tweak_book/__init__.py b/src/calibre/gui2/tweak_book/__init__.py
index d203a7576a..b09a2c1b12 100644
--- a/src/calibre/gui2/tweak_book/__init__.py
+++ b/src/calibre/gui2/tweak_book/__init__.py
@@ -7,7 +7,7 @@ __license__ = 'GPL v3'
 __copyright__ = '2013, Kovid Goyal '
 
 import string
-from polyglot.builtins import map
+from polyglot.builtins import iteritems, map
 
 from calibre.utils.config import JSONConfig
 from calibre.spell.dictionary import Dictionaries, parse_lang_code
@@ -118,7 +118,7 @@ dictionaries = Dictionaries()
 
 
 def editor_name(editor):
-    for n, ed in editors.iteritems():
+    for n, ed in iteritems(editors):
         if ed is editor:
             return n
 
diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py
index e179135a4f..27dc8af7aa 100644
--- a/src/calibre/gui2/tweak_book/boss.py
+++ b/src/calibre/gui2/tweak_book/boss.py
@@ -69,7 +69,7 @@ from calibre.utils.config import JSONConfig
 from calibre.utils.icu import numeric_sort_key
 from calibre.utils.imghdr import identify
 from calibre.utils.tdir_in_cache import tdir_in_cache
-from polyglot.builtins import iteritems, string_or_bytes
+from polyglot.builtins import iteritems, itervalues, string_or_bytes
 from polyglot.urllib import urlparse
 
 _diff_dialogs = []
@@ -185,11 +185,11 @@ class Boss(QObject):
             dictionaries.initialize(force=True)  # Reread user dictionaries
         if p.toolbars_changed:
             self.gui.populate_toolbars()
-            for ed in editors.itervalues():
+            for ed in itervalues(editors):
                 if hasattr(ed, 'populate_toolbars'):
                     ed.populate_toolbars()
         if orig_size != tprefs['toolbar_icon_size']:
-            for ed in editors.itervalues():
+            for ed in itervalues(editors):
                 if hasattr(ed, 'bars'):
                     for bar in ed.bars:
                         bar.setIconSize(QSize(tprefs['toolbar_icon_size'], tprefs['toolbar_icon_size']))
@@ -199,12 +199,12 @@ class Boss(QObject):
             self.gui.apply_settings()
             self.refresh_file_list()
         if ret == p.Accepted or p.dictionaries_changed:
-            for ed in editors.itervalues():
+            for ed in itervalues(editors):
                 ed.apply_settings(dictionaries_changed=p.dictionaries_changed)
         if orig_spell != tprefs['inline_spell_check']:
             from calibre.gui2.tweak_book.editor.syntax.html import refresh_spell_check_status
             refresh_spell_check_status()
-            for ed in editors.itervalues():
+            for ed in itervalues(editors):
                 try:
                     ed.editor.highlighter.rehighlight()
                 except AttributeError:
@@ -387,7 +387,7 @@ class Boss(QObject):
 
     def update_editors_from_container(self, container=None, names=None):
         c = container or current_container()
-        for name, ed in tuple(editors.iteritems()):
+        for name, ed in tuple(iteritems(editors)):
             if c.has_name(name):
                 if names is None or name in names:
                     ed.replace_data(c.raw_data(name))
@@ -505,7 +505,7 @@ class Boss(QObject):
         if files:
             folder_map = get_recommended_folders(current_container(), files)
             files = {x:('/'.join((folder, os.path.basename(x))) if folder else os.path.basename(x))
-                     for x, folder in folder_map.iteritems()}
+                     for x, folder in iteritems(folder_map)}
             self.add_savepoint(_('Before Add files'))
             c = current_container()
             for path in sorted(files, key=numeric_sort_key):
@@ -712,7 +712,7 @@ class Boss(QObject):
                                 det_msg=job.traceback, show=True)
         self.gui.file_list.build(current_container())
         self.set_modified()
-        for oldname, newname in name_map.iteritems():
+        for oldname, newname in iteritems(name_map):
             if oldname in editors:
                 editors[newname] = ed = editors.pop(oldname)
                 ed.change_document_name(newname)
@@ -721,7 +721,7 @@ class Boss(QObject):
                 self.gui.preview.current_name = newname
         self.apply_container_update_to_gui()
         if from_filelist:
-            self.gui.file_list.select_names(frozenset(name_map.itervalues()), current_name=name_map.get(from_filelist))
+            self.gui.file_list.select_names(frozenset(itervalues(name_map)), current_name=name_map.get(from_filelist))
             self.gui.file_list.file_list.setFocus(Qt.PopupFocusReason)
 
     # }}}
@@ -1052,7 +1052,7 @@ class Boss(QObject):
 
     def word_ignored(self, word, locale):
         if tprefs['inline_spell_check']:
-            for ed in editors.itervalues():
+            for ed in itervalues(editors):
                 try:
                     ed.editor.recheck_word(word, locale)
                 except AttributeError:
@@ -1115,7 +1115,7 @@ class Boss(QObject):
         actions on the current container '''
         changed = False
         with BusyCursor():
-            for name, ed in editors.iteritems():
+            for name, ed in iteritems(editors):
                 if not ed.is_synced_to_container:
                     self.commit_editor_to_container(name)
                     ed.is_synced_to_container = True
@@ -1125,7 +1125,7 @@ class Boss(QObject):
     def save_book(self):
         ' Save the book. Saving is performed in the background '
         c = current_container()
-        for name, ed in editors.iteritems():
+        for name, ed in iteritems(editors):
             if ed.is_modified or not ed.is_synced_to_container:
                 self.commit_editor_to_container(name, c)
                 ed.is_modified = False
@@ -1169,7 +1169,7 @@ class Boss(QObject):
             path += '.' + ext.lower()
         tdir = self.mkdtemp(prefix='save-copy-')
         container = clone_container(c, tdir)
-        for name, ed in editors.iteritems():
+        for name, ed in iteritems(editors):
             if ed.is_modified or not ed.is_synced_to_container:
                 self.commit_editor_to_container(name, container)
 
@@ -1361,7 +1361,7 @@ class Boss(QObject):
             name:container.get_file_path_for_processing(name, allow_modification=False)
             for name in names
         }
-        md.setUrls(list(map(QUrl.fromLocalFile, url_map.values())))
+        md.setUrls(list(map(QUrl.fromLocalFile, list(url_map.values()))))
         import json
         md.setData(FILE_COPY_MIME, json.dumps({
             name: (url_map[name], container.mime_map.get(name)) for name in names
@@ -1564,7 +1564,7 @@ class Boss(QObject):
         if not self.ensure_book(_('No book is currently open. You must first open a book to edit.')):
             return
         c = current_container()
-        files = [name for name, mime in c.mime_map.iteritems() if c.exists(name) and syntax_from_mime(name, mime) is not None]
+        files = [name for name, mime in iteritems(c.mime_map) if c.exists(name) and syntax_from_mime(name, mime) is not None]
         d = QuickOpen(files, parent=self.gui)
         if d.exec_() == d.Accepted and d.selected_result is not None:
             self.edit_file_requested(d.selected_result, None, c.mime_map[d.selected_result])
@@ -1597,7 +1597,7 @@ class Boss(QObject):
 
     def editor_data_changed(self, editor):
         self.gui.preview.start_refresh_timer()
-        for name, ed in editors.iteritems():
+        for name, ed in iteritems(editors):
             if ed is editor:
                 self.gui.toc_view.start_refresh_timer(name)
                 break
@@ -1776,7 +1776,7 @@ class Boss(QObject):
                 order = [k for k in order[extra:] if k in mem]
                 mem = {k:mem[k] for k in order}
             mem[c.path_to_ebook] = {
-                'editors':{name:ed.current_editing_state for name, ed in editors.iteritems()},
+                'editors':{name:ed.current_editing_state for name, ed in iteritems(editors)},
                 'currently_editing':self.currently_editing,
                 'tab_order':self.gui.central.tab_order,
             }
diff --git a/src/calibre/gui2/tweak_book/check_links.py b/src/calibre/gui2/tweak_book/check_links.py
index 481f2244e3..7b51f1aa6b 100644
--- a/src/calibre/gui2/tweak_book/check_links.py
+++ b/src/calibre/gui2/tweak_book/check_links.py
@@ -16,6 +16,7 @@ from calibre.gui2 import error_dialog
 from calibre.gui2.tweak_book import current_container, editors, set_current_container, tprefs
 from calibre.gui2.tweak_book.boss import get_boss
 from calibre.gui2.tweak_book.widgets import Dialog
+from polyglot.builtins import iteritems
 
 
 def get_data(name):
@@ -149,7 +150,7 @@ class CheckExternalLinks(Dialog):
             for name, href in {(l[0], l[1]) for l in err[0]}:
                 nmap[name].add(href)
 
-            for name, hrefs in nmap.iteritems():
+            for name, hrefs in iteritems(nmap):
                 raw = oraw = get_data(name)
                 for href in hrefs:
                     raw = raw.replace(href, newurl)
diff --git a/src/calibre/gui2/tweak_book/completion/basic.py b/src/calibre/gui2/tweak_book/completion/basic.py
index 4a46dd9774..2fb008ead7 100644
--- a/src/calibre/gui2/tweak_book/completion/basic.py
+++ b/src/calibre/gui2/tweak_book/completion/basic.py
@@ -21,7 +21,7 @@ from calibre.gui2.tweak_book.completion.utils import control, data, DataError
 from calibre.utils.ipc import eintr_retry_call
 from calibre.utils.matcher import Matcher
 from calibre.utils.icu import numeric_sort_key
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, itervalues, unicode_type
 
 Request = namedtuple('Request', 'id type data query')
 
@@ -80,23 +80,23 @@ class Name(unicode_type):
 def complete_names(names_data, data_conn):
     if not names_cache:
         mime_map, spine_names = get_data(data_conn, 'names_data')
-        names_cache[None] = all_names = frozenset(Name(name, mt, spine_names) for name, mt in mime_map.iteritems())
+        names_cache[None] = all_names = frozenset(Name(name, mt, spine_names) for name, mt in iteritems(mime_map))
         names_cache['text_link'] = frozenset(n for n in all_names if n.in_spine)
         names_cache['stylesheet'] = frozenset(n for n in all_names if n.mime_type in OEB_STYLES)
         names_cache['image'] = frozenset(n for n in all_names if n.mime_type.startswith('image/'))
         names_cache['font'] = frozenset(n for n in all_names if n.mime_type in OEB_FONTS)
         names_cache['css_resource'] = names_cache['image'] | names_cache['font']
         names_cache['descriptions'] = d = {}
-        for x, desc in {'text_link':_('Text'), 'stylesheet':_('Stylesheet'), 'image':_('Image'), 'font':_('Font')}.iteritems():
+        for x, desc in iteritems({'text_link':_('Text'), 'stylesheet':_('Stylesheet'), 'image':_('Image'), 'font':_('Font')}):
             for n in names_cache[x]:
                 d[n] = desc
     names_type, base, root = names_data
     quote = (lambda x:x) if base.lower().endswith('.css') else prepare_string_for_xml
     names = names_cache.get(names_type, names_cache[None])
     nmap = {name:name_to_href(name, root, base, quote) for name in names}
-    items = tuple(sorted(frozenset(nmap.itervalues()), key=numeric_sort_key))
+    items = tuple(sorted(frozenset(itervalues(nmap)), key=numeric_sort_key))
     d = names_cache['descriptions'].get
-    descriptions = {href:d(name) for name, href in nmap.iteritems()}
+    descriptions = {href:d(name) for name, href in iteritems(nmap)}
     return items, descriptions, {}
 
 
@@ -184,5 +184,5 @@ class HandleDataRequest(QObject):
 
 handle_data_request = HandleDataRequest()
 
-control_funcs = {name:func for name, func in globals().iteritems() if getattr(func, 'function_type', None) == 'control'}
-data_funcs = {name:func for name, func in globals().iteritems() if getattr(func, 'function_type', None) == 'data'}
+control_funcs = {name:func for name, func in iteritems(globals()) if getattr(func, 'function_type', None) == 'control'}
+data_funcs = {name:func for name, func in iteritems(globals()) if getattr(func, 'function_type', None) == 'data'}
diff --git a/src/calibre/gui2/tweak_book/completion/popup.py b/src/calibre/gui2/tweak_book/completion/popup.py
index e58a192ec4..c94fcc2469 100644
--- a/src/calibre/gui2/tweak_book/completion/popup.py
+++ b/src/calibre/gui2/tweak_book/completion/popup.py
@@ -16,6 +16,7 @@ from calibre import prints, prepare_string_for_xml
 from calibre.gui2 import error_dialog
 from calibre.gui2.tweak_book.widgets import make_highlighted_text
 from calibre.utils.icu import string_length
+from polyglot.builtins import iteritems
 
 
 class ChoosePopupWidget(QWidget):
@@ -246,7 +247,7 @@ class CompletionPopup(ChoosePopupWidget):
 
     def set_items(self, items, descriptions=None, query=None):
         self.current_query = query
-        ChoosePopupWidget.set_items(self, tuple(items.iteritems()), descriptions=descriptions)
+        ChoosePopupWidget.set_items(self, tuple(iteritems(items)), descriptions=descriptions)
 
     def choose_next_result(self, previous=False):
         ChoosePopupWidget.choose_next_result(self, previous=previous)
diff --git a/src/calibre/gui2/tweak_book/diff/highlight.py b/src/calibre/gui2/tweak_book/diff/highlight.py
index 401ed0379b..38519bed97 100644
--- a/src/calibre/gui2/tweak_book/diff/highlight.py
+++ b/src/calibre/gui2/tweak_book/diff/highlight.py
@@ -14,7 +14,7 @@ from calibre.gui2.tweak_book import tprefs
 from calibre.gui2.tweak_book.editor.text import get_highlighter as calibre_highlighter, SyntaxHighlighter
 from calibre.gui2.tweak_book.editor.themes import get_theme, highlight_to_char_format
 from calibre.gui2.tweak_book.editor.syntax.utils import format_for_pygments_token, NULL_FMT
-from polyglot.builtins import range
+from polyglot.builtins import iteritems, range
 
 
 class QtHighlighter(QTextDocument):
@@ -84,7 +84,7 @@ class PygmentsHighlighter(object):
 
     def __init__(self, text, lexer):
         theme, cache = get_theme(tprefs['editor_theme']), {}
-        theme = {k:highlight_to_char_format(v) for k, v in theme.iteritems()}
+        theme = {k:highlight_to_char_format(v) for k, v in iteritems(theme)}
         theme[None] = NULL_FMT
 
         def fmt(token):
diff --git a/src/calibre/gui2/tweak_book/diff/main.py b/src/calibre/gui2/tweak_book/diff/main.py
index 6b01d12d90..0b41d6beb3 100644
--- a/src/calibre/gui2/tweak_book/diff/main.py
+++ b/src/calibre/gui2/tweak_book/diff/main.py
@@ -24,7 +24,7 @@ from calibre.gui2.tweak_book.widgets import Dialog
 from calibre.gui2.widgets2 import HistoryLineEdit2
 from calibre.utils.filenames import samefile
 from calibre.utils.icu import numeric_sort_key
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, unicode_type
 
 
 class BusyWidget(QWidget):  # {{{
@@ -80,11 +80,11 @@ def changed_files(list_of_names1, list_of_names2, get_data1, get_data2):
     removals = list_of_names1 - common_names
     adds = set(list_of_names2 - common_names)
     adata, rdata = {a:get_data2(a) for a in adds}, {r:get_data1(r) for r in removals}
-    ahash = {a:hash(d) for a, d in adata.iteritems()}
-    rhash = {r:hash(d) for r, d in rdata.iteritems()}
+    ahash = {a:hash(d) for a, d in iteritems(adata)}
+    rhash = {r:hash(d) for r, d in iteritems(rdata)}
     renamed_names, removed_names, added_names = {}, set(), set()
-    for name, rh in rhash.iteritems():
-        for n, ah in ahash.iteritems():
+    for name, rh in iteritems(rhash):
+        for n, ah in iteritems(ahash):
             if ah == rh:
                 renamed_names[name] = n
                 adds.discard(n)
@@ -139,7 +139,7 @@ def string_diff(left, right, left_syntax=None, right_syntax=None, left_name='lef
 
 def file_diff(left, right):
     (raw1, syntax1), (raw2, syntax2) = map(get_decoded_raw, (left, right))
-    if type(raw1) is not type(raw2):
+    if not isinstance(raw1, type(raw2)):
         raw1, raw2 = open(left, 'rb').read(), open(right, 'rb').read()
     cache = Cache()
     cache.set_left(left, raw1), cache.set_right(right, raw2)
@@ -420,7 +420,7 @@ class Diff(Dialog):
         kwargs = lambda name: {'context':self.context, 'beautify':self.beautify, 'syntax':syntax_map.get(name, None)}
 
         if isinstance(changed_names, dict):
-            for name, other_name in sorted(changed_names.iteritems(), key=lambda x:numeric_sort_key(x[0])):
+            for name, other_name in sorted(iteritems(changed_names), key=lambda x:numeric_sort_key(x[0])):
                 args = (name, other_name, cache.left(name), cache.right(other_name))
                 add(args, kwargs(name))
         else:
@@ -436,7 +436,7 @@ class Diff(Dialog):
             args = (name, _('[%s was removed]') % name, cache.left(name), None)
             add(args, kwargs(name))
 
-        for name, new_name in sorted(renamed_names.iteritems(), key=lambda x:numeric_sort_key(x[0])):
+        for name, new_name in sorted(iteritems(renamed_names), key=lambda x:numeric_sort_key(x[0])):
             args = (name, new_name, None, None)
             add(args, kwargs(name))
 
diff --git a/src/calibre/gui2/tweak_book/diff/view.py b/src/calibre/gui2/tweak_book/diff/view.py
index 24c31a517e..e2fcd9841a 100644
--- a/src/calibre/gui2/tweak_book/diff/view.py
+++ b/src/calibre/gui2/tweak_book/diff/view.py
@@ -12,7 +12,7 @@ from math import ceil
 from functools import partial
 from collections import namedtuple, OrderedDict
 from difflib import SequenceMatcher
-from polyglot.builtins import unicode_type, zip, range
+from polyglot.builtins import iteritems, unicode_type, zip, range
 
 import regex
 from PyQt5.Qt import (
@@ -652,12 +652,12 @@ class DiffSplit(QSplitter):  # {{{
                     return x if x <= top else x + delta
                 lnm = LineNumberMap()
                 lnm.max_width = v.line_number_map.max_width
-                for x, val in v.line_number_map.iteritems():
+                for x, val in iteritems(v.line_number_map):
                     dict.__setitem__(lnm, mapnum(x), val)
                 v.line_number_map = lnm
                 v.changes = [(mapnum(t), mapnum(b), k) for t, b, k in v.changes]
                 v.headers = [(mapnum(x), name) for x, name in v.headers]
-                v.images = OrderedDict((mapnum(x), v) for x, v in v.images.iteritems())
+                v.images = OrderedDict((mapnum(x), v) for x, v in iteritems(v.images))
             v.viewport().update()
 
     def get_lines_for_image(self, img, view):
diff --git a/src/calibre/gui2/tweak_book/download.py b/src/calibre/gui2/tweak_book/download.py
index 9f0cb4b2c7..2b017ce152 100644
--- a/src/calibre/gui2/tweak_book/download.py
+++ b/src/calibre/gui2/tweak_book/download.py
@@ -15,7 +15,7 @@ from calibre.gui2.tweak_book import current_container
 from calibre.gui2.tweak_book.widgets import Dialog
 from calibre.gui2.progress_indicator import WaitStack
 from calibre.ebooks.oeb.polish.download import get_external_resources, download_external_resources, replace_resources
-from polyglot.builtins import range
+from polyglot.builtins import iteritems, range
 
 
 class ChooseResources(QWidget):
@@ -50,7 +50,7 @@ class ChooseResources(QWidget):
         self.items.clear()
         self.original_resources = resources
         dc = 0
-        for url, matches in resources.iteritems():
+        for url, matches in iteritems(resources):
             text = url
             num = len(matches)
             if text.startswith('data:'):
@@ -180,7 +180,7 @@ class DownloadResources(Dialog):
         else:
             replacements, failures = ret
             if failures:
-                tb = ['{}\n\t{}\n'.format(url, err) for url, err in failures.iteritems()]
+                tb = ['{}\n\t{}\n'.format(url, err) for url, err in iteritems(failures)]
                 if not replacements:
                     error_dialog(self, _('Download failed'), _(
                         'Failed to download external resources, click "Show Details" for more information.'),
diff --git a/src/calibre/gui2/tweak_book/editor/image.py b/src/calibre/gui2/tweak_book/editor/image.py
index cb9bbf71e3..2c1b72aa5c 100644
--- a/src/calibre/gui2/tweak_book/editor/image.py
+++ b/src/calibre/gui2/tweak_book/editor/image.py
@@ -15,6 +15,7 @@ from PyQt5.Qt import (
 from calibre.gui2 import error_dialog
 from calibre.gui2.tweak_book import actions, tprefs, editors
 from calibre.gui2.tweak_book.editor.canvas import Canvas
+from polyglot.builtins import itervalues
 
 
 class ResizeDialog(QDialog):  # {{{
@@ -300,7 +301,7 @@ class Editor(QMainWindow):
     def toolbar_floated(self, floating):
         if not floating:
             self.save_state()
-            for ed in editors.itervalues():
+            for ed in itervalues(editors):
                 if ed is not self:
                     ed.restore_state()
 
diff --git a/src/calibre/gui2/tweak_book/editor/snippets.py b/src/calibre/gui2/tweak_book/editor/snippets.py
index 3c2e3b46d8..23512db75b 100644
--- a/src/calibre/gui2/tweak_book/editor/snippets.py
+++ b/src/calibre/gui2/tweak_book/editor/snippets.py
@@ -24,7 +24,7 @@ from calibre.gui2.tweak_book.widgets import Dialog, PlainTextEdit
 from calibre.utils.config import JSONConfig
 from calibre.utils.icu import string_length as strlen
 from calibre.utils.localization import localize_user_manual_link
-from polyglot.builtins import codepoint_to_chr, unicode_type, range
+from polyglot.builtins import codepoint_to_chr, iteritems, itervalues, unicode_type, range
 
 string_length = lambda x: strlen(unicode_type(x))  # Needed on narrow python builds, as subclasses of unicode dont work
 KEY = Qt.Key_J
@@ -98,7 +98,7 @@ def escape_funcs():
         escapem = {('\\' + x):codepoint_to_chr(i+1) for i, x in enumerate('\\${}')}
         escape_pat = re.compile('|'.join(map(re.escape, escapem)))
         escape = lambda x: escape_pat.sub(lambda m: escapem[m.group()], x.replace(r'\\', '\x01'))
-        unescapem = {v:k[1] for k, v in escapem.iteritems()}
+        unescapem = {v:k[1] for k, v in iteritems(escapem)}
         unescape_pat = re.compile('|'.join(unescapem))
         unescape = lambda x:unescape_pat.sub(lambda m:unescapem[m.group()], x)
     return escape, unescape
@@ -177,7 +177,7 @@ def snippets(refresh=False):
             if snip['trigger'] and isinstance(snip['trigger'], type('')):
                 key = snip_key(snip['trigger'], *snip['syntaxes'])
                 _snippets[key] = {'template':snip['template'], 'description':snip['description']}
-        _snippets = sorted(_snippets.iteritems(), key=(lambda key_snip:string_length(key_snip[0].trigger)), reverse=True)
+        _snippets = sorted(iteritems(_snippets), key=(lambda key_snip:string_length(key_snip[0].trigger)), reverse=True)
     return _snippets
 
 # Editor integration {{{
@@ -352,7 +352,7 @@ def expand_template(editor, trigger, template):
     left = right - string_length(trigger)
     text, tab_stops = parse_template(template)
     c.setPosition(left), c.setPosition(right, c.KeepAnchor), c.insertText(text)
-    editor_tab_stops = [EditorTabStop(left, ts, editor) for ts in tab_stops.itervalues()]
+    editor_tab_stops = [EditorTabStop(left, ts, editor) for ts in itervalues(tab_stops)]
 
     tl = Template(editor_tab_stops)
     if tl.has_tab_stops:
@@ -699,7 +699,7 @@ class UserSnippets(Dialog):
     def change_builtin(self):
         d = QDialog(self)
         lw = QListWidget(d)
-        for (trigger, syntaxes), snip in builtin_snippets.iteritems():
+        for (trigger, syntaxes), snip in iteritems(builtin_snippets):
             snip = copy.deepcopy(snip)
             snip['trigger'], snip['syntaxes'] = trigger, syntaxes
             i = QListWidgetItem(self.snip_to_text(snip), lw)
diff --git a/src/calibre/gui2/tweak_book/editor/syntax/base.py b/src/calibre/gui2/tweak_book/editor/syntax/base.py
index 6618805549..c89ec23928 100644
--- a/src/calibre/gui2/tweak_book/editor/syntax/base.py
+++ b/src/calibre/gui2/tweak_book/editor/syntax/base.py
@@ -14,7 +14,7 @@ from PyQt5.Qt import QTextCursor, QTextBlockUserData, QTextLayout, QTimer
 from ..themes import highlight_to_char_format
 from calibre.gui2.tweak_book.widgets import BusyCursor
 from calibre.utils.icu import utf16_length
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, unicode_type
 
 is_wide_build = sys.maxunicode >= 0x10ffff
 
@@ -86,7 +86,7 @@ class SyntaxHighlighter(object):
         return bool(self.requests)
 
     def apply_theme(self, theme):
-        self.theme = {k:highlight_to_char_format(v) for k, v in theme.iteritems()}
+        self.theme = {k:highlight_to_char_format(v) for k, v in iteritems(theme)}
         self.create_formats()
         self.rehighlight()
 
diff --git a/src/calibre/gui2/tweak_book/editor/syntax/css.py b/src/calibre/gui2/tweak_book/editor/syntax/css.py
index be68dae79a..ba67904dd3 100644
--- a/src/calibre/gui2/tweak_book/editor/syntax/css.py
+++ b/src/calibre/gui2/tweak_book/editor/syntax/css.py
@@ -13,6 +13,7 @@ from PyQt5.Qt import QTextBlockUserData
 from calibre.gui2.tweak_book import verify_link
 from calibre.gui2.tweak_book.editor import syntax_text_char_format, LINK_PROPERTY, CSS_PROPERTY
 from calibre.gui2.tweak_book.editor.syntax.base import SyntaxHighlighter
+from polyglot.builtins import iteritems
 
 space_pat = re.compile(r'[ \n\t\r\f]+')
 cdo_pat = re.compile(r'/\*')
@@ -268,6 +269,7 @@ def in_string(state, text, i, formats, user_data):
     state.parse = (NORMAL if state.blocks < 1 else IN_CONTENT)
     return [(pos - i + len(q), formats['string'])]
 
+
 state_map = {
     NORMAL:normal,
     IN_COMMENT_NORMAL: comment,
@@ -294,10 +296,10 @@ def create_formats(highlighter):
         'pseudo_selector': theme['Special'],
         'tag': theme['Identifier'],
     }
-    for name, msg in {
+    for name, msg in iteritems({
         'unknown-normal': _('Invalid text'),
         'unterminated-string': _('Unterminated string'),
-    }.iteritems():
+    }):
         f = formats[name] = syntax_text_char_format(formats['error'])
         f.setToolTip(msg)
     formats['link'] = syntax_text_char_format(theme['Link'])
@@ -340,4 +342,3 @@ li[rel="mewl"], p.mewl {
 }
 
 ''', path_is_raw=True, syntax='css')
-
diff --git a/src/calibre/gui2/tweak_book/editor/syntax/html.py b/src/calibre/gui2/tweak_book/editor/syntax/html.py
index e0296dd5e3..7aba9d4be5 100644
--- a/src/calibre/gui2/tweak_book/editor/syntax/html.py
+++ b/src/calibre/gui2/tweak_book/editor/syntax/html.py
@@ -22,6 +22,7 @@ from calibre.gui2.tweak_book.editor import (
 from calibre.gui2.tweak_book.editor.syntax.base import SyntaxHighlighter, run_loop
 from calibre.gui2.tweak_book.editor.syntax.css import (
     create_formats as create_css_formats, state_map as css_state_map, CSSState, CSSUserData)
+from polyglot.builtins import iteritems
 
 cdata_tags = frozenset(['title', 'textarea', 'style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'noscript'])
 normal_pat = re.compile(r'[^<>&]+')
@@ -544,7 +545,7 @@ def create_formats(highlighter, add_css=True):
         'nbsp': t['SpecialCharacter'],
         'spell': t['SpellError'],
     }
-    for name, msg in {
+    for name, msg in iteritems({
             '<': _('An unescaped < is not allowed. Replace it with <'),
             '&': _('An unescaped ampersand is not allowed. Replace it with &'),
             '>': _('An unescaped > is not allowed. Replace it with >'),
@@ -553,7 +554,7 @@ def create_formats(highlighter, add_css=True):
             'bad-closing': _('A closing tag must contain only the tag name and nothing else'),
             'no-attr-value': _('Expecting an attribute value'),
             'only-prefix': _('A tag name cannot end with a colon'),
-    }.iteritems():
+    }):
         f = formats[name] = syntax_text_char_format(formats['error'])
         f.setToolTip(msg)
     f = formats['title'] = syntax_text_char_format()
diff --git a/src/calibre/gui2/tweak_book/editor/themes.py b/src/calibre/gui2/tweak_book/editor/themes.py
index 8e76121182..758c931d6f 100644
--- a/src/calibre/gui2/tweak_book/editor/themes.py
+++ b/src/calibre/gui2/tweak_book/editor/themes.py
@@ -18,7 +18,7 @@ from calibre.gui2 import error_dialog
 from calibre.gui2.tweak_book import tprefs
 from calibre.gui2.tweak_book.editor import syntax_text_char_format
 from calibre.gui2.tweak_book.widgets import Dialog
-from polyglot.builtins import unicode_type, range
+from polyglot.builtins import iteritems, iterkeys, unicode_type, range
 
 underline_styles = {'single', 'dash', 'dot', 'dash_dot', 'dash_dot_dot', 'wave', 'spell'}
 
@@ -32,13 +32,14 @@ def default_theme():
         _default_theme = 'wombat-dark' if isdark else 'pyte-light'
     return _default_theme
 
+
 # The solarized themes {{{
 SLDX = {'base03':'1c1c1c', 'base02':'262626', 'base01':'585858', 'base00':'626262', 'base0':'808080', 'base1':'8a8a8a', 'base2':'e4e4e4', 'base3':'ffffd7', 'yellow':'af8700', 'orange':'d75f00', 'red':'d70000', 'magenta':'af005f', 'violet':'5f5faf', 'blue':'0087ff', 'cyan':'00afaf', 'green':'5f8700'}  # noqa
 SLD  = {'base03':'002b36', 'base02':'073642', 'base01':'586e75', 'base00':'657b83', 'base0':'839496', 'base1':'93a1a1', 'base2':'eee8d5', 'base3':'fdf6e3', 'yellow':'b58900', 'orange':'cb4b16', 'red':'dc322f', 'magenta':'d33682', 'violet':'6c71c4', 'blue':'268bd2', 'cyan':'2aa198', 'green':'859900'}  # noqa
 m = {'base%d'%n:'base%02d'%n for n in range(1, 4)}
 m.update({'base%02d'%n:'base%d'%n for n in range(1, 4)})
-SLL = {m.get(k, k) : v for k, v in SLD.iteritems()}
-SLLX = {m.get(k, k) : v for k, v in SLDX.iteritems()}
+SLL = {m.get(k, k) : v for k, v in iteritems(SLD)}
+SLLX = {m.get(k, k) : v for k, v in iteritems(SLDX)}
 SOLARIZED = \
     '''
     CursorLine   bg={base02}
@@ -238,7 +239,7 @@ def read_theme(raw):
     return ans
 
 
-THEMES = {k:read_theme(raw) for k, raw in THEMES.iteritems()}
+THEMES = {k:read_theme(raw) for k, raw in iteritems(THEMES)}
 
 
 def u(x):
@@ -260,7 +261,7 @@ def to_highlight(data):
 
 def read_custom_theme(data):
     dt = THEMES[default_theme()].copy()
-    dt.update({k:to_highlight(v) for k, v in data.iteritems()})
+    dt.update({k:to_highlight(v) for k, v in iteritems(data)})
     return dt
 
 
@@ -309,11 +310,11 @@ def theme_format(theme, name):
 
 
 def custom_theme_names():
-    return tuple(tprefs['custom_themes'].iterkeys())
+    return tuple(iterkeys(tprefs['custom_themes']))
 
 
 def builtin_theme_names():
-    return tuple(THEMES.iterkeys())
+    return tuple(iterkeys(THEMES))
 
 
 def all_theme_names():
@@ -611,13 +612,13 @@ class ThemeEditor(Dialog):
 
     def update_theme(self, name):
         data = tprefs['custom_themes'][name]
-        extra = set(data.iterkeys()) - set(THEMES[default_theme()].iterkeys())
-        missing = set(THEMES[default_theme()].iterkeys()) - set(data.iterkeys())
+        extra = set(iterkeys(data)) - set(iterkeys(THEMES[default_theme()]))
+        missing = set(iterkeys(THEMES[default_theme()])) - set(iterkeys(data))
         for k in extra:
             data.pop(k)
         for k in missing:
             data[k] = dict(THEMES[default_theme()][k]._asdict())
-            for nk, nv in data[k].iteritems():
+            for nk, nv in iteritems(data[k]):
                 if isinstance(nv, QBrush):
                     data[k][nk] = unicode_type(nv.color().name())
         if extra or missing:
@@ -663,8 +664,8 @@ class ThemeEditor(Dialog):
             name = '*' + d.theme_name
             base = unicode_type(d.base.currentText())
             theme = {}
-            for key, val in THEMES[base].iteritems():
-                theme[key] = {k:col_to_string(v.color()) if isinstance(v, QBrush) else v for k, v in val._asdict().iteritems()}
+            for key, val in iteritems(THEMES[base]):
+                theme[key] = {k:col_to_string(v.color()) if isinstance(v, QBrush) else v for k, v in iteritems(val._asdict())}
             tprefs['custom_themes'][name] = theme
             tprefs['custom_themes'] = tprefs['custom_themes']
             t = self.theme
diff --git a/src/calibre/gui2/tweak_book/editor/widget.py b/src/calibre/gui2/tweak_book/editor/widget.py
index b1aa5cb5c7..6b31933c5f 100644
--- a/src/calibre/gui2/tweak_book/editor/widget.py
+++ b/src/calibre/gui2/tweak_book/editor/widget.py
@@ -24,7 +24,7 @@ from calibre.gui2.tweak_book.editor import SPELL_PROPERTY, LINK_PROPERTY, TAG_NA
 from calibre.gui2.tweak_book.editor.help import help_url
 from calibre.gui2.tweak_book.editor.text import TextEdit
 from calibre.utils.icu import utf16_length
-from polyglot.builtins import unicode_type, string_or_bytes
+from polyglot.builtins import itervalues, unicode_type, string_or_bytes
 
 
 def create_icon(text, palette=None, sz=None, divider=2, fill='white'):
@@ -346,7 +346,7 @@ class Editor(QMainWindow):
     def toolbar_floated(self, floating):
         if not floating:
             self.save_state()
-            for ed in editors.itervalues():
+            for ed in itervalues(editors):
                 if ed is not self:
                     ed.restore_state()
 
diff --git a/src/calibre/gui2/tweak_book/file_list.py b/src/calibre/gui2/tweak_book/file_list.py
index 9acbe741e9..674d37ceab 100644
--- a/src/calibre/gui2/tweak_book/file_list.py
+++ b/src/calibre/gui2/tweak_book/file_list.py
@@ -39,7 +39,7 @@ from calibre.gui2.tweak_book import (
 from calibre.gui2.tweak_book.editor import syntax_from_mime
 from calibre.gui2.tweak_book.templates import template_for
 from calibre.utils.icu import numeric_sort_key
-from polyglot.builtins import iteritems, unicode_type, range
+from polyglot.builtins import iteritems, itervalues, unicode_type, range
 
 try:
     from PyQt5 import sip
@@ -264,29 +264,29 @@ class FileList(QTreeWidget):
 
     def get_state(self):
         s = {'pos':self.verticalScrollBar().value()}
-        s['expanded'] = {c for c, item in self.categories.iteritems() if item.isExpanded()}
+        s['expanded'] = {c for c, item in iteritems(self.categories) if item.isExpanded()}
         s['selected'] = {unicode_type(i.data(0, NAME_ROLE) or '') for i in self.selectedItems()}
         return s
 
     def set_state(self, state):
-        for category, item in self.categories.iteritems():
+        for category, item in iteritems(self.categories):
             item.setExpanded(category in state['expanded'])
         self.verticalScrollBar().setValue(state['pos'])
-        for parent in self.categories.itervalues():
+        for parent in itervalues(self.categories):
             for c in (parent.child(i) for i in range(parent.childCount())):
                 name = unicode_type(c.data(0, NAME_ROLE) or '')
                 if name in state['selected']:
                     c.setSelected(True)
 
     def item_from_name(self, name):
-        for parent in self.categories.itervalues():
+        for parent in itervalues(self.categories):
             for c in (parent.child(i) for i in range(parent.childCount())):
                 q = unicode_type(c.data(0, NAME_ROLE) or '')
                 if q == name:
                     return c
 
     def select_name(self, name, set_as_current_index=False):
-        for parent in self.categories.itervalues():
+        for parent in itervalues(self.categories):
             for c in (parent.child(i) for i in range(parent.childCount())):
                 q = unicode_type(c.data(0, NAME_ROLE) or '')
                 c.setSelected(q == name)
@@ -296,7 +296,7 @@ class FileList(QTreeWidget):
                         self.setCurrentItem(c)
 
     def select_names(self, names, current_name=None):
-        for parent in self.categories.itervalues():
+        for parent in itervalues(self.categories):
             for c in (parent.child(i) for i in range(parent.childCount())):
                 q = unicode_type(c.data(0, NAME_ROLE) or '')
                 c.setSelected(q in names)
@@ -355,7 +355,7 @@ class FileList(QTreeWidget):
         cover_page_name = get_cover_page_name(container)
         cover_image_name = get_raster_cover_name(container)
         manifested_names = set()
-        for names in container.manifest_type_map.itervalues():
+        for names in itervalues(container.manifest_type_map):
             manifested_names |= set(names)
 
         def get_category(name, mt):
@@ -481,7 +481,7 @@ class FileList(QTreeWidget):
                 continue
             processed[name] = create_item(name)
 
-        for name, c in self.categories.iteritems():
+        for name, c in iteritems(self.categories):
             c.setExpanded(True)
             if name != 'text':
                 c.sortChildren(1, Qt.AscendingOrder)
@@ -496,7 +496,7 @@ class FileList(QTreeWidget):
 
     def show_context_menu(self, point):
         item = self.itemAt(point)
-        if item is None or item in set(self.categories.itervalues()):
+        if item is None or item in set(itervalues(self.categories)):
             return
         m = QMenu(self)
         sel = self.selectedItems()
@@ -542,7 +542,7 @@ class FileList(QTreeWidget):
         for item in sel:
             selected_map[unicode_type(item.data(0, CATEGORY_ROLE) or '')].append(unicode_type(item.data(0, NAME_ROLE) or ''))
 
-        for items in selected_map.itervalues():
+        for items in itervalues(selected_map):
             items.sort(key=self.index_of_name)
 
         if selected_map['text']:
@@ -557,7 +557,7 @@ class FileList(QTreeWidget):
             m.popup(self.mapToGlobal(point))
 
     def index_of_name(self, name):
-        for category, parent in self.categories.iteritems():
+        for category, parent in iteritems(self.categories):
             for i in range(parent.childCount()):
                 item = parent.child(i)
                 if unicode_type(item.data(0, NAME_ROLE) or '') == name:
@@ -682,7 +682,7 @@ class FileList(QTreeWidget):
         for i, (name, remove) in enumerate(spine_removals):
             if remove:
                 removals.append(self.categories['text'].child(i))
-        for category, parent in self.categories.iteritems():
+        for category, parent in iteritems(self.categories):
             if category != 'text':
                 for i in range(parent.childCount()):
                     child = parent.child(i)
@@ -770,7 +770,7 @@ class FileList(QTreeWidget):
 
     @property
     def all_files(self):
-        return (category.child(i) for category in self.categories.itervalues() for i in range(category.childCount()))
+        return (category.child(i) for category in itervalues(self.categories) for i in range(category.childCount()))
 
     @property
     def searchable_names(self):
@@ -1012,7 +1012,7 @@ class FileListWidget(QWidget):
         self.file_list = FileList(self)
         self.layout().addWidget(self.file_list)
         self.layout().setContentsMargins(0, 0, 0, 0)
-        self.forwarded_signals = {k for k, o in vars(self.file_list.__class__).iteritems() if isinstance(o, pyqtSignal) and '_' in k and not hasattr(self, k)}
+        self.forwarded_signals = {k for k, o in iteritems(vars(self.file_list.__class__)) if isinstance(o, pyqtSignal) and '_' in k and not hasattr(self, k)}
         for x in ('delete_done', 'select_name', 'select_names', 'request_edit', 'mark_name_as_current', 'clear_currently_edited_name'):
             setattr(self, x, getattr(self.file_list, x))
         self.setFocusProxy(self.file_list)
diff --git a/src/calibre/gui2/tweak_book/function_replace.py b/src/calibre/gui2/tweak_book/function_replace.py
index c588f63a77..039f80df6d 100644
--- a/src/calibre/gui2/tweak_book/function_replace.py
+++ b/src/calibre/gui2/tweak_book/function_replace.py
@@ -23,7 +23,7 @@ from calibre.utils.config import JSONConfig
 from calibre.utils.icu import capitalize, upper, lower, swapcase
 from calibre.utils.titlecase import titlecase
 from calibre.utils.localization import localize_user_manual_link
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, unicode_type
 
 user_functions = JSONConfig('editor-search-replace-functions')
 
@@ -69,7 +69,7 @@ class Function(object):
         self.boss = get_boss()
         self.data = {}
         self.debug_buf = StringIO()
-        self.functions = {name:func.mod for name, func in functions().iteritems() if func.mod is not None}
+        self.functions = {name:func.mod for name, func in iteritems(functions()) if func.mod is not None}
 
     def __hash__(self):
         return hash(self.name)
@@ -138,7 +138,7 @@ class DebugOutput(Dialog):
 
 
 def builtin_functions():
-    for name, obj in globals().iteritems():
+    for name, obj in iteritems(globals()):
         if name.startswith('replace_') and callable(obj) and hasattr(obj, 'imports'):
             yield obj
 
@@ -152,7 +152,7 @@ def functions(refresh=False):
         ans = _functions = {}
         for func in builtin_functions():
             ans[func.name] = Function(func.name, func=func)
-        for name, source in user_functions.iteritems():
+        for name, source in iteritems(user_functions):
             try:
                 f = Function(name, source=source)
             except Exception:
diff --git a/src/calibre/gui2/tweak_book/manage_fonts.py b/src/calibre/gui2/tweak_book/manage_fonts.py
index 3be05b2f4c..bc1d0c06f3 100644
--- a/src/calibre/gui2/tweak_book/manage_fonts.py
+++ b/src/calibre/gui2/tweak_book/manage_fonts.py
@@ -22,7 +22,7 @@ from calibre.gui2.tweak_book.widgets import Dialog, BusyCursor
 from calibre.utils.icu import primary_sort_key as sort_key
 from calibre.utils.fonts.scanner import font_scanner, NoFonts
 from calibre.utils.fonts.metadata import FontMetadata, UnsupportedFont
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, iterkeys, unicode_type
 
 
 def show_font_face_rule_for_font_file(file_data, added_name, parent=None):
@@ -103,7 +103,7 @@ class AllFonts(QAbstractTableModel):
 
     def do_sort(self):
         reverse = not self.sorted_on[1]
-        self.items = sorted(self.font_data.iterkeys(), key=sort_key, reverse=reverse)
+        self.items = sorted(iterkeys(self.font_data), key=sort_key, reverse=reverse)
         if self.sorted_on[0] != 'name':
             self.items.sort(key=self.font_data.get, reverse=reverse)
 
@@ -315,7 +315,7 @@ class ManageFonts(Dialog):
         fonts = self.get_selected_data()
         if not fonts:
             return
-        d = ChangeFontFamily(', '.join(fonts), {f for f, embedded in self.model.font_data.iteritems() if embedded}, self)
+        d = ChangeFontFamily(', '.join(fonts), {f for f, embedded in iteritems(self.model.font_data) if embedded}, self)
         if d.exec_() != d.Accepted:
             return
         changed = False
diff --git a/src/calibre/gui2/tweak_book/plugin.py b/src/calibre/gui2/tweak_book/plugin.py
index e06f862625..78100c83c8 100644
--- a/src/calibre/gui2/tweak_book/plugin.py
+++ b/src/calibre/gui2/tweak_book/plugin.py
@@ -14,7 +14,7 @@ from calibre import prints
 from calibre.customize.ui import all_edit_book_tool_plugins
 from calibre.gui2.tweak_book import tprefs, current_container
 from calibre.gui2.tweak_book.boss import get_boss
-from polyglot.builtins import unicode_type
+from polyglot.builtins import itervalues, unicode_type
 
 
 class Tool(object):
@@ -120,7 +120,7 @@ def load_plugin_tools(plugin):
         import traceback
         traceback.print_exc()
     else:
-        for x in vars(main).itervalues():
+        for x in itervalues(vars(main)):
             if isinstance(x, type) and x is not Tool and issubclass(x, Tool):
                 ans = x()
                 ans.plugin = plugin
diff --git a/src/calibre/gui2/tweak_book/preferences.py b/src/calibre/gui2/tweak_book/preferences.py
index 9ee6fe3cc5..5ee795480e 100644
--- a/src/calibre/gui2/tweak_book/preferences.py
+++ b/src/calibre/gui2/tweak_book/preferences.py
@@ -9,7 +9,8 @@ __copyright__ = '2013, Kovid Goyal '
 import numbers
 from operator import attrgetter, methodcaller
 from collections import namedtuple
-from polyglot.builtins import map, unicode_type, range
+from polyglot.builtins import (
+        iteritems, iterkeys, itervalues, map, unicode_type, range)
 from itertools import product
 from copy import copy, deepcopy
 
@@ -72,7 +73,7 @@ class BasicSettings(QWidget):  # {{{
         prefs = prefs or tprefs
         widget = QComboBox(self)
         widget.currentIndexChanged[int].connect(self.emit_changed)
-        for key, human in sorted(choices.iteritems(), key=lambda key_human: key_human[1] or key_human[0]):
+        for key, human in sorted(iteritems(choices), key=lambda key_human: key_human[1] or key_human[0]):
             widget.addItem(human or key, key)
 
         def getter(w):
@@ -134,7 +135,7 @@ class BasicSettings(QWidget):  # {{{
                         prefs[name] = cv
 
     def restore_defaults(self):
-        for setting in self.settings.itervalues():
+        for setting in itervalues(self.settings):
             setting.setter(setting.widget, self.default_value(setting.name))
 
     def initial_value(self, name):
@@ -263,7 +264,7 @@ class EditorSettings(BasicSettings):
         s = self.settings['editor_theme']
         current_val = s.getter(s.widget)
         s.widget.clear()
-        for key, human in sorted(choices.iteritems(), key=lambda key_human1: key_human1[1] or key_human1[0]):
+        for key, human in sorted(iteritems(choices), key=lambda key_human1: key_human1[1] or key_human1[0]):
             s.widget.addItem(human or key, key)
         s.setter(s.widget, current_val)
         if d.theme_name:
@@ -489,7 +490,7 @@ class ToolbarSettings(QWidget):
             ans.setToolTip(ac.toolTip())
             return ans
 
-        for key, ac in sorted(all_items.iteritems(), key=lambda k_ac: unicode_type(k_ac[1].text())):
+        for key, ac in sorted(iteritems(all_items), key=lambda k_ac: unicode_type(k_ac[1].text())):
             if key not in applied:
                 to_item(key, ac, self.available)
         if name == 'global_book_toolbar' and 'donate' not in applied:
@@ -593,7 +594,7 @@ class TemplatesDialog(Dialog):  # {{{
         self.l = l = QVBoxLayout(self)
 
         self.syntaxes = s = QComboBox(self)
-        s.addItems(sorted(DEFAULT_TEMPLATES.iterkeys()))
+        s.addItems(sorted(iterkeys(DEFAULT_TEMPLATES)))
         s.setCurrentIndex(s.findText('html'))
         h = QHBoxLayout()
         l.addLayout(h)
diff --git a/src/calibre/gui2/tweak_book/reports.py b/src/calibre/gui2/tweak_book/reports.py
index 443420872f..ee424b82cf 100644
--- a/src/calibre/gui2/tweak_book/reports.py
+++ b/src/calibre/gui2/tweak_book/reports.py
@@ -8,7 +8,7 @@ __copyright__ = '2015, Kovid Goyal '
 
 import time, textwrap, os
 from threading import Thread
-from polyglot.builtins import map, range
+from polyglot.builtins import iteritems, map, range
 from operator import itemgetter
 from functools import partial
 from collections import defaultdict
@@ -1338,7 +1338,7 @@ class ReportsWidget(QWidget):
             self.stack.widget(i)(data)
             if DEBUG:
                 category = self.reports.item(i).data(Qt.DisplayRole)
-                print ('Widget time for %12s: %.2fs seconds' % (category, time.time() - st))
+                print('Widget time for %12s: %.2fs seconds' % (category, time.time() - st))
 
     def save(self):
         save_state('splitter-state', bytearray(self.splitter.saveState()))
@@ -1439,8 +1439,8 @@ class Reports(Dialog):
                 ' information.'), det_msg=data, show=True)
         data, timing = data
         if DEBUG:
-            for x, t in sorted(timing.iteritems(), key=itemgetter(1)):
-                print ('Time for %6s data: %.3f seconds' % (x, t))
+            for x, t in sorted(iteritems(timing), key=itemgetter(1)):
+                print('Time for %6s data: %.3f seconds' % (x, t))
         self.reports(data)
 
     def accept(self):
diff --git a/src/calibre/gui2/tweak_book/search.py b/src/calibre/gui2/tweak_book/search.py
index eb7432aa94..abe2535916 100644
--- a/src/calibre/gui2/tweak_book/search.py
+++ b/src/calibre/gui2/tweak_book/search.py
@@ -34,7 +34,7 @@ from calibre.gui2.tweak_book.widgets import BusyCursor
 from calibre.gui2.widgets2 import FlowLayout, HistoryComboBox
 from calibre.utils.icu import primary_contains
 from calibre.ebooks.conversion.search_replace import REGEX_FLAGS, compile_regular_expression
-from polyglot.builtins import unicode_type, range
+from polyglot.builtins import iteritems, iterkeys, unicode_type, range
 
 
 # The search panel {{{
@@ -160,7 +160,7 @@ class WhereBox(QComboBox):
             return wm[self.currentIndex()]
 
         def fset(self, val):
-            self.setCurrentIndex({v:k for k, v in wm.iteritems()}[val])
+            self.setCurrentIndex({v:k for k, v in iteritems(wm)}[val])
         return property(fget=fget, fset=fset)
 
     def showPopup(self):
@@ -569,8 +569,7 @@ class SearchesModel(QAbstractListModel):
     def dropMimeData(self, data, action, row, column, parent):
         if parent.isValid() or action != Qt.MoveAction or not data.hasFormat('x-calibre/searches-rows') or not self.filtered_searches:
             return False
-        rows = map(int, bytes(bytearray(data.data('x-calibre/searches-rows'))).decode('ascii').split(','))
-        rows.sort()
+        rows = sorted(map(int, bytes(bytearray(data.data('x-calibre/searches-rows'))).decode('ascii').split(',')))
         moved_searches = [self.searches[self.filtered_searches[r]] for r in rows]
         moved_searches_q = {id(s) for s in moved_searches}
         insert_at = max(0, min(row, len(self.filtered_searches)))
@@ -1221,7 +1220,7 @@ class SavedSearches(QWidget):
                 return err()
             searches = []
             for item in obj['searches']:
-                if not isinstance(item, dict) or not set(item.iterkeys()).issuperset(needed_keys):
+                if not isinstance(item, dict) or not set(iterkeys(item)).issuperset(needed_keys):
                     return err
                 searches.append({k:item[k] for k in needed_keys})
 
@@ -1422,7 +1421,7 @@ def run_search(
                     return True
                 if wrap and not files and editor.find(p, wrap=True, marked=marked, save_match='gui'):
                     return True
-            for fname, syntax in files.iteritems():
+            for fname, syntax in iteritems(files):
                 ed = editors.get(fname, None)
                 if ed is not None:
                     if not wrap and ed is editor:
diff --git a/src/calibre/gui2/tweak_book/spell.py b/src/calibre/gui2/tweak_book/spell.py
index 3fe4e0522a..130f2deac9 100644
--- a/src/calibre/gui2/tweak_book/spell.py
+++ b/src/calibre/gui2/tweak_book/spell.py
@@ -37,7 +37,7 @@ from calibre.spell.import_from import import_from_oxt
 from calibre.spell.break_iterator import split_into_words
 from calibre.utils.localization import calibre_langcode_to_name, get_language, get_lang, canonicalize_lang
 from calibre.utils.icu import sort_key, primary_sort_key, primary_contains, contains
-from polyglot.builtins import unicode_type, range
+from polyglot.builtins import iteritems, unicode_type, range
 
 LANG = 0
 COUNTRY = 1
@@ -707,7 +707,7 @@ class WordsModel(QAbstractTableModel):
         self.endResetModel()
 
     def update_counts(self, emit_signal=True):
-        self.counts = (len([None for w, recognized in self.spell_map.iteritems() if not recognized]), len(self.words))
+        self.counts = (len([None for w, recognized in iteritems(self.spell_map) if not recognized]), len(self.words))
         if emit_signal:
             self.counts_changed.emit()
 
@@ -1342,7 +1342,7 @@ def find_next(word, locations, current_editor, current_editor_name,
 
     if current_editor_name not in files:
         current_editor_name = None
-        locations = [(fname, {l.original_word for l in _locations}, False) for fname, _locations in files.iteritems()]
+        locations = [(fname, {l.original_word for l in _locations}, False) for fname, _locations in iteritems(files)]
     else:
         # Re-order the list of locations to search so that we search in the
         # current editor first
diff --git a/src/calibre/gui2/tweak_book/templates.py b/src/calibre/gui2/tweak_book/templates.py
index 5c845ab282..762d9904ad 100644
--- a/src/calibre/gui2/tweak_book/templates.py
+++ b/src/calibre/gui2/tweak_book/templates.py
@@ -8,6 +8,7 @@ __copyright__ = '2013, Kovid Goyal '
 
 from calibre import prepare_string_for_xml
 from calibre.gui2.tweak_book import current_container, tprefs
+from polyglot.builtins import iteritems
 
 DEFAULT_TEMPLATES = {
     'html':
@@ -46,4 +47,4 @@ def template_for(syntax):
         'AUTHOR': ' & '.join(mi.authors),
     }
     return raw_template_for(syntax).format(
-        **{k:prepare_string_for_xml(v, True) for k, v in data.iteritems()})
+        **{k:prepare_string_for_xml(v, True) for k, v in iteritems(data)})
diff --git a/src/calibre/gui2/tweak_book/text_search.py b/src/calibre/gui2/tweak_book/text_search.py
index 48ad66aea2..eed04a90d0 100644
--- a/src/calibre/gui2/tweak_book/text_search.py
+++ b/src/calibre/gui2/tweak_book/text_search.py
@@ -17,7 +17,7 @@ from calibre.gui2.tweak_book import tprefs, editors, current_container
 from calibre.gui2.tweak_book.search import get_search_regex, InvalidRegex, initialize_search_request
 from calibre.gui2.tweak_book.widgets import BusyCursor
 from calibre.gui2.widgets2 import HistoryComboBox
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, unicode_type
 
 # UI {{{
 
@@ -79,7 +79,7 @@ class WhereBox(QComboBox):
             return wm[self.currentIndex()]
 
         def fset(self, val):
-            self.setCurrentIndex({v:k for k, v in wm.iteritems()}[val])
+            self.setCurrentIndex({v:k for k, v in iteritems(wm)}[val])
         return property(fget=fget, fset=fset)
 
     def showPopup(self):
@@ -174,7 +174,7 @@ def run_text_search(search, current_editor, current_editor_name, searchable_name
                 return True
             if not files and editor.find_text(pat, wrap=True):
                 return True
-        for fname, syntax in files.iteritems():
+        for fname, syntax in iteritems(files):
             ed = editors.get(fname, None)
             if ed is not None:
                 if ed.find_text(pat, complete=True):
diff --git a/src/calibre/gui2/tweak_book/ui.py b/src/calibre/gui2/tweak_book/ui.py
index fbd7e11b93..f328c0f54f 100644
--- a/src/calibre/gui2/tweak_book/ui.py
+++ b/src/calibre/gui2/tweak_book/ui.py
@@ -9,7 +9,7 @@ __copyright__ = '2013, Kovid Goyal '
 import os
 from functools import partial
 from itertools import product
-from polyglot.builtins import map, unicode_type, range
+from polyglot.builtins import iteritems, itervalues, map, unicode_type, range
 
 from PyQt5.Qt import (
     QDockWidget, Qt, QLabel, QIcon, QAction, QApplication, QWidget, QEvent,
@@ -107,7 +107,7 @@ class Central(QStackedWidget):  # {{{
     @property
     def tab_order(self):
         ans = []
-        rmap = {v:k for k, v in editors.iteritems()}
+        rmap = {v:k for k, v in iteritems(editors)}
         for i in range(self.editor_tabs.count()):
             name = rmap.get(self.editor_tabs.widget(i))
             if name is not None:
@@ -166,7 +166,7 @@ class Central(QStackedWidget):  # {{{
     def save_state(self):
         tprefs.set('search-panel-visible', self.search_panel.isVisible())
         self.search_panel.save_state()
-        for ed in editors.itervalues():
+        for ed in itervalues(editors):
             ed.save_state()
         if self.current_editor is not None:
             self.current_editor.save_state()  # Ensure the current editor saves it state last
diff --git a/src/calibre/gui2/tweak_book/widgets.py b/src/calibre/gui2/tweak_book/widgets.py
index cb93518123..835b038d4b 100644
--- a/src/calibre/gui2/tweak_book/widgets.py
+++ b/src/calibre/gui2/tweak_book/widgets.py
@@ -27,7 +27,7 @@ from calibre.gui2.widgets2 import Dialog as BaseDialog, HistoryComboBox
 from calibre.utils.icu import primary_sort_key, sort_key, primary_contains, numeric_sort_key
 from calibre.utils.matcher import get_char, Matcher
 from calibre.gui2.complete2 import EditWithComplete
-from polyglot.builtins import unicode_type, zip
+from polyglot.builtins import iteritems, unicode_type, zip
 
 ROOT = QModelIndex()
 PARAGRAPH_SEPARATOR = '\u2029'
@@ -347,7 +347,7 @@ class Results(QWidget):
             [(p.setTextFormat(Qt.RichText), p.setTextOption(self.text_option)) for p in prefixes]
             self.maxwidth = max([x.size().width() for x in prefixes])
             self.results = tuple((prefix, self.make_text(text, positions), text)
-                for prefix, (text, positions) in zip(prefixes, results.iteritems()))
+                for prefix, (text, positions) in zip(prefixes, iteritems(results)))
         else:
             self.results = ()
             self.current_result = -1
@@ -551,7 +551,7 @@ class NamesModel(QAbstractListModel):
         if not query:
             self.items = tuple((text, None) for text in self.names)
         else:
-            self.items = tuple(self.matcher(query).iteritems())
+            self.items = tuple(iteritems(self.matcher(query)))
         self.endResetModel()
         self.filtered.emit(not bool(query))
 
@@ -820,7 +820,7 @@ class InsertSemantics(Dialog):
             'text': _('First "real" page of content'),
         }
         t = _
-        all_types = [(k, (('%s (%s)' % (t(v), type_map_help[k])) if k in type_map_help else t(v))) for k, v in self.known_type_map.iteritems()]
+        all_types = [(k, (('%s (%s)' % (t(v), type_map_help[k])) if k in type_map_help else t(v))) for k, v in iteritems(self.known_type_map)]
         all_types.sort(key=lambda x: sort_key(x[1]))
         self.all_types = OrderedDict(all_types)
 
@@ -830,7 +830,7 @@ class InsertSemantics(Dialog):
 
         self.tl = tl = QFormLayout()
         self.semantic_type = QComboBox(self)
-        for key, val in self.all_types.iteritems():
+        for key, val in iteritems(self.all_types):
             self.semantic_type.addItem(val, key)
         tl.addRow(_('Type of &semantics:'), self.semantic_type)
         self.target = t = QLineEdit(self)
@@ -946,13 +946,13 @@ class InsertSemantics(Dialog):
 
     @property
     def changed_type_map(self):
-        return {k:v for k, v in self.final_type_map.iteritems() if v != self.original_type_map.get(k, None)}
+        return {k:v for k, v in iteritems(self.final_type_map) if v != self.original_type_map.get(k, None)}
 
     def apply_changes(self, container):
         from calibre.ebooks.oeb.polish.opf import set_guide_item, get_book_language
         from calibre.translations.dynamic import translate
         lang = get_book_language(container)
-        for item_type, (name, frag) in self.changed_type_map.iteritems():
+        for item_type, (name, frag) in iteritems(self.changed_type_map):
             title = self.known_type_map[item_type]
             if lang:
                 title = translate(lang, title)
@@ -1093,7 +1093,7 @@ class AddCover(Dialog):
     @property
     def image_names(self):
         img_types = {guess_type('a.'+x) for x in ('png', 'jpeg', 'gif')}
-        for name, mt in self.container.mime_map.iteritems():
+        for name, mt in iteritems(self.container.mime_map):
             if mt.lower() in img_types:
                 yield name
 
diff --git a/src/calibre/gui2/viewer/config.py b/src/calibre/gui2/viewer/config.py
index cc5e71c188..2eae758e1d 100644
--- a/src/calibre/gui2/viewer/config.py
+++ b/src/calibre/gui2/viewer/config.py
@@ -22,7 +22,7 @@ from calibre.gui2 import min_available_height, error_dialog
 from calibre.gui2.languages import LanguagesEdit
 from calibre.gui2.shortcuts import ShortcutConfig
 from calibre.gui2.viewer.config_ui import Ui_Dialog
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, iterkeys, unicode_type
 
 
 def config(defaults=None):
@@ -213,7 +213,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
         for x in ('load', 'delete'):
             m = getattr(self, '%s_theme_button'%x).menu()
             m.clear()
-            for x in self.themes.iterkeys():
+            for x in iterkeys(self.themes):
                 title = x[len('theme_'):]
                 ac = m.addAction(title)
                 ac.theme_id = x
@@ -243,7 +243,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
 
         def fset(self, wl):
             self.dictionary_list.clear()
-            for langcode, url in sorted(wl.iteritems(), key=lambda lc_url:sort_key(calibre_langcode_to_name(lc_url[0]))):
+            for langcode, url in sorted(iteritems(wl), key=lambda lc_url:sort_key(calibre_langcode_to_name(lc_url[0]))):
                 i = QListWidgetItem('%s: %s' % (calibre_langcode_to_name(langcode), url), self.dictionary_list)
                 i.setData(Qt.UserRole, (langcode, url))
         return property(fget=fget, fset=fset)
diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py
index 857e1be147..9430df1d7a 100644
--- a/src/calibre/gui2/viewer/documentview.py
+++ b/src/calibre/gui2/viewer/documentview.py
@@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
 import math, json
 from base64 import b64encode
 from functools import partial
-from polyglot.builtins import map, unicode_type, string_or_bytes
+from polyglot.builtins import iteritems, map, unicode_type, string_or_bytes
 
 from PyQt5.Qt import (
     QSize, QSizePolicy, QUrl, Qt, QPainter, QPalette, QBrush,
@@ -259,7 +259,7 @@ class Document(QWebPage):  # {{{
         if not isinstance(self.anchor_positions, dict):
             # Some weird javascript error happened
             self.anchor_positions = {}
-        return {k:tuple(v) for k, v in self.anchor_positions.iteritems()}
+        return {k:tuple(v) for k, v in iteritems(self.anchor_positions)}
 
     def switch_to_paged_mode(self, onresize=False, last_loaded_path=None):
         if onresize and not self.loaded_javascript:
diff --git a/src/calibre/gui2/viewer/gestures.py b/src/calibre/gui2/viewer/gestures.py
index b99d870baf..027090e9ce 100644
--- a/src/calibre/gui2/viewer/gestures.py
+++ b/src/calibre/gui2/viewer/gestures.py
@@ -13,6 +13,7 @@ from PyQt5.Qt import (
     QContextMenuEvent, QDialog, QDialogButtonBox, QLabel, QVBoxLayout)
 
 from calibre.constants import iswindows
+from polyglot.builtins import itervalues
 
 touch_supported = False
 if iswindows and sys.getwindowsversion()[:2] >= (6, 2):  # At least windows 7
@@ -182,14 +183,14 @@ class State(QObject):
         else:
             self.check_for_holds()
             if {Swipe, SwipeAndHold} & self.possible_gestures:
-                tp = next(self.touch_points.itervalues())
+                tp = next(itervalues(self.touch_points))
                 self.swiping.emit(*tp.swipe_live)
 
     def check_for_holds(self):
         if not {SwipeAndHold, TapAndHold} & self.possible_gestures:
             return
         now = time.time()
-        tp = next(self.touch_points.itervalues())
+        tp = next(itervalues(self.touch_points))
         if now - tp.time_of_last_move < HOLD_THRESHOLD:
             return
         if self.hold_started:
@@ -216,20 +217,20 @@ class State(QObject):
 
     def finalize(self):
         if Tap in self.possible_gestures:
-            tp = next(self.touch_points.itervalues())
+            tp = next(itervalues(self.touch_points))
             if tp.total_movement <= TAP_THRESHOLD:
                 self.tapped.emit(tp)
                 return
 
         if Swipe in self.possible_gestures:
-            tp = next(self.touch_points.itervalues())
+            tp = next(itervalues(self.touch_points))
             st = tp.swipe_type
             if st is not None:
                 self.swiped.emit(st)
                 return
 
         if Pinch in self.possible_gestures:
-            points = tuple(self.touch_points.itervalues())
+            points = tuple(itervalues(self.touch_points))
             if len(points) == 2:
                 pinch_dir = get_pinch(*points)
                 if pinch_dir is not None:
@@ -239,7 +240,7 @@ class State(QObject):
             return
 
         if TapAndHold in self.possible_gestures:
-            tp = next(self.touch_points.itervalues())
+            tp = next(itervalues(self.touch_points))
             self.tap_hold_finished.emit(tp)
             return
 
diff --git a/src/calibre/gui2/viewer/javascript.py b/src/calibre/gui2/viewer/javascript.py
index 1bc617d8b9..3348227460 100644
--- a/src/calibre/gui2/viewer/javascript.py
+++ b/src/calibre/gui2/viewer/javascript.py
@@ -11,11 +11,12 @@ import os
 
 import calibre
 from calibre.utils.resources import compiled_coffeescript, load_hyphenator_dicts
+from polyglot.builtins import iteritems
 
 
 class JavaScriptLoader(object):
 
-    JS = {x:('viewer/%s.js'%x if y is None else y) for x, y in {
+    JS = {x:('viewer/%s.js'%x if y is None else y) for x, y in iteritems({
 
             'bookmarks':None,
             'referencing':None,
@@ -25,7 +26,7 @@ class JavaScriptLoader(object):
             'hyphenator':'viewer/hyphenate/Hyphenator.js',
             'images':None
 
-        }.iteritems()}
+        })}
 
     CS = {
             'cfi':'ebooks.oeb.display.cfi',
@@ -49,7 +50,7 @@ class JavaScriptLoader(object):
                 compile_coffeescript
             except:
                 self._dynamic_coffeescript = False
-                print ('WARNING: Failed to load serve_coffee, not compiling '
+                print('WARNING: Failed to load serve_coffee, not compiling '
                         'coffeescript dynamically.')
 
         self._cache = {}
diff --git a/src/calibre/gui2/viewer/toc.py b/src/calibre/gui2/viewer/toc.py
index 5202a27a7f..a993bda91b 100644
--- a/src/calibre/gui2/viewer/toc.py
+++ b/src/calibre/gui2/viewer/toc.py
@@ -19,6 +19,7 @@ from calibre.ebooks.metadata.toc import TOC as MTOC
 from calibre.gui2 import error_dialog
 from calibre.gui2.search_box import SearchBox2
 from calibre.utils.icu import primary_contains
+from polyglot.builtins import iteritems
 
 
 class Delegate(QStyledItemDelegate):
@@ -211,7 +212,7 @@ class TOCItem(QStandardItem):
         # to count a partial line as being visible.
 
         # We only care about y position
-        anchor_map = {k:v[1] for k, v in anchor_map.iteritems()}
+        anchor_map = {k:v[1] for k, v in iteritems(anchor_map)}
 
         if spine_index >= self.starts_at and spine_index <= self.ends_at:
             # The position at which this anchor is present in the document
@@ -358,10 +359,10 @@ class TOC(QStandardItemModel):
 
         if in_paged_mode:
             start = viewport_rect[0]
-            anchor_map = {k:v[0] for k, v in anchor_map.iteritems()}
+            anchor_map = {k:v[0] for k, v in iteritems(anchor_map)}
         else:
             start = viewport_rect[1]
-            anchor_map = {k:v[1] for k, v in anchor_map.iteritems()}
+            anchor_map = {k:v[1] for k, v in iteritems(anchor_map)}
 
         for item in items:
             if found:
diff --git a/src/calibre/gui2/wizard/__init__.py b/src/calibre/gui2/wizard/__init__.py
index 93b0d9ba1b..ec61d6c0fe 100644
--- a/src/calibre/gui2/wizard/__init__.py
+++ b/src/calibre/gui2/wizard/__init__.py
@@ -25,7 +25,7 @@ from calibre.utils.localization import localize_user_manual_link
 
 from calibre.utils.config import dynamic, prefs
 from calibre.gui2 import choose_dir, error_dialog
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, unicode_type
 
 if iswindows:
     winutil = plugins['winutil'][0]
@@ -492,7 +492,7 @@ class KindlePage(QWizardPage, KindleUI):
         opts = smtp_prefs().parse()
         accs = []
         has_default = False
-        for x, ac in opts.accounts.iteritems():
+        for x, ac in iteritems(opts.accounts):
             default = ac[2]
             if x.strip().endswith('@kindle.com'):
                 accs.append((x, default))
@@ -871,7 +871,7 @@ class Wizard(QWizard):
         self.resize(600, 520)
 
     def set_button_texts(self):
-        for but, text in self.BUTTON_TEXTS.iteritems():
+        for but, text in iteritems(self.BUTTON_TEXTS):
             self.setButtonText(getattr(self, but+'Button'), _(text))
 
     def retranslate(self):
diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py
index 16eb2698ce..c8fdfbf5c9 100644
--- a/src/calibre/library/caches.py
+++ b/src/calibre/library/caches.py
@@ -20,7 +20,8 @@ from calibre.db.search import CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH, _match
 from calibre.ebooks.metadata import title_sort, author_to_author_sort
 from calibre.ebooks.metadata.opf2 import metadata_to_opf
 from calibre import prints, force_unicode
-from polyglot.builtins import map, unicode_type, string_or_bytes, zip
+from polyglot.builtins import (iteritems, iterkeys, itervalues, map,
+        unicode_type, string_or_bytes, zip)
 
 
 class MetadataBackup(Thread):  # {{{
@@ -774,7 +775,7 @@ class ResultCache(SearchQueryParser):  # {{{
                     q = canonicalize_lang(query)
                     if q is None:
                         lm = lang_map()
-                        rm = {v.lower():k for k,v in lm.iteritems()}
+                        rm = {v.lower():k for k,v in iteritems(lm)}
                         q = rm.get(query, query)
                 else:
                     q = query
@@ -917,15 +918,15 @@ class ResultCache(SearchQueryParser):  # {{{
             self.marked_ids_dict = dict.fromkeys(id_dict, u'true')
         else:
             # Ensure that all the items in the dict are text
-            self.marked_ids_dict = dict(zip(id_dict.iterkeys(), map(unicode_type,
-                id_dict.itervalues())))
+            self.marked_ids_dict = dict(zip(iterkeys(id_dict), map(unicode_type,
+                itervalues(id_dict))))
 
         # Set the values in the cache
         marked_col = self.FIELD_MAP['marked']
         for r in self.iterall():
             r[marked_col] = None
 
-        for id_, val in self.marked_ids_dict.iteritems():
+        for id_, val in iteritems(self.marked_ids_dict):
             try:
                 self._data[id_][marked_col] = val
             except:
@@ -1052,7 +1053,7 @@ class ResultCache(SearchQueryParser):  # {{{
                 item.extend((None, None))
 
         marked_col = self.FIELD_MAP['marked']
-        for id_,val in self.marked_ids_dict.iteritems():
+        for id_,val in iteritems(self.marked_ids_dict):
             try:
                 self._data[id_][marked_col] = val
             except:
diff --git a/src/calibre/library/catalogs/epub_mobi_builder.py b/src/calibre/library/catalogs/epub_mobi_builder.py
index 83736fb65a..686345f767 100644
--- a/src/calibre/library/catalogs/epub_mobi_builder.py
+++ b/src/calibre/library/catalogs/epub_mobi_builder.py
@@ -4616,7 +4616,9 @@ class CatalogBuilder(object):
         """
 
         templates = {}
-        execfile(P('catalog/section_list_templates.py'), templates)
+        ef = P('catalog/section_list_templates.py')
+        with open(ef, 'rb')) as f:
+            exec(compile(f.read(), ef, 'exec'), templates)
         for name, template in templates.iteritems():
             if name.startswith('by_') and name.endswith('_template'):
                 setattr(self, name, force_unicode(template, 'utf-8'))
diff --git a/src/calibre/library/check_library.py b/src/calibre/library/check_library.py
index 20ef7a4862..0b958c73d4 100644
--- a/src/calibre/library/check_library.py
+++ b/src/calibre/library/check_library.py
@@ -10,6 +10,7 @@ import re, os, traceback, fnmatch
 from calibre import isbytestring
 from calibre.constants import filesystem_encoding
 from calibre.ebooks import BOOK_EXTENSIONS
+from polyglot.builtins import iteritems
 
 EBOOK_EXTENSIONS = frozenset(BOOK_EXTENSIONS)
 NORMALS = frozenset(['metadata.opf', 'cover.jpg'])
@@ -219,14 +220,14 @@ class CheckLibrary(object):
             missing = book_formats_lc - formats_lc
 
             # Check: any books that aren't formats or normally there?
-            for lcfn,ccfn in lc_map(filenames, unknowns).iteritems():
+            for lcfn,ccfn in iteritems(lc_map(filenames, unknowns)):
                 if lcfn in missing:  # An unknown format correctly registered
                     continue
                 self.extra_files.append((title_dir, os.path.join(db_path, ccfn),
                                          book_id))
 
             # Check: any book formats that should be there?
-            for lcfn,ccfn in lc_map(book_formats, missing).iteritems():
+            for lcfn,ccfn in iteritems(lc_map(book_formats, missing)):
                 if lcfn in unknowns:  # An unknown format correctly registered
                     continue
                 self.missing_formats.append((title_dir,
diff --git a/src/calibre/library/database.py b/src/calibre/library/database.py
index 8c78324215..b303833439 100644
--- a/src/calibre/library/database.py
+++ b/src/calibre/library/database.py
@@ -1337,10 +1337,10 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
         formats, metadata, uris = iter(formats), iter(metadata), iter(uris)
         duplicates = []
         for path in paths:
-            mi = metadata.next()
-            format = formats.next()
+            mi = next(metadata)
+            format = next(formats)
             try:
-                uri = uris.next()
+                uri = next(uris)
             except StopIteration:
                 uri = None
             if not add_duplicates and self.has_book(mi):
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index 239f72871f..80f11ea65e 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -47,7 +47,7 @@ from calibre.db.lazy import FormatMetadata, FormatsList
 from calibre.db.categories import Tag, CATEGORY_SORTS
 from calibre.utils.localization import (canonicalize_lang,
         calibre_langcode_to_name)
-from polyglot.builtins import unicode_type, string_or_bytes
+from polyglot.builtins import iteritems, iterkeys, unicode_type, string_or_bytes
 
 copyfile = os.link if hasattr(os, 'link') else shutil.copyfile
 SPOOL_SIZE = 30*1024*1024
@@ -405,17 +405,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
              '(SELECT MAX(uncompressed_size) FROM data WHERE book=books.id) size',
             ('rating', 'ratings', 'rating', 'ratings.rating'),
             ('tags', 'tags', 'tag', 'group_concat(name)'),
-             '(SELECT text FROM comments WHERE book=books.id) comments',
+            '(SELECT text FROM comments WHERE book=books.id) comments',
             ('series', 'series', 'series', 'name'),
             ('publisher', 'publishers', 'publisher', 'name'),
-             'series_index',
-             'sort',
-             'author_sort',
-             '(SELECT group_concat(format) FROM data WHERE data.book=books.id) formats',
-             'path',
-             'pubdate',
-             'uuid',
-             'has_cover',
+            'series_index',
+            'sort',
+            'author_sort',
+            '(SELECT group_concat(format) FROM data WHERE data.book=books.id) formats',
+            'path',
+            'pubdate',
+            'uuid',
+            'has_cover',
             ('au_map', 'authors', 'author',
                 'aum_sortconcat(link.id, authors.name, authors.sort, authors.link)'),
             'last_modified',
@@ -442,7 +442,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
              'formats':13, 'path':14, 'pubdate':15, 'uuid':16, 'cover':17,
              'au_map':18, 'last_modified':19, 'identifiers':20, 'languages':21}
 
-        for k,v in self.FIELD_MAP.iteritems():
+        for k,v in iteritems(self.FIELD_MAP):
             self.field_metadata.set_field_record_index(k, v, prefer_custom=False)
 
         base = max(self.FIELD_MAP.values())
@@ -931,7 +931,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
                 # The random stuff is here to prevent a single book from
                 # blocking progress if its metadata cannot be written for some
                 # reason.
-                id_ = self.dirtied_cache.keys()[random.randint(0, l-1)]
+                id_ = list(self.dirtied_cache.keys())[random.randint(0, l-1)]
                 sequence = self.dirtied_cache[id_]
                 return (id_, sequence)
             return (None, None)
@@ -1259,7 +1259,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
 
     def format_files(self, index, index_is_id=False):
         id = index if index_is_id else self.id(index)
-        return [(v, k) for k, v in self.format_filename_cache[id].iteritems()]
+        return [(v, k) for k, v in iteritems(self.format_filename_cache[id])]
 
     def formats(self, index, index_is_id=False, verify_formats=True):
         ''' Return available formats as a comma separated list or None if there are no available formats '''
@@ -1798,7 +1798,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
 
         # First, build the maps. We need a category->items map and an
         # item -> (item_id, sort_val) map to use in the books loop
-        for category in tb_cats.iterkeys():
+        for category in iterkeys(tb_cats):
             cat = tb_cats[category]
             if not cat['is_category'] or cat['kind'] in ['user', 'search'] \
                     or category in ['news', 'formats'] or cat.get('is_csp',
@@ -1854,7 +1854,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
             md.append((category, cat['rec_index'],
                        cat['is_multiple'].get('cache_to_list', None), False))
 
-        for category in tb_cats.iterkeys():
+        for category in iterkeys(tb_cats):
             cat = tb_cats[category]
             if cat['datatype'] == 'composite' and \
                                 cat['display'].get('make_category', False):
@@ -1959,7 +1959,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
         # and building the Tag instances.
         categories = {}
         tag_class = Tag
-        for category in tb_cats.iterkeys():
+        for category in iterkeys(tb_cats):
             if category not in tcategories:
                 continue
             cat = tb_cats[category]
@@ -2119,7 +2119,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
                 continue
             user_categories[c] = []
             for sc in gst[c]:
-                if sc in categories.keys():
+                if sc in list(categories.keys()):
                     for t in categories[sc]:
                         user_categories[c].append([t.name, sc, 0])
 
@@ -2367,13 +2367,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
             self.set_identifiers(id, mi_idents, notify=False, commit=False)
         elif mi_idents:
             identifiers = self.get_identifiers(id, index_is_id=True)
-            for key, val in mi_idents.iteritems():
+            for key, val in iteritems(mi_idents):
                 if val and val.strip():  # Don't delete an existing identifier
                     identifiers[icu_lower(key)] = val
             self.set_identifiers(id, identifiers, notify=False, commit=False)
 
         user_mi = mi.get_all_user_metadata(make_copy=False)
-        for key in user_mi.iterkeys():
+        for key in iterkeys(user_mi):
             if key in self.field_metadata and \
                     user_mi[key]['datatype'] == self.field_metadata[key]['datatype'] and \
                     (user_mi[key]['datatype'] != 'text' or
@@ -3321,7 +3321,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
                 'INSERT OR REPLACE INTO identifiers (book, type, val) VALUES (?, ?, ?)', (id_, typ, val))
         if changed:
             raw = ','.join(['%s:%s'%(k, v) for k, v in
-                identifiers.iteritems()])
+                iteritems(identifiers)])
             self.data.set(id_, self.FIELD_MAP['identifiers'], raw,
                     row_is_id=True)
             if commit:
@@ -3333,16 +3333,16 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
         cleaned = {}
         if not identifiers:
             identifiers = {}
-        for typ, val in identifiers.iteritems():
+        for typ, val in iteritems(identifiers):
             typ, val = self._clean_identifier(typ, val)
             if val:
                 cleaned[typ] = val
         self.conn.execute('DELETE FROM identifiers WHERE book=?', (id_,))
         self.conn.executemany(
             'INSERT INTO identifiers (book, type, val) VALUES (?, ?, ?)',
-            [(id_, k, v) for k, v in cleaned.iteritems()])
+            [(id_, k, v) for k, v in iteritems(cleaned)])
         raw = ','.join(['%s:%s'%(k, v) for k, v in
-                cleaned.iteritems()])
+                iteritems(cleaned)])
         self.data.set(id_, self.FIELD_MAP['identifiers'], raw,
                     row_is_id=True)
         if commit:
@@ -3498,9 +3498,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
         ids = []
         postimport = []
         for path in paths:
-            mi = metadata.next()
+            mi = next(metadata)
             self._add_newbook_tag(mi)
-            format = formats.next()
+            format = next(formats)
             if not add_duplicates and self.has_book(mi):
                 duplicates.append((path, format, mi))
                 continue
@@ -3683,7 +3683,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
         self.conn.executemany(
             'INSERT OR REPLACE INTO books_plugin_data (book, name, val) VALUES (?, ?, ?)',
             [(book_id, name, json.dumps(val, default=to_json))
-                    for book_id, val in vals.iteritems()])
+                    for book_id, val in iteritems(vals)])
         self.commit()
 
     def get_custom_book_data(self, book_id, name, default=None):
diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py
index 2569b56523..9abdd6d853 100644
--- a/src/calibre/library/field_metadata.py
+++ b/src/calibre/library/field_metadata.py
@@ -7,6 +7,7 @@ import traceback
 from collections import OrderedDict
 
 from calibre.utils.config_base import tweaks
+from polyglot.builtins import iteritems, iterkeys, itervalues
 
 category_icon_map = {
                     'authors'    : 'user_profile.png',
@@ -428,7 +429,7 @@ class FieldMetadata(object):
         return key in self
 
     def keys(self):
-        return self._tb_cats.keys()
+        return list(self._tb_cats.keys())
 
     def __eq__(self, other):
         if not isinstance(other, FieldMetadata):
@@ -484,21 +485,21 @@ class FieldMetadata(object):
             yield key
 
     def itervalues(self):
-        return self._tb_cats.itervalues()
+        return itervalues(self._tb_cats)
 
     def values(self):
-        return self._tb_cats.values()
+        return list(self._tb_cats.values())
 
     def iteritems(self):
         for key in self._tb_cats:
             yield (key, self._tb_cats[key])
 
     def custom_iteritems(self):
-        for key, meta in self._tb_custom_fields.iteritems():
+        for key, meta in iteritems(self._tb_custom_fields):
             yield (key, meta)
 
     def items(self):
-        return list(self.iteritems())
+        return list(iteritems(self))
 
     def is_custom_field(self, key):
         return key.startswith(self.custom_field_prefix)
@@ -508,7 +509,7 @@ class FieldMetadata(object):
         return self.is_custom_field(key) or key.startswith('@')
 
     def ignorable_field_keys(self):
-        return [k for k in self._tb_cats.iterkeys() if self.is_ignorable_field(k)]
+        return [k for k in iterkeys(self._tb_cats) if self.is_ignorable_field(k)]
 
     def is_series_index(self, key):
         try:
@@ -681,8 +682,8 @@ def fm_as_dict(self):
         'custom_fields': self._tb_custom_fields,
         'search_term_map': self._search_term_map,
         'custom_label_to_key_map': self.custom_label_to_key_map,
-        'user_categories': {k:v for k, v in self._tb_cats.iteritems() if v['kind'] == 'user'},
-        'search_categories': {k:v for k, v in self._tb_cats.iteritems() if v['kind'] == 'search'},
+        'user_categories': {k:v for k, v in iteritems(self._tb_cats) if v['kind'] == 'user'},
+        'search_categories': {k:v for k, v in iteritems(self._tb_cats) if v['kind'] == 'search'},
     }
 
 
@@ -692,6 +693,6 @@ def fm_from_dict(src):
     ans._search_term_map = src['search_term_map']
     ans.custom_label_to_key_map = src['custom_label_to_key_map']
     for q in ('custom_fields', 'user_categories', 'search_categories'):
-        for k, v in src[q].iteritems():
+        for k, v in iteritems(src[q]):
             ans._tb_cats[k] = v
     return ans
diff --git a/src/calibre/library/prefs.py b/src/calibre/library/prefs.py
index d5e7398ffa..3c41a4d78f 100644
--- a/src/calibre/library/prefs.py
+++ b/src/calibre/library/prefs.py
@@ -10,7 +10,7 @@ import json, os
 from calibre.constants import preferred_encoding
 from calibre.utils.config import to_json, from_json
 from calibre import prints
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, unicode_type
 
 
 class DBPrefs(dict):
@@ -98,7 +98,7 @@ class DBPrefs(dict):
                     return d
                 cls.clear()
                 cls.db.conn.execute('DELETE FROM preferences')
-                for k,v in d.iteritems():
+                for k,v in iteritems(d):
                     raw = cls.to_raw(v)
                     cls.db.conn.execute(
                         'INSERT INTO preferences (key,val) VALUES (?,?)', (k, raw))
diff --git a/src/calibre/library/restore.py b/src/calibre/library/restore.py
index b22ec16253..4a2f428f60 100644
--- a/src/calibre/library/restore.py
+++ b/src/calibre/library/restore.py
@@ -16,6 +16,8 @@ from calibre.library.prefs import DBPrefs
 from calibre.constants import filesystem_encoding
 from calibre.utils.date import utcfromtimestamp
 from calibre import isbytestring
+from polyglot.builtins import iteritems, iterkeys
+i
 
 NON_EBOOK_EXTENSIONS = frozenset([
         'jpg', 'jpeg', 'gif', 'png', 'bmp',
@@ -196,7 +198,7 @@ class Restore(Thread):
             self.mismatched_dirs.append(dirpath)
 
         alm = mi.get('author_link_map', {})
-        for author, link in alm.iteritems():
+        for author, link in iteritems(alm):
             existing_link, timestamp = self.authors_links.get(author, (None, None))
             if existing_link is None or existing_link != link and timestamp < mi.timestamp:
                 self.authors_links[author] = (link, mi.timestamp)
@@ -247,7 +249,7 @@ class Restore(Thread):
                 self.failed_restores.append((book, traceback.format_exc()))
             self.progress_callback(book['mi'].title, i+1)
 
-        for author in self.authors_links.iterkeys():
+        for author in iterkeys(self.authors_links):
             link, ign = self.authors_links[author]
             db.conn.execute('UPDATE authors SET link=? WHERE name=?',
                             (link, author.replace(',', '|')))
@@ -278,4 +280,3 @@ class Restore(Thread):
             os.remove(save_path)
         os.rename(dbpath, save_path)
         shutil.copyfile(ndbpath, dbpath)
-
diff --git a/src/calibre/library/schema_upgrades.py b/src/calibre/library/schema_upgrades.py
index a0ff54c302..8b4b6e6c83 100644
--- a/src/calibre/library/schema_upgrades.py
+++ b/src/calibre/library/schema_upgrades.py
@@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en'
 import os
 
 from calibre.utils.date import isoformat, DEFAULT_DATE
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iterkeys, itervalues, unicode_type
 
 
 class SchemaUpgrade(object):
@@ -293,7 +293,7 @@ class SchemaUpgrade(object):
                 '''.format(tn=table_name, cn=column_name, vcn=view_column_name))
             self.conn.executescript(script)
 
-        for field in self.field_metadata.itervalues():
+        for field in itervalues(self.field_metadata):
             if field['is_category'] and not field['is_custom'] and 'link_column' in field:
                 table = self.conn.get(
                     'SELECT name FROM sqlite_master WHERE type="table" AND name=?',
@@ -369,7 +369,7 @@ class SchemaUpgrade(object):
                 '''.format(lt=link_table_name, table=table_name)
             self.conn.executescript(script)
 
-        for field in self.field_metadata.itervalues():
+        for field in itervalues(self.field_metadata):
             if field['is_category'] and not field['is_custom'] and 'link_column' in field:
                 table = self.conn.get(
                     'SELECT name FROM sqlite_master WHERE type="table" AND name=?',
@@ -590,7 +590,7 @@ class SchemaUpgrade(object):
                     custom_recipe_filename
             bdir = os.path.dirname(custom_recipes.file_path)
             for id_, title, script in recipes:
-                existing = frozenset(map(int, custom_recipes.iterkeys()))
+                existing = frozenset(map(int, iterkeys(custom_recipes)))
                 if id_ in existing:
                     id_ = max(existing) + 1000
                 id_ = str(id_)
diff --git a/src/calibre/linux.py b/src/calibre/linux.py
index 194059540b..8700c0ec08 100644
--- a/src/calibre/linux.py
+++ b/src/calibre/linux.py
@@ -13,6 +13,7 @@ from calibre.constants import islinux, isbsd
 from calibre.customize.ui import all_input_formats
 from calibre.ptempfile import TemporaryDirectory
 from calibre import CurrentDir
+from polyglot.builtins import iteritems
 
 
 entry_points = {
@@ -70,7 +71,7 @@ class PreserveMIMEDefaults(object):
                 self.initial_values[x] = None
 
     def __exit__(self, *args):
-        for path, val in self.initial_values.iteritems():
+        for path, val in iteritems(self.initial_values):
             if val is None:
                 try:
                     os.remove(path)
@@ -416,13 +417,13 @@ _ebook_edit() {
         f.write('\n_calibredb_cmds() {\n  local commands; commands=(\n')
         f.write('    {-h,--help}":Show help"\n')
         f.write('    "--version:Show version"\n')
-        for command, desc in descs.iteritems():
+        for command, desc in iteritems(descs):
             f.write('    "%s:%s"\n'%(
                 command, desc.replace(':', '\\:').replace('"', '\'')))
         f.write('  )\n  _describe -t commands "calibredb command" commands \n}\n')
 
         subcommands = []
-        for command, parser in parsers.iteritems():
+        for command, parser in iteritems(parsers):
             exts = []
             if command == 'catalog':
                 exts = [x.lower() for x in available_catalog_formats()]
@@ -477,7 +478,7 @@ _ebook_edit() {
                 self.do_calibredb(f)
                 self.do_ebook_edit(f)
                 f.write('case $service in\n')
-                for c, txt in self.commands.iteritems():
+                for c, txt in iteritems(self.commands):
                     if isinstance(txt, type(u'')):
                         txt = txt.encode('utf-8')
                     if isinstance(c, type(u'')):
@@ -651,7 +652,7 @@ class PostInstall:
         print('\n'+'_'*20, 'WARNING','_'*20)
         prints(*args, **kwargs)
         print('_'*50)
-        print ('\n')
+        print('\n')
         self.warnings.append((args, kwargs))
         sys.stdout.flush()
 
@@ -1101,7 +1102,7 @@ def write_appdata(key, entry, base, translators):
     description = E.description()
     for para in entry['description']:
         description.append(E.p(para))
-        for lang, t in translators.iteritems():
+        for lang, t in iteritems(translators):
             tp = t.ugettext(para)
             if tp != para:
                 description.append(E.p(tp))
@@ -1118,7 +1119,7 @@ def write_appdata(key, entry, base, translators):
         screenshots,
         type='desktop'
     )
-    for lang, t in translators.iteritems():
+    for lang, t in iteritems(translators):
         tp = t.ugettext(entry['summary'])
         if tp != entry['summary']:
             root.append(E.summary(tp))
diff --git a/src/calibre/spell/dictionary.py b/src/calibre/spell/dictionary.py
index a49ee8a04c..598c6e302d 100644
--- a/src/calibre/spell/dictionary.py
+++ b/src/calibre/spell/dictionary.py
@@ -18,7 +18,7 @@ from calibre.spell import parse_lang_code
 from calibre.utils.config import JSONConfig
 from calibre.utils.icu import capitalize
 from calibre.utils.localization import get_lang, get_system_locale
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, itervalues, unicode_type
 
 Dictionary = namedtuple('Dictionary', 'primary_locale locales dicpath affpath builtin name id')
 LoadedDictionary = namedtuple('Dictionary', 'primary_locale locales obj builtin name id')
@@ -102,7 +102,7 @@ def best_locale_for_language(langcode):
 
 
 def preferred_dictionary(locale):
-    return {parse_lang_code(k):v for k, v in dprefs['preferred_dictionaries'].iteritems()}.get(locale, None)
+    return {parse_lang_code(k):v for k, v in iteritems(dprefs['preferred_dictionaries'])}.get(locale, None)
 
 
 def remove_dictionary(dictionary):
@@ -110,7 +110,7 @@ def remove_dictionary(dictionary):
         raise ValueError('Cannot remove builtin dictionaries')
     base = os.path.dirname(dictionary.dicpath)
     shutil.rmtree(base)
-    dprefs['preferred_dictionaries'] = {k:v for k, v in dprefs['preferred_dictionaries'].iteritems() if v != dictionary.id}
+    dprefs['preferred_dictionaries'] = {k:v for k, v in iteritems(dprefs['preferred_dictionaries']) if v != dictionary.id}
 
 
 def rename_dictionary(dictionary, name):
@@ -255,13 +255,13 @@ class Dictionaries(object):
         dprefs['user_dictionaries'] = [d.serialize() for d in self.all_user_dictionaries]
 
     def add_user_words(self, words, langcode):
-        for d in self.dictionaries.itervalues():
+        for d in itervalues(self.dictionaries):
             if d and getattr(d.primary_locale, 'langcode', None) == langcode:
                 for word in words:
                     d.obj.add(word)
 
     def remove_user_words(self, words, langcode):
-        for d in self.dictionaries.itervalues():
+        for d in itervalues(self.dictionaries):
             if d and d.primary_locale.langcode == langcode:
                 for word in words:
                     d.obj.remove(word)
@@ -313,7 +313,7 @@ class Dictionaries(object):
         if changed:
             for key in words:
                 self.word_cache.pop(key, None)
-            for langcode, words in removals.iteritems():
+            for langcode, words in iteritems(removals):
                 self.remove_user_words(words, langcode)
             self.save_user_dictionaries()
         return changed
diff --git a/src/calibre/spell/import_from.py b/src/calibre/spell/import_from.py
index e2763eb04e..1d29fdca80 100644
--- a/src/calibre/spell/import_from.py
+++ b/src/calibre/spell/import_from.py
@@ -12,6 +12,7 @@ from lxml import etree
 
 from calibre.constants import config_dir
 from calibre.utils.zipfile import ZipFile
+from polyglot.builtins import iteritems
 
 NS_MAP = {
     'oor': "http://openoffice.org/2001/registry",
@@ -68,7 +69,7 @@ def import_from_libreoffice_source_tree(source_path):
     base = P('dictionaries', allow_user_override=False)
     want_locales = set(BUILTIN_LOCALES)
 
-    for (dic, aff), locales in dictionaries.iteritems():
+    for (dic, aff), locales in iteritems(dictionaries):
         c = set(locales) & want_locales
         if c:
             locale = tuple(c)[0]
@@ -126,7 +127,7 @@ def import_from_oxt(source_path, name, dest_dir=None, prefix='dic-'):
         root = etree.fromstring(zf.open('META-INF/manifest.xml').read())
         xcu = XPath('//manifest:file-entry[@manifest:media-type="application/vnd.sun.star.configuration-data"]')(root)[0].get(
             '{%s}full-path' % NS_MAP['manifest'])
-        for (dic, aff), locales in parse_xcu(zf.open(xcu).read(), origin='').iteritems():
+        for (dic, aff), locales in iteritems(parse_xcu(zf.open(xcu).read(), origin='')):
             dic, aff = dic.lstrip('/'), aff.lstrip('/')
             d = tempfile.mkdtemp(prefix=prefix, dir=dest_dir)
             locales = uniq([x for x in map(fill_country_code, locales) if parse_lang_code(x).countrycode])
@@ -143,5 +144,6 @@ def import_from_oxt(source_path, name, dest_dir=None, prefix='dic-'):
             num += 1
     return num
 
+
 if __name__ == '__main__':
     import_from_libreoffice_source_tree(sys.argv[-1])
diff --git a/src/calibre/srv/ajax.py b/src/calibre/srv/ajax.py
index ccd8319eaf..dd577408f5 100644
--- a/src/calibre/srv/ajax.py
+++ b/src/calibre/srv/ajax.py
@@ -7,7 +7,7 @@ __license__ = 'GPL v3'
 __copyright__ = '2015, Kovid Goyal '
 
 from functools import partial
-from polyglot.builtins import unicode_type, zip, string_or_bytes
+from polyglot.builtins import iteritems, iterkeys, itervalues, unicode_type, zip, string_or_bytes
 from itertools import cycle
 
 from calibre import force_unicode
@@ -77,13 +77,13 @@ def book_to_json(ctx, rd, db, book_id,
 
     if not device_compatible:
         mi.format_metadata = {k.lower():dict(v) for k, v in
-                mi.format_metadata.iteritems()}
-        for v in mi.format_metadata.itervalues():
+                iteritems(mi.format_metadata)}
+        for v in itervalues(mi.format_metadata):
             mtime = v.get('mtime', None)
             if mtime is not None:
                 v['mtime'] = isoformat(mtime, as_utc=True)
         data['format_metadata'] = mi.format_metadata
-        fmts = set(x.lower() for x in mi.format_metadata.iterkeys())
+        fmts = set(x.lower() for x in iterkeys(mi.format_metadata))
         pf = prefs['output_format'].lower()
         other_fmts = list(fmts)
         try:
@@ -280,7 +280,7 @@ def categories(ctx, rd, library_id):
             ans[url] = (display_name, icon)
 
         ans = [{'url':k, 'name':v[0], 'icon':v[1], 'is_category':True}
-                for k, v in ans.iteritems()]
+                for k, v in iteritems(ans)]
         ans.sort(key=lambda x: sort_key(x['name']))
         for name, url, icon in [
                 (_('All books'), 'allbooks', 'book.png'),
diff --git a/src/calibre/srv/auto_reload.py b/src/calibre/srv/auto_reload.py
index e986846cac..7051a540d8 100644
--- a/src/calibre/srv/auto_reload.py
+++ b/src/calibre/srv/auto_reload.py
@@ -17,6 +17,7 @@ from calibre.srv.standalone import create_option_parser
 from calibre.srv.utils import create_sock_pair
 from calibre.srv.web_socket import DummyHandler
 from calibre.utils.monotonic import monotonic
+from polyglot.builtins import iterkeys, itervalues
 from polyglot.queue import Queue, Empty
 
 MAX_RETRIES = 10
@@ -75,7 +76,7 @@ if islinux:
 
         def loop(self):
             while True:
-                r = select.select([self.srv_sock] + list(self.fd_map.iterkeys()), [], [])[0]
+                r = select.select([self.srv_sock] + list(iterkeys(self.fd_map)), [], [])[0]
                 modified = set()
                 for fd in r:
                     if fd is self.srv_sock:
@@ -345,14 +346,14 @@ class ReloadHandler(DummyHandler):
 
     def notify_reload(self):
         with self.conn_lock:
-            for connref in self.connections.itervalues():
+            for connref in itervalues(self.connections):
                 conn = connref()
                 if conn is not None and conn.ready:
                     conn.send_websocket_message('reload')
 
     def ping(self):
         with self.conn_lock:
-            for connref in self.connections.itervalues():
+            for connref in itervalues(self.connections):
                 conn = connref()
                 if conn is not None and conn.ready:
                     conn.send_websocket_message('ping')
diff --git a/src/calibre/srv/cdb.py b/src/calibre/srv/cdb.py
index 7f2cf13d0a..7ed12d5d7d 100644
--- a/src/calibre/srv/cdb.py
+++ b/src/calibre/srv/cdb.py
@@ -19,6 +19,7 @@ from calibre.srv.routes import endpoint, json, msgpack_or_json
 from calibre.srv.utils import get_db, get_library_data
 from calibre.utils.imghdr import what
 from calibre.utils.serialize import MSGPACK_MIME, json_loads, msgpack_loads
+from polyglot.builtins import iteritems
 
 receive_data_methods = {'GET', 'POST'}
 
@@ -170,7 +171,7 @@ def cdb_set_fields(ctx, rd, book_id, library_id):
                 raise HTTPBadRequest('Cover data must be either JPEG or PNG')
         dirtied |= db.set_cover({book_id: cdata})
 
-    for field, value in changes.iteritems():
+    for field, value in iteritems(changes):
         dirtied |= db.set_field(field, {book_id: value})
     ctx.notify_changes(db.backend.library_path, metadata(dirtied))
     all_ids = dirtied if all_dirtied else (dirtied & loaded_book_ids)
diff --git a/src/calibre/srv/code.py b/src/calibre/srv/code.py
index 806577d525..99b7d160d6 100644
--- a/src/calibre/srv/code.py
+++ b/src/calibre/srv/code.py
@@ -29,6 +29,7 @@ from calibre.utils.icu import sort_key, numeric_sort_key
 from calibre.utils.localization import get_lang, lang_map_for_ui, localize_website_link
 from calibre.utils.search_query_parser import ParseException
 from calibre.utils.serialize import json_dumps
+from polyglot.builtins import iteritems, itervalues
 
 POSTABLE = frozenset({'GET', 'POST', 'HEAD'})
 
@@ -195,7 +196,7 @@ def get_library_init_data(ctx, rd, db, num, sorts, orders, vl):
         sf.pop('ondevice', None)
         ans['sortable_fields'] = sorted(
             ((sanitize_sort_field_name(db.field_metadata, k), v)
-             for k, v in sf.iteritems()),
+             for k, v in iteritems(sf)),
             key=lambda field_name: sort_key(field_name[1])
         )
         ans['field_metadata'] = db.field_metadata.all_metadata()
@@ -396,7 +397,7 @@ def tag_browser(ctx, rd):
 def all_lang_names():
     ans = getattr(all_lang_names, 'ans', None)
     if ans is None:
-        ans = all_lang_names.ans = tuple(sorted(lang_map_for_ui().itervalues(), key=numeric_sort_key))
+        ans = all_lang_names.ans = tuple(sorted(itervalues(lang_map_for_ui()), key=numeric_sort_key))
     return ans
 
 
diff --git a/src/calibre/srv/convert.py b/src/calibre/srv/convert.py
index 2246b5576e..811c8232de 100644
--- a/src/calibre/srv/convert.py
+++ b/src/calibre/srv/convert.py
@@ -17,6 +17,7 @@ from calibre.srv.routes import endpoint, json
 from calibre.srv.utils import get_library_data
 from calibre.utils.monotonic import monotonic
 from calibre.utils.shared_file import share_open
+from polyglot.builtins import iteritems
 
 receive_data_methods = {'GET', 'POST'}
 conversion_jobs = {}
@@ -61,8 +62,7 @@ class JobStatus(object):
 def expire_old_jobs():
     now = monotonic()
     with cache_lock:
-        remove = [job_id for job_id, job_status in conversion_jobs.iteritems(
-        ) if now - job_status.last_check_at >= 360]
+        remove = [job_id for job_id, job_status in iteritems(conversion_jobs) if now - job_status.last_check_at >= 360]
         for job_id in remove:
             job_status = conversion_jobs.pop(job_id)
             job_status.cleanup()
@@ -140,7 +140,7 @@ def queue_job(ctx, rd, library_id, db, fmt, book_id, conversion_data):
     recs.update(conversion_data['options'])
     recs['gui_preferred_input_format'] = conversion_data['input_fmt'].lower()
     save_specifics(db, book_id, recs)
-    recs = [(k, v, OptionRecommendation.HIGH) for k, v in recs.iteritems()]
+    recs = [(k, v, OptionRecommendation.HIGH) for k, v in iteritems(recs)]
 
     job_id = ctx.start_job(
         'Convert book %s (%s)' % (book_id, fmt), 'calibre.srv.convert',
@@ -234,7 +234,7 @@ def get_conversion_options(input_fmt, output_fmt, book_id, db):
         ans['defaults'].update(defaults)
         ans['help'] = plumber.get_all_help()
 
-    for group_name, option_names in OPTIONS['pipe'].iteritems():
+    for group_name, option_names in iteritems(OPTIONS['pipe']):
         merge_group(group_name, option_names)
 
     group_name, option_names = options_for_input_fmt(input_fmt)
diff --git a/src/calibre/srv/handler.py b/src/calibre/srv/handler.py
index dcce493d47..d4ec69c111 100644
--- a/src/calibre/srv/handler.py
+++ b/src/calibre/srv/handler.py
@@ -15,6 +15,7 @@ from calibre.srv.routes import Router
 from calibre.srv.users import UserManager
 from calibre.utils.date import utcnow
 from calibre.utils.search_query_parser import ParseException
+from polyglot.builtins import iterkeys, itervalues
 
 
 class Context(object):
@@ -66,7 +67,7 @@ class Context(object):
         allowed_libraries = self.library_broker.allowed_libraries(lf)
         if not allowed_libraries:
             raise HTTPForbidden('The user {} is not allowed to access any libraries on this server'.format(request_data.username))
-        library_id = library_id or next(allowed_libraries.iterkeys())
+        library_id = library_id or next(iterkeys(allowed_libraries))
         if library_id in allowed_libraries:
             return self.library_broker.get(library_id)
         raise HTTPForbidden('The user {} is not allowed to access the library {}'.format(request_data.username, library_id))
@@ -78,7 +79,7 @@ class Context(object):
         allowed_libraries = self.library_broker.allowed_libraries(lf)
         if not allowed_libraries:
             raise HTTPForbidden('The user {} is not allowed to access any libraries on this server'.format(request_data.username))
-        return dict(allowed_libraries), next(allowed_libraries.iterkeys())
+        return dict(allowed_libraries), next(iterkeys(allowed_libraries))
 
     def restriction_for(self, request_data, db):
         return self.user_manager.library_restriction(request_data.username, path_for_db(db))
@@ -198,7 +199,7 @@ class Handler(object):
         self.router = Router(ctx=ctx, url_prefix=opts.url_prefix, auth_controller=self.auth_controller)
         for module in SRV_MODULES:
             module = import_module('calibre.srv.' + module)
-            self.router.load_routes(vars(module).itervalues())
+            self.router.load_routes(itervalues(vars(module)))
         self.router.finalize()
         self.router.ctx.url_for = self.router.url_for
         self.dispatch = self.router.dispatch
diff --git a/src/calibre/srv/http_response.py b/src/calibre/srv/http_response.py
index 4873182849..b64db6dab6 100644
--- a/src/calibre/srv/http_response.py
+++ b/src/calibre/srv/http_response.py
@@ -13,7 +13,7 @@ from itertools import chain, repeat
 from operator import itemgetter
 from functools import wraps
 
-from polyglot.builtins import reraise, map, is_py3
+from polyglot.builtins import iteritems, itervalues, reraise, map, is_py3
 
 from calibre import guess_type, force_unicode
 from calibre.constants import __version__, plugins
@@ -419,7 +419,7 @@ class HTTPConnection(HTTPRequest):
         if self.close_after_response and self.response_protocol is HTTP11:
             buf.append("Connection: close")
         if extra_headers is not None:
-            for h, v in extra_headers.iteritems():
+            for h, v in iteritems(extra_headers):
                 buf.append('%s: %s' % (h, v))
         buf.append('')
         buf = [(x + '\r\n').encode('ascii') for x in buf]
@@ -510,9 +510,9 @@ class HTTPConnection(HTTPRequest):
             outheaders.set('Content-Type', ct + '; charset=UTF-8', replace_all=True)
 
         buf = [HTTP11 + (' %d ' % data.status_code) + httplib.responses[data.status_code]]
-        for header, value in sorted(outheaders.iteritems(), key=itemgetter(0)):
+        for header, value in sorted(iteritems(outheaders), key=itemgetter(0)):
             buf.append('%s: %s' % (header, value))
-        for morsel in data.outcookie.itervalues():
+        for morsel in itervalues(data.outcookie):
             morsel['version'] = '1'
             x = morsel.output()
             if isinstance(x, bytes):
diff --git a/src/calibre/srv/jobs.py b/src/calibre/srv/jobs.py
index d529ba3f6c..8385f715dd 100644
--- a/src/calibre/srv/jobs.py
+++ b/src/calibre/srv/jobs.py
@@ -14,6 +14,7 @@ from calibre import detect_ncpus, force_unicode
 from calibre.utils.monotonic import monotonic
 from calibre.utils.ipc.simple_worker import fork_job, WorkerError
 from polyglot.queue import Queue, Empty
+from polyglot.builtins import iteritems, itervalues
 
 StartEvent = namedtuple('StartEvent', 'job_id name module function args kwargs callback data')
 DoneEvent = namedtuple('DoneEvent', 'job_id')
@@ -145,12 +146,12 @@ class JobsManager(object):
     def shutdown(self, timeout=5.0):
         with self.lock:
             self.shutting_down = True
-            for job in self.jobs.itervalues():
+            for job in itervalues(self.jobs):
                 job.abort_event.set()
             self.events.put(False)
 
     def wait_for_shutdown(self, wait_till):
-        for job in self.jobs.itervalues():
+        for job in itervalues(self.jobs):
             delta = wait_till - monotonic()
             if delta > 0:
                 job.join(delta)
@@ -194,7 +195,7 @@ class JobsManager(object):
         with self.lock:
             mb = None
             now = monotonic()
-            for job in self.jobs.itervalues():
+            for job in itervalues(self.jobs):
                 if not job.done and not job.abort_event.is_set():
                     delta = self.max_job_time - (now - job.start_time)
                     if delta <= 0:
@@ -209,7 +210,7 @@ class JobsManager(object):
     def abort_hanging_jobs(self):
         now = monotonic()
         found = False
-        for job in self.jobs.itervalues():
+        for job in itervalues(self.jobs):
             if not job.done and not job.abort_event.is_set():
                 delta = self.max_job_time - (now - job.start_time)
                 if delta <= 0:
@@ -238,7 +239,7 @@ class JobsManager(object):
         with self.lock:
             remove = []
             now = monotonic()
-            for job_id, job in self.finished_jobs.iteritems():
+            for job_id, job in iteritems(self.finished_jobs):
                 if now - job.end_time > 3600:
                     remove.append(job_id)
             for job_id in remove:
diff --git a/src/calibre/srv/legacy.py b/src/calibre/srv/legacy.py
index 4d9cb81be9..197d56ac18 100644
--- a/src/calibre/srv/legacy.py
+++ b/src/calibre/srv/legacy.py
@@ -19,7 +19,7 @@ from calibre.srv.routes import endpoint
 from calibre.srv.utils import get_library_data, http_date
 from calibre.utils.cleantext import clean_xml_chars
 from calibre.utils.date import dt_as_local, is_date_undefined, timestampfromdt
-from polyglot.builtins import string_or_bytes
+from polyglot.builtins import iteritems, string_or_bytes
 from polyglot.urllib import urlencode
 
 # /mobile {{{
@@ -33,7 +33,7 @@ def clean(x):
 
 def E(tag, *children, **attribs):
     children = list(map(clean, children))
-    attribs = {k.rstrip('_').replace('_', '-'):clean(v) for k, v in attribs.iteritems()}
+    attribs = {k.rstrip('_').replace('_', '-'):clean(v) for k, v in iteritems(attribs)}
     return getattr(E_, tag)(*children, **attribs)
 
 
@@ -125,7 +125,7 @@ def build_navigation(start, num, total, url_base):  # {{{
 
 def build_choose_library(ctx, library_map):
     select = E.select(name='library_id')
-    for library_id, library_name in library_map.iteritems():
+    for library_id, library_name in iteritems(library_map):
         select.append(E.option(library_name, value=library_id))
     return E.div(
         E.form(
@@ -247,7 +247,7 @@ def mobile(ctx, rd):
     order = 'ascending' if ascending else 'descending'
     q = {b'search':search.encode('utf-8'), b'order':bytes(order), b'sort':sort_by.encode('utf-8'), b'num':bytes(num), 'library_id':library_id}
     url_base = ctx.url_for('/mobile') + '?' + urlencode(q)
-    lm = {k:v for k, v in library_map.iteritems() if k != library_id}
+    lm = {k:v for k, v in iteritems(library_map) if k != library_id}
     return build_index(rd, books, num, search, sort_by, order, start, total, url_base, db.field_metadata, ctx, lm, library_id)
 # }}}
 
diff --git a/src/calibre/srv/library_broker.py b/src/calibre/srv/library_broker.py
index 24f5e5938b..6d02eb062e 100644
--- a/src/calibre/srv/library_broker.py
+++ b/src/calibre/srv/library_broker.py
@@ -13,6 +13,7 @@ from calibre.db.cache import Cache
 from calibre.db.legacy import LibraryDatabase, create_backend, set_global_state
 from calibre.utils.filenames import samefile as _samefile
 from calibre.utils.monotonic import monotonic
+from polyglot.builtins import iteritems, iterkeys, itervalues
 
 
 def canonicalize_path(p):
@@ -114,13 +115,13 @@ class LibraryBroker(object):
 
     def close(self):
         with self:
-            for db in self.loaded_dbs.itervalues():
+            for db in itervalues(self.loaded_dbs):
                 getattr(db, 'close', lambda: None)()
             self.lmap, self.loaded_dbs = OrderedDict(), {}
 
     @property
     def default_library(self):
-        return next(self.lmap.iterkeys())
+        return next(iterkeys(self.lmap))
 
     @property
     def library_map(self):
@@ -130,9 +131,9 @@ class LibraryBroker(object):
     def allowed_libraries(self, filter_func):
         with self:
             allowed_names = filter_func(
-                basename(l) for l in self.lmap.itervalues())
+                basename(l) for l in itervalues(self.lmap))
             return OrderedDict(((lid, self.library_map[lid])
-                                for lid, path in self.lmap.iteritems()
+                                for lid, path in iteritems(self.lmap)
                                 if basename(path) in allowed_names))
 
     def __enter__(self):
@@ -179,7 +180,7 @@ class GuiLibraryBroker(LibraryBroker):
     def get_library(self, original_library_path):
         library_path = canonicalize_path(original_library_path)
         with self:
-            for library_id, path in self.lmap.iteritems():
+            for library_id, path in iteritems(self.lmap):
                 if samefile(library_path, path):
                     db = self.loaded_dbs.get(library_id)
                     if db is None:
@@ -201,7 +202,7 @@ class GuiLibraryBroker(LibraryBroker):
 
     def prepare_for_gui_library_change(self, newloc):
         # Must be called with lock held
-        for library_id, path in self.lmap.iteritems():
+        for library_id, path in iteritems(self.lmap):
             db = self.loaded_dbs.get(library_id)
             if db is not None and samefile(newloc, path):
                 if library_id == self.gui_library_id:
@@ -215,7 +216,7 @@ class GuiLibraryBroker(LibraryBroker):
         # Must be called with lock held
         original_path = path_for_db(db)
         newloc = canonicalize_path(original_path)
-        for library_id, path in self.lmap.iteritems():
+        for library_id, path in iteritems(self.lmap):
             if samefile(newloc, path):
                 self.loaded_dbs[library_id] = db
                 self.gui_library_id = library_id
@@ -256,7 +257,7 @@ class GuiLibraryBroker(LibraryBroker):
     def unload_library(self, library_path):
         with self:
             path = canonicalize_path(library_path)
-            for library_id, q in self.lmap.iteritems():
+            for library_id, q in iteritems(self.lmap):
                 if samefile(path, q):
                     break
             else:
@@ -269,7 +270,7 @@ class GuiLibraryBroker(LibraryBroker):
     def remove_library(self, path):
         with self:
             path = canonicalize_path(path)
-            for library_id, q in self.lmap.iteritems():
+            for library_id, q in iteritems(self.lmap):
                 if samefile(path, q):
                     break
             else:
diff --git a/src/calibre/srv/loop.py b/src/calibre/srv/loop.py
index 180603c42a..3c84587d64 100644
--- a/src/calibre/srv/loop.py
+++ b/src/calibre/srv/loop.py
@@ -24,7 +24,7 @@ from calibre.utils.socket_inheritance import set_socket_inherit
 from calibre.utils.logging import ThreadSafeLog
 from calibre.utils.monotonic import monotonic
 from calibre.utils.mdns import get_external_ip
-from polyglot.builtins import range
+from polyglot.builtins import iteritems, range
 from polyglot.queue import Empty, Full
 
 READ, WRITE, RDWR, WAIT = 'READ', 'WRITE', 'RDWR', 'WAIT'
@@ -505,7 +505,7 @@ class ServerLoop(object):
         now = monotonic()
         read_needed, write_needed, readable, remove, close_needed = [], [], [], [], []
         has_ssl = self.ssl_context is not None
-        for s, conn in self.connection_map.iteritems():
+        for s, conn in iteritems(self.connection_map):
             if now - conn.last_activity > self.opts.timeout:
                 if conn.handle_timeout():
                     conn.last_activity = now
@@ -551,7 +551,7 @@ class ServerLoop(object):
                 # e.args[0]
                 if getattr(e, 'errno', e.args[0]) in socket_errors_eintr:
                     return
-                for s, conn in tuple(self.connection_map.iteritems()):
+                for s, conn in tuple(iteritems(self.connection_map)):
                     try:
                         select.select([s], [], [], 0)
                     except (select.error, socket.error) as e:
@@ -681,7 +681,7 @@ class ServerLoop(object):
                 self.socket = None
         except socket.error:
             pass
-        for s, conn in tuple(self.connection_map.iteritems()):
+        for s, conn in tuple(iteritems(self.connection_map)):
             self.close(s, conn)
         wait_till = monotonic() + self.opts.shutdown_timeout
         for pool in (self.plugin_pool, self.pool):
diff --git a/src/calibre/srv/manage_users_cli.py b/src/calibre/srv/manage_users_cli.py
index 70ee4aada0..916e6d7358 100644
--- a/src/calibre/srv/manage_users_cli.py
+++ b/src/calibre/srv/manage_users_cli.py
@@ -9,6 +9,7 @@ from functools import partial
 
 from calibre import prints
 from calibre.constants import preferred_encoding
+from polyglot.builtins import iteritems
 
 # Manage users CLI {{{
 
@@ -137,7 +138,7 @@ def manage_users_cli(path=None):
             prints(
                 _('{} has the following additional per-library restrictions:')
                 .format(username))
-            for k, v in r['library_restrictions'].iteritems():
+            for k, v in iteritems(r['library_restrictions']):
                 prints(k + ':', v)
         else:
             prints(_('{} has no additional per-library restrictions').format(username))
diff --git a/src/calibre/srv/metadata.py b/src/calibre/srv/metadata.py
index 0a41c41161..2e28cf7786 100644
--- a/src/calibre/srv/metadata.py
+++ b/src/calibre/srv/metadata.py
@@ -22,7 +22,7 @@ from calibre.utils.icu import collation_order
 from calibre.utils.localization import calibre_langcode_to_name
 from calibre.library.comments import comments_to_html, markdown
 from calibre.library.field_metadata import category_icon_map
-from polyglot.builtins import range
+from polyglot.builtins import iteritems, itervalues, range
 from polyglot.urllib import quote
 
 IGNORED_FIELDS = frozenset('cover ondevice path marked au_map size'.split())
@@ -183,11 +183,11 @@ def icon_map():
             from calibre.gui2 import gprefs
             _icon_map = category_icon_map.copy()
             custom_icons = gprefs.get('tags_browser_category_icons', {})
-            for k, v in custom_icons.iteritems():
+            for k, v in iteritems(custom_icons):
                 if os.access(os.path.join(config_dir, 'tb_icons', v), os.R_OK):
                     _icon_map[k] = '_' + quote(v)
             _icon_map['file_type_icons'] = {
-                k:'mimetypes/%s.png' % v for k, v in EXT_MAP.iteritems()
+                k:'mimetypes/%s.png' % v for k, v in iteritems(EXT_MAP)
             }
         return _icon_map
 
@@ -512,7 +512,7 @@ def fillout_tree(root, items, node_id_map, category_nodes, category_data, field_
                 count += 1
         item['avg_rating'] = float(total)/count if count else 0
 
-    for item_id, item in tag_map.itervalues():
+    for item_id, item in itervalues(tag_map):
         id_len = len(item.pop('id_set', ()))
         if id_len:
             item['count'] = id_len
diff --git a/src/calibre/srv/opds.py b/src/calibre/srv/opds.py
index 4319eecd5d..d62112ec22 100644
--- a/src/calibre/srv/opds.py
+++ b/src/calibre/srv/opds.py
@@ -26,7 +26,7 @@ from calibre import force_unicode
 from calibre.srv.errors import HTTPNotFound, HTTPInternalServerError
 from calibre.srv.routes import endpoint
 from calibre.srv.utils import get_library_data, http_date, Offsets
-from polyglot.builtins import unicode_type
+from polyglot.builtins import iteritems, unicode_type
 from polyglot.urllib import urlencode
 
 
@@ -301,7 +301,7 @@ class TopLevel(Feed):  # {{{
             categories]
         for x in subcatalogs:
             self.root.append(x)
-        for library_id, library_name in sorted(request_context.library_map.iteritems(), key=lambda item: sort_key(item[1])):
+        for library_id, library_name in sorted(iteritems(request_context.library_map), key=lambda item: sort_key(item[1])):
             id_ = 'calibre-library:' + library_id
             self.root.append(E.entry(
                 TITLE(_('Library:') + ' ' + library_name),
diff --git a/src/calibre/srv/opts.py b/src/calibre/srv/opts.py
index 75d14ab56e..48177b72d6 100644
--- a/src/calibre/srv/opts.py
+++ b/src/calibre/srv/opts.py
@@ -13,7 +13,7 @@ from functools import partial
 
 from calibre.constants import config_dir
 from calibre.utils.lock import ExclusiveFile
-from polyglot.builtins import is_py3
+from polyglot.builtins import itervalues, is_py3
 if is_py3:
     from itertools import zip_longest
 else:
@@ -215,7 +215,7 @@ class Options(object):
     __slots__ = tuple(name for name in options)
 
     def __init__(self, **kwargs):
-        for opt in options.itervalues():
+        for opt in itervalues(options):
             setattr(self, opt.name, kwargs.get(opt.name, opt.default))
 
 
@@ -242,7 +242,7 @@ def boolean_option(add_option, opt):
 def opts_to_parser(usage):
     from calibre.utils.config import OptionParser
     parser =  OptionParser(usage)
-    for opt in options.itervalues():
+    for opt in itervalues(options):
         add_option = partial(parser.add_option, dest=opt.name, help=opt_to_cli_help(opt), default=opt.default)
         if opt.default is True or opt.default is False:
             boolean_option(add_option, opt)
diff --git a/src/calibre/srv/render_book.py b/src/calibre/srv/render_book.py
index 9f03211a92..8f9a5cd7f6 100644
--- a/src/calibre/srv/render_book.py
+++ b/src/calibre/srv/render_book.py
@@ -9,7 +9,6 @@ from base64 import standard_b64encode, standard_b64decode
 from collections import defaultdict, OrderedDict
 from itertools import count
 from functools import partial
-from polyglot.builtins import map, unicode_type
 
 from css_parser import replaceUrls
 from css_parser.css import CSSRule
@@ -28,6 +27,7 @@ from calibre.ebooks.oeb.polish.toc import get_toc, get_landmarks
 from calibre.ebooks.oeb.polish.utils import guess_type
 from calibre.utils.short_uuid import uuid4
 from calibre.utils.logging import default_log
+from polyglot.builtins import iteritems, iterkeys, map, unicode_type
 from polyglot.urllib import quote, urlparse
 
 RENDER_VERSION = 1
@@ -179,7 +179,7 @@ class Container(ContainerBase):
         # browser has no good way to distinguish between zero byte files and
         # load failures.
         excluded_names = {
-            name for name, mt in self.mime_map.iteritems() if
+            name for name, mt in iteritems(self.mime_map) if
             name == self.opf_name or mt == guess_type('a.ncx') or name.startswith('META-INF/') or
             name == 'mimetype' or not self.has_name_and_is_not_empty(name)}
         raster_cover_name, titlepage_name = self.create_cover_page(input_fmt.lower())
@@ -276,7 +276,7 @@ class Container(ContainerBase):
         # Firefox flakes out sometimes when dynamically creating