diff --git a/deluge/common.py b/deluge/common.py index b8f7ff528..d5f0d8a03 100644 --- a/deluge/common.py +++ b/deluge/common.py @@ -21,14 +21,20 @@ import re import subprocess import sys import time -import urllib -import urlparse import chardet import pkg_resources from deluge.error import InvalidPathError +try: + from urllib.parse import unquote_plus, urljoin + from urllib.request import pathname2url +except ImportError: + # PY2 fallback + from urlparse import urljoin # pylint: disable=ungrouped-imports + from urllib import pathname2url, unquote_plus # pylint: disable=ungrouped-imports + DBUS_FILEMAN = None # gi makes dbus available on Window but don't import it as unused. if platform.system() not in ('Windows', 'Microsoft', 'Darwin'): @@ -56,6 +62,8 @@ TORRENT_STATE = [ 'Moving' ] +PY2 = sys.version_info.major == 2 + def get_version(): """ @@ -82,12 +90,16 @@ def get_default_config_dir(filename=None): def save_config_path(resource): app_data_path = os.environ.get('APPDATA') if not app_data_path: - import _winreg - hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, - 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders') - app_data_reg = _winreg.QueryValueEx(hkey, 'AppData') + try: + import winreg + except ImportError: + import _winreg as winreg # For Python 2. + hkey = winreg.OpenKey( + winreg.HKEY_CURRENT_USER, + 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders') + app_data_reg = winreg.QueryValueEx(hkey, 'AppData') app_data_path = app_data_reg[0] - _winreg.CloseKey(hkey) + winreg.CloseKey(hkey) return os.path.join(app_data_path, resource) else: from xdg.BaseDirectory import save_config_path @@ -241,7 +253,7 @@ def show_file(path, timestamp=None): timestamp = int(time.time()) startup_id = '%s_%u_%s-dbus_TIME%d' % (os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp) if DBUS_FILEMAN: - paths = [urlparse.urljoin('file:', urllib.pathname2url(path))] + paths = [urljoin('file:', pathname2url(path))] DBUS_FILEMAN.ShowItems(paths, startup_id, dbus_interface='org.freedesktop.FileManager1') else: env = os.environ.copy() @@ -626,7 +638,7 @@ def get_magnet_info(uri): else: break elif param.startswith(dn_param): - name = urllib.unquote_plus(param[len(dn_param):]) + name = unquote_plus(param[len(dn_param):]) if info_hash: if not name: @@ -837,9 +849,9 @@ def utf8_encode_structure(data): """ if isinstance(data, (list, tuple)): - return type(data)(map(utf8_encode_structure, data)) + return type(data)([utf8_encode_structure(d) for d in data]) elif isinstance(data, dict): - return dict(map(utf8_encode_structure, data.items())) + return dict([utf8_encode_structure(d) for d in data.items()]) elif not isinstance(data, bytes): try: return data.encode('utf8') @@ -1048,7 +1060,7 @@ def unicode_argv(): # Remove Python executable and commands if present start = argc.value - len(sys.argv) return [argv[i] for i in - xrange(start, argc.value)] + range(start, argc.value)] else: # On other platforms, we have to find the likely encoding of the args and decode # First check if sys.stdout or stdin have encoding set diff --git a/deluge/component.py b/deluge/component.py index 476311410..882f3c2fa 100644 --- a/deluge/component.py +++ b/deluge/component.py @@ -17,6 +17,8 @@ from twisted.internet import reactor from twisted.internet.defer import DeferredList, fail, maybeDeferred, succeed from twisted.internet.task import LoopingCall, deferLater +from deluge.common import PY2 + log = logging.getLogger(__name__) @@ -307,7 +309,7 @@ class ComponentRegistry(object): # Start all the components if names is empty if not names: names = self.components.keys() - elif not isinstance(names, (list, tuple)): + elif isinstance(names, str if not PY2 else basestring): names = [names] def on_depends_started(result, name): @@ -341,7 +343,7 @@ class ComponentRegistry(object): """ if not names: names = self.components.keys() - elif not isinstance(names, (list, tuple)): + elif isinstance(names, str if not PY2 else basestring): names = [names] def on_dependents_stopped(result, name): @@ -379,7 +381,7 @@ class ComponentRegistry(object): """ if not names: names = self.components.keys() - elif not isinstance(names, (list, tuple)): + elif isinstance(names, str if not PY2 else basestring): names = [names] deferreds = [] @@ -405,7 +407,7 @@ class ComponentRegistry(object): """ if not names: names = self.components.keys() - elif not isinstance(names, (list, tuple)): + elif isinstance(names, str if not PY2 else basestring): names = [names] deferreds = [] @@ -429,7 +431,7 @@ class ComponentRegistry(object): def on_stopped(result): return DeferredList([comp._component_shutdown() for comp in self.components.values()]) - return self.stop(self.components.keys()).addCallback(on_stopped) + return self.stop(list(self.components.keys())).addCallback(on_stopped) def update(self): """Update all Components that are in a Started state.""" diff --git a/deluge/config.py b/deluge/config.py index ae867989a..84f24f66a 100644 --- a/deluge/config.py +++ b/deluge/config.py @@ -129,7 +129,7 @@ class Config(object): self._save_timer = None if defaults: - for key, value in defaults.iteritems(): + for key, value in defaults.items(): self.set_item(key, value) # Load the config from file in the config_dir @@ -367,7 +367,7 @@ class Config(object): """ log.debug('Calling all set functions..') - for key, value in self.__set_functions.iteritems(): + for key, value in self.__set_functions.items(): for func in value: func(key, self.__config[key]) diff --git a/deluge/configmanager.py b/deluge/configmanager.py index bfd39ca1b..f7b0e35aa 100644 --- a/deluge/configmanager.py +++ b/deluge/configmanager.py @@ -90,7 +90,7 @@ class _ConfigManager(object): """Get a reference to the Config object for this filename""" log.debug('Getting config: %s', config_file) # Create the config object if not already created - if config_file not in self.config_files.keys(): + if config_file not in self.config_files: self.config_files[config_file] = Config(config_file, defaults, config_dir=self.config_directory, file_version=file_version) diff --git a/deluge/core/authmanager.py b/deluge/core/authmanager.py index b9d429d57..ae0a5c520 100644 --- a/deluge/core/authmanager.py +++ b/deluge/core/authmanager.py @@ -27,12 +27,8 @@ AUTH_LEVELS_MAPPING = { 'READONLY': AUTH_LEVEL_READONLY, 'DEFAULT': AUTH_LEVEL_NORMAL, 'NORMAL': AUTH_LEVEL_DEFAULT, - 'ADMIN': AUTH_LEVEL_ADMIN -} - -AUTH_LEVELS_MAPPING_REVERSE = {} -for key, value in AUTH_LEVELS_MAPPING.iteritems(): - AUTH_LEVELS_MAPPING_REVERSE[value] = key + 'ADMIN': AUTH_LEVEL_ADMIN} +AUTH_LEVELS_MAPPING_REVERSE = {v: k for k, v in AUTH_LEVELS_MAPPING.items()} class Account(object): diff --git a/deluge/core/core.py b/deluge/core/core.py index 52cacafdf..5daf1a675 100644 --- a/deluge/core/core.py +++ b/deluge/core/core.py @@ -25,6 +25,7 @@ import deluge.common import deluge.component as component from deluge import path_chooser_common from deluge._libtorrent import lt +from deluge.common import PY2 from deluge.configmanager import ConfigManager, get_config_dir from deluge.core.alertmanager import AlertManager from deluge.core.authmanager import (AUTH_LEVEL_ADMIN, AUTH_LEVEL_NONE, AUTH_LEVELS_MAPPING, @@ -40,6 +41,12 @@ from deluge.error import AddTorrentError, DelugeError, InvalidPathError, Invalid from deluge.event import NewVersionAvailableEvent, SessionPausedEvent, SessionResumedEvent, TorrentQueueChangedEvent from deluge.httpdownloader import download_file +try: + from urllib.request import urlopen, URLError +except ImportError: + # PY2 fallback + from urllib2 import urlopen, URLError + log = logging.getLogger(__name__) OLD_SESSION_STATUS_KEYS = { @@ -293,7 +300,6 @@ class Core(component.Component): def get_new_release(self): log.debug('get_new_release') - from urllib2 import urlopen, URLError try: self.new_release = urlopen('http://download.deluge-torrent.org/version-1.0').read().strip() except URLError as ex: @@ -596,7 +602,7 @@ class Core(component.Component): status_dict, plugin_keys = args # Ask the plugin manager to fill in the plugin keys if len(plugin_keys) > 0: - for key in status_dict.keys(): + for key in status_dict: status_dict[key].update(self.pluginmanager.get_status(key, plugin_keys)) return status_dict d.addCallback(add_plugin_fields) @@ -635,7 +641,7 @@ class Core(component.Component): def set_config(self, config): """Set the config with values from dictionary""" # Load all the values into the configuration - for key in config.keys(): + for key in config: if self.read_only_config_keys and key in self.read_only_config_keys: continue self.config[key] = config[key] @@ -710,7 +716,7 @@ class Core(component.Component): if 'owner' in options and not self.core.authmanager.has_account(options['owner']): raise DelugeError('Username "%s" is not known.' % options['owner']) - if not isinstance(torrent_ids, (list, tuple)): + if isinstance(torrent_ids, str if not PY2 else basestring): torrent_ids = [torrent_ids] for torrent_id in torrent_ids: diff --git a/deluge/core/filtermanager.py b/deluge/core/filtermanager.py index 7919b0c5e..b2ade1abe 100644 --- a/deluge/core/filtermanager.py +++ b/deluge/core/filtermanager.py @@ -12,7 +12,7 @@ from __future__ import unicode_literals import logging import deluge.component as component -from deluge.common import TORRENT_STATE +from deluge.common import PY2, TORRENT_STATE log = logging.getLogger(__name__) @@ -133,7 +133,7 @@ class FilterManager(component.Component): # Sanitize input: filter-value must be a list of strings for key, value in filter_dict.items(): - if not isinstance(value, (list, tuple)): + if isinstance(value, str if not PY2 else basestring): filter_dict[key] = [value] # Optimized filter for id @@ -171,11 +171,11 @@ class FilterManager(component.Component): if not filter_dict: return torrent_ids - torrent_keys, plugin_keys = self.torrents.separate_keys(filter_dict.keys(), torrent_ids) + torrent_keys, plugin_keys = self.torrents.separate_keys(list(filter_dict), torrent_ids) # Leftover filter arguments, default filter on status fields. for torrent_id in list(torrent_ids): status = self.core.create_torrent_status(torrent_id, torrent_keys, plugin_keys) - for field, values in filter_dict.iteritems(): + for field, values in filter_dict.items(): if field in status and status[field] in values: continue elif torrent_id in torrent_ids: @@ -212,9 +212,7 @@ class FilterManager(component.Component): self._hide_state_items(items[cat]) # Return a dict of tuples: - sorted_items = {} - for field in tree_keys: - sorted_items[field] = sorted(items[field].iteritems()) + sorted_items = {field: sorted(items[field].items()) for field in tree_keys} if 'state' in tree_keys: sorted_items['state'].sort(self._sort_state_items) diff --git a/deluge/core/preferencesmanager.py b/deluge/core/preferencesmanager.py index 414c9904f..3ce3d8557 100644 --- a/deluge/core/preferencesmanager.py +++ b/deluge/core/preferencesmanager.py @@ -12,6 +12,7 @@ from __future__ import unicode_literals import logging import os +import platform import random import threading @@ -28,6 +29,13 @@ try: except ImportError: GeoIP = None +try: + from urllib.parse import quote_plus + from urllib.request import urlopen +except ImportError: + from urllib import quote_plus + from urllib2 import urlopen + log = logging.getLogger(__name__) DEFAULT_PREFS = { @@ -322,9 +330,6 @@ class PreferencesManager(component.Component): now = time.time() # check if we've done this within the last week or never if (now - self.config['info_sent']) >= (60 * 60 * 24 * 7): - from urllib import quote_plus - from urllib2 import urlopen - import platform try: url = 'http://deluge-torrent.org/stats_get.php?processor=' + \ platform.machine() + '&python=' + platform.python_version() \ diff --git a/deluge/core/rpcserver.py b/deluge/core/rpcserver.py index c7a104c75..83123d83c 100644 --- a/deluge/core/rpcserver.py +++ b/deluge/core/rpcserver.py @@ -437,7 +437,7 @@ class RPCServer(component.Component): :returns: the exported methods :rtype: list """ - return self.factory.methods.keys() + return list(self.factory.methods.keys()) def get_session_id(self): """ diff --git a/deluge/core/torrent.py b/deluge/core/torrent.py index ce6aecaf1..27a620e34 100644 --- a/deluge/core/torrent.py +++ b/deluge/core/torrent.py @@ -159,7 +159,7 @@ class TorrentOptions(dict): 'stop_ratio': 'stop_seed_ratio', 'super_seeding': 'super_seeding' } - for opt_k, conf_k in options_conf_map.iteritems(): + for opt_k, conf_k in options_conf_map.items(): self[opt_k] = config[conf_k] self['file_priorities'] = [] self['mapped_files'] = {} @@ -924,7 +924,7 @@ class Torrent(object): self.update_status(self.handle.status()) if all_keys: - keys = self.status_funcs.keys() + keys = self.status_funcs status_dict = {} @@ -1307,7 +1307,7 @@ class Torrent(object): torrent.waiting_on_folder_rename = [_dir for _dir in torrent.waiting_on_folder_rename if _dir] component.get('TorrentManager').save_resume_data((self.torrent_id,)) - d = DeferredList(wait_on_folder.values()) + d = DeferredList(list(wait_on_folder.values())) d.addBoth(on_folder_rename_complete, self, folder, new_folder) return d diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index 890b64b1f..14afe087b 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -10,7 +10,7 @@ """TorrentManager handles Torrent objects""" from __future__ import unicode_literals -import cPickle +import cPickle as pickle import datetime import logging import operator @@ -262,7 +262,7 @@ class TorrentManager(component.Component): list: A list of torrent_ids. """ - torrent_ids = self.torrents.keys() + torrent_ids = list(self.torrents.keys()) if component.get('RPCServer').get_session_auth_level() == AUTH_LEVEL_ADMIN: return torrent_ids @@ -493,8 +493,8 @@ class TorrentManager(component.Component): log.info('Loading torrent state: %s', filepath) try: with open(filepath, 'rb') as _file: - state = cPickle.load(_file) - except (IOError, EOFError, cPickle.UnpicklingError) as ex: + state = pickle.load(_file) + except (IOError, EOFError, pickle.UnpicklingError) as ex: log.warning('Unable to load %s: %s', filepath, ex) state = None else: @@ -640,10 +640,10 @@ class TorrentManager(component.Component): try: log.debug('Creating the temporary file: %s', filepath_tmp) with open(filepath_tmp, 'wb', 0) as _file: - cPickle.dump(state, _file) + pickle.dump(state, _file) _file.flush() os.fsync(_file.fileno()) - except (OSError, cPickle.PicklingError) as ex: + except (OSError, pickle.PicklingError) as ex: log.error('Unable to save %s: %s', filename, ex) return @@ -680,7 +680,7 @@ class TorrentManager(component.Component): """ if torrent_ids is None: - torrent_ids = (t[0] for t in self.torrents.iteritems() if t[1].handle.need_save_resume_data()) + torrent_ids = (tid for tid, t in self.torrents.items() if t.handle.need_save_resume_data()) def on_torrent_resume_save(dummy_result, torrent_id): """Recieved torrent resume_data alert so remove from waiting list""" @@ -852,8 +852,8 @@ class TorrentManager(component.Component): def cleanup_torrents_prev_status(self): """Run cleanup_prev_status for each registered torrent""" - for torrent in self.torrents.iteritems(): - torrent[1].cleanup_prev_status() + for torrent in self.torrents.values(): + torrent.cleanup_prev_status() def on_set_max_connections_per_torrent(self, key, value): """Sets the per-torrent connection limit""" @@ -1270,7 +1270,7 @@ class TorrentManager(component.Component): if self.torrents: for torrent_id in torrent_ids: if torrent_id in self.torrents: - status_keys = self.torrents[torrent_id].status_funcs.keys() + status_keys = list(self.torrents[torrent_id].status_funcs.keys()) leftover_keys = list(set(keys) - set(status_keys)) torrent_keys = list(set(keys) - set(leftover_keys)) return torrent_keys, leftover_keys diff --git a/deluge/metafile.py b/deluge/metafile.py index 1362d5b37..7e0da8bd8 100644 --- a/deluge/metafile.py +++ b/deluge/metafile.py @@ -27,9 +27,9 @@ log = logging.getLogger(__name__) ignore = ['core', 'CVS', 'Thumbs.db', 'desktop.ini'] noncharacter_translate = {} -for i in xrange(0xD800, 0xE000): +for i in range(0xD800, 0xE000): noncharacter_translate[i] = ord('-') -for i in xrange(0xFDD0, 0xFDF0): +for i in range(0xFDD0, 0xFDF0): noncharacter_translate[i] = ord('-') for i in (0xFFFE, 0xFFFF): noncharacter_translate[i] = ord('-') diff --git a/deluge/pluginmanagerbase.py b/deluge/pluginmanagerbase.py index 1eba1ea76..ae8488415 100644 --- a/deluge/pluginmanagerbase.py +++ b/deluge/pluginmanagerbase.py @@ -88,7 +88,7 @@ class PluginManagerBase(object): def get_enabled_plugins(self): """Returns a list of enabled plugins""" - return self.plugins.keys() + return list(self.plugins.keys()) def scan_for_plugins(self): """Scans for available plugins""" @@ -245,14 +245,14 @@ class PluginManagerBase(object): for line in self.pkg_env[name][0].get_metadata('PKG-INFO').splitlines(): if not line: continue - if line[0] in ' \t' and (len(line.split(':', 1)) == 1 or line.split(':', 1)[0] not in info.keys()): + if line[0] in ' \t' and (len(line.split(':', 1)) == 1 or line.split(':', 1)[0] not in list(info.keys())): # This is a continuation cont_lines.append(line.strip()) else: if cont_lines: info[last_header] = '\n'.join(cont_lines).strip() cont_lines = [] - if line.split(':', 1)[0] in info.keys(): + if line.split(':', 1)[0] in list(info.keys()): last_header = line.split(':', 1)[0] info[last_header] = line.split(':', 1)[1].strip() return info diff --git a/deluge/plugins/AutoAdd/deluge/plugins/autoadd/core.py b/deluge/plugins/AutoAdd/deluge/plugins/autoadd/core.py index 19fa0f2a2..e29f589b5 100644 --- a/deluge/plugins/AutoAdd/deluge/plugins/autoadd/core.py +++ b/deluge/plugins/AutoAdd/deluge/plugins/autoadd/core.py @@ -101,7 +101,7 @@ class Core(CorePluginBase): def enable_looping(self): # Enable all looping calls for enabled watchdirs here - for watchdir_id, watchdir in self.watchdirs.iteritems(): + for watchdir_id, watchdir in self.watchdirs.items(): if watchdir['enabled']: self.enable_watchdir(watchdir_id) @@ -110,7 +110,7 @@ class Core(CorePluginBase): component.get('EventManager').deregister_event_handler( 'PreTorrentRemovedEvent', self.__on_pre_torrent_removed ) - for loopingcall in self.update_timers.itervalues(): + for loopingcall in self.update_timers.values(): loopingcall.stop() self.config.save() @@ -130,12 +130,12 @@ class Core(CorePluginBase): check_input( os.path.isdir(options['abspath']), _('Path does not exist.') ) - for w_id, w in self.watchdirs.iteritems(): + for w_id, w in self.watchdirs.items(): if options['abspath'] == w['abspath'] and watchdir_id != w_id: raise Exception('Path is already being watched.') for key in options: if key not in OPTIONS_AVAILABLE: - if key not in [key2 + '_toggle' for key2 in OPTIONS_AVAILABLE.iterkeys()]: + if key not in [key2 + '_toggle' for key2 in OPTIONS_AVAILABLE]: raise Exception('autoadd: Invalid options key:%s' % key) # disable the watch loop if it was active if watchdir_id in self.update_timers: @@ -225,7 +225,7 @@ class Core(CorePluginBase): watchdir['stop_ratio_toggle'] = watchdir['stop_at_ratio_toggle'] # We default to True when reading _toggle values, so a config # without them is valid, and applies all its settings. - for option, value in watchdir.iteritems(): + for option, value in watchdir.items(): if OPTIONS_AVAILABLE.get(option): if watchdir.get(option + '_toggle', True) or option in ['owner', 'seed_mode']: opts[option] = value @@ -383,12 +383,12 @@ class Core(CorePluginBase): return self.watchdirs watchdirs = {} - for watchdir_id, watchdir in self.watchdirs.iteritems(): + for watchdir_id, watchdir in self.watchdirs.items(): if watchdir.get('owner', 'localclient') == session_user: watchdirs[watchdir_id] = watchdir log.debug('Current logged in user %s is not an ADMIN, send only ' - 'his watchdirs: %s', session_user, watchdirs.keys()) + 'his watchdirs: %s', session_user, list(watchdirs.keys())) return watchdirs def _make_unicode(self, options): @@ -411,7 +411,7 @@ class Core(CorePluginBase): os.access(abswatchdir, os.R_OK | os.W_OK), 'You must have read and write access to watch folder.' ) - if abswatchdir in [wd['abspath'] for wd in self.watchdirs.itervalues()]: + if abswatchdir in [wd['abspath'] for wd in self.watchdirs.values()]: raise Exception('Path is already being watched.') options.setdefault('enabled', False) options['abspath'] = abswatchdir @@ -436,7 +436,7 @@ class Core(CorePluginBase): component.get('EventManager').emit(AutoaddOptionsChangedEvent()) def __migrate_config_1_to_2(self, config): - for watchdir_id in config['watchdirs'].iterkeys(): + for watchdir_id in config['watchdirs']: config['watchdirs'][watchdir_id]['owner'] = 'localclient' return config @@ -449,7 +449,7 @@ class Core(CorePluginBase): torrent_id) return torrent_fname = torrent.filename - for watchdir in self.watchdirs.itervalues(): + for watchdir in self.watchdirs.values(): if not watchdir.get('copy_torrent_toggle', False): # This watchlist does copy torrents continue diff --git a/deluge/plugins/AutoAdd/deluge/plugins/autoadd/gtkui.py b/deluge/plugins/AutoAdd/deluge/plugins/autoadd/gtkui.py index 59843e7b4..05f9d8223 100644 --- a/deluge/plugins/AutoAdd/deluge/plugins/autoadd/gtkui.py +++ b/deluge/plugins/AutoAdd/deluge/plugins/autoadd/gtkui.py @@ -403,7 +403,7 @@ class GtkUI(GtkPluginBase): def create_model(self): store = gtk.ListStore(str, bool, str, str) - for watchdir_id, watchdir in self.watchdirs.iteritems(): + for watchdir_id, watchdir in self.watchdirs.items(): store.append([ watchdir_id, watchdir['enabled'], watchdir.get('owner', 'localclient'), watchdir['path'] @@ -476,7 +476,7 @@ class GtkUI(GtkPluginBase): def on_apply_prefs(self): log.debug('applying prefs for AutoAdd') - for watchdir_id, watchdir in self.watchdirs.iteritems(): + for watchdir_id, watchdir in self.watchdirs.items(): client.autoadd.set_options(watchdir_id, watchdir) def on_show_prefs(self): @@ -490,7 +490,7 @@ class GtkUI(GtkPluginBase): log.trace('Got whatchdirs from core: %s', watchdirs) self.watchdirs = watchdirs or {} self.store.clear() - for watchdir_id, watchdir in self.watchdirs.iteritems(): + for watchdir_id, watchdir in self.watchdirs.items(): self.store.append([ watchdir_id, watchdir['enabled'], watchdir.get('owner', 'localclient'), watchdir['path'] diff --git a/deluge/plugins/Execute/deluge/plugins/execute/core.py b/deluge/plugins/Execute/deluge/plugins/execute/core.py index 5d8ed1591..5c5f622db 100644 --- a/deluge/plugins/Execute/deluge/plugins/execute/core.py +++ b/deluge/plugins/Execute/deluge/plugins/execute/core.py @@ -134,7 +134,7 @@ class Core(CorePluginBase): def disable(self): self.config.save() event_manager = component.get('EventManager') - for event, handler in self.registered_events.iteritems(): + for event, handler in self.registered_events.items(): event_manager.deregister_event_handler(event, handler) log.debug('Execute core plugin disabled!') diff --git a/deluge/plugins/Extractor/deluge/plugins/extractor/core.py b/deluge/plugins/Extractor/deluge/plugins/extractor/core.py index 5bddeccb2..dab0a0c9c 100644 --- a/deluge/plugins/Extractor/deluge/plugins/extractor/core.py +++ b/deluge/plugins/Extractor/deluge/plugins/extractor/core.py @@ -40,14 +40,18 @@ if windows_check(): 'C:\\Program Files (x86)\\7-Zip\\7z.exe', ] - import _winreg try: - hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\7-Zip') + import winreg + except ImportError: + import _winreg as winreg # For Python 2. + + try: + hkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\7-Zip') except WindowsError: pass else: - win_7z_path = os.path.join(_winreg.QueryValueEx(hkey, 'Path')[0], '7z.exe') - _winreg.CloseKey(hkey) + win_7z_path = os.path.join(winreg.QueryValueEx(hkey, 'Path')[0], '7z.exe') + winreg.CloseKey(hkey) win_7z_exes.insert(1, win_7z_path) switch_7z = 'x -y' diff --git a/deluge/plugins/Label/deluge/plugins/label/core.py b/deluge/plugins/Label/deluge/plugins/label/core.py index 9f176b9ba..7f78ed028 100644 --- a/deluge/plugins/Label/deluge/plugins/label/core.py +++ b/deluge/plugins/Label/deluge/plugins/label/core.py @@ -109,7 +109,7 @@ class Core(CorePluginBase): def init_filter_dict(self): filter_dict = dict([(label, 0) for label in self.labels.keys()]) - filter_dict['All'] = len(self.torrents.keys()) + filter_dict['All'] = len(self.torrents) return filter_dict # Plugin hooks # @@ -119,7 +119,7 @@ class Core(CorePluginBase): log.debug('post_torrent_add') torrent = self.torrents[torrent_id] - for label_id, options in self.labels.iteritems(): + for label_id, options in self.labels.items(): if options['auto_add']: if self._has_auto_match(torrent, options): self.set_torrent(torrent_id, label_id) @@ -133,7 +133,7 @@ class Core(CorePluginBase): # Utils # def clean_config(self): """remove invalid data from config-file""" - for torrent_id, label_id in list(self.torrent_labels.iteritems()): + for torrent_id, label_id in list(self.torrent_labels.items()): if (label_id not in self.labels) or (torrent_id not in self.torrents): log.debug('label: rm %s:%s', torrent_id, label_id) del self.torrent_labels[torrent_id] @@ -143,7 +143,7 @@ class Core(CorePluginBase): *add any new keys in OPTIONS_DEFAULTS *set all None values to default <-fix development config """ - log.debug(self.labels.keys()) + log.debug(list(self.labels.keys())) for key in self.labels.keys(): options = dict(OPTIONS_DEFAULTS) options.update(self.labels[key]) @@ -267,14 +267,14 @@ class Core(CorePluginBase): self.labels[label_id].update(options_dict) # apply - for torrent_id, label in self.torrent_labels.iteritems(): + for torrent_id, label in self.torrent_labels.items(): if label_id == label and torrent_id in self.torrents: self._set_torrent_options(torrent_id, label_id) # auto add options = self.labels[label_id] if options['auto_add']: - for torrent_id, torrent in self.torrents.iteritems(): + for torrent_id, torrent in self.torrents.items(): if self._has_auto_match(torrent, options): self.set_torrent(torrent_id, label_id) diff --git a/deluge/plugins/Label/deluge/plugins/label/gtkui/sidebar_menu.py b/deluge/plugins/Label/deluge/plugins/label/gtkui/sidebar_menu.py index f46da255c..13e162ae6 100644 --- a/deluge/plugins/Label/deluge/plugins/label/gtkui/sidebar_menu.py +++ b/deluge/plugins/Label/deluge/plugins/label/gtkui/sidebar_menu.py @@ -174,7 +174,7 @@ class OptionsDialog(object): self.dialog.run() def load_options(self, options): - log.debug(options.keys()) + log.debug(list(options.keys())) for spin_id in self.spin_ids + self.spin_int_ids: self.glade.get_widget(spin_id).set_value(options[spin_id]) diff --git a/deluge/plugins/Notifications/deluge/plugins/notifications/common.py b/deluge/plugins/Notifications/deluge/plugins/notifications/common.py index 034abd6df..9e2c19235 100644 --- a/deluge/plugins/Notifications/deluge/plugins/notifications/common.py +++ b/deluge/plugins/Notifications/deluge/plugins/notifications/common.py @@ -19,15 +19,10 @@ import logging from twisted.internet import defer from deluge import component +from deluge.event import known_events log = logging.getLogger(__name__) -try: - from deluge.event import known_events -except ImportError: - # Old deluge version - known_events = {} - def get_resource(filename): import os @@ -49,8 +44,8 @@ class CustomNotifications(object): pass def disable(self): - for kind in self.custom_notifications.iterkeys(): - for eventtype in self.custom_notifications[kind].copy().iterkeys(): + for kind in self.custom_notifications: + for eventtype in list(self.custom_notifications[kind]): wrapper, handler = self.custom_notifications[kind][eventtype] self._deregister_custom_provider(kind, eventtype) diff --git a/deluge/plugins/Notifications/deluge/plugins/notifications/gtkui.py b/deluge/plugins/Notifications/deluge/plugins/notifications/gtkui.py index 7ff0a725b..4426328ea 100644 --- a/deluge/plugins/Notifications/deluge/plugins/notifications/gtkui.py +++ b/deluge/plugins/Notifications/deluge/plugins/notifications/gtkui.py @@ -67,10 +67,10 @@ DEFAULT_PREFS = { }, } -RECIPIENT_FIELD, RECIPIENT_EDIT = range(2) +RECIPIENT_FIELD, RECIPIENT_EDIT = list(range(2)) (SUB_EVENT, SUB_EVENT_DOC, SUB_NOT_EMAIL, SUB_NOT_POPUP, SUB_NOT_BLINK, - SUB_NOT_SOUND) = range(6) -SND_EVENT, SND_EVENT_DOC, SND_NAME, SND_PATH = range(4) + SUB_NOT_SOUND) = list(range(6)) +SND_EVENT, SND_EVENT_DOC, SND_NAME, SND_PATH = list(range(4)) class GtkUiNotifications(CustomNotifications): diff --git a/deluge/plugins/Scheduler/deluge/plugins/scheduler/core.py b/deluge/plugins/Scheduler/deluge/plugins/scheduler/core.py index 2f2465364..6b5a9c04f 100644 --- a/deluge/plugins/Scheduler/deluge/plugins/scheduler/core.py +++ b/deluge/plugins/Scheduler/deluge/plugins/scheduler/core.py @@ -32,7 +32,7 @@ DEFAULT_PREFS = { 'low_active': -1, 'low_active_down': -1, 'low_active_up': -1, - 'button_state': [[0] * 7 for dummy in xrange(24)] + 'button_state': [[0] * 7 for dummy in range(24)] } STATES = { diff --git a/deluge/plugins/Scheduler/deluge/plugins/scheduler/gtkui.py b/deluge/plugins/Scheduler/deluge/plugins/scheduler/gtkui.py index 3eacca8d5..5f4ef9351 100644 --- a/deluge/plugins/Scheduler/deluge/plugins/scheduler/gtkui.py +++ b/deluge/plugins/Scheduler/deluge/plugins/scheduler/gtkui.py @@ -43,7 +43,7 @@ class SchedulerSelectWidget(gtk.DrawingArea): self.colors = [[115 / 255, 210 / 255, 22 / 255], [237 / 255, 212 / 255, 0 / 255], [204 / 255, 0 / 255, 0 / 255]] - self.button_state = [[0] * 7 for dummy in xrange(24)] + self.button_state = [[0] * 7 for dummy in range(24)] self.start_point = [0, 0] self.hover_point = [-1, -1] @@ -67,8 +67,8 @@ class SchedulerSelectWidget(gtk.DrawingArea): width = self.window.get_size()[0] height = self.window.get_size()[1] - for y in xrange(7): - for x in xrange(24): + for y in range(7): + for x in range(24): context.set_source_rgba(self.colors[self.button_state[x][y]][0], self.colors[self.button_state[x][y]][1], self.colors[self.button_state[x][y]][2], 0.7) @@ -130,8 +130,8 @@ class SchedulerSelectWidget(gtk.DrawingArea): if self.mouse_press: points = [[self.hover_point[0], self.start_point[0]], [self.hover_point[1], self.start_point[1]]] - for x in xrange(min(points[0]), max(points[0]) + 1): - for y in xrange(min(points[1]), max(points[1]) + 1): + for x in range(min(points[0]), max(points[0]) + 1): + for y in range(min(points[1]), max(points[1]) + 1): self.button_state[x][y] = self.button_state[self.start_point[0]][self.start_point[1]] self.queue_draw() diff --git a/deluge/plugins/Stats/deluge/plugins/stats/core.py b/deluge/plugins/Stats/deluge/plugins/stats/core.py index c93b03dcd..ba52317bb 100644 --- a/deluge/plugins/Stats/deluge/plugins/stats/core.py +++ b/deluge/plugins/Stats/deluge/plugins/stats/core.py @@ -136,7 +136,7 @@ class Core(CorePluginBase): # extract the ones we are interested in # adding them to the 1s array - for stat, stat_list in self.stats[1].iteritems(): + for stat, stat_list in self.stats[1].items(): if stat in stats: stat_list.insert(0, int(stats[stat])) else: @@ -150,7 +150,7 @@ class Core(CorePluginBase): self.last_update[interval] = update_time self.count[interval] = 0 current_stats = self.stats[interval] - for stat, stat_list in self.stats[base].iteritems(): + for stat, stat_list in self.stats[base].items(): try: avg = mean(stat_list[0:multiplier]) except ValueError: diff --git a/deluge/plugins/Stats/deluge/plugins/stats/graph.py b/deluge/plugins/Stats/deluge/plugins/stats/graph.py index 782e66c73..d58af1fab 100644 --- a/deluge/plugins/Stats/deluge/plugins/stats/graph.py +++ b/deluge/plugins/Stats/deluge/plugins/stats/graph.py @@ -135,7 +135,7 @@ class Graph(object): # this doesnt allow for dst and timezones... seconds_to_step = math.ceil(start / x_step) * x_step - start - for i in xrange(0, duration // x_step + 1): + for i in range(0, duration // x_step + 1): text = time.strftime('%H:%M', time.localtime(start + seconds_to_step + i * x_step)) # + 0.5 to allign x to nearest pixel x = int(ratio * (seconds_to_step + i * x_step) + left) + 0.5 @@ -220,7 +220,7 @@ class Graph(object): else: interval = interval * 2 - intervals = [i * interval * scale for i in xrange(1 + int(math.ceil(x / interval)))] + intervals = [i * interval * scale for i in range(1 + int(math.ceil(x / interval)))] return intervals def draw_left_axis(self, bounds, y_ticks, y_tick_text): @@ -244,7 +244,7 @@ class Graph(object): self.draw_y_text(y_tick_text[i], left, y) self.draw_line(gray, left, top, left, bottom) - for stat, info in stats.iteritems(): + for stat, info in stats.items(): if len(info['values']) > 0: self.draw_value_poly(info['values'], info['color'], max_value, bounds) self.draw_value_poly(info['values'], info['fill_color'], max_value, bounds, info['fill']) diff --git a/deluge/plugins/Stats/deluge/plugins/stats/gtkui.py b/deluge/plugins/Stats/deluge/plugins/stats/gtkui.py index bebd46dac..0a83f7ef2 100644 --- a/deluge/plugins/Stats/deluge/plugins/stats/gtkui.py +++ b/deluge/plugins/Stats/deluge/plugins/stats/gtkui.py @@ -129,7 +129,7 @@ class GraphsTab(Tab): return False def update(self): - d1 = client.stats.get_stats(self.graph.stat_info.keys(), self.selected_interval) + d1 = client.stats.get_stats(list(self.graph.stat_info.keys()), self.selected_interval) d1.addCallback(self.graph.set_stats) def _update_complete(result): diff --git a/deluge/plugins/Stats/deluge/plugins/stats/tests/test_stats.py b/deluge/plugins/Stats/deluge/plugins/stats/tests/test_stats.py index bb1ce41d0..34c54bf36 100644 --- a/deluge/plugins/Stats/deluge/plugins/stats/tests/test_stats.py +++ b/deluge/plugins/Stats/deluge/plugins/stats/tests/test_stats.py @@ -18,7 +18,7 @@ from deluge.ui.client import client def print_totals(totals): - for name, value in totals.iteritems(): + for name, value in totals.items(): print(name, fsize(value)) print('overhead:') diff --git a/deluge/rencode.py b/deluge/rencode.py index ef5af25fd..b8c72a3ce 100644 --- a/deluge/rencode.py +++ b/deluge/rencode.py @@ -60,6 +60,7 @@ same rencode version throughout your project. import struct import sys +from future_builtins import zip from threading import Lock __version__ = ('Python', 1, 0, 4) diff --git a/deluge/tests/test_core.py b/deluge/tests/test_core.py index f2870d522..edb60063f 100644 --- a/deluge/tests/test_core.py +++ b/deluge/tests/test_core.py @@ -8,7 +8,6 @@ from __future__ import unicode_literals import base64 -import sys from hashlib import sha1 as sha import pytest @@ -23,6 +22,7 @@ from twisted.web.static import File import deluge.common import deluge.component as component import deluge.core.torrent +from deluge.common import PY2 from deluge.core.core import Core from deluge.core.rpcserver import RPCServer from deluge.error import AddTorrentError, InvalidTorrentError @@ -270,10 +270,7 @@ class CoreTestCase(BaseTestCase): def test_get_free_space(self): space = self.core.get_free_space('.') # get_free_space returns long on Python 2 (32-bit). - if sys.version_info >= (3, 0): - self.assertTrue(isinstance(space, int)) - else: - self.assertTrue(isinstance(space, (int, long))) + self.assertTrue(isinstance(space, int if not PY2 else (int, long))) self.assertTrue(space >= 0) self.assertEquals(self.core.get_free_space('/someinvalidpath'), -1) diff --git a/deluge/tests/test_json_api.py b/deluge/tests/test_json_api.py index 7a26df7e8..1ffc9b193 100644 --- a/deluge/tests/test_json_api.py +++ b/deluge/tests/test_json_api.py @@ -187,7 +187,7 @@ class RPCRaiseDelugeErrorJSONTestCase(JSONBase): self.assertTrue('testclass.test' in methods) request = MagicMock() - request.getCookie = MagicMock(return_value=auth.config['sessions'].keys()[0]) + request.getCookie = MagicMock(return_value=list(auth.config['sessions'].keys())[0]) json_data = {'method': 'testclass.test', 'id': 0, 'params': []} request.json = json_lib.dumps(json_data) request_id, result, error = json._handle_request(request) diff --git a/deluge/tests/test_sessionproxy.py b/deluge/tests/test_sessionproxy.py index 566879609..e65b90f83 100644 --- a/deluge/tests/test_sessionproxy.py +++ b/deluge/tests/test_sessionproxy.py @@ -35,7 +35,7 @@ class Core(object): def get_torrent_status(self, torrent_id, keys, diff=False): if not keys: - keys = self.torrents[torrent_id].keys() + keys = list(self.torrents[torrent_id].keys()) if not diff: ret = {} @@ -57,9 +57,9 @@ class Core(object): def get_torrents_status(self, filter_dict, keys, diff=False): if not filter_dict: - filter_dict['id'] = self.torrents.keys() + filter_dict['id'] = list(self.torrents.keys()) if not keys: - keys = self.torrents['a'].keys() + keys = list(self.torrents['a'].keys()) if not diff: if 'id' in filter_dict: torrents = filter_dict['id'] diff --git a/deluge/tests/test_ui_entry.py b/deluge/tests/test_ui_entry.py index fd567870c..2cabf1824 100644 --- a/deluge/tests/test_ui_entry.py +++ b/deluge/tests/test_ui_entry.py @@ -152,7 +152,7 @@ class GtkUIBaseTestCase(UIBaseTestCase): """Implement all GtkUI tests here""" def test_start_gtkui(self): - self.patch(sys, 'argv', self.var['sys_arg_cmd']) + self.patch(sys, 'argv', utf8_encode_structure(self.var['sys_arg_cmd'])) from deluge.ui.gtkui import gtkui with mock.patch.object(gtkui.GtkUI, 'start', autospec=True): @@ -168,7 +168,7 @@ class GtkUIDelugeScriptEntryTestCase(BaseTestCase, GtkUIBaseTestCase): self.var['cmd_name'] = 'deluge gtk' self.var['start_cmd'] = ui_entry.start_ui - self.var['sys_arg_cmd'] = utf8_encode_structure(['./deluge', 'gtk']) + self.var['sys_arg_cmd'] = ['./deluge', 'gtk'] def set_up(self): return GtkUIBaseTestCase.set_up(self) diff --git a/deluge/ui/Win32IconImagePlugin.py b/deluge/ui/Win32IconImagePlugin.py index 41b44d64a..8d88ef430 100644 --- a/deluge/ui/Win32IconImagePlugin.py +++ b/deluge/ui/Win32IconImagePlugin.py @@ -48,6 +48,7 @@ from __future__ import division, unicode_literals import logging import struct +from future_builtins import zip import PIL.BmpImagePlugin import PIL.Image @@ -77,9 +78,9 @@ class Win32IcoFile(object): self.nb_items = header[2] dir_fields = ('width', 'height', 'nb_color', 'reserved', 'planes', 'bpp', 'size', 'offset') - for i in xrange(self.nb_items): + for i in range(self.nb_items): directory = list(struct.unpack('<4B2H2I', buf.read(16))) - for j in xrange(3): + for j in range(3): if not directory[j]: directory[j] = 256 icon_header = dict(zip(dir_fields, directory)) diff --git a/deluge/ui/client.py b/deluge/ui/client.py index 9483e6b00..452f767a3 100644 --- a/deluge/ui/client.py +++ b/deluge/ui/client.py @@ -397,7 +397,7 @@ class DaemonSSLProxy(DaemonProxy): # We need to tell the daemon what events we're interested in receiving if self.__factory.event_handlers: self.call('daemon.set_event_interest', - self.__factory.event_handlers.keys()) + list(self.__factory.event_handlers.keys())) self.call('core.get_auth_levels_mappings').addCallback( self.__on_auth_levels_mappings diff --git a/deluge/ui/common.py b/deluge/ui/common.py index cc5b92838..8c7eb314e 100644 --- a/deluge/ui/common.py +++ b/deluge/ui/common.py @@ -207,7 +207,7 @@ class TorrentInfo(object): item.update(paths[path]) item['download'] = True - file_tree = FileTree2(paths.keys()) + file_tree = FileTree2(list(paths.keys())) file_tree.walk(walk) else: def walk(path, item): diff --git a/deluge/ui/console/cmdline/commands/add.py b/deluge/ui/console/cmdline/commands/add.py index 3b1b970b3..d5cf52642 100644 --- a/deluge/ui/console/cmdline/commands/add.py +++ b/deluge/ui/console/cmdline/commands/add.py @@ -12,8 +12,6 @@ from __future__ import unicode_literals import base64 import os -from urllib import url2pathname -from urlparse import urlparse from twisted.internet import defer @@ -23,6 +21,14 @@ from deluge.ui.client import client from . import BaseCommand +try: + from urllib.parse import urlparse + from urllib.request import url2pathname +except ImportError: + # PY2 fallback + from urlparse import urlparse # pylint: disable=ungrouped-imports + from urllib import url2pathname # pylint: disable=ungrouped-imports + class Command(BaseCommand): """Add torrents""" diff --git a/deluge/ui/console/cmdline/commands/config.py b/deluge/ui/console/cmdline/commands/config.py index 1d7489d7c..a4be506ab 100644 --- a/deluge/ui/console/cmdline/commands/config.py +++ b/deluge/ui/console/cmdline/commands/config.py @@ -123,7 +123,7 @@ class Command(BaseCommand): self.console.write('{!error!}%s' % ex) return - if key not in config.keys(): + if key not in list(config.keys()): self.console.write('{!error!}Invalid key: %s' % key) return diff --git a/deluge/ui/console/cmdline/commands/info.py b/deluge/ui/console/cmdline/commands/info.py index fc80d1aba..d33ba2728 100644 --- a/deluge/ui/console/cmdline/commands/info.py +++ b/deluge/ui/console/cmdline/commands/info.py @@ -147,7 +147,7 @@ class Command(BaseCommand): self.console.write('{!error!}Unknown sort key: ' + sort_key + ', will sort on name') sort_key = 'name' sort_reverse = False - for key, value in sorted(status.items(), key=lambda x: x[1].get(sort_key), reverse=sort_reverse): + for key, value in sorted(list(status.items()), key=lambda x: x[1].get(sort_key), reverse=sort_reverse): self.show_info(key, status[key], options.verbose, options.detailed) def on_torrents_status_fail(reason): diff --git a/deluge/ui/console/modes/addtorrents.py b/deluge/ui/console/modes/addtorrents.py index e35af806c..2edd5d502 100644 --- a/deluge/ui/console/modes/addtorrents.py +++ b/deluge/ui/console/modes/addtorrents.py @@ -12,6 +12,7 @@ from __future__ import unicode_literals import base64 import logging import os +from future_builtins import zip import deluge.common import deluge.component as component @@ -513,9 +514,9 @@ class AddTorrents(BaseMode): elif chr(c) == 'M': if self.last_mark != -1: if self.last_mark > self.cursel: - m = range(self.cursel, self.last_mark) + m = list(range(self.cursel, self.last_mark)) else: - m = range(self.last_mark, self.cursel + 1) + m = list(range(self.last_mark, self.cursel + 1)) for i in m: s = self.raw_rows[i][0] diff --git a/deluge/ui/console/modes/preferences/preferences.py b/deluge/ui/console/modes/preferences/preferences.py index d7d0e1557..4912655e4 100644 --- a/deluge/ui/console/modes/preferences/preferences.py +++ b/deluge/ui/console/modes/preferences/preferences.py @@ -68,7 +68,7 @@ arrow to edit the other value, and escape to get back to the check box. class ZONE(object): length = 3 - CATEGORIES, PREFRENCES, ACTIONS = range(length) + CATEGORIES, PREFRENCES, ACTIONS = list(range(length)) class PreferenceSidebar(Sidebar): diff --git a/deluge/ui/console/modes/torrentlist/queue_mode.py b/deluge/ui/console/modes/torrentlist/queue_mode.py index dac88e77d..42d138cc7 100644 --- a/deluge/ui/console/modes/torrentlist/queue_mode.py +++ b/deluge/ui/console/modes/torrentlist/queue_mode.py @@ -79,7 +79,7 @@ class QueueMode(object): self.torrentview.cursel = 1 + sorted(self.torrentview.marked).index(self.torrentview.cursel) else: self.torrentview.cursel = 1 - self.torrentview.marked = range(1, selected_num + 1) + self.torrentview.marked = list(range(1, selected_num + 1)) elif qact == ACTION.QUEUE_UP: self.torrentview.cursel = max(1, self.torrentview.cursel - 1) self.torrentview.marked = [marked - 1 for marked in self.torrentview.marked] @@ -94,7 +94,7 @@ class QueueMode(object): sorted(self.torrentview.marked).index(self.torrentview.cursel)) else: self.torrentview.cursel = queue_length - self.torrentview.marked = range(queue_length - selected_num + 1, queue_length + 1) + self.torrentview.marked = list(range(queue_length - selected_num + 1, queue_length + 1)) def do_queue(self, qact, *args, **kwargs): if qact == ACTION.QUEUE_TOP: diff --git a/deluge/ui/console/modes/torrentlist/torrentactions.py b/deluge/ui/console/modes/torrentlist/torrentactions.py index 404d2c27d..52baa56f7 100644 --- a/deluge/ui/console/modes/torrentlist/torrentactions.py +++ b/deluge/ui/console/modes/torrentlist/torrentactions.py @@ -103,7 +103,7 @@ def action_torrent_info(mode=None, torrent_ids=None, **kwargs): def _do_set_torrent_options(torrent_ids, result): options = {} - for opt, val in result.iteritems(): + for opt, val in result.items(): if val['value'] not in ['multiple', None]: options[opt] = val['value'] client.core.set_torrent_options(torrent_ids, options) diff --git a/deluge/ui/console/modes/torrentlist/torrentview.py b/deluge/ui/console/modes/torrentlist/torrentview.py index 6ef1d7e83..b3b1aaba5 100644 --- a/deluge/ui/console/modes/torrentlist/torrentview.py +++ b/deluge/ui/console/modes/torrentlist/torrentview.py @@ -235,7 +235,7 @@ class TorrentView(InputKeyHandler): # Get first element so we can check if it has given field # and if it's a string - first_element = state[state.keys()[0]] + first_element = state[list(state.keys())[0]] if field in first_element: def sort_key(s): try: @@ -449,9 +449,9 @@ class TorrentView(InputKeyHandler): elif c == ord('M'): if self.last_mark >= 0: if self.cursel > self.last_mark: - mrange = range(self.last_mark, self.cursel + 1) + mrange = list(range(self.last_mark, self.cursel + 1)) else: - mrange = range(self.cursel, self.last_mark) + mrange = list(range(self.cursel, self.last_mark)) self.add_marked(mrange, self.cursel) affected_lines = mrange else: diff --git a/deluge/ui/console/widgets/popup.py b/deluge/ui/console/widgets/popup.py index a310fc35c..18ec8d24a 100644 --- a/deluge/ui/console/widgets/popup.py +++ b/deluge/ui/console/widgets/popup.py @@ -260,7 +260,7 @@ class SelectablePopup(BaseInputPane, Popup): @overrides(Popup, BaseInputPane) def handle_read(self, c): if c in [curses.KEY_ENTER, util.KEY_ENTER2]: - for k, v in self.get_values().iteritems(): + for k, v in self.get_values().items(): if v['active']: if self.selection_cb(k, **dict(self.cb_args, data=self.cb_arg)): self.close(None) diff --git a/deluge/ui/gtkui/addtorrentdialog.py b/deluge/ui/gtkui/addtorrentdialog.py index 06e18f113..33310e53f 100644 --- a/deluge/ui/gtkui/addtorrentdialog.py +++ b/deluge/ui/gtkui/addtorrentdialog.py @@ -299,7 +299,7 @@ class AddTorrentDialog(component.Component): def add_files(self, parent_iter, split_files): ret = 0 - for key, value in split_files.iteritems(): + for key, value in split_files.items(): if key.endswith(os.path.sep): chunk_iter = self.files_treestore.append( parent_iter, [True, key, 0, -1, False, gtk.STOCK_DIRECTORY]) diff --git a/deluge/ui/gtkui/common.py b/deluge/ui/gtkui/common.py index 84b786f35..21f311ae4 100644 --- a/deluge/ui/gtkui/common.py +++ b/deluge/ui/gtkui/common.py @@ -10,7 +10,7 @@ from __future__ import unicode_literals import contextlib -import cPickle +import cPickle as pickle import logging import os import shutil @@ -143,7 +143,7 @@ def reparent_iter(treestore, itr, parent, move_siblings=False): def move_children(i, dest): while i: - n_cols = treestore.append(dest, treestore.get(i, *xrange(treestore.get_n_columns()))) + n_cols = treestore.append(dest, treestore.get(i, *range(treestore.get_n_columns()))) to_remove = i if treestore.iter_children(i): move_children(treestore.iter_children(i), n_cols) @@ -188,29 +188,32 @@ def associate_magnet_links(overwrite=False): """ if windows_check(): - import _winreg + try: + import winreg + except ImportError: + import _winreg as winreg # For Python 2. try: - hkey = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, 'Magnet') + hkey = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, 'Magnet') except WindowsError: overwrite = True else: - _winreg.CloseKey(hkey) + winreg.CloseKey(hkey) if overwrite: deluge_exe = os.path.join(os.path.dirname(sys.executable), 'deluge.exe') try: - magnet_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT, 'Magnet') + magnet_key = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, 'Magnet') except WindowsError: # Could not create for all users, falling back to current user - magnet_key = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, 'Software\\Classes\\Magnet') + magnet_key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, 'Software\\Classes\\Magnet') - _winreg.SetValue(magnet_key, '', _winreg.REG_SZ, 'URL:Magnet Protocol') - _winreg.SetValueEx(magnet_key, 'URL Protocol', 0, _winreg.REG_SZ, '') - _winreg.SetValueEx(magnet_key, 'BrowserFlags', 0, _winreg.REG_DWORD, 0x8) - _winreg.SetValue(magnet_key, 'DefaultIcon', _winreg.REG_SZ, '{},0'.format(deluge_exe)) - _winreg.SetValue(magnet_key, r'shell\open\command', _winreg.REG_SZ, '"{}" "%1"'.format(deluge_exe)) - _winreg.CloseKey(magnet_key) + winreg.SetValue(magnet_key, '', winreg.REG_SZ, 'URL:Magnet Protocol') + winreg.SetValueEx(magnet_key, 'URL Protocol', 0, winreg.REG_SZ, '') + winreg.SetValueEx(magnet_key, 'BrowserFlags', 0, winreg.REG_DWORD, 0x8) + winreg.SetValue(magnet_key, 'DefaultIcon', winreg.REG_SZ, '{},0'.format(deluge_exe)) + winreg.SetValue(magnet_key, r'shell\open\command', winreg.REG_SZ, '"{}" "%1"'.format(deluge_exe)) + winreg.CloseKey(magnet_key) # Don't try associate magnet on OSX see: #2420 elif not osx_check(): @@ -259,11 +262,11 @@ def save_pickled_state_file(filename, state): try: with open(filepath_tmp, 'wb') as _file: # Pickle the state object - cPickle.dump(state, _file) + pickle.dump(state, _file) _file.flush() os.fsync(_file.fileno()) shutil.move(filepath_tmp, filepath) - except (IOError, EOFError, cPickle.PicklingError) as ex: + except (IOError, EOFError, pickle.PicklingError) as ex: log.error('Unable to save %s: %s', filename, ex) if os.path.isfile(filepath_bak): log.info('Restoring backup of %s from: %s', filename, filepath_bak) @@ -288,8 +291,8 @@ def load_pickled_state_file(filename): log.info('Opening %s for load: %s', filename, _filepath) try: with open(_filepath, 'rb') as _file: - state = cPickle.load(_file) - except (IOError, cPickle.UnpicklingError) as ex: + state = pickle.load(_file) + except (IOError, pickle.UnpicklingError) as ex: log.warning('Unable to load %s: %s', _filepath, ex) else: log.info('Successfully loaded %s: %s', filename, _filepath) diff --git a/deluge/ui/gtkui/files_tab.py b/deluge/ui/gtkui/files_tab.py index a5ff30665..2eab50ad4 100644 --- a/deluge/ui/gtkui/files_tab.py +++ b/deluge/ui/gtkui/files_tab.py @@ -9,7 +9,7 @@ from __future__ import division, unicode_literals -import cPickle +import cPickle as pickle import logging import os.path @@ -344,7 +344,7 @@ class FilesTab(Tab): def add_files(self, parent_iter, split_files): chunk_size_total = 0 - for key, value in split_files.iteritems(): + for key, value in split_files.items(): if key.endswith('/'): chunk_iter = self.treestore.append(parent_iter, [key, 0, '', 0, 0, -1, gtk.STOCK_DIRECTORY]) @@ -623,7 +623,7 @@ class FilesTab(Tab): p_itr = self.get_iter_at_path('/'.join(parent_path) + '/') old_name_itr = self.get_iter_at_path(old_name) self.treestore.append(p_itr, - self.treestore.get(old_name_itr, *xrange(self.treestore.get_n_columns()))) + self.treestore.get(old_name_itr, *range(self.treestore.get_n_columns()))) self.treestore.remove(old_name_itr) # Remove old parent path @@ -637,7 +637,7 @@ class FilesTab(Tab): parent_iter, [f + '/', 0, '', 0, 0, -1, gtk.STOCK_DIRECTORY]) child = self.get_iter_at_path(old_name) self.treestore.append(parent_iter, - self.treestore.get(child, *xrange(self.treestore.get_n_columns()))) + self.treestore.get(child, *range(self.treestore.get_n_columns()))) self.treestore.remove(child) else: @@ -750,12 +750,12 @@ class FilesTab(Tab): def _on_drag_data_get_data(self, treeview, context, selection, target_id, etime): paths = self.listview.get_selection().get_selected_rows()[1] - selection.set_text(cPickle.dumps(paths)) + selection.set_text(pickle.dumps(paths)) def _on_drag_data_received_data(self, treeview, context, x, y, selection, info, etime): try: - selected = cPickle.loads(selection.data) - except cPickle.UnpicklingError: + selected = pickle.loads(selection.data) + except pickle.UnpicklingError: log.debug('Invalid selection data: %s', selection.data) return log.debug('selection.data: %s', selected) diff --git a/deluge/ui/gtkui/filtertreeview.py b/deluge/ui/gtkui/filtertreeview.py index 687bb6615..5ac6af7fb 100644 --- a/deluge/ui/gtkui/filtertreeview.py +++ b/deluge/ui/gtkui/filtertreeview.py @@ -161,7 +161,7 @@ class FilterTreeView(component.Component): # update rows visible_filters = [] - for cat, filters in filter_items.iteritems(): + for cat, filters in filter_items.items(): for value, count in filters: self.update_row(cat, value, count) visible_filters.append((cat, value)) diff --git a/deluge/ui/gtkui/ipcinterface.py b/deluge/ui/gtkui/ipcinterface.py index 50e0e2edd..d84ccbd79 100644 --- a/deluge/ui/gtkui/ipcinterface.py +++ b/deluge/ui/gtkui/ipcinterface.py @@ -15,8 +15,6 @@ import os import sys from glob import glob from tempfile import mkstemp -from urllib import url2pathname -from urlparse import urlparse import twisted.internet.error from twisted.internet import reactor @@ -32,6 +30,14 @@ try: except ImportError: import deluge.rencode as rencode # pylint: disable=ungrouped-imports +try: + from urllib.parse import urlparse + from urllib.request import url2pathname +except ImportError: + # PY2 fallback + from urlparse import urlparse # pylint: disable=ungrouped-imports + from urllib import url2pathname # pylint: disable=ungrouped-imports + log = logging.getLogger(__name__) diff --git a/deluge/ui/gtkui/listview.py b/deluge/ui/gtkui/listview.py index 2b3f7b1e5..b96403835 100644 --- a/deluge/ui/gtkui/listview.py +++ b/deluge/ui/gtkui/listview.py @@ -118,7 +118,7 @@ class ListView(object): def set_col_attributes(self, renderer, add=True, **kw): if add is True: - for attr, value in kw.iteritems(): + for attr, value in kw.items(): self.add_attribute(renderer, attr, value) else: self.set_attributes(renderer, **kw) diff --git a/deluge/ui/gtkui/mainwindow.py b/deluge/ui/gtkui/mainwindow.py index 00cf093a5..094f82dfc 100644 --- a/deluge/ui/gtkui/mainwindow.py +++ b/deluge/ui/gtkui/mainwindow.py @@ -39,7 +39,7 @@ class _GtkBuilderSignalsHolder(object): def connect_signals(self, mapping_or_class): if isinstance(mapping_or_class, dict): - for name, handler in mapping_or_class.iteritems(): + for name, handler in mapping_or_class.items(): if hasattr(self, name): raise RuntimeError( 'A handler for signal %r has already been registered: %s' % diff --git a/deluge/ui/gtkui/menubar.py b/deluge/ui/gtkui/menubar.py index 8c0ce69ef..b3864dc9d 100644 --- a/deluge/ui/gtkui/menubar.py +++ b/deluge/ui/gtkui/menubar.py @@ -411,7 +411,7 @@ class MenuBar(component.Component): 'menuitem_max_connections': 'max_connections', 'menuitem_upload_slots': 'max_upload_slots' } - if widget.get_name() in funcs.keys(): + if widget.get_name() in list(funcs.keys()): torrent_ids = component.get('TorrentView').get_selected_torrents() client.core.set_torrent_options(torrent_ids, {funcs[widget.get_name()]: -1}) @@ -494,7 +494,7 @@ class MenuBar(component.Component): known_accounts_to_log = [] for account in known_accounts: account_to_log = {} - for key, value in account.copy().iteritems(): + for key, value in account.copy().items(): if key == 'password': value = '*' * len(value) account_to_log[key] = value @@ -537,7 +537,7 @@ class MenuBar(component.Component): return torrent_owner = component.get('TorrentView').get_torrent_status(selected[0])['owner'] - for username, item in self.change_owner_submenu_items.iteritems(): + for username, item in self.change_owner_submenu_items.items(): item.set_active(username == torrent_owner) def _on_change_owner_toggled(self, widget, username): diff --git a/deluge/ui/gtkui/options_tab.py b/deluge/ui/gtkui/options_tab.py index 5d13b7234..a1089b1d0 100644 --- a/deluge/ui/gtkui/options_tab.py +++ b/deluge/ui/gtkui/options_tab.py @@ -116,7 +116,7 @@ class OptionsTab(Tab): # We only want to update values that have been applied in the core. This # is so we don't overwrite the user changes that haven't been applied yet. if self.prev_status is None: - self.prev_status = {}.fromkeys(status.keys(), None) + self.prev_status = {}.fromkeys(list(status.keys()), None) if status != self.prev_status: if status['max_download_speed'] != self.prev_status['max_download_speed']: diff --git a/deluge/ui/gtkui/path_chooser.py b/deluge/ui/gtkui/path_chooser.py index 7a2874590..bbd64593b 100644 --- a/deluge/ui/gtkui/path_chooser.py +++ b/deluge/ui/gtkui/path_chooser.py @@ -60,7 +60,7 @@ class PathChoosersHandler(component.Component): self.config_properties.update(config) for chooser in self.path_choosers: chooser.set_config(config) - keys = self.config_keys_to_funcs_mapping.keys() + keys = list(self.config_keys_to_funcs_mapping.keys()) keys += self.paths_list_keys client.core.get_config_values(keys).addCallback(_on_config_values) @@ -109,7 +109,7 @@ class PathChoosersHandler(component.Component): chooser.set_values(values) def get_config_keys(self): - keys = self.config_keys_to_funcs_mapping.keys() + keys = list(self.config_keys_to_funcs_mapping.keys()) keys += self.paths_list_keys return keys diff --git a/deluge/ui/gtkui/preferences.py b/deluge/ui/gtkui/preferences.py index 83b41d900..896900a44 100644 --- a/deluge/ui/gtkui/preferences.py +++ b/deluge/ui/gtkui/preferences.py @@ -36,8 +36,8 @@ except ImportError: log = logging.getLogger(__name__) -ACCOUNTS_USERNAME, ACCOUNTS_LEVEL, ACCOUNTS_PASSWORD = range(3) -COLOR_MISSING, COLOR_WAITING, COLOR_DOWNLOADING, COLOR_COMPLETED = range(4) +ACCOUNTS_USERNAME, ACCOUNTS_LEVEL, ACCOUNTS_PASSWORD = list(range(3)) +COLOR_MISSING, COLOR_WAITING, COLOR_DOWNLOADING, COLOR_COMPLETED = list(range(4)) COLOR_STATES = { 'missing': COLOR_MISSING, @@ -1020,7 +1020,7 @@ class Preferences(component.Component): known_accounts_to_log = [] for account in known_accounts: account_to_log = {} - for key, value in account.copy().iteritems(): + for key, value in account.copy().items(): if key == 'password': value = '*' * len(value) account_to_log[key] = value diff --git a/deluge/ui/gtkui/statusbar.py b/deluge/ui/gtkui/statusbar.py index 030cd2685..8521ee1cb 100644 --- a/deluge/ui/gtkui/statusbar.py +++ b/deluge/ui/gtkui/statusbar.py @@ -287,7 +287,7 @@ class StatusBar(component.Component): This is called when we receive a ConfigValueChangedEvent from the core. """ - if key in self.config_value_changed_dict.keys(): + if key in list(self.config_value_changed_dict.keys()): self.config_value_changed_dict[key](value) def _on_max_connections_global(self, max_connections): diff --git a/deluge/ui/gtkui/systemtray.py b/deluge/ui/gtkui/systemtray.py index 4d5f80be1..a93acd8b1 100644 --- a/deluge/ui/gtkui/systemtray.py +++ b/deluge/ui/gtkui/systemtray.py @@ -179,7 +179,7 @@ class SystemTray(component.Component): def config_value_changed(self, key, value): """This is called when we received a config_value_changed signal from the core.""" - if key in self.config_value_changed_dict.keys(): + if key in list(self.config_value_changed_dict.keys()): self.config_value_changed_dict[key](value) def _on_max_download_speed(self, max_download_speed): diff --git a/deluge/ui/gtkui/torrentdetails.py b/deluge/ui/gtkui/torrentdetails.py index 25b9f4bf0..f230b1d07 100644 --- a/deluge/ui/gtkui/torrentdetails.py +++ b/deluge/ui/gtkui/torrentdetails.py @@ -129,7 +129,7 @@ class TorrentDetails(component.Component): # We need to rename the tab in the state for backwards compat self.state = [(tab_name.replace('Statistics', 'Status'), visible) for tab_name, visible in state] - for tab in default_tabs.itervalues(): + for tab in default_tabs.values(): self.add_tab(tab(), generate_menu=False) # Generate the checklist menu @@ -140,7 +140,7 @@ class TorrentDetails(component.Component): # Determine insert position based on weight # weights is a list of visible tab names in weight order - weights = sorted([(tab.weight, name) for name, tab in self.tabs.iteritems() if tab.is_visible]) + weights = sorted([(tab.weight, name) for name, tab in self.tabs.items() if tab.is_visible]) log.debug('weights: %s', weights) log.debug('weight of tab: %s', weight) @@ -219,7 +219,7 @@ class TorrentDetails(component.Component): def hide_all_tabs(self): """Hides all tabs""" log.debug('n_pages: %s', self.notebook.get_n_pages()) - for n in xrange(self.notebook.get_n_pages() - 1, -1, -1): + for n in range(self.notebook.get_n_pages() - 1, -1, -1): self.notebook.remove_page(n) for tab in self.tabs: @@ -243,7 +243,7 @@ class TorrentDetails(component.Component): self.generate_menu() show = False - for name, tab in self.tabs.iteritems(): + for name, tab in self.tabs.items(): show = show or tab.is_visible self.visible(show) diff --git a/deluge/ui/gtkui/torrentview.py b/deluge/ui/gtkui/torrentview.py index 92f8f73a5..8e2fdf802 100644 --- a/deluge/ui/gtkui/torrentview.py +++ b/deluge/ui/gtkui/torrentview.py @@ -413,7 +413,7 @@ class TorrentView(ListView, component.Component): if columns is None: # We need to iterate through all columns - columns = self.columns.keys() + columns = list(self.columns.keys()) # Iterate through supplied list of columns to update for column in columns: @@ -486,7 +486,7 @@ class TorrentView(ListView, component.Component): # Get the columns to update from one of the torrents if status: - torrent_id = status.keys()[0] + torrent_id = list(status.keys())[0] fields_to_update = [] for column in self.columns_to_update: column_index = self.get_column_index(column) @@ -626,7 +626,7 @@ class TorrentView(ListView, component.Component): return {} def get_visible_torrents(self): - return self.status.keys() + return list(self.status.keys()) # Callbacks # def on_button_press_event(self, widget, event): diff --git a/deluge/ui/sessionproxy.py b/deluge/ui/sessionproxy.py index 72d60edd4..b288cf54e 100644 --- a/deluge/ui/sessionproxy.py +++ b/deluge/ui/sessionproxy.py @@ -92,7 +92,7 @@ class SessionProxy(component.Component): keys_to_remove = keys_diff_cached else: # Not the same keys so create a new diff - keys_to_remove = set(sd[torrent_id].iterkeys()) - keys + keys_to_remove = set(sd[torrent_id]) - keys # Update the cached diff keys_diff_cached = keys_to_remove keys_len = len(sd[torrent_id]) @@ -180,7 +180,7 @@ class SessionProxy(component.Component): def on_status(result, torrent_ids, keys): # Update the internal torrent status dict with the update values t = time() - for key, value in result.iteritems(): + for key, value in result.items(): try: self.torrents[key][0] = t self.torrents[key][1].update(value) @@ -192,7 +192,7 @@ class SessionProxy(component.Component): # Create the status dict if not torrent_ids: - torrent_ids = result.keys() + torrent_ids = list(result.keys()) return self.create_status_dict(torrent_ids, keys) @@ -216,13 +216,13 @@ class SessionProxy(component.Component): if not filter_dict: # This means we want all the torrents status # We get a list of any torrent_ids with expired status dicts - to_fetch = find_torrents_to_fetch(self.torrents.keys()) + to_fetch = find_torrents_to_fetch(list(self.torrents.keys())) if to_fetch: d = client.core.get_torrents_status({'id': to_fetch}, keys, True) - return d.addCallback(on_status, self.torrents.keys(), keys) + return d.addCallback(on_status, list(self.torrents.keys()), keys) # Don't need to fetch anything - return maybeDeferred(self.create_status_dict, self.torrents.keys(), keys) + return maybeDeferred(self.create_status_dict, list(self.torrents.keys()), keys) if len(filter_dict) == 1 and 'id' in filter_dict: # At this point we should have a filter with just "id" in it diff --git a/deluge/ui/translations_util.py b/deluge/ui/translations_util.py index 656cabd1c..b4b966ce8 100644 --- a/deluge/ui/translations_util.py +++ b/deluge/ui/translations_util.py @@ -9,6 +9,7 @@ from __future__ import unicode_literals +import __builtin__ import gettext import locale import logging @@ -22,7 +23,6 @@ log.addHandler(logging.NullHandler()) # Silence: No handlers could be found for def set_dummy_trans(warn_msg=None): - import __builtin__ def _func(*txt): if warn_msg: @@ -122,9 +122,7 @@ def setup_translations(setup_gettext=True, setup_pygtk=False): gettext.bindtextdomain(domain, translations_path) gettext.bind_textdomain_codeset(domain, 'UTF-8') gettext.textdomain(domain) - gettext.install(domain, translations_path, unicode=True) - import __builtin__ - __builtin__.__dict__['_n'] = gettext.ngettext + gettext.install(domain, translations_path) except Exception as ex: log.error('Unable to initialize gettext/locale!') log.exception(ex) diff --git a/deluge/ui/web/auth.py b/deluge/ui/web/auth.py index d5a439d42..4438004f6 100644 --- a/deluge/ui/web/auth.py +++ b/deluge/ui/web/auth.py @@ -90,7 +90,7 @@ class Auth(JSONComponent): self.worker.stop() def _clean_sessions(self): - session_ids = self.config['sessions'].keys() + session_ids = list(self.config['sessions'].keys()) now = time.gmtime() for session_id in session_ids: diff --git a/deluge/ui/web/json_api.py b/deluge/ui/web/json_api.py index a8b549186..ac946f627 100644 --- a/deluge/ui/web/json_api.py +++ b/deluge/ui/web/json_api.py @@ -918,7 +918,7 @@ class WebApi(JSONComponent): """ return { - 'enabled_plugins': component.get('Web.PluginManager').plugins.keys(), + 'enabled_plugins': list(component.get('Web.PluginManager').plugins.keys()), 'available_plugins': component.get('Web.PluginManager').available_plugins } diff --git a/setup.cfg b/setup.cfg index b7924ac3d..7066be629 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,7 +20,8 @@ known_third_party = # Ignore Windows specific modules. bbfreeze, win32verstamp, # Ignore gtk modules, primarily for tox testing. - pygtk, gtk, gobject, gtk.gdk, pango, cairo, pangocairo + pygtk, gtk, gobject, gtk.gdk, pango, cairo, pangocairo, + six known_first_party = msgfmt, deluge order_by_type = true line_length = 120