[Lint] Convert all python double quotes to single quotes

* A rather disruptive change but for a few reasons such as easier to read,
   easier type, keep consistent and javascript code uses single quotes.
 * There are a few exceptions for the automated process:
    * Any double quotes in comments
    * Triple double quotes for docstrings
    * Strings containing single quotes are left e.g. "they're"

 * To deal with merge conflicts from feature branches it is best to follow
   these steps for each commit:
     * Create a patch: `git format-patch -1 <sha1>`
     * Edit the patch and replace double quotes with single except those in
       comments or strings containing an unescaped apostrophe.
     * Check the patch `git apply --check <patchfile>` and fix any remaining
       issues if it outputs an error.
     * Apply the patch `git am < <patchfile>`
This commit is contained in:
Calum Lind 2016-11-03 21:26:46 +00:00
parent d4a8a38586
commit 3a2ff0c188
231 changed files with 8812 additions and 8812 deletions

View File

@ -23,7 +23,7 @@ try:
except ImportError: except ImportError:
import libtorrent as lt import libtorrent as lt
REQUIRED_VERSION = "1.0.7.0" REQUIRED_VERSION = '1.0.7.0'
if VersionSplit(lt.__version__) < VersionSplit(REQUIRED_VERSION): if VersionSplit(lt.__version__) < VersionSplit(REQUIRED_VERSION):
raise ImportError("Deluge %s requires libtorrent >= %s" % (get_version(), REQUIRED_VERSION)) raise ImportError('Deluge %s requires libtorrent >= %s' % (get_version(), REQUIRED_VERSION))

View File

@ -75,7 +75,7 @@ def bdecode(x):
try: try:
r, l = decode_func[x[0]](x, 0) r, l = decode_func[x[0]](x, 0)
except (IndexError, KeyError, ValueError): except (IndexError, KeyError, ValueError):
raise BTFailure("not a valid bencoded string") raise BTFailure('not a valid bencoded string')
return r return r

View File

@ -32,7 +32,7 @@ from deluge.error import InvalidPathError
try: try:
import dbus import dbus
bus = dbus.SessionBus() bus = dbus.SessionBus()
dbus_fileman = bus.get_object("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1") dbus_fileman = bus.get_object('org.freedesktop.FileManager1', '/org/freedesktop/FileManager1')
except Exception: except Exception:
dbus_fileman = None dbus_fileman = None
@ -40,29 +40,29 @@ except Exception:
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
TORRENT_STATE = [ TORRENT_STATE = [
"Allocating", 'Allocating',
"Checking", 'Checking',
"Downloading", 'Downloading',
"Seeding", 'Seeding',
"Paused", 'Paused',
"Error", 'Error',
"Queued", 'Queued',
"Moving" 'Moving'
] ]
FILE_PRIORITY = { FILE_PRIORITY = {
0: "Do Not Download", 0: 'Do Not Download',
1: "Normal Priority", 1: 'Normal Priority',
2: "High Priority", 2: 'High Priority',
3: "High Priority", 3: 'High Priority',
4: "High Priority", 4: 'High Priority',
5: "High Priority", 5: 'High Priority',
6: "High Priority", 6: 'High Priority',
7: "Highest Priority", 7: 'Highest Priority',
"Do Not Download": 0, 'Do Not Download': 0,
"Normal Priority": 1, 'Normal Priority': 1,
"High Priority": 5, 'High Priority': 5,
"Highest Priority": 7 'Highest Priority': 7
} }
@ -74,7 +74,7 @@ def get_version():
:rtype: string :rtype: string
""" """
return pkg_resources.require("Deluge")[0].version return pkg_resources.require('Deluge')[0].version
def get_default_config_dir(filename=None): def get_default_config_dir(filename=None):
@ -89,12 +89,12 @@ def get_default_config_dir(filename=None):
if windows_check(): if windows_check():
def save_config_path(resource): def save_config_path(resource):
app_data_path = os.environ.get("APPDATA") app_data_path = os.environ.get('APPDATA')
if not app_data_path: if not app_data_path:
import _winreg import _winreg
hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders')
app_data_reg = _winreg.QueryValueEx(hkey, "AppData") app_data_reg = _winreg.QueryValueEx(hkey, 'AppData')
app_data_path = app_data_reg[0] app_data_path = app_data_reg[0]
_winreg.CloseKey(hkey) _winreg.CloseKey(hkey)
return os.path.join(app_data_path, resource) return os.path.join(app_data_path, resource)
@ -103,9 +103,9 @@ def get_default_config_dir(filename=None):
if not filename: if not filename:
filename = '' filename = ''
try: try:
return os.path.join(save_config_path("deluge"), filename) return os.path.join(save_config_path('deluge'), filename)
except OSError as ex: except OSError as ex:
log.error("Unable to use default config directory, exiting... (%s)", ex) log.error('Unable to use default config directory, exiting... (%s)', ex)
sys.exit(1) sys.exit(1)
@ -115,20 +115,20 @@ def get_default_download_dir():
:rtype: string :rtype: string
""" """
download_dir = "" download_dir = ''
if not windows_check(): if not windows_check():
from xdg.BaseDirectory import xdg_config_home from xdg.BaseDirectory import xdg_config_home
try: try:
with open(os.path.join(xdg_config_home, 'user-dirs.dirs'), 'r') as _file: with open(os.path.join(xdg_config_home, 'user-dirs.dirs'), 'r') as _file:
for line in _file: for line in _file:
if not line.startswith('#') and line.startswith('XDG_DOWNLOAD_DIR'): if not line.startswith('#') and line.startswith('XDG_DOWNLOAD_DIR'):
download_dir = os.path.expandvars(line.partition("=")[2].rstrip().strip('"')) download_dir = os.path.expandvars(line.partition('=')[2].rstrip().strip('"'))
break break
except IOError: except IOError:
pass pass
if not download_dir: if not download_dir:
download_dir = os.path.join(os.path.expanduser("~"), 'Downloads') download_dir = os.path.join(os.path.expanduser('~'), 'Downloads')
return download_dir return download_dir
@ -151,7 +151,7 @@ def vista_check():
:rtype: bool :rtype: bool
""" """
return platform.release() == "Vista" return platform.release() == 'Vista'
def osx_check(): def osx_check():
@ -162,7 +162,7 @@ def osx_check():
:rtype: bool :rtype: bool
""" """
return platform.system() == "Darwin" return platform.system() == 'Darwin'
def linux_check(): def linux_check():
@ -173,7 +173,7 @@ def linux_check():
:rtype: bool :rtype: bool
""" """
return platform.system() == "Linux" return platform.system() == 'Linux'
def get_os_version(): def get_os_version():
@ -197,7 +197,7 @@ def get_pixmap(fname):
:rtype: string :rtype: string
""" """
return resource_filename("deluge", os.path.join("ui", "data", "pixmaps", fname)) return resource_filename('deluge', os.path.join('ui', 'data', 'pixmaps', fname))
def resource_filename(module, path): def resource_filename(module, path):
@ -207,8 +207,8 @@ def resource_filename(module, path):
# not, it returns the first found on the python path, which is not good # not, it returns the first found on the python path, which is not good
# enough. # enough.
# This is a work-around that. # This is a work-around that.
return pkg_resources.require("Deluge>=%s" % get_version())[0].get_resource_filename( return pkg_resources.require('Deluge>=%s' % get_version())[0].get_resource_filename(
pkg_resources._manager, os.path.join(*(module.split(".") + [path])) pkg_resources._manager, os.path.join(*(module.split('.') + [path]))
) )
@ -223,14 +223,14 @@ def open_file(path, timestamp=None):
if windows_check(): if windows_check():
os.startfile(path) os.startfile(path)
elif osx_check(): elif osx_check():
subprocess.Popen(["open", path]) subprocess.Popen(['open', path])
else: else:
if timestamp is None: if timestamp is None:
timestamp = int(time.time()) timestamp = int(time.time())
env = os.environ.copy() env = os.environ.copy()
env["DESKTOP_STARTUP_ID"] = "%s-%u-%s-xdg_open_TIME%d" % \ env['DESKTOP_STARTUP_ID'] = '%s-%u-%s-xdg_open_TIME%d' % \
(os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp) (os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp)
subprocess.Popen(["xdg-open", "%s" % path], env=env) subprocess.Popen(['xdg-open', '%s' % path], env=env)
def show_file(path, timestamp=None): def show_file(path, timestamp=None):
@ -242,21 +242,21 @@ def show_file(path, timestamp=None):
""" """
if windows_check(): if windows_check():
subprocess.Popen(["explorer", "/select,", path]) subprocess.Popen(['explorer', '/select,', path])
elif osx_check(): elif osx_check():
subprocess.Popen(["open", "-R", path]) subprocess.Popen(['open', '-R', path])
else: else:
if timestamp is None: if timestamp is None:
timestamp = int(time.time()) timestamp = int(time.time())
startup_id = "%s_%u_%s-dbus_TIME%d" % (os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp) startup_id = '%s_%u_%s-dbus_TIME%d' % (os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp)
if dbus_fileman: if dbus_fileman:
paths = [urlparse.urljoin("file:", urllib.pathname2url(utf8_encoded(path)))] paths = [urlparse.urljoin('file:', urllib.pathname2url(utf8_encoded(path)))]
dbus_fileman.ShowItems(paths, startup_id, dbus_interface="org.freedesktop.FileManager1") dbus_fileman.ShowItems(paths, startup_id, dbus_interface='org.freedesktop.FileManager1')
else: else:
env = os.environ.copy() env = os.environ.copy()
env["DESKTOP_STARTUP_ID"] = startup_id.replace("dbus", "xdg-open") env['DESKTOP_STARTUP_ID'] = startup_id.replace('dbus', 'xdg-open')
# No option in xdg to highlight a file so just open parent folder. # No option in xdg to highlight a file so just open parent folder.
subprocess.Popen(["xdg-open", os.path.dirname(path.rstrip("/"))], env=env) subprocess.Popen(['xdg-open', os.path.dirname(path.rstrip('/'))], env=env)
def open_url_in_browser(url): def open_url_in_browser(url):
@ -272,15 +272,15 @@ def open_url_in_browser(url):
# Formatting text functions # Formatting text functions
byte_txt = "B" byte_txt = 'B'
kib_txt = "KiB" kib_txt = 'KiB'
mib_txt = "MiB" mib_txt = 'MiB'
gib_txt = "GiB" gib_txt = 'GiB'
tib_txt = "TiB" tib_txt = 'TiB'
kib_txt_short = "K" kib_txt_short = 'K'
mib_txt_short = "M" mib_txt_short = 'M'
gib_txt_short = "G" gib_txt_short = 'G'
tib_txt_short = "T" tib_txt_short = 'T'
def translate_size_units(): def translate_size_units():
@ -289,15 +289,15 @@ def translate_size_units():
global byte_txt, kib_txt, mib_txt, gib_txt, tib_txt global byte_txt, kib_txt, mib_txt, gib_txt, tib_txt
global kib_txt_short, mib_txt_short, gib_txt_short, tib_txt_short global kib_txt_short, mib_txt_short, gib_txt_short, tib_txt_short
byte_txt = _("B") byte_txt = _('B')
kib_txt = _("KiB") kib_txt = _('KiB')
mib_txt = _("MiB") mib_txt = _('MiB')
gib_txt = _("GiB") gib_txt = _('GiB')
tib_txt = _("TiB") tib_txt = _('TiB')
kib_txt_short = _("K") kib_txt_short = _('K')
mib_txt_short = _("M") mib_txt_short = _('M')
gib_txt_short = _("G") gib_txt_short = _('G')
tib_txt_short = _("T") tib_txt_short = _('T')
def fsize(fsize_b, precision=1, shortform=False): def fsize(fsize_b, precision=1, shortform=False):
@ -324,15 +324,15 @@ def fsize(fsize_b, precision=1, shortform=False):
""" """
if fsize_b >= 1024 ** 4: if fsize_b >= 1024 ** 4:
return "%.*f %s" % (precision, fsize_b / 1024 ** 4, tib_txt_short if shortform else tib_txt) return '%.*f %s' % (precision, fsize_b / 1024 ** 4, tib_txt_short if shortform else tib_txt)
elif fsize_b >= 1024 ** 3: elif fsize_b >= 1024 ** 3:
return "%.*f %s" % (precision, fsize_b / 1024 ** 3, gib_txt_short if shortform else gib_txt) return '%.*f %s' % (precision, fsize_b / 1024 ** 3, gib_txt_short if shortform else gib_txt)
elif fsize_b >= 1024 ** 2: elif fsize_b >= 1024 ** 2:
return "%.*f %s" % (precision, fsize_b / 1024 ** 2, mib_txt_short if shortform else mib_txt) return '%.*f %s' % (precision, fsize_b / 1024 ** 2, mib_txt_short if shortform else mib_txt)
elif fsize_b >= 1024: elif fsize_b >= 1024:
return "%.*f %s" % (precision, fsize_b / 1024, kib_txt_short if shortform else kib_txt) return '%.*f %s' % (precision, fsize_b / 1024, kib_txt_short if shortform else kib_txt)
else: else:
return "%d %s" % (fsize_b, byte_txt) return '%d %s' % (fsize_b, byte_txt)
def fpcnt(dec, precision=2): def fpcnt(dec, precision=2):
@ -375,13 +375,13 @@ def fspeed(bps, precision=1, shortform=False):
""" """
if bps < 1024 ** 2: if bps < 1024 ** 2:
return "%.*f %s" % (precision, bps / 1024, _("K/s") if shortform else _("KiB/s")) return '%.*f %s' % (precision, bps / 1024, _('K/s') if shortform else _('KiB/s'))
elif bps < 1024 ** 3: elif bps < 1024 ** 3:
return "%.*f %s" % (precision, bps / 1024 ** 2, _("M/s") if shortform else _("MiB/s")) return '%.*f %s' % (precision, bps / 1024 ** 2, _('M/s') if shortform else _('MiB/s'))
elif bps < 1024 ** 4: elif bps < 1024 ** 4:
return "%.*f %s" % (precision, bps / 1024 ** 3, _("G/s") if shortform else _("GiB/s")) return '%.*f %s' % (precision, bps / 1024 ** 3, _('G/s') if shortform else _('GiB/s'))
else: else:
return "%.*f %s" % (precision, bps / 1024 ** 4, _("T/s") if shortform else _("TiB/s")) return '%.*f %s' % (precision, bps / 1024 ** 4, _('T/s') if shortform else _('TiB/s'))
def fpeer(num_peers, total_peers): def fpeer(num_peers, total_peers):
@ -402,9 +402,9 @@ def fpeer(num_peers, total_peers):
""" """
if total_peers > -1: if total_peers > -1:
return "{:d} ({:d})".format(num_peers, total_peers) return '{:d} ({:d})'.format(num_peers, total_peers)
else: else:
return "{:d}".format(num_peers) return '{:d}'.format(num_peers)
def ftime(secs): def ftime(secs):
@ -456,8 +456,8 @@ def fdate(seconds, date_only=False, precision_secs=False):
""" """
if seconds < 0: if seconds < 0:
return "" return ''
time_format = "%x %X" if precision_secs else "%x %H:%M" time_format = '%x %X' if precision_secs else '%x %H:%M'
if date_only: if date_only:
time_format = time_format.split()[0] time_format = time_format.split()[0]
return time.strftime(time_format, time.localtime(seconds)) return time.strftime(time_format, time.localtime(seconds))
@ -535,7 +535,7 @@ def parse_human_size(size):
if normalized_unit.startswith(unit['prefix'].lower()): if normalized_unit.startswith(unit['prefix'].lower()):
return int(tokens[0] * unit['divider']) return int(tokens[0] * unit['divider'])
# We failed to parse the size specification. # We failed to parse the size specification.
msg = "Failed to parse size! (input %r was tokenized as %r)" msg = 'Failed to parse size! (input %r was tokenized as %r)'
raise InvalidSize(msg % (size, tokens)) raise InvalidSize(msg % (size, tokens))
@ -554,7 +554,7 @@ def is_url(url):
True True
""" """
return url.partition('://')[0] in ("http", "https", "ftp", "udp") return url.partition('://')[0] in ('http', 'https', 'ftp', 'udp')
def is_infohash(infohash): def is_infohash(infohash):
@ -623,9 +623,9 @@ def get_magnet_info(uri):
xt_hash = param[len(xt_param):] xt_hash = param[len(xt_param):]
if len(xt_hash) == 32: if len(xt_hash) == 32:
try: try:
info_hash = base64.b32decode(xt_hash.upper()).encode("hex") info_hash = base64.b32decode(xt_hash.upper()).encode('hex')
except TypeError as ex: except TypeError as ex:
log.debug("Invalid base32 magnet hash: %s, %s", xt_hash, ex) log.debug('Invalid base32 magnet hash: %s, %s', xt_hash, ex)
break break
elif is_infohash(xt_hash): elif is_infohash(xt_hash):
info_hash = xt_hash.lower() info_hash = xt_hash.lower()
@ -637,7 +637,7 @@ def get_magnet_info(uri):
if info_hash: if info_hash:
if not name: if not name:
name = info_hash name = info_hash
return {"name": name, "info_hash": info_hash, "files_tree": ''} return {'name': name, 'info_hash': info_hash, 'files_tree': ''}
return False return False
@ -657,12 +657,12 @@ def create_magnet_uri(infohash, name=None, trackers=None):
""" """
from base64 import b32encode from base64 import b32encode
uri = "magnet:?xt=urn:btih:" + b32encode(infohash.decode("hex")) uri = 'magnet:?xt=urn:btih:' + b32encode(infohash.decode('hex'))
if name: if name:
uri = uri + "&dn=" + name uri = uri + '&dn=' + name
if trackers: if trackers:
for t in trackers: for t in trackers:
uri = uri + "&tr=" + t uri = uri + '&tr=' + t
return uri return uri
@ -704,13 +704,13 @@ def free_space(path):
""" """
if not path or not os.path.exists(path): if not path or not os.path.exists(path):
raise InvalidPathError("%s is not a valid path" % path) raise InvalidPathError('%s is not a valid path' % path)
if windows_check(): if windows_check():
from win32file import GetDiskFreeSpaceEx from win32file import GetDiskFreeSpaceEx
return GetDiskFreeSpaceEx(path)[0] return GetDiskFreeSpaceEx(path)[0]
else: else:
disk_data = os.statvfs(path.encode("utf8")) disk_data = os.statvfs(path.encode('utf8'))
block_size = disk_data.f_frsize block_size = disk_data.f_frsize
return disk_data.f_bavail * block_size return disk_data.f_bavail * block_size
@ -745,7 +745,7 @@ def is_ip(ip):
# now test ipv6 # now test ipv6
try: try:
if windows_check(): if windows_check():
log.warning("ipv6 check unavailable on windows") log.warning('ipv6 check unavailable on windows')
return True return True
else: else:
if socket.inet_pton(socket.AF_INET6, ip): if socket.inet_pton(socket.AF_INET6, ip):
@ -754,7 +754,7 @@ def is_ip(ip):
return False return False
def decode_string(s, encoding="utf8"): def decode_string(s, encoding='utf8'):
""" """
Decodes a string and return unicode. If it cannot decode using Decodes a string and return unicode. If it cannot decode using
`:param:encoding` then it will try latin1, and if that fails, `:param:encoding` then it will try latin1, and if that fails,
@ -774,12 +774,12 @@ def decode_string(s, encoding="utf8"):
elif isinstance(s, unicode): elif isinstance(s, unicode):
return s return s
encodings = [lambda: ("utf8", 'strict'), encodings = [lambda: ('utf8', 'strict'),
lambda: ("iso-8859-1", 'strict'), lambda: ('iso-8859-1', 'strict'),
lambda: (chardet.detect(s)["encoding"], 'strict'), lambda: (chardet.detect(s)['encoding'], 'strict'),
lambda: (encoding, 'ignore')] lambda: (encoding, 'ignore')]
if encoding is not "utf8": if encoding is not 'utf8':
encodings.insert(0, lambda: (encoding, 'strict')) encodings.insert(0, lambda: (encoding, 'strict'))
for l in encodings: for l in encodings:
@ -790,7 +790,7 @@ def decode_string(s, encoding="utf8"):
return u'' return u''
def utf8_encoded(s, encoding="utf8"): def utf8_encoded(s, encoding='utf8'):
""" """
Returns a utf8 encoded string of s Returns a utf8 encoded string of s
@ -803,9 +803,9 @@ def utf8_encoded(s, encoding="utf8"):
""" """
if isinstance(s, str): if isinstance(s, str):
s = decode_string(s, encoding).encode("utf8") s = decode_string(s, encoding).encode('utf8')
elif isinstance(s, unicode): elif isinstance(s, unicode):
s = s.encode("utf8") s = s.encode('utf8')
return s return s
@ -838,13 +838,13 @@ class VersionSplit(object):
vs = [''.join(group[0:2]), ''.join(group[2:4]), group[4].lstrip('.')] vs = [''.join(group[0:2]), ''.join(group[2:4]), group[4].lstrip('.')]
else: else:
ver = ver.lower() ver = ver.lower()
vs = ver.replace("_", "-").split("-") vs = ver.replace('_', '-').split('-')
self.version = [int(x) for x in vs[0].split(".") if x.isdigit()] self.version = [int(x) for x in vs[0].split('.') if x.isdigit()]
self.suffix = None self.suffix = None
self.dev = False self.dev = False
if len(vs) > 1: if len(vs) > 1:
if vs[1].startswith(("rc", "a", "b", "c")): if vs[1].startswith(('rc', 'a', 'b', 'c')):
self.suffix = vs[1] self.suffix = vs[1]
if vs[-1].startswith('dev'): if vs[-1].startswith('dev'):
self.dev = vs[-1] self.dev = vs[-1]
@ -889,10 +889,10 @@ def create_auth_file():
import stat import stat
import deluge.configmanager import deluge.configmanager
auth_file = deluge.configmanager.get_config_dir("auth") auth_file = deluge.configmanager.get_config_dir('auth')
# Check for auth file and create if necessary # Check for auth file and create if necessary
if not os.path.exists(auth_file): if not os.path.exists(auth_file):
with open(auth_file, "w") as _file: with open(auth_file, 'w') as _file:
_file.flush() _file.flush()
os.fsync(_file.fileno()) os.fsync(_file.fileno())
# Change the permissions on the file so only this user can read/write it # Change the permissions on the file so only this user can read/write it
@ -904,13 +904,13 @@ def create_localclient_account(append=False):
from hashlib import sha1 as sha from hashlib import sha1 as sha
import deluge.configmanager import deluge.configmanager
auth_file = deluge.configmanager.get_config_dir("auth") auth_file = deluge.configmanager.get_config_dir('auth')
if not os.path.exists(auth_file): if not os.path.exists(auth_file):
create_auth_file() create_auth_file()
with open(auth_file, "a" if append else "w") as _file: with open(auth_file, 'a' if append else 'w') as _file:
_file.write(":".join([ _file.write(':'.join([
"localclient", 'localclient',
sha(str(random.random())).hexdigest(), sha(str(random.random())).hexdigest(),
str(AUTH_LEVEL_ADMIN) str(AUTH_LEVEL_ADMIN)
]) + '\n') ]) + '\n')
@ -1008,11 +1008,11 @@ def unicode_argv():
else: else:
# On other platforms, we have to find the likely encoding of the args and decode # 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 # First check if sys.stdout or stdin have encoding set
encoding = getattr(sys.stdout, "encoding") or getattr(sys.stdin, "encoding") encoding = getattr(sys.stdout, 'encoding') or getattr(sys.stdin, 'encoding')
# If that fails, check what the locale is set to # If that fails, check what the locale is set to
encoding = encoding or locale.getpreferredencoding() encoding = encoding or locale.getpreferredencoding()
# As a last resort, just default to utf-8 # As a last resort, just default to utf-8
encoding = encoding or "utf-8" encoding = encoding or 'utf-8'
return [arg.decode(encoding) for arg in sys.argv] return [arg.decode(encoding) for arg in sys.argv]
@ -1028,16 +1028,16 @@ def run_profiled(func, *args, **kwargs):
output_file (str, optional): Filename to save profile results. If None, print to stdout. output_file (str, optional): Filename to save profile results. If None, print to stdout.
Defaults to None. Defaults to None.
""" """
if kwargs.get("do_profile", True) is not False: if kwargs.get('do_profile', True) is not False:
import cProfile import cProfile
profiler = cProfile.Profile() profiler = cProfile.Profile()
def on_shutdown(): def on_shutdown():
output_file = kwargs.get("output_file", None) output_file = kwargs.get('output_file', None)
if output_file: if output_file:
profiler.dump_stats(output_file) profiler.dump_stats(output_file)
log.info("Profile stats saved to %s", output_file) log.info('Profile stats saved to %s', output_file)
print("Profile stats saved to %s" % output_file) print('Profile stats saved to %s' % output_file)
else: else:
import pstats import pstats
import StringIO import StringIO

View File

@ -31,7 +31,7 @@ class ComponentException(Exception):
def __str__(self): def __str__(self):
s = super(ComponentException, self).__str__() s = super(ComponentException, self).__str__()
return "%s\n%s" % (s, "".join(self.tb)) return '%s\n%s' % (s, ''.join(self.tb))
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
@ -101,7 +101,7 @@ class Component(object):
self._component_name = name self._component_name = name
self._component_interval = interval self._component_interval = interval
self._component_depend = depend self._component_depend = depend
self._component_state = "Stopped" self._component_state = 'Stopped'
self._component_timer = None self._component_timer = None
self._component_starting_deferred = None self._component_starting_deferred = None
self._component_stopping_deferred = None self._component_stopping_deferred = None
@ -112,34 +112,34 @@ class Component(object):
_ComponentRegistry.deregister(self) _ComponentRegistry.deregister(self)
def _component_start_timer(self): def _component_start_timer(self):
if hasattr(self, "update"): if hasattr(self, 'update'):
self._component_timer = LoopingCall(self.update) self._component_timer = LoopingCall(self.update)
self._component_timer.start(self._component_interval) self._component_timer.start(self._component_interval)
def _component_start(self): def _component_start(self):
def on_start(result): def on_start(result):
self._component_state = "Started" self._component_state = 'Started'
self._component_starting_deferred = None self._component_starting_deferred = None
self._component_start_timer() self._component_start_timer()
return True return True
def on_start_fail(result): def on_start_fail(result):
self._component_state = "Stopped" self._component_state = 'Stopped'
self._component_starting_deferred = None self._component_starting_deferred = None
log.error(result) log.error(result)
return fail(result) return fail(result)
if self._component_state == "Stopped": if self._component_state == 'Stopped':
if hasattr(self, "start"): if hasattr(self, 'start'):
self._component_state = "Starting" self._component_state = 'Starting'
d = deferLater(reactor, 0, self.start) d = deferLater(reactor, 0, self.start)
d.addCallbacks(on_start, on_start_fail) d.addCallbacks(on_start, on_start_fail)
self._component_starting_deferred = d self._component_starting_deferred = d
else: else:
d = maybeDeferred(on_start, None) d = maybeDeferred(on_start, None)
elif self._component_state == "Starting": elif self._component_state == 'Starting':
return self._component_starting_deferred return self._component_starting_deferred
elif self._component_state == "Started": elif self._component_state == 'Started':
d = succeed(True) d = succeed(True)
else: else:
d = fail(ComponentException("Trying to start a component ('%s') not in stopped state. Current state: '%s'" % d = fail(ComponentException("Trying to start a component ('%s') not in stopped state. Current state: '%s'" %
@ -148,20 +148,20 @@ class Component(object):
def _component_stop(self): def _component_stop(self):
def on_stop(result): def on_stop(result):
self._component_state = "Stopped" self._component_state = 'Stopped'
if self._component_timer and self._component_timer.running: if self._component_timer and self._component_timer.running:
self._component_timer.stop() self._component_timer.stop()
return True return True
def on_stop_fail(result): def on_stop_fail(result):
self._component_state = "Started" self._component_state = 'Started'
self._component_stopping_deferred = None self._component_stopping_deferred = None
log.error(result) log.error(result)
return result return result
if self._component_state != "Stopped" and self._component_state != "Stopping": if self._component_state != 'Stopped' and self._component_state != 'Stopping':
if hasattr(self, "stop"): if hasattr(self, 'stop'):
self._component_state = "Stopping" self._component_state = 'Stopping'
d = maybeDeferred(self.stop) d = maybeDeferred(self.stop)
d.addCallback(on_stop) d.addCallback(on_stop)
d.addErrback(on_stop_fail) d.addErrback(on_stop_fail)
@ -169,22 +169,22 @@ class Component(object):
else: else:
d = maybeDeferred(on_stop, None) d = maybeDeferred(on_stop, None)
if self._component_state == "Stopping": if self._component_state == 'Stopping':
return self._component_stopping_deferred return self._component_stopping_deferred
return succeed(None) return succeed(None)
def _component_pause(self): def _component_pause(self):
def on_pause(result): def on_pause(result):
self._component_state = "Paused" self._component_state = 'Paused'
if self._component_state == "Started": if self._component_state == 'Started':
if self._component_timer and self._component_timer.running: if self._component_timer and self._component_timer.running:
d = maybeDeferred(self._component_timer.stop) d = maybeDeferred(self._component_timer.stop)
d.addCallback(on_pause) d.addCallback(on_pause)
else: else:
d = succeed(None) d = succeed(None)
elif self._component_state == "Paused": elif self._component_state == 'Paused':
d = succeed(None) d = succeed(None)
else: else:
d = fail(ComponentException("Trying to pause a component ('%s') not in started state. Current state: '%s'" % d = fail(ComponentException("Trying to pause a component ('%s') not in started state. Current state: '%s'" %
@ -193,9 +193,9 @@ class Component(object):
def _component_resume(self): def _component_resume(self):
def on_resume(result): def on_resume(result):
self._component_state = "Started" self._component_state = 'Started'
if self._component_state == "Paused": if self._component_state == 'Paused':
d = maybeDeferred(self._component_start_timer) d = maybeDeferred(self._component_start_timer)
d.addCallback(on_resume) d.addCallback(on_resume)
else: else:
@ -205,7 +205,7 @@ class Component(object):
def _component_shutdown(self): def _component_shutdown(self):
def on_stop(result): def on_stop(result):
if hasattr(self, "shutdown"): if hasattr(self, 'shutdown'):
return maybeDeferred(self.shutdown) return maybeDeferred(self.shutdown)
return succeed(None) return succeed(None)
@ -254,7 +254,7 @@ class ComponentRegistry(object):
""" """
name = obj._component_name name = obj._component_name
if name in self.components: if name in self.components:
raise ComponentAlreadyRegistered("Component already registered with name %s" % name) raise ComponentAlreadyRegistered('Component already registered with name %s' % name)
self.components[obj._component_name] = obj self.components[obj._component_name] = obj
if obj._component_depend: if obj._component_depend:
@ -273,7 +273,7 @@ class ComponentRegistry(object):
""" """
if obj in self.components.values(): if obj in self.components.values():
log.debug("Deregistering Component: %s", obj._component_name) log.debug('Deregistering Component: %s', obj._component_name)
d = self.stop([obj._component_name]) d = self.stop([obj._component_name])
def on_stop(result, name): def on_stop(result, name):
@ -377,7 +377,7 @@ class ComponentRegistry(object):
deferreds = [] deferreds = []
for name in names: for name in names:
if self.components[name]._component_state == "Started": if self.components[name]._component_state == 'Started':
deferreds.append(self.components[name]._component_pause()) deferreds.append(self.components[name]._component_pause())
return DeferredList(deferreds) return DeferredList(deferreds)
@ -403,7 +403,7 @@ class ComponentRegistry(object):
deferreds = [] deferreds = []
for name in names: for name in names:
if self.components[name]._component_state == "Paused": if self.components[name]._component_state == 'Paused':
deferreds.append(self.components[name]._component_resume()) deferreds.append(self.components[name]._component_resume())
return DeferredList(deferreds) return DeferredList(deferreds)

View File

@ -82,16 +82,16 @@ def find_json_objects(s):
""" """
objects = [] objects = []
opens = 0 opens = 0
start = s.find("{") start = s.find('{')
offset = start offset = start
if start < 0: if start < 0:
return [] return []
for index, c in enumerate(s[offset:]): for index, c in enumerate(s[offset:]):
if c == "{": if c == '{':
opens += 1 opens += 1
elif c == "}": elif c == '}':
opens -= 1 opens -= 1
if opens == 0: if opens == 0:
objects.append((start, index + offset + 1)) objects.append((start, index + offset + 1))
@ -119,8 +119,8 @@ class Config(object):
# These hold the version numbers and they will be set when loaded # These hold the version numbers and they will be set when loaded
self.__version = { self.__version = {
"format": 1, 'format': 1,
"file": file_version 'file': file_version
} }
# This will get set with a reactor.callLater whenever a config option # This will get set with a reactor.callLater whenever a config option
@ -186,7 +186,7 @@ class Config(object):
try: try:
oldtype = type(self.__config[key]) oldtype = type(self.__config[key])
if isinstance(self.__config[key], unicode): if isinstance(self.__config[key], unicode):
value = oldtype(value, "utf8") value = oldtype(value, 'utf8')
else: else:
value = oldtype(value) value = oldtype(value)
except ValueError: except ValueError:
@ -244,7 +244,7 @@ class Config(object):
""" """
if isinstance(self.__config[key], str): if isinstance(self.__config[key], str):
try: try:
return self.__config[key].decode("utf8") return self.__config[key].decode('utf8')
except UnicodeDecodeError: except UnicodeDecodeError:
return self.__config[key] return self.__config[key]
else: else:
@ -342,7 +342,7 @@ class Config(object):
test 5 test 5
""" """
log.debug("Registering function for %s key..", key) log.debug('Registering function for %s key..', key)
if key not in self.__set_functions: if key not in self.__set_functions:
self.__set_functions[key] = [] self.__set_functions[key] = []
@ -367,7 +367,7 @@ class Config(object):
test 5 test 5
""" """
log.debug("Calling all set functions..") log.debug('Calling all set functions..')
for key, value in self.__set_functions.iteritems(): for key, value in self.__set_functions.iteritems():
for func in value: for func in value:
func(key, self.__config[key]) func(key, self.__config[key])
@ -379,7 +379,7 @@ class Config(object):
key (str): the config key key (str): the config key
""" """
log.debug("Calling set functions for key %s..", key) log.debug('Calling set functions for key %s..', key)
if key in self.__set_functions: if key in self.__set_functions:
for func in self.__set_functions[key]: for func in self.__set_functions[key]:
func(key, self.__config[key]) func(key, self.__config[key])
@ -395,10 +395,10 @@ class Config(object):
filename = self.__config_file filename = self.__config_file
try: try:
with open(filename, "rb") as _file: with open(filename, 'rb') as _file:
data = _file.read() data = _file.read()
except IOError as ex: except IOError as ex:
log.warning("Unable to open config file %s: %s", filename, ex) log.warning('Unable to open config file %s: %s', filename, ex)
return return
objects = find_json_objects(data) objects = find_json_objects(data)
@ -409,14 +409,14 @@ class Config(object):
self.__config.update(pickle.loads(data)) self.__config.update(pickle.loads(data))
except Exception as ex: except Exception as ex:
log.exception(ex) log.exception(ex)
log.warning("Unable to load config file: %s", filename) log.warning('Unable to load config file: %s', filename)
elif len(objects) == 1: elif len(objects) == 1:
start, end = objects[0] start, end = objects[0]
try: try:
self.__config.update(json.loads(data[start:end])) self.__config.update(json.loads(data[start:end]))
except Exception as ex: except Exception as ex:
log.exception(ex) log.exception(ex)
log.warning("Unable to load config file: %s", filename) log.warning('Unable to load config file: %s', filename)
elif len(objects) == 2: elif len(objects) == 2:
try: try:
start, end = objects[0] start, end = objects[0]
@ -425,10 +425,10 @@ class Config(object):
self.__config.update(json.loads(data[start:end])) self.__config.update(json.loads(data[start:end]))
except Exception as ex: except Exception as ex:
log.exception(ex) log.exception(ex)
log.warning("Unable to load config file: %s", filename) log.warning('Unable to load config file: %s', filename)
log.debug("Config %s version: %s.%s loaded: %s", filename, log.debug('Config %s version: %s.%s loaded: %s', filename,
self.__version["format"], self.__version["file"], self.__config) self.__version['format'], self.__version['file'], self.__config)
def save(self, filename=None): def save(self, filename=None):
"""Save configuration to disk """Save configuration to disk
@ -445,7 +445,7 @@ class Config(object):
# Check to see if the current config differs from the one on disk # Check to see if the current config differs from the one on disk
# We will only write a new config file if there is a difference # We will only write a new config file if there is a difference
try: try:
with open(filename, "rb") as _file: with open(filename, 'rb') as _file:
data = _file.read() data = _file.read()
objects = find_json_objects(data) objects = find_json_objects(data)
start, end = objects[0] start, end = objects[0]
@ -458,34 +458,34 @@ class Config(object):
self._save_timer.cancel() self._save_timer.cancel()
return True return True
except (IOError, IndexError) as ex: except (IOError, IndexError) as ex:
log.warning("Unable to open config file: %s because: %s", filename, ex) log.warning('Unable to open config file: %s because: %s', filename, ex)
# Save the new config and make sure it's written to disk # Save the new config and make sure it's written to disk
try: try:
log.debug("Saving new config file %s", filename + ".new") log.debug('Saving new config file %s', filename + '.new')
with open(filename + ".new", "wb") as _file: with open(filename + '.new', 'wb') as _file:
json.dump(self.__version, _file, indent=2) json.dump(self.__version, _file, indent=2)
json.dump(self.__config, _file, indent=2, sort_keys=True) json.dump(self.__config, _file, indent=2, sort_keys=True)
_file.flush() _file.flush()
os.fsync(_file.fileno()) os.fsync(_file.fileno())
except IOError as ex: except IOError as ex:
log.error("Error writing new config file: %s", ex) log.error('Error writing new config file: %s', ex)
return False return False
# Make a backup of the old config # Make a backup of the old config
try: try:
log.debug("Backing up old config file to %s.bak", filename) log.debug('Backing up old config file to %s.bak', filename)
shutil.move(filename, filename + ".bak") shutil.move(filename, filename + '.bak')
except IOError as ex: except IOError as ex:
log.warning("Unable to backup old config: %s", ex) log.warning('Unable to backup old config: %s', ex)
# The new config file has been written successfully, so let's move it over # The new config file has been written successfully, so let's move it over
# the existing one. # the existing one.
try: try:
log.debug("Moving new config file %s to %s..", filename + ".new", filename) log.debug('Moving new config file %s to %s..', filename + '.new', filename)
shutil.move(filename + ".new", filename) shutil.move(filename + '.new', filename)
except IOError as ex: except IOError as ex:
log.error("Error moving new config file: %s", ex) log.error('Error moving new config file: %s', ex)
return False return False
else: else:
return True return True
@ -508,22 +508,22 @@ class Config(object):
""" """
if output_version in input_range or output_version <= max(input_range): if output_version in input_range or output_version <= max(input_range):
raise ValueError("output_version needs to be greater than input_range") raise ValueError('output_version needs to be greater than input_range')
if self.__version["file"] not in input_range: if self.__version['file'] not in input_range:
log.debug("File version %s is not in input_range %s, ignoring converter function..", log.debug('File version %s is not in input_range %s, ignoring converter function..',
self.__version["file"], input_range) self.__version['file'], input_range)
return return
try: try:
self.__config = func(self.__config) self.__config = func(self.__config)
except Exception as ex: except Exception as ex:
log.exception(ex) log.exception(ex)
log.error("There was an exception try to convert config file %s %s to %s", log.error('There was an exception try to convert config file %s %s to %s',
self.__config_file, self.__version["file"], output_version) self.__config_file, self.__version['file'], output_version)
raise ex raise ex
else: else:
self.__version["file"] = output_version self.__version['file'] = output_version
self.save() self.save()
@property @property

View File

@ -19,7 +19,7 @@ log = logging.getLogger(__name__)
class _ConfigManager(object): class _ConfigManager(object):
def __init__(self): def __init__(self):
log.debug("ConfigManager started..") log.debug('ConfigManager started..')
self.config_files = {} self.config_files = {}
self.__config_directory = None self.__config_directory = None
@ -44,16 +44,16 @@ class _ConfigManager(object):
if not directory: if not directory:
return False return False
log.info("Setting config directory to: %s", directory) log.info('Setting config directory to: %s', directory)
if not os.path.exists(directory): if not os.path.exists(directory):
# Try to create the config folder if it doesn't exist # Try to create the config folder if it doesn't exist
try: try:
os.makedirs(directory) os.makedirs(directory)
except OSError as ex: except OSError as ex:
log.error("Unable to make config directory: %s", ex) log.error('Unable to make config directory: %s', ex)
return False return False
elif not os.path.isdir(directory): elif not os.path.isdir(directory):
log.error("Config directory needs to be a directory!") log.error('Config directory needs to be a directory!')
return False return False
self.__config_directory = directory self.__config_directory = directory

View File

@ -30,9 +30,9 @@ log = logging.getLogger(__name__)
class AlertManager(component.Component): class AlertManager(component.Component):
"""AlertManager fetches and processes libtorrent alerts""" """AlertManager fetches and processes libtorrent alerts"""
def __init__(self): def __init__(self):
log.debug("AlertManager init...") log.debug('AlertManager init...')
component.Component.__init__(self, "AlertManager", interval=0.3) component.Component.__init__(self, 'AlertManager', interval=0.3)
self.session = component.get("Core").session self.session = component.get('Core').session
# Increase the alert queue size so that alerts don't get lost. # Increase the alert queue size so that alerts don't get lost.
self.alert_queue_size = 10000 self.alert_queue_size = 10000
@ -47,7 +47,7 @@ class AlertManager(component.Component):
lt.alert.category_t.performance_warning) lt.alert.category_t.performance_warning)
try: try:
self.session.apply_settings("alert_mask", alert_mask) self.session.apply_settings('alert_mask', alert_mask)
except AttributeError: except AttributeError:
self.session.set_alert_mask(alert_mask) self.session.set_alert_mask(alert_mask)
@ -81,7 +81,7 @@ class AlertManager(component.Component):
# Append the handler to the list in the handlers dictionary # Append the handler to the list in the handlers dictionary
self.handlers[alert_type].append(handler) self.handlers[alert_type].append(handler)
log.debug("Registered handler for alert %s", alert_type) log.debug('Registered handler for alert %s', alert_type)
def deregister_handler(self, handler): def deregister_handler(self, handler):
""" """
@ -105,16 +105,16 @@ class AlertManager(component.Component):
num_alerts = len(alerts) num_alerts = len(alerts)
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Alerts queued: %s", num_alerts) log.debug('Alerts queued: %s', num_alerts)
if num_alerts > 0.9 * self.alert_queue_size: if num_alerts > 0.9 * self.alert_queue_size:
log.warning("Warning total alerts queued, %s, passes 90%% of queue size.", num_alerts) log.warning('Warning total alerts queued, %s, passes 90%% of queue size.', num_alerts)
# Loop through all alerts in the queue # Loop through all alerts in the queue
for alert in alerts: for alert in alerts:
alert_type = type(alert).__name__ alert_type = type(alert).__name__
# Display the alert message # Display the alert message
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("%s: %s", alert_type, decode_string(alert.message())) log.debug('%s: %s', alert_type, decode_string(alert.message()))
# Call any handlers for this alert type # Call any handlers for this alert type
if alert_type in self.handlers: if alert_type in self.handlers:
for handler in self.handlers[alert_type]: for handler in self.handlers[alert_type]:
@ -122,6 +122,6 @@ class AlertManager(component.Component):
def set_alert_queue_size(self, queue_size): def set_alert_queue_size(self, queue_size):
"""Sets the maximum size of the libtorrent alert queue""" """Sets the maximum size of the libtorrent alert queue"""
log.info("Alert Queue Size set to %s", queue_size) log.info('Alert Queue Size set to %s', queue_size)
self.alert_queue_size = queue_size self.alert_queue_size = queue_size
component.get("Core").apply_session_setting("alert_queue_size", self.alert_queue_size) component.get('Core').apply_session_setting('alert_queue_size', self.alert_queue_size)

View File

@ -51,12 +51,12 @@ class Account(object):
def __repr__(self): def __repr__(self):
return ('<Account username="%(username)s" authlevel=%(authlevel)s>' % return ('<Account username="%(username)s" authlevel=%(authlevel)s>' %
{"username": self.username, "authlevel": self.authlevel}) {'username': self.username, 'authlevel': self.authlevel})
class AuthManager(component.Component): class AuthManager(component.Component):
def __init__(self): def __init__(self):
component.Component.__init__(self, "AuthManager", interval=10) component.Component.__init__(self, 'AuthManager', interval=10)
self.__auth = {} self.__auth = {}
self.__auth_modification_time = None self.__auth_modification_time = None
@ -70,16 +70,16 @@ class AuthManager(component.Component):
pass pass
def update(self): def update(self):
auth_file = configmanager.get_config_dir("auth") auth_file = configmanager.get_config_dir('auth')
# Check for auth file and create if necessary # Check for auth file and create if necessary
if not os.path.isfile(auth_file): if not os.path.isfile(auth_file):
log.info("Authfile not found, recreating it.") log.info('Authfile not found, recreating it.')
self.__load_auth_file() self.__load_auth_file()
return return
auth_file_modification_time = os.stat(auth_file).st_mtime auth_file_modification_time = os.stat(auth_file).st_mtime
if self.__auth_modification_time != auth_file_modification_time: if self.__auth_modification_time != auth_file_modification_time:
log.info("Auth file changed, reloading it!") log.info('Auth file changed, reloading it!')
self.__load_auth_file() self.__load_auth_file()
def authorize(self, username, password): def authorize(self, username, password):
@ -99,22 +99,22 @@ class AuthManager(component.Component):
""" """
if not username: if not username:
raise AuthenticationRequired( raise AuthenticationRequired(
"Username and Password are required.", username 'Username and Password are required.', username
) )
if username not in self.__auth: if username not in self.__auth:
# Let's try to re-load the file.. Maybe it's been updated # Let's try to re-load the file.. Maybe it's been updated
self.__load_auth_file() self.__load_auth_file()
if username not in self.__auth: if username not in self.__auth:
raise BadLoginError("Username does not exist", username) raise BadLoginError('Username does not exist', username)
if self.__auth[username].password == password: if self.__auth[username].password == password:
# Return the users auth level # Return the users auth level
return self.__auth[username].authlevel return self.__auth[username].authlevel
elif not password and self.__auth[username].password: elif not password and self.__auth[username].password:
raise AuthenticationRequired("Password is required", username) raise AuthenticationRequired('Password is required', username)
else: else:
raise BadLoginError("Password does not match", username) raise BadLoginError('Password does not match', username)
def has_account(self, username): def has_account(self, username):
return username in self.__auth return username in self.__auth
@ -126,7 +126,7 @@ class AuthManager(component.Component):
def create_account(self, username, password, authlevel): def create_account(self, username, password, authlevel):
if username in self.__auth: if username in self.__auth:
raise AuthManagerError("Username in use.", username) raise AuthManagerError('Username in use.', username)
if authlevel not in AUTH_LEVELS_MAPPING: if authlevel not in AUTH_LEVELS_MAPPING:
raise AuthManagerError("Invalid auth level: '%s'" % authlevel) raise AuthManagerError("Invalid auth level: '%s'" % authlevel)
try: try:
@ -140,7 +140,7 @@ class AuthManager(component.Component):
def update_account(self, username, password, authlevel): def update_account(self, username, password, authlevel):
if username not in self.__auth: if username not in self.__auth:
raise AuthManagerError("Username not known", username) raise AuthManagerError('Username not known', username)
if authlevel not in AUTH_LEVELS_MAPPING: if authlevel not in AUTH_LEVELS_MAPPING:
raise AuthManagerError("Invalid auth level: '%s'" % authlevel) raise AuthManagerError("Invalid auth level: '%s'" % authlevel)
try: try:
@ -155,10 +155,10 @@ class AuthManager(component.Component):
def remove_account(self, username): def remove_account(self, username):
if username not in self.__auth: if username not in self.__auth:
raise AuthManagerError("Username not known", username) raise AuthManagerError('Username not known', username)
elif username == component.get("RPCServer").get_session_user(): elif username == component.get('RPCServer').get_session_user():
raise AuthManagerError( raise AuthManagerError(
"You cannot delete your own account while logged in!", username 'You cannot delete your own account while logged in!', username
) )
del self.__auth[username] del self.__auth[username]
@ -166,39 +166,39 @@ class AuthManager(component.Component):
return True return True
def write_auth_file(self): def write_auth_file(self):
filename = "auth" filename = 'auth'
filepath = os.path.join(configmanager.get_config_dir(), filename) filepath = os.path.join(configmanager.get_config_dir(), filename)
filepath_bak = filepath + ".bak" filepath_bak = filepath + '.bak'
filepath_tmp = filepath + ".tmp" filepath_tmp = filepath + '.tmp'
try: try:
if os.path.isfile(filepath): if os.path.isfile(filepath):
log.debug("Creating backup of %s at: %s", filename, filepath_bak) log.debug('Creating backup of %s at: %s', filename, filepath_bak)
shutil.copy2(filepath, filepath_bak) shutil.copy2(filepath, filepath_bak)
except IOError as ex: except IOError as ex:
log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex) log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
else: else:
log.info("Saving the %s at: %s", filename, filepath) log.info('Saving the %s at: %s', filename, filepath)
try: try:
with open(filepath_tmp, "wb") as _file: with open(filepath_tmp, 'wb') as _file:
for account in self.__auth.values(): for account in self.__auth.values():
_file.write("%(username)s:%(password)s:%(authlevel_int)s\n" % account.data()) _file.write('%(username)s:%(password)s:%(authlevel_int)s\n' % account.data())
_file.flush() _file.flush()
os.fsync(_file.fileno()) os.fsync(_file.fileno())
shutil.move(filepath_tmp, filepath) shutil.move(filepath_tmp, filepath)
except IOError as ex: except IOError as ex:
log.error("Unable to save %s: %s", filename, ex) log.error('Unable to save %s: %s', filename, ex)
if os.path.isfile(filepath_bak): if os.path.isfile(filepath_bak):
log.info("Restoring backup of %s from: %s", filename, filepath_bak) log.info('Restoring backup of %s from: %s', filename, filepath_bak)
shutil.move(filepath_bak, filepath) shutil.move(filepath_bak, filepath)
self.__load_auth_file() self.__load_auth_file()
def __load_auth_file(self): def __load_auth_file(self):
save_and_reload = False save_and_reload = False
filename = "auth" filename = 'auth'
auth_file = configmanager.get_config_dir(filename) auth_file = configmanager.get_config_dir(filename)
auth_file_bak = auth_file + ".bak" auth_file_bak = auth_file + '.bak'
# Check for auth file and create if necessary # Check for auth file and create if necessary
if not os.path.isfile(auth_file): if not os.path.isfile(auth_file):
@ -213,28 +213,28 @@ class AuthManager(component.Component):
return return
for _filepath in (auth_file, auth_file_bak): for _filepath in (auth_file, auth_file_bak):
log.info("Opening %s for load: %s", filename, _filepath) log.info('Opening %s for load: %s', filename, _filepath)
try: try:
with open(_filepath, "rb") as _file: with open(_filepath, 'rb') as _file:
file_data = _file.readlines() file_data = _file.readlines()
except IOError as ex: except IOError as ex:
log.warning("Unable to load %s: %s", _filepath, ex) log.warning('Unable to load %s: %s', _filepath, ex)
file_data = [] file_data = []
else: else:
log.info("Successfully loaded %s: %s", filename, _filepath) log.info('Successfully loaded %s: %s', filename, _filepath)
break break
# Load the auth file into a dictionary: {username: Account(...)} # Load the auth file into a dictionary: {username: Account(...)}
for line in file_data: for line in file_data:
line = line.strip() line = line.strip()
if line.startswith("#") or not line: if line.startswith('#') or not line:
# This line is a comment or empty # This line is a comment or empty
continue continue
lsplit = line.split(":") lsplit = line.split(':')
if len(lsplit) == 2: if len(lsplit) == 2:
username, password = lsplit username, password = lsplit
log.warning("Your auth entry for %s contains no auth level, " log.warning('Your auth entry for %s contains no auth level, '
"using AUTH_LEVEL_DEFAULT(%s)..", username, AUTH_LEVEL_DEFAULT) 'using AUTH_LEVEL_DEFAULT(%s)..', username, AUTH_LEVEL_DEFAULT)
if username == 'localclient': if username == 'localclient':
authlevel = AUTH_LEVEL_ADMIN authlevel = AUTH_LEVEL_ADMIN
else: else:
@ -244,7 +244,7 @@ class AuthManager(component.Component):
elif len(lsplit) == 3: elif len(lsplit) == 3:
username, password, authlevel = lsplit username, password, authlevel = lsplit
else: else:
log.error("Your auth file is malformed: Incorrect number of fields!") log.error('Your auth file is malformed: Incorrect number of fields!')
continue continue
username = username.strip() username = username.strip()
@ -255,16 +255,16 @@ class AuthManager(component.Component):
try: try:
authlevel = AUTH_LEVELS_MAPPING[authlevel] authlevel = AUTH_LEVELS_MAPPING[authlevel]
except KeyError: except KeyError:
log.error("Your auth file is malformed: %r is not a valid auth level", authlevel) log.error('Your auth file is malformed: %r is not a valid auth level', authlevel)
continue continue
self.__auth[username] = Account(username, password, authlevel) self.__auth[username] = Account(username, password, authlevel)
if "localclient" not in self.__auth: if 'localclient' not in self.__auth:
create_localclient_account(True) create_localclient_account(True)
return self.__load_auth_file() return self.__load_auth_file()
if save_and_reload: if save_and_reload:
log.info("Re-writing auth file (upgrade)") log.info('Re-writing auth file (upgrade)')
self.write_auth_file() self.write_auth_file()
self.__auth_modification_time = auth_file_modification_time self.__auth_modification_time = auth_file_modification_time

View File

@ -44,22 +44,22 @@ log = logging.getLogger(__name__)
class Core(component.Component): class Core(component.Component):
def __init__(self, listen_interface=None, read_only_config_keys=None): def __init__(self, listen_interface=None, read_only_config_keys=None):
log.debug("Core init...") log.debug('Core init...')
component.Component.__init__(self, "Core") component.Component.__init__(self, 'Core')
# These keys will be dropped from the set_config() RPC and are # These keys will be dropped from the set_config() RPC and are
# configurable from the command-line. # configurable from the command-line.
self.read_only_config_keys = read_only_config_keys self.read_only_config_keys = read_only_config_keys
log.debug("read_only_config_keys: %s", read_only_config_keys) log.debug('read_only_config_keys: %s', read_only_config_keys)
# Create the client fingerprint # Create the client fingerprint
client_id = "DE" client_id = 'DE'
client_version = deluge.common.VersionSplit(deluge.common.get_version()).version client_version = deluge.common.VersionSplit(deluge.common.get_version()).version
while len(client_version) < 4: while len(client_version) < 4:
client_version.append(0) client_version.append(0)
# Start the libtorrent session # Start the libtorrent session
log.info("Starting libtorrent %s (%s, %s) session...", lt.__version__, client_id, client_version) log.info('Starting libtorrent %s (%s, %s) session...', lt.__version__, client_id, client_version)
self.session = lt.session(lt.fingerprint(client_id, *client_version), flags=0) self.session = lt.session(lt.fingerprint(client_id, *client_version), flags=0)
# Load the session state if available # Load the session state if available
@ -67,20 +67,20 @@ class Core(component.Component):
# Apply session settings # Apply session settings
self.apply_session_setting( self.apply_session_setting(
"user_agent", 'user_agent',
"Deluge/%(deluge_version)s libtorrent/%(lt_version)s" % { 'Deluge/%(deluge_version)s libtorrent/%(lt_version)s' % {
'deluge_version': deluge.common.get_version(), 'deluge_version': deluge.common.get_version(),
'lt_version': self.get_libtorrent_version().rpartition(".")[0]} 'lt_version': self.get_libtorrent_version().rpartition('.')[0]}
) )
# No SSL torrent support in code so disable the listen port. # No SSL torrent support in code so disable the listen port.
self.apply_session_setting("ssl_listen", 0) self.apply_session_setting('ssl_listen', 0)
# Enable libtorrent extensions # Enable libtorrent extensions
# Allows peers to download the metadata from the swarm directly # Allows peers to download the metadata from the swarm directly
self.session.add_extension("ut_metadata") self.session.add_extension('ut_metadata')
# Ban peers that sends bad data # Ban peers that sends bad data
self.session.add_extension("smart_ban") self.session.add_extension('smart_ban')
# Create the components # Create the components
self.eventmanager = EventManager() self.eventmanager = EventManager()
@ -96,13 +96,13 @@ class Core(component.Component):
# External IP Address from libtorrent # External IP Address from libtorrent
self.external_ip = None self.external_ip = None
self.eventmanager.register_event_handler("ExternalIPEvent", self._on_external_ip_event) self.eventmanager.register_event_handler('ExternalIPEvent', self._on_external_ip_event)
# GeoIP instance with db loaded # GeoIP instance with db loaded
self.geoip_instance = None self.geoip_instance = None
# Get the core config # Get the core config
self.config = ConfigManager("core.conf") self.config = ConfigManager('core.conf')
self.config.save() self.config.save()
# If there was an interface value from the command line, use it, but # If there was an interface value from the command line, use it, but
@ -110,10 +110,10 @@ class Core(component.Component):
self.__old_interface = None self.__old_interface = None
if listen_interface: if listen_interface:
if deluge.common.is_ip(listen_interface): if deluge.common.is_ip(listen_interface):
self.__old_interface = self.config["listen_interface"] self.__old_interface = self.config['listen_interface']
self.config["listen_interface"] = listen_interface self.config['listen_interface'] = listen_interface
else: else:
log.error("Invalid listen interface (must be IP Address): %s", listen_interface) log.error('Invalid listen interface (must be IP Address): %s', listen_interface)
# New release check information # New release check information
self.__new_release = None self.__new_release = None
@ -123,14 +123,14 @@ class Core(component.Component):
pass pass
def stop(self): def stop(self):
log.debug("Core stopping...") log.debug('Core stopping...')
# Save the libtorrent session state # Save the libtorrent session state
self.__save_session_state() self.__save_session_state()
# We stored a copy of the old interface value # We stored a copy of the old interface value
if self.__old_interface: if self.__old_interface:
self.config["listen_interface"] = self.__old_interface self.config['listen_interface'] = self.__old_interface
# Make sure the config file has been saved # Make sure the config file has been saved
self.config.save() self.config.save()
@ -156,64 +156,64 @@ class Core(component.Component):
def __save_session_state(self): def __save_session_state(self):
"""Saves the libtorrent session state""" """Saves the libtorrent session state"""
filename = "session.state" filename = 'session.state'
filepath = get_config_dir(filename) filepath = get_config_dir(filename)
filepath_bak = filepath + ".bak" filepath_bak = filepath + '.bak'
filepath_tmp = filepath + ".tmp" filepath_tmp = filepath + '.tmp'
try: try:
if os.path.isfile(filepath): if os.path.isfile(filepath):
log.debug("Creating backup of %s at: %s", filename, filepath_bak) log.debug('Creating backup of %s at: %s', filename, filepath_bak)
shutil.copy2(filepath, filepath_bak) shutil.copy2(filepath, filepath_bak)
except IOError as ex: except IOError as ex:
log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex) log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
else: else:
log.info("Saving the %s at: %s", filename, filepath) log.info('Saving the %s at: %s', filename, filepath)
try: try:
with open(filepath_tmp, "wb") as _file: with open(filepath_tmp, 'wb') as _file:
_file.write(lt.bencode(self.session.save_state())) _file.write(lt.bencode(self.session.save_state()))
_file.flush() _file.flush()
os.fsync(_file.fileno()) os.fsync(_file.fileno())
shutil.move(filepath_tmp, filepath) shutil.move(filepath_tmp, filepath)
except (IOError, EOFError) as ex: except (IOError, EOFError) as ex:
log.error("Unable to save %s: %s", filename, ex) log.error('Unable to save %s: %s', filename, ex)
if os.path.isfile(filepath_bak): if os.path.isfile(filepath_bak):
log.info("Restoring backup of %s from: %s", filename, filepath_bak) log.info('Restoring backup of %s from: %s', filename, filepath_bak)
shutil.move(filepath_bak, filepath) shutil.move(filepath_bak, filepath)
def __load_session_state(self): def __load_session_state(self):
"""Loads the libtorrent session state""" """Loads the libtorrent session state"""
filename = "session.state" filename = 'session.state'
filepath = get_config_dir(filename) filepath = get_config_dir(filename)
filepath_bak = filepath + ".bak" filepath_bak = filepath + '.bak'
for _filepath in (filepath, filepath_bak): for _filepath in (filepath, filepath_bak):
log.info("Opening %s for load: %s", filename, _filepath) log.info('Opening %s for load: %s', filename, _filepath)
try: try:
with open(_filepath, "rb") as _file: with open(_filepath, 'rb') as _file:
state = lt.bdecode(_file.read()) state = lt.bdecode(_file.read())
except (IOError, EOFError, RuntimeError) as ex: except (IOError, EOFError, RuntimeError) as ex:
log.warning("Unable to load %s: %s", _filepath, ex) log.warning('Unable to load %s: %s', _filepath, ex)
else: else:
log.info("Successfully loaded %s: %s", filename, _filepath) log.info('Successfully loaded %s: %s', filename, _filepath)
self.session.load_state(state) self.session.load_state(state)
return return
def get_new_release(self): def get_new_release(self):
log.debug("get_new_release") log.debug('get_new_release')
from urllib2 import urlopen, URLError from urllib2 import urlopen, URLError
try: try:
self.new_release = urlopen("http://download.deluge-torrent.org/version-1.0").read().strip() self.new_release = urlopen('http://download.deluge-torrent.org/version-1.0').read().strip()
except URLError as ex: except URLError as ex:
log.debug("Unable to get release info from website: %s", ex) log.debug('Unable to get release info from website: %s', ex)
return return
self.check_new_release() self.check_new_release()
def check_new_release(self): def check_new_release(self):
if self.new_release: if self.new_release:
log.debug("new_release: %s", self.new_release) log.debug('new_release: %s', self.new_release)
if deluge.common.VersionSplit(self.new_release) > deluge.common.VersionSplit(deluge.common.get_version()): if deluge.common.VersionSplit(self.new_release) > deluge.common.VersionSplit(deluge.common.get_version()):
component.get("EventManager").emit(NewVersionAvailableEvent(self.new_release)) component.get('EventManager').emit(NewVersionAvailableEvent(self.new_release))
return self.new_release return self.new_release
return False return False
@ -233,14 +233,14 @@ class Core(component.Component):
try: try:
filedump = base64.decodestring(filedump) filedump = base64.decodestring(filedump)
except Exception as ex: except Exception as ex:
log.error("There was an error decoding the filedump string: %s", ex) log.error('There was an error decoding the filedump string: %s', ex)
try: try:
d = self.torrentmanager.add( d = self.torrentmanager.add(
filedump=filedump, options=options, filename=filename, save_state=save_state filedump=filedump, options=options, filename=filename, save_state=save_state
) )
except RuntimeError as ex: except RuntimeError as ex:
log.error("There was an error adding the torrent file %s: %s", filename, ex) log.error('There was an error adding the torrent file %s: %s', filename, ex)
raise raise
else: else:
return d return d
@ -301,11 +301,11 @@ class Core(component.Component):
:returns: a Deferred which returns the torrent_id as a str or None :returns: a Deferred which returns the torrent_id as a str or None
""" """
log.info("Attempting to add url %s", url) log.info('Attempting to add url %s', url)
def on_download_success(filename): def on_download_success(filename):
# We got the file, so add it to the session # We got the file, so add it to the session
with open(filename, "rb") as _file: with open(filename, 'rb') as _file:
data = _file.read() data = _file.read()
try: try:
os.remove(filename) os.remove(filename)
@ -315,7 +315,7 @@ class Core(component.Component):
def on_download_fail(failure): def on_download_fail(failure):
# Log the error and pass the failure onto the client # Log the error and pass the failure onto the client
log.error("Failed to add torrent from url %s", url) log.error('Failed to add torrent from url %s', url)
return failure return failure
tmp_fd, tmp_file = tempfile.mkstemp(prefix='deluge_url.', suffix='.torrent') tmp_fd, tmp_file = tempfile.mkstemp(prefix='deluge_url.', suffix='.torrent')
@ -338,7 +338,7 @@ class Core(component.Component):
:rtype: string :rtype: string
""" """
log.debug("Attempting to add by magnet uri: %s", uri) log.debug('Attempting to add by magnet uri: %s', uri)
return self.torrentmanager.add(magnet=uri, options=options) return self.torrentmanager.add(magnet=uri, options=options)
@ -357,7 +357,7 @@ class Core(component.Component):
InvalidTorrentError: If the torrent ID does not exist in the session. InvalidTorrentError: If the torrent ID does not exist in the session.
""" """
log.debug("Removing torrent %s from the core.", torrent_id) log.debug('Removing torrent %s from the core.', torrent_id)
return self.torrentmanager.remove(torrent_id, remove_data) return self.torrentmanager.remove(torrent_id, remove_data)
@export @export
@ -375,7 +375,7 @@ class Core(component.Component):
[("<torrent_id>", "Error removing torrent")] [("<torrent_id>", "Error removing torrent")]
""" """
log.info("Removing %d torrents from core.", len(torrent_ids)) log.info('Removing %d torrents from core.', len(torrent_ids))
def do_remove_torrents(): def do_remove_torrents():
errors = [] errors = []
@ -387,7 +387,7 @@ class Core(component.Component):
# Save the session state # Save the session state
self.torrentmanager.save_state() self.torrentmanager.save_state()
if errors: if errors:
log.warn("Failed to remove %d of %d torrents.", len(errors), len(torrent_ids)) log.warn('Failed to remove %d of %d torrents.', len(errors), len(torrent_ids))
return errors return errors
return task.deferLater(reactor, 0, do_remove_torrents) return task.deferLater(reactor, 0, do_remove_torrents)
@ -426,55 +426,55 @@ class Core(component.Component):
status = self.session.get_cache_status() status = self.session.get_cache_status()
cache = {} cache = {}
for attr in dir(status): for attr in dir(status):
if attr.startswith("_"): if attr.startswith('_'):
continue continue
cache[attr] = getattr(status, attr) cache[attr] = getattr(status, attr)
# Add in a couple ratios # Add in a couple ratios
try: try:
cache["write_hit_ratio"] = (cache["blocks_written"] - cache["writes"]) / cache["blocks_written"] cache['write_hit_ratio'] = (cache['blocks_written'] - cache['writes']) / cache['blocks_written']
except ZeroDivisionError: except ZeroDivisionError:
cache["write_hit_ratio"] = 0.0 cache['write_hit_ratio'] = 0.0
try: try:
cache["read_hit_ratio"] = cache["blocks_read_hit"] / cache["blocks_read"] cache['read_hit_ratio'] = cache['blocks_read_hit'] / cache['blocks_read']
except ZeroDivisionError: except ZeroDivisionError:
cache["read_hit_ratio"] = 0.0 cache['read_hit_ratio'] = 0.0
return cache return cache
@export @export
def force_reannounce(self, torrent_ids): def force_reannounce(self, torrent_ids):
log.debug("Forcing reannouncment to: %s", torrent_ids) log.debug('Forcing reannouncment to: %s', torrent_ids)
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
self.torrentmanager[torrent_id].force_reannounce() self.torrentmanager[torrent_id].force_reannounce()
@export @export
def pause_torrent(self, torrent_ids): def pause_torrent(self, torrent_ids):
log.debug("Pausing: %s", torrent_ids) log.debug('Pausing: %s', torrent_ids)
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
if not self.torrentmanager[torrent_id].pause(): if not self.torrentmanager[torrent_id].pause():
log.warning("Error pausing torrent %s", torrent_id) log.warning('Error pausing torrent %s', torrent_id)
@export @export
def connect_peer(self, torrent_id, ip, port): def connect_peer(self, torrent_id, ip, port):
log.debug("adding peer %s to %s", ip, torrent_id) log.debug('adding peer %s to %s', ip, torrent_id)
if not self.torrentmanager[torrent_id].connect_peer(ip, port): if not self.torrentmanager[torrent_id].connect_peer(ip, port):
log.warning("Error adding peer %s:%s to %s", ip, port, torrent_id) log.warning('Error adding peer %s:%s to %s', ip, port, torrent_id)
@export @export
def move_storage(self, torrent_ids, dest): def move_storage(self, torrent_ids, dest):
log.debug("Moving storage %s to %s", torrent_ids, dest) log.debug('Moving storage %s to %s', torrent_ids, dest)
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
if not self.torrentmanager[torrent_id].move_storage(dest): if not self.torrentmanager[torrent_id].move_storage(dest):
log.warning("Error moving torrent %s to %s", torrent_id, dest) log.warning('Error moving torrent %s to %s', torrent_id, dest)
@export @export
def pause_session(self): def pause_session(self):
"""Pause all torrents in the session""" """Pause all torrents in the session"""
if not self.session.is_paused(): if not self.session.is_paused():
self.session.pause() self.session.pause()
component.get("EventManager").emit(SessionPausedEvent()) component.get('EventManager').emit(SessionPausedEvent())
@export @export
def resume_session(self): def resume_session(self):
@ -483,11 +483,11 @@ class Core(component.Component):
self.session.resume() self.session.resume()
for torrent_id in self.torrentmanager.torrents: for torrent_id in self.torrentmanager.torrents:
self.torrentmanager[torrent_id].update_state() self.torrentmanager[torrent_id].update_state()
component.get("EventManager").emit(SessionResumedEvent()) component.get('EventManager').emit(SessionResumedEvent())
@export @export
def resume_torrent(self, torrent_ids): def resume_torrent(self, torrent_ids):
log.debug("Resuming: %s", torrent_ids) log.debug('Resuming: %s', torrent_ids)
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
self.torrentmanager[torrent_id].resume() self.torrentmanager[torrent_id].resume()
@ -566,7 +566,7 @@ class Core(component.Component):
if self.read_only_config_keys and key in self.read_only_config_keys: if self.read_only_config_keys and key in self.read_only_config_keys:
continue continue
if isinstance(config[key], basestring): if isinstance(config[key], basestring):
config[key] = config[key].encode("utf8") config[key] = config[key].encode('utf8')
self.config[key] = config[key] self.config[key] = config[key]
@export @export
@ -578,7 +578,7 @@ class Core(component.Component):
def get_i2p_proxy(self): def get_i2p_proxy(self):
"""Returns the active listen port""" """Returns the active listen port"""
i2p_settings = self.session.i2p_proxy() # Deprecated, moved to proxy types i2p_settings = self.session.i2p_proxy() # Deprecated, moved to proxy types
i2p_dict = {"hostname": i2p_settings.hostname, "port": i2p_settings.port} i2p_dict = {'hostname': i2p_settings.hostname, 'port': i2p_settings.port}
return i2p_dict return i2p_dict
@export @export
@ -586,13 +586,13 @@ class Core(component.Component):
"""Returns the active listen port""" """Returns the active listen port"""
proxy_settings = self.session.proxy() proxy_settings = self.session.proxy()
proxy_dict = { proxy_dict = {
"type": int(proxy_settings.type), 'type': int(proxy_settings.type),
"hostname": proxy_settings.hostname, 'hostname': proxy_settings.hostname,
"username": proxy_settings.username, 'username': proxy_settings.username,
"password": proxy_settings.password, 'password': proxy_settings.password,
"port": proxy_settings.port, 'port': proxy_settings.port,
"proxy_hostnames": proxy_settings.proxy_hostnames, 'proxy_hostnames': proxy_settings.proxy_hostnames,
"proxy_peer_connections": proxy_settings.proxy_peer_connections 'proxy_peer_connections': proxy_settings.proxy_peer_connections
} }
return proxy_dict return proxy_dict
@ -733,7 +733,7 @@ class Core(component.Component):
def create_torrent(self, path, tracker, piece_length, comment, target, def create_torrent(self, path, tracker, piece_length, comment, target,
webseeds, private, created_by, trackers, add_to_session): webseeds, private, created_by, trackers, add_to_session):
log.debug("creating torrent..") log.debug('creating torrent..')
threading.Thread(target=self._create_torrent_thread, threading.Thread(target=self._create_torrent_thread,
args=( args=(
path, path,
@ -760,11 +760,11 @@ class Core(component.Component):
private=private, private=private,
created_by=created_by, created_by=created_by,
trackers=trackers) trackers=trackers)
log.debug("torrent created!") log.debug('torrent created!')
if add_to_session: if add_to_session:
options = {} options = {}
options["download_location"] = os.path.split(path)[0] options['download_location'] = os.path.split(path)[0]
with open(target, "rb") as _file: with open(target, 'rb') as _file:
self.add_torrent_file(os.path.split(target)[1], _file.read(), options) self.add_torrent_file(os.path.split(target)[1], _file.read(), options)
@export @export
@ -777,20 +777,20 @@ class Core(component.Component):
try: try:
filedump = base64.decodestring(filedump) filedump = base64.decodestring(filedump)
except Exception as ex: except Exception as ex:
log.error("There was an error decoding the filedump string!") log.error('There was an error decoding the filedump string!')
log.exception(ex) log.exception(ex)
return return
with open(os.path.join(get_config_dir(), "plugins", filename), "wb") as _file: with open(os.path.join(get_config_dir(), 'plugins', filename), 'wb') as _file:
_file.write(filedump) _file.write(filedump)
component.get("CorePluginManager").scan_for_plugins() component.get('CorePluginManager').scan_for_plugins()
@export @export
def rescan_plugins(self): def rescan_plugins(self):
""" """
Rescans the plugin folders for new plugins Rescans the plugin folders for new plugins
""" """
component.get("CorePluginManager").scan_for_plugins() component.get('CorePluginManager').scan_for_plugins()
@export @export
def rename_files(self, torrent_id, filenames): def rename_files(self, torrent_id, filenames):
@ -808,7 +808,7 @@ class Core(component.Component):
""" """
if torrent_id not in self.torrentmanager.torrents: if torrent_id not in self.torrentmanager.torrents:
raise InvalidTorrentError("torrent_id is not in session") raise InvalidTorrentError('torrent_id is not in session')
def rename(): def rename():
self.torrentmanager[torrent_id].rename_files(filenames) self.torrentmanager[torrent_id].rename_files(filenames)
@ -833,25 +833,25 @@ class Core(component.Component):
""" """
if torrent_id not in self.torrentmanager.torrents: if torrent_id not in self.torrentmanager.torrents:
raise InvalidTorrentError("torrent_id is not in session") raise InvalidTorrentError('torrent_id is not in session')
return self.torrentmanager[torrent_id].rename_folder(folder, new_folder) return self.torrentmanager[torrent_id].rename_folder(folder, new_folder)
@export @export
def queue_top(self, torrent_ids): def queue_top(self, torrent_ids):
log.debug("Attempting to queue %s to top", torrent_ids) log.debug('Attempting to queue %s to top', torrent_ids)
# torrent_ids must be sorted in reverse before moving to preserve order # torrent_ids must be sorted in reverse before moving to preserve order
for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position, reverse=True): for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position, reverse=True):
try: try:
# If the queue method returns True, then we should emit a signal # If the queue method returns True, then we should emit a signal
if self.torrentmanager.queue_top(torrent_id): if self.torrentmanager.queue_top(torrent_id):
component.get("EventManager").emit(TorrentQueueChangedEvent()) component.get('EventManager').emit(TorrentQueueChangedEvent())
except KeyError: except KeyError:
log.warning("torrent_id: %s does not exist in the queue", torrent_id) log.warning('torrent_id: %s does not exist in the queue', torrent_id)
@export @export
def queue_up(self, torrent_ids): def queue_up(self, torrent_ids):
log.debug("Attempting to queue %s to up", torrent_ids) log.debug('Attempting to queue %s to up', torrent_ids)
torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids) torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids)
torrent_moved = True torrent_moved = True
prev_queue_position = None prev_queue_position = None
@ -862,16 +862,16 @@ class Core(component.Component):
try: try:
torrent_moved = self.torrentmanager.queue_up(torrent_id) torrent_moved = self.torrentmanager.queue_up(torrent_id)
except KeyError: except KeyError:
log.warning("torrent_id: %s does not exist in the queue", torrent_id) log.warning('torrent_id: %s does not exist in the queue', torrent_id)
# If the torrent moved, then we should emit a signal # If the torrent moved, then we should emit a signal
if torrent_moved: if torrent_moved:
component.get("EventManager").emit(TorrentQueueChangedEvent()) component.get('EventManager').emit(TorrentQueueChangedEvent())
else: else:
prev_queue_position = queue_position prev_queue_position = queue_position
@export @export
def queue_down(self, torrent_ids): def queue_down(self, torrent_ids):
log.debug("Attempting to queue %s to down", torrent_ids) log.debug('Attempting to queue %s to down', torrent_ids)
torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids) torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids)
torrent_moved = True torrent_moved = True
prev_queue_position = None prev_queue_position = None
@ -882,24 +882,24 @@ class Core(component.Component):
try: try:
torrent_moved = self.torrentmanager.queue_down(torrent_id) torrent_moved = self.torrentmanager.queue_down(torrent_id)
except KeyError: except KeyError:
log.warning("torrent_id: %s does not exist in the queue", torrent_id) log.warning('torrent_id: %s does not exist in the queue', torrent_id)
# If the torrent moved, then we should emit a signal # If the torrent moved, then we should emit a signal
if torrent_moved: if torrent_moved:
component.get("EventManager").emit(TorrentQueueChangedEvent()) component.get('EventManager').emit(TorrentQueueChangedEvent())
else: else:
prev_queue_position = queue_position prev_queue_position = queue_position
@export @export
def queue_bottom(self, torrent_ids): def queue_bottom(self, torrent_ids):
log.debug("Attempting to queue %s to bottom", torrent_ids) log.debug('Attempting to queue %s to bottom', torrent_ids)
# torrent_ids must be sorted before moving to preserve order # torrent_ids must be sorted before moving to preserve order
for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position): for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position):
try: try:
# If the queue method returns True, then we should emit a signal # If the queue method returns True, then we should emit a signal
if self.torrentmanager.queue_bottom(torrent_id): if self.torrentmanager.queue_bottom(torrent_id):
component.get("EventManager").emit(TorrentQueueChangedEvent()) component.get('EventManager').emit(TorrentQueueChangedEvent())
except KeyError: except KeyError:
log.warning("torrent_id: %s does not exist in the queue", torrent_id) log.warning('torrent_id: %s does not exist in the queue', torrent_id)
@export @export
def glob(self, path): def glob(self, path):
@ -914,14 +914,14 @@ class Core(component.Component):
:rtype: bool :rtype: bool
""" """
d = getPage("http://deluge-torrent.org/test_port.php?port=%s" % d = getPage('http://deluge-torrent.org/test_port.php?port=%s' %
self.get_listen_port(), timeout=30) self.get_listen_port(), timeout=30)
def on_get_page(result): def on_get_page(result):
return bool(int(result)) return bool(int(result))
def on_error(failure): def on_error(failure):
log.warning("Error testing listen port: %s", failure) log.warning('Error testing listen port: %s', failure)
d.addCallback(on_get_page) d.addCallback(on_get_page)
d.addErrback(on_error) d.addErrback(on_error)
@ -943,7 +943,7 @@ class Core(component.Component):
""" """
if not path: if not path:
path = self.config["download_location"] path = self.config['download_location']
try: try:
return deluge.common.free_space(path) return deluge.common.free_space(path)
except InvalidPathError: except InvalidPathError:

View File

@ -43,7 +43,7 @@ def is_daemon_running(pid_file):
try: try:
with open(pid_file) as _file: with open(pid_file) as _file:
pid, port = [int(x) for x in _file.readline().strip().split(";")] pid, port = [int(x) for x in _file.readline().strip().split(';')]
except EnvironmentError: except EnvironmentError:
return False return False
@ -51,7 +51,7 @@ def is_daemon_running(pid_file):
# Ensure it's a deluged process by trying to open a socket to it's port. # Ensure it's a deluged process by trying to open a socket to it's port.
_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try: try:
_socket.connect(("127.0.0.1", port)) _socket.connect(('127.0.0.1', port))
except socket.error: except socket.error:
# Can't connect, so pid is not a deluged process. # Can't connect, so pid is not a deluged process.
return False return False
@ -77,19 +77,19 @@ class Daemon(object):
altered by core.set_config() RPC method. altered by core.set_config() RPC method.
""" """
self.standalone = standalone self.standalone = standalone
self.pid_file = get_config_dir("deluged.pid") self.pid_file = get_config_dir('deluged.pid')
log.info("Deluge daemon %s", get_version()) log.info('Deluge daemon %s', get_version())
if is_daemon_running(self.pid_file): if is_daemon_running(self.pid_file):
raise DaemonRunningError("Deluge daemon already running with this config directory!") raise DaemonRunningError('Deluge daemon already running with this config directory!')
# Twisted catches signals to terminate, so just have it call the shutdown method. # Twisted catches signals to terminate, so just have it call the shutdown method.
reactor.addSystemEventTrigger("before", "shutdown", self._shutdown) reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)
# Catch some Windows specific signals # Catch some Windows specific signals
if windows_check(): if windows_check():
def win_handler(ctrl_type): def win_handler(ctrl_type):
"""Handle the Windows shutdown or close events.""" """Handle the Windows shutdown or close events."""
log.debug("windows handler ctrl_type: %s", ctrl_type) log.debug('windows handler ctrl_type: %s', ctrl_type)
if ctrl_type == CTRL_CLOSE_EVENT or ctrl_type == CTRL_SHUTDOWN_EVENT: if ctrl_type == CTRL_CLOSE_EVENT or ctrl_type == CTRL_SHUTDOWN_EVENT:
self._shutdown() self._shutdown()
return 1 return 1
@ -100,21 +100,21 @@ class Daemon(object):
read_only_config_keys=read_only_config_keys) read_only_config_keys=read_only_config_keys)
if port is None: if port is None:
port = self.core.config["daemon_port"] port = self.core.config['daemon_port']
self.port = port self.port = port
if interface and not is_ip(interface): if interface and not is_ip(interface):
log.error("Invalid UI interface (must be IP Address): %s", interface) log.error('Invalid UI interface (must be IP Address): %s', interface)
interface = None interface = None
self.rpcserver = RPCServer( self.rpcserver = RPCServer(
port=port, port=port,
allow_remote=self.core.config["allow_remote"], allow_remote=self.core.config['allow_remote'],
listen=not standalone, listen=not standalone,
interface=interface interface=interface
) )
log.debug("Listening to UI on: %s:%s and bittorrent on: %s", interface, port, listen_interface) log.debug('Listening to UI on: %s:%s and bittorrent on: %s', interface, port, listen_interface)
def start(self): def start(self):
# Register the daemon and the core RPCs # Register the daemon and the core RPCs
@ -122,32 +122,32 @@ class Daemon(object):
self.rpcserver.register_object(self) self.rpcserver.register_object(self)
# Make sure we start the PreferencesManager first # Make sure we start the PreferencesManager first
component.start("PreferencesManager") component.start('PreferencesManager')
if not self.standalone: if not self.standalone:
log.info("Deluge daemon starting...") log.info('Deluge daemon starting...')
# Create pid file to track if deluged is running, also includes the port number. # Create pid file to track if deluged is running, also includes the port number.
pid = os.getpid() pid = os.getpid()
log.debug("Storing pid %s & port %s in: %s", pid, self.port, self.pid_file) log.debug('Storing pid %s & port %s in: %s', pid, self.port, self.pid_file)
with open(self.pid_file, "wb") as _file: with open(self.pid_file, 'wb') as _file:
_file.write("%s;%s\n" % (pid, self.port)) _file.write('%s;%s\n' % (pid, self.port))
component.start() component.start()
try: try:
reactor.run() reactor.run()
finally: finally:
log.debug("Remove pid file: %s", self.pid_file) log.debug('Remove pid file: %s', self.pid_file)
os.remove(self.pid_file) os.remove(self.pid_file)
log.info("Deluge daemon shutdown successfully") log.info('Deluge daemon shutdown successfully')
@export() @export()
def shutdown(self, *args, **kwargs): def shutdown(self, *args, **kwargs):
log.debug("Deluge daemon shutdown requested...") log.debug('Deluge daemon shutdown requested...')
reactor.callLater(0, reactor.stop) reactor.callLater(0, reactor.stop)
def _shutdown(self, *args, **kwargs): def _shutdown(self, *args, **kwargs):
log.info("Deluge daemon shutting down, waiting for components to shutdown...") log.info('Deluge daemon shutting down, waiting for components to shutdown...')
if not self.standalone: if not self.standalone:
return component.shutdown() return component.shutdown()

View File

@ -20,15 +20,15 @@ from deluge.ui.util import lang
def add_daemon_options(parser): def add_daemon_options(parser):
group = parser.add_argument_group(_("Daemon Options")) group = parser.add_argument_group(_('Daemon Options'))
group.add_argument("-u", "--ui-interface", metavar="<ip-addr>", action="store", group.add_argument('-u', '--ui-interface', metavar='<ip-addr>', action='store',
help=_("IP address to listen for UI connections")) help=_('IP address to listen for UI connections'))
group.add_argument("-p", "--port", metavar="<port>", action="store", type=int, group.add_argument('-p', '--port', metavar='<port>', action='store', type=int,
help=_("Port to listen for UI connections on")) help=_('Port to listen for UI connections on'))
group.add_argument("-i", "--interface", metavar="<ip-addr>", dest="listen_interface", action="store", group.add_argument('-i', '--interface', metavar='<ip-addr>', dest='listen_interface', action='store',
help=_("IP address to listen for BitTorrent connections")) help=_('IP address to listen for BitTorrent connections'))
group.add_argument("--read-only-config-keys", metavar="<comma-separated-keys>", action="store", group.add_argument('--read-only-config-keys', metavar='<comma-separated-keys>', action='store',
help=_("Config keys to be unmodified by `set_config` RPC"), type=str, default="") help=_('Config keys to be unmodified by `set_config` RPC'), type=str, default='')
parser.add_process_arg_group() parser.add_process_arg_group()
@ -53,17 +53,17 @@ def start_daemon(skip_start=False):
# Check for any daemons running with this same config # Check for any daemons running with this same config
from deluge.core.daemon import is_daemon_running from deluge.core.daemon import is_daemon_running
pid_file = get_config_dir("deluged.pid") pid_file = get_config_dir('deluged.pid')
if is_daemon_running(pid_file): if is_daemon_running(pid_file):
print("Cannot run multiple daemons using the same config directory.\n" print('Cannot run multiple daemons using the same config directory.\n'
"If you believe this is an error, you can force a start by deleting: %s" % pid_file) 'If you believe this is an error, you can force a start by deleting: %s' % pid_file)
sys.exit(1) sys.exit(1)
log = getLogger(__name__) log = getLogger(__name__)
# If no logfile specified add logging to default location (as well as stdout) # If no logfile specified add logging to default location (as well as stdout)
if not options.logfile: if not options.logfile:
options.logfile = get_config_dir("deluged.log") options.logfile = get_config_dir('deluged.log')
file_handler = FileHandler(options.logfile) file_handler = FileHandler(options.logfile)
log.addHandler(file_handler) log.addHandler(file_handler)
@ -73,7 +73,7 @@ def start_daemon(skip_start=False):
daemon = Daemon(listen_interface=options.listen_interface, daemon = Daemon(listen_interface=options.listen_interface,
interface=options.ui_interface, interface=options.ui_interface,
port=options.port, port=options.port,
read_only_config_keys=options.read_only_config_keys.split(",")) read_only_config_keys=options.read_only_config_keys.split(','))
if skip_start: if skip_start:
return daemon return daemon
else: else:

View File

@ -16,7 +16,7 @@ log = logging.getLogger(__name__)
class EventManager(component.Component): class EventManager(component.Component):
def __init__(self): def __init__(self):
component.Component.__init__(self, "EventManager") component.Component.__init__(self, 'EventManager')
self.handlers = {} self.handlers = {}
def emit(self, event): def emit(self, event):
@ -26,7 +26,7 @@ class EventManager(component.Component):
:param event: DelugeEvent :param event: DelugeEvent
""" """
# Emit the event to the interested clients # Emit the event to the interested clients
component.get("RPCServer").emit_event(event) component.get('RPCServer').emit_event(event)
# Call any handlers for the event # Call any handlers for the event
if event.name in self.handlers: if event.name in self.handlers:
for handler in self.handlers[event.name]: for handler in self.handlers[event.name]:
@ -34,7 +34,7 @@ class EventManager(component.Component):
try: try:
handler(*event.args) handler(*event.args)
except Exception as ex: except Exception as ex:
log.error("Event handler %s failed in %s with exception %s", event.name, handler, ex) log.error('Event handler %s failed in %s with exception %s', event.name, handler, ex)
def register_event_handler(self, event, handler): def register_event_handler(self, event, handler):
""" """

View File

@ -14,14 +14,14 @@ from deluge.common import TORRENT_STATE
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
STATE_SORT = ["All", "Active"] + TORRENT_STATE STATE_SORT = ['All', 'Active'] + TORRENT_STATE
# Special purpose filters: # Special purpose filters:
def filter_keywords(torrent_ids, values): def filter_keywords(torrent_ids, values):
# Cleanup # Cleanup
keywords = ",".join([v.lower() for v in values]) keywords = ','.join([v.lower() for v in values])
keywords = keywords.split(",") keywords = keywords.split(',')
for keyword in keywords: for keyword in keywords:
torrent_ids = filter_one_keyword(torrent_ids, keyword) torrent_ids = filter_one_keyword(torrent_ids, keyword)
@ -33,7 +33,7 @@ def filter_one_keyword(torrent_ids, keyword):
search torrent on keyword. search torrent on keyword.
searches title,state,tracker-status,tracker,files searches title,state,tracker-status,tracker,files
""" """
all_torrents = component.get("TorrentManager").torrents all_torrents = component.get('TorrentManager').torrents
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
torrent = all_torrents[torrent_id] torrent = all_torrents[torrent_id]
@ -41,7 +41,7 @@ def filter_one_keyword(torrent_ids, keyword):
yield torrent_id yield torrent_id
elif keyword in torrent.state.lower(): elif keyword in torrent.state.lower():
yield torrent_id yield torrent_id
elif torrent.trackers and keyword in torrent.trackers[0]["url"]: elif torrent.trackers and keyword in torrent.trackers[0]['url']:
yield torrent_id yield torrent_id
elif keyword in torrent_id: elif keyword in torrent_id:
yield torrent_id yield torrent_id
@ -50,13 +50,13 @@ def filter_one_keyword(torrent_ids, keyword):
yield torrent_id yield torrent_id
else: else:
for t_file in torrent.get_files(): for t_file in torrent.get_files():
if keyword in t_file["path"].lower(): if keyword in t_file['path'].lower():
yield torrent_id yield torrent_id
break break
def filter_by_name(torrent_ids, search_string): def filter_by_name(torrent_ids, search_string):
all_torrents = component.get("TorrentManager").torrents all_torrents = component.get('TorrentManager').torrents
try: try:
search_string, match_case = search_string[0].split('::match') search_string, match_case = search_string[0].split('::match')
except ValueError: except ValueError:
@ -79,18 +79,18 @@ def filter_by_name(torrent_ids, search_string):
def tracker_error_filter(torrent_ids, values): def tracker_error_filter(torrent_ids, values):
filtered_torrent_ids = [] filtered_torrent_ids = []
tm = component.get("TorrentManager") tm = component.get('TorrentManager')
# If this is a tracker_host, then we need to filter on it # If this is a tracker_host, then we need to filter on it
if values[0] != "Error": if values[0] != 'Error':
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
if values[0] == tm[torrent_id].get_status(["tracker_host"])["tracker_host"]: if values[0] == tm[torrent_id].get_status(['tracker_host'])['tracker_host']:
filtered_torrent_ids.append(torrent_id) filtered_torrent_ids.append(torrent_id)
return filtered_torrent_ids return filtered_torrent_ids
# Check torrent's tracker_status for 'Error:' and return those torrent_ids # Check torrent's tracker_status for 'Error:' and return those torrent_ids
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
if "Error:" in tm[torrent_id].get_status(["tracker_status"])["tracker_status"]: if 'Error:' in tm[torrent_id].get_status(['tracker_status'])['tracker_status']:
filtered_torrent_ids.append(torrent_id) filtered_torrent_ids.append(torrent_id)
return filtered_torrent_ids return filtered_torrent_ids
@ -100,26 +100,26 @@ class FilterManager(component.Component):
""" """
def __init__(self, core): def __init__(self, core):
component.Component.__init__(self, "FilterManager") component.Component.__init__(self, 'FilterManager')
log.debug("FilterManager init..") log.debug('FilterManager init..')
self.core = core self.core = core
self.torrents = core.torrentmanager self.torrents = core.torrentmanager
self.registered_filters = {} self.registered_filters = {}
self.register_filter("keyword", filter_keywords) self.register_filter('keyword', filter_keywords)
self.register_filter("name", filter_by_name) self.register_filter('name', filter_by_name)
self.tree_fields = {} self.tree_fields = {}
self.register_tree_field("state", self._init_state_tree) self.register_tree_field('state', self._init_state_tree)
def _init_tracker_tree(): def _init_tracker_tree():
return {"Error": 0} return {'Error': 0}
self.register_tree_field("tracker_host", _init_tracker_tree) self.register_tree_field('tracker_host', _init_tracker_tree)
self.register_filter("tracker_host", tracker_error_filter) self.register_filter('tracker_host', tracker_error_filter)
def _init_users_tree(): def _init_users_tree():
return {"": 0} return {'': 0}
self.register_tree_field("owner", _init_users_tree) self.register_tree_field('owner', _init_users_tree)
def filter_torrent_ids(self, filter_dict): def filter_torrent_ids(self, filter_dict):
""" """
@ -135,9 +135,9 @@ class FilterManager(component.Component):
filter_dict[key] = [value] filter_dict[key] = [value]
# Optimized filter for id # Optimized filter for id
if "id" in filter_dict: if 'id' in filter_dict:
torrent_ids = list(filter_dict["id"]) torrent_ids = list(filter_dict['id'])
del filter_dict["id"] del filter_dict['id']
else: else:
torrent_ids = self.torrents.get_torrent_list() torrent_ids = self.torrents.get_torrent_list()
@ -146,14 +146,14 @@ class FilterManager(component.Component):
return torrent_ids return torrent_ids
# Special purpose, state=Active. # Special purpose, state=Active.
if "state" in filter_dict: if 'state' in filter_dict:
# We need to make sure this is a list for the logic below # We need to make sure this is a list for the logic below
filter_dict["state"] = list(filter_dict["state"]) filter_dict['state'] = list(filter_dict['state'])
if "state" in filter_dict and "Active" in filter_dict["state"]: if 'state' in filter_dict and 'Active' in filter_dict['state']:
filter_dict["state"].remove("Active") filter_dict['state'].remove('Active')
if not filter_dict["state"]: if not filter_dict['state']:
del filter_dict["state"] del filter_dict['state']
torrent_ids = self.filter_state_active(torrent_ids) torrent_ids = self.filter_state_active(torrent_ids)
if not filter_dict: if not filter_dict:
@ -200,12 +200,12 @@ class FilterManager(component.Component):
value = status[field] value = status[field]
items[field][value] = items[field].get(value, 0) + 1 items[field][value] = items[field].get(value, 0) + 1
if "tracker_host" in items: if 'tracker_host' in items:
items["tracker_host"]["All"] = len(torrent_ids) items['tracker_host']['All'] = len(torrent_ids)
items["tracker_host"]["Error"] = len(tracker_error_filter(torrent_ids, ("Error",))) items['tracker_host']['Error'] = len(tracker_error_filter(torrent_ids, ('Error',)))
if not show_zero_hits: if not show_zero_hits:
for cat in ["state", "owner", "tracker_host"]: for cat in ['state', 'owner', 'tracker_host']:
if cat in tree_keys: if cat in tree_keys:
self._hide_state_items(items[cat]) self._hide_state_items(items[cat])
@ -214,17 +214,17 @@ class FilterManager(component.Component):
for field in tree_keys: for field in tree_keys:
sorted_items[field] = sorted(items[field].iteritems()) sorted_items[field] = sorted(items[field].iteritems())
if "state" in tree_keys: if 'state' in tree_keys:
sorted_items["state"].sort(self._sort_state_items) sorted_items['state'].sort(self._sort_state_items)
return sorted_items return sorted_items
def _init_state_tree(self): def _init_state_tree(self):
init_state = {} init_state = {}
init_state["All"] = len(self.torrents.get_torrent_list()) init_state['All'] = len(self.torrents.get_torrent_list())
for state in TORRENT_STATE: for state in TORRENT_STATE:
init_state[state] = 0 init_state[state] = 0
init_state["Active"] = len(self.filter_state_active(self.torrents.get_torrent_list())) init_state['Active'] = len(self.filter_state_active(self.torrents.get_torrent_list()))
return init_state return init_state
def register_filter(self, filter_id, filter_func, filter_value=None): def register_filter(self, filter_id, filter_func, filter_value=None):
@ -242,8 +242,8 @@ class FilterManager(component.Component):
def filter_state_active(self, torrent_ids): def filter_state_active(self, torrent_ids):
for torrent_id in list(torrent_ids): for torrent_id in list(torrent_ids):
status = self.torrents[torrent_id].get_status(["download_payload_rate", "upload_payload_rate"]) status = self.torrents[torrent_id].get_status(['download_payload_rate', 'upload_payload_rate'])
if status["download_payload_rate"] or status["upload_payload_rate"]: if status['download_payload_rate'] or status['upload_payload_rate']:
pass pass
else: else:
torrent_ids.remove(torrent_id) torrent_ids.remove(torrent_id)
@ -252,7 +252,7 @@ class FilterManager(component.Component):
def _hide_state_items(self, state_items): def _hide_state_items(self, state_items):
"""For hide(show)-zero hits""" """For hide(show)-zero hits"""
for (value, count) in state_items.items(): for (value, count) in state_items.items():
if value != "All" and count == 0: if value != 'All' and count == 0:
del state_items[value] del state_items[value]
def _sort_state_items(self, x, y): def _sort_state_items(self, x, y):

View File

@ -26,13 +26,13 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
functions to access parts of the core.""" functions to access parts of the core."""
def __init__(self, core): def __init__(self, core):
component.Component.__init__(self, "CorePluginManager") component.Component.__init__(self, 'CorePluginManager')
self.status_fields = {} self.status_fields = {}
# Call the PluginManagerBase constructor # Call the PluginManagerBase constructor
deluge.pluginmanagerbase.PluginManagerBase.__init__( deluge.pluginmanagerbase.PluginManagerBase.__init__(
self, "core.conf", "deluge.plugin.core") self, 'core.conf', 'deluge.plugin.core')
def start(self): def start(self):
# Enable plugins that are enabled in the config # Enable plugins that are enabled in the config
@ -47,7 +47,7 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
def update_plugins(self): def update_plugins(self):
for plugin in self.plugins: for plugin in self.plugins:
if hasattr(self.plugins[plugin], "update"): if hasattr(self.plugins[plugin], 'update'):
try: try:
self.plugins[plugin].update() self.plugins[plugin].update()
except Exception as ex: except Exception as ex:
@ -60,7 +60,7 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
def on_enable_plugin(result): def on_enable_plugin(result):
if result is True and name in self.plugins: if result is True and name in self.plugins:
component.get("EventManager").emit(PluginEnabledEvent(name)) component.get('EventManager').emit(PluginEnabledEvent(name))
return result return result
d.addBoth(on_enable_plugin) d.addBoth(on_enable_plugin)
@ -73,7 +73,7 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
def on_disable_plugin(result): def on_disable_plugin(result):
if name not in self.plugins: if name not in self.plugins:
component.get("EventManager").emit(PluginDisabledEvent(name)) component.get('EventManager').emit(PluginDisabledEvent(name))
return result return result
d.addBoth(on_disable_plugin) d.addBoth(on_disable_plugin)
return d return d
@ -93,13 +93,13 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
def register_status_field(self, field, function): def register_status_field(self, field, function):
"""Register a new status field. This can be used in the same way the """Register a new status field. This can be used in the same way the
client requests other status information from core.""" client requests other status information from core."""
log.debug("Registering status field %s with PluginManager", field) log.debug('Registering status field %s with PluginManager', field)
self.status_fields[field] = function self.status_fields[field] = function
def deregister_status_field(self, field): def deregister_status_field(self, field):
"""Deregisters a status field""" """Deregisters a status field"""
log.debug("Deregistering status field %s with PluginManager", field) log.debug('Deregistering status field %s with PluginManager', field)
try: try:
del self.status_fields[field] del self.status_fields[field]
except Exception: except Exception:
log.warning("Unable to deregister status field %s", field) log.warning('Unable to deregister status field %s', field)

View File

@ -29,119 +29,119 @@ except ImportError:
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DEFAULT_PREFS = { DEFAULT_PREFS = {
"send_info": False, 'send_info': False,
"info_sent": 0.0, 'info_sent': 0.0,
"daemon_port": 58846, 'daemon_port': 58846,
"allow_remote": False, 'allow_remote': False,
"pre_allocate_storage": False, 'pre_allocate_storage': False,
"download_location": deluge.common.get_default_download_dir(), 'download_location': deluge.common.get_default_download_dir(),
"listen_ports": [6881, 6891], 'listen_ports': [6881, 6891],
"listen_interface": "", 'listen_interface': '',
"random_port": True, 'random_port': True,
"listen_random_port": None, 'listen_random_port': None,
"listen_use_sys_port": False, 'listen_use_sys_port': False,
"listen_reuse_port": True, 'listen_reuse_port': True,
"outgoing_ports": [0, 0], 'outgoing_ports': [0, 0],
"random_outgoing_ports": True, 'random_outgoing_ports': True,
"copy_torrent_file": False, 'copy_torrent_file': False,
"del_copy_torrent_file": False, 'del_copy_torrent_file': False,
"torrentfiles_location": deluge.common.get_default_download_dir(), 'torrentfiles_location': deluge.common.get_default_download_dir(),
"plugins_location": os.path.join(deluge.configmanager.get_config_dir(), "plugins"), 'plugins_location': os.path.join(deluge.configmanager.get_config_dir(), 'plugins'),
"prioritize_first_last_pieces": False, 'prioritize_first_last_pieces': False,
"sequential_download": False, 'sequential_download': False,
"dht": True, 'dht': True,
"upnp": True, 'upnp': True,
"natpmp": True, 'natpmp': True,
"utpex": True, 'utpex': True,
"lsd": True, 'lsd': True,
"enc_in_policy": 1, 'enc_in_policy': 1,
"enc_out_policy": 1, 'enc_out_policy': 1,
"enc_level": 2, 'enc_level': 2,
"max_connections_global": 200, 'max_connections_global': 200,
"max_upload_speed": -1.0, 'max_upload_speed': -1.0,
"max_download_speed": -1.0, 'max_download_speed': -1.0,
"max_upload_slots_global": 4, 'max_upload_slots_global': 4,
"max_half_open_connections": (lambda: deluge.common.windows_check() and 'max_half_open_connections': (lambda: deluge.common.windows_check() and
(lambda: deluge.common.vista_check() and 4 or 8)() or 50)(), (lambda: deluge.common.vista_check() and 4 or 8)() or 50)(),
"max_connections_per_second": 20, 'max_connections_per_second': 20,
"ignore_limits_on_local_network": True, 'ignore_limits_on_local_network': True,
"max_connections_per_torrent": -1, 'max_connections_per_torrent': -1,
"max_upload_slots_per_torrent": -1, 'max_upload_slots_per_torrent': -1,
"max_upload_speed_per_torrent": -1, 'max_upload_speed_per_torrent': -1,
"max_download_speed_per_torrent": -1, 'max_download_speed_per_torrent': -1,
"enabled_plugins": [], 'enabled_plugins': [],
"add_paused": False, 'add_paused': False,
"max_active_seeding": 5, 'max_active_seeding': 5,
"max_active_downloading": 3, 'max_active_downloading': 3,
"max_active_limit": 8, 'max_active_limit': 8,
"dont_count_slow_torrents": False, 'dont_count_slow_torrents': False,
"queue_new_to_top": False, 'queue_new_to_top': False,
"stop_seed_at_ratio": False, 'stop_seed_at_ratio': False,
"remove_seed_at_ratio": False, 'remove_seed_at_ratio': False,
"stop_seed_ratio": 2.00, 'stop_seed_ratio': 2.00,
"share_ratio_limit": 2.00, 'share_ratio_limit': 2.00,
"seed_time_ratio_limit": 7.00, 'seed_time_ratio_limit': 7.00,
"seed_time_limit": 180, 'seed_time_limit': 180,
"auto_managed": True, 'auto_managed': True,
"move_completed": False, 'move_completed': False,
"move_completed_path": deluge.common.get_default_download_dir(), 'move_completed_path': deluge.common.get_default_download_dir(),
"move_completed_paths_list": [], 'move_completed_paths_list': [],
"download_location_paths_list": [], 'download_location_paths_list': [],
"path_chooser_show_chooser_button_on_localhost": True, 'path_chooser_show_chooser_button_on_localhost': True,
"path_chooser_auto_complete_enabled": True, 'path_chooser_auto_complete_enabled': True,
"path_chooser_accelerator_string": "Tab", 'path_chooser_accelerator_string': 'Tab',
"path_chooser_max_popup_rows": 20, 'path_chooser_max_popup_rows': 20,
"path_chooser_show_hidden_files": False, 'path_chooser_show_hidden_files': False,
"new_release_check": True, 'new_release_check': True,
"proxy": { 'proxy': {
"type": 0, 'type': 0,
"hostname": "", 'hostname': '',
"username": "", 'username': '',
"password": "", 'password': '',
"port": 8080, 'port': 8080,
"proxy_hostnames": True, 'proxy_hostnames': True,
"proxy_peer_connections": True, 'proxy_peer_connections': True,
}, },
"i2p_proxy": { 'i2p_proxy': {
"hostname": "", 'hostname': '',
"port": 0 'port': 0
}, },
"peer_tos": "0x00", 'peer_tos': '0x00',
"rate_limit_ip_overhead": True, 'rate_limit_ip_overhead': True,
"anonymous_mode": False, 'anonymous_mode': False,
"geoip_db_location": "/usr/share/GeoIP/GeoIP.dat", 'geoip_db_location': '/usr/share/GeoIP/GeoIP.dat',
"cache_size": 512, 'cache_size': 512,
"cache_expiry": 60, 'cache_expiry': 60,
"auto_manage_prefer_seeds": False, 'auto_manage_prefer_seeds': False,
"shared": False, 'shared': False,
"super_seeding": False, 'super_seeding': False,
"priority": 0 'priority': 0
} }
class PreferencesManager(component.Component): class PreferencesManager(component.Component):
def __init__(self): def __init__(self):
component.Component.__init__(self, "PreferencesManager") component.Component.__init__(self, 'PreferencesManager')
self.config = deluge.configmanager.ConfigManager("core.conf", DEFAULT_PREFS) self.config = deluge.configmanager.ConfigManager('core.conf', DEFAULT_PREFS)
if "proxies" in self.config: if 'proxies' in self.config:
log.warning("Updating config file for proxy, using 'peer' values to fill new 'proxy' setting") log.warning("Updating config file for proxy, using 'peer' values to fill new 'proxy' setting")
self.config["proxy"].update(self.config["proxies"]['peer']) self.config['proxy'].update(self.config['proxies']['peer'])
log.warning("New proxy config is: %s", self.config["proxy"]) log.warning('New proxy config is: %s', self.config['proxy'])
del self.config["proxies"] del self.config['proxies']
self.core = component.get("Core") self.core = component.get('Core')
self.session = component.get("Core").session self.session = component.get('Core').session
self.new_release_timer = None self.new_release_timer = None
def start(self): def start(self):
# Setup listen port followed by dht to ensure both use same port. # Setup listen port followed by dht to ensure both use same port.
self.__set_listen_on() self.__set_listen_on()
self._on_set_dht("dht", self.config["dht"]) self._on_set_dht('dht', self.config['dht'])
# Set the initial preferences on start-up # Set the initial preferences on start-up
for key in DEFAULT_PREFS: for key in DEFAULT_PREFS:
# Listen port and dht already setup in correct order so skip running again. # Listen port and dht already setup in correct order so skip running again.
if key in ("dht", "random_port") or key.startswith("listen_"): if key in ('dht', 'random_port') or key.startswith('listen_'):
continue continue
self.do_config_set_func(key, self.config[key]) self.do_config_set_func(key, self.config[key])
@ -153,10 +153,10 @@ class PreferencesManager(component.Component):
# Config set functions # Config set functions
def do_config_set_func(self, key, value): def do_config_set_func(self, key, value):
on_set_func = getattr(self, "_on_set_" + key, None) on_set_func = getattr(self, '_on_set_' + key, None)
if on_set_func: if on_set_func:
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Config key: %s set to %s..", key, value) log.debug('Config key: %s set to %s..', key, value)
on_set_func(key, value) on_set_func(key, value)
def session_set_setting(self, key, value): def session_set_setting(self, key, value):
@ -164,27 +164,27 @@ class PreferencesManager(component.Component):
self.session.apply_settings({key: value}) self.session.apply_settings({key: value})
except AttributeError: except AttributeError:
# Deprecated in libtorrent 1.1 # Deprecated in libtorrent 1.1
if key in ("enable_lsd", "enable_upnp", "enable_natpmp", "enable_dht"): if key in ('enable_lsd', 'enable_upnp', 'enable_natpmp', 'enable_dht'):
start_stop = key.replace("enable", "start") if value else key.replace("enable", "stop") start_stop = key.replace('enable', 'start') if value else key.replace('enable', 'stop')
getattr(self.session, start_stop)() getattr(self.session, start_stop)()
elif key == "dht_bootstrap_nodes": elif key == 'dht_bootstrap_nodes':
self.session.add_dht_router("router.bittorrent.com", 6881) self.session.add_dht_router('router.bittorrent.com', 6881)
self.session.add_dht_router("router.utorrent.com", 6881) self.session.add_dht_router('router.utorrent.com', 6881)
self.session.add_dht_router("router.bitcomet.com", 6881) self.session.add_dht_router('router.bitcomet.com', 6881)
else: else:
self.session.set_settings({key: value}) self.session.set_settings({key: value})
def _on_config_value_change(self, key, value): def _on_config_value_change(self, key, value):
if self.get_state() == "Started": if self.get_state() == 'Started':
self.do_config_set_func(key, value) self.do_config_set_func(key, value)
component.get("EventManager").emit(ConfigValueChangedEvent(key, value)) component.get('EventManager').emit(ConfigValueChangedEvent(key, value))
def _on_set_torrentfiles_location(self, key, value): def _on_set_torrentfiles_location(self, key, value):
if self.config["copy_torrent_file"]: if self.config['copy_torrent_file']:
try: try:
os.makedirs(value) os.makedirs(value)
except OSError as ex: except OSError as ex:
log.debug("Unable to make directory: %s", ex) log.debug('Unable to make directory: %s', ex)
def _on_set_listen_ports(self, key, value): def _on_set_listen_ports(self, key, value):
self.__set_listen_on() self.__set_listen_on()
@ -197,35 +197,35 @@ class PreferencesManager(component.Component):
def __set_listen_on(self): def __set_listen_on(self):
""" Set the ports and interface address to listen for incoming connections on.""" """ Set the ports and interface address to listen for incoming connections on."""
if self.config["random_port"]: if self.config['random_port']:
if not self.config["listen_random_port"]: if not self.config['listen_random_port']:
self.config["listen_random_port"] = random.randrange(49152, 65525) self.config['listen_random_port'] = random.randrange(49152, 65525)
listen_ports = [self.config["listen_random_port"]] * 2 # use single port range listen_ports = [self.config['listen_random_port']] * 2 # use single port range
else: else:
self.config["listen_random_port"] = None self.config['listen_random_port'] = None
listen_ports = self.config["listen_ports"] listen_ports = self.config['listen_ports']
interface = str(self.config["listen_interface"].strip()) interface = str(self.config['listen_interface'].strip())
log.debug("Listen Interface: %s, Ports: %s with use_sys_port: %s", log.debug('Listen Interface: %s, Ports: %s with use_sys_port: %s',
interface, listen_ports, self.config["listen_use_sys_port"]) interface, listen_ports, self.config['listen_use_sys_port'])
try: try:
interfaces = ["%s:%s" % (interface, port) for port in range(listen_ports[0], listen_ports[1]+1)] interfaces = ['%s:%s' % (interface, port) for port in range(listen_ports[0], listen_ports[1]+1)]
self.session.apply_setting({"listen_system_port_fallback", self.config["listen_use_sys_port"]}) self.session.apply_setting({'listen_system_port_fallback', self.config['listen_use_sys_port']})
self.session.apply_setting({"listen_interfaces", interfaces}) self.session.apply_setting({'listen_interfaces', interfaces})
except AttributeError: except AttributeError:
# Deprecated in libtorrent 1.1 # Deprecated in libtorrent 1.1
# If a single port range then always enable re-use port flag. # If a single port range then always enable re-use port flag.
reuse_port = True if listen_ports[0] == listen_ports[1] else self.config["listen_reuse_port"] reuse_port = True if listen_ports[0] == listen_ports[1] else self.config['listen_reuse_port']
flags = ((lt.listen_on_flags_t.listen_no_system_port flags = ((lt.listen_on_flags_t.listen_no_system_port
if not self.config["listen_use_sys_port"] else 0) | if not self.config['listen_use_sys_port'] else 0) |
(lt.listen_on_flags_t.listen_reuse_address (lt.listen_on_flags_t.listen_reuse_address
if reuse_port else 0)) if reuse_port else 0))
try: try:
self.session.listen_on(listen_ports[0], listen_ports[1], interface, flags) self.session.listen_on(listen_ports[0], listen_ports[1], interface, flags)
except RuntimeError as ex: except RuntimeError as ex:
if ex.message == "Invalid Argument": if ex.message == 'Invalid Argument':
log.error("Error setting listen interface (must be IP Address): %s %s-%s", log.error('Error setting listen interface (must be IP Address): %s %s-%s',
interface, listen_ports[0], listen_ports[1]) interface, listen_ports[0], listen_ports[1])
def _on_set_outgoing_ports(self, key, value): def _on_set_outgoing_ports(self, key, value):
@ -235,34 +235,34 @@ class PreferencesManager(component.Component):
self.__set_outgoing_ports() self.__set_outgoing_ports()
def __set_outgoing_ports(self): def __set_outgoing_ports(self):
ports = [0, 0] if self.config["random_outgoing_ports"] else self.config["outgoing_ports"] ports = [0, 0] if self.config['random_outgoing_ports'] else self.config['outgoing_ports']
log.debug("Outgoing ports set to %s", ports) log.debug('Outgoing ports set to %s', ports)
self.session_set_setting("outgoing_ports", (ports[0], ports[1])) self.session_set_setting('outgoing_ports', (ports[0], ports[1]))
def _on_set_peer_tos(self, key, value): def _on_set_peer_tos(self, key, value):
try: try:
self.session_set_setting("peer_tos", chr(int(value, 16))) self.session_set_setting('peer_tos', chr(int(value, 16)))
except ValueError as ex: except ValueError as ex:
log.debug("Invalid tos byte: %s", ex) log.debug('Invalid tos byte: %s', ex)
return return
def _on_set_dht(self, key, value): def _on_set_dht(self, key, value):
dht_bootstraps = "router.bittorrent.com:6881,router.utorrent.com:6881,router.bitcomet.com:6881" dht_bootstraps = 'router.bittorrent.com:6881,router.utorrent.com:6881,router.bitcomet.com:6881'
self.session_set_setting("dht_bootstrap_nodes", dht_bootstraps) self.session_set_setting('dht_bootstrap_nodes', dht_bootstraps)
self.session_set_setting("enable_dht", value) self.session_set_setting('enable_dht', value)
def _on_set_upnp(self, key, value): def _on_set_upnp(self, key, value):
self.session_set_setting("enable_upnp", value) self.session_set_setting('enable_upnp', value)
def _on_set_natpmp(self, key, value): def _on_set_natpmp(self, key, value):
self.session_set_setting("enable_natpmp", value) self.session_set_setting('enable_natpmp', value)
def _on_set_lsd(self, key, value): def _on_set_lsd(self, key, value):
self.session_set_setting("enable_lsd", value) self.session_set_setting('enable_lsd', value)
def _on_set_utpex(self, key, value): def _on_set_utpex(self, key, value):
if value: if value:
self.session.add_extension("ut_pex") self.session.add_extension('ut_pex')
def _on_set_enc_in_policy(self, key, value): def _on_set_enc_in_policy(self, key, value):
self._on_set_encryption(key, value) self._on_set_encryption(key, value)
@ -277,76 +277,76 @@ class PreferencesManager(component.Component):
# Convert Deluge enc_level values to libtorrent enc_level values. # Convert Deluge enc_level values to libtorrent enc_level values.
pe_enc_level = {0: lt.enc_level.plaintext, 1: lt.enc_level.rc4, 2: lt.enc_level.both} pe_enc_level = {0: lt.enc_level.plaintext, 1: lt.enc_level.rc4, 2: lt.enc_level.both}
try: try:
self.session.apply_setting("out_enc_policy", lt.enc_policy(self.config["enc_out_policy"])) self.session.apply_setting('out_enc_policy', lt.enc_policy(self.config['enc_out_policy']))
self.session.apply_setting("in_enc_policy", lt.enc_policy(self.config["enc_in_policy"])) self.session.apply_setting('in_enc_policy', lt.enc_policy(self.config['enc_in_policy']))
self.session.apply_setting("allowed_enc_level", lt.enc_level(pe_enc_level[self.config["enc_level"]])) self.session.apply_setting('allowed_enc_level', lt.enc_level(pe_enc_level[self.config['enc_level']]))
self.session.apply_setting("prefer_rc4", True) self.session.apply_setting('prefer_rc4', True)
except AttributeError: except AttributeError:
# Deprecated in libtorrent 1.1 # Deprecated in libtorrent 1.1
pe_settings = lt.pe_settings() pe_settings = lt.pe_settings()
pe_settings.out_enc_policy = lt.enc_policy(self.config["enc_out_policy"]) pe_settings.out_enc_policy = lt.enc_policy(self.config['enc_out_policy'])
pe_settings.in_enc_policy = lt.enc_policy(self.config["enc_in_policy"]) pe_settings.in_enc_policy = lt.enc_policy(self.config['enc_in_policy'])
pe_settings.allowed_enc_level = lt.enc_level(pe_enc_level[self.config["enc_level"]]) pe_settings.allowed_enc_level = lt.enc_level(pe_enc_level[self.config['enc_level']])
pe_settings.prefer_rc4 = True pe_settings.prefer_rc4 = True
self.session.set_pe_settings(pe_settings) self.session.set_pe_settings(pe_settings)
pe_sess_settings = self.session.get_pe_settings() pe_sess_settings = self.session.get_pe_settings()
log.debug("encryption settings:\n\t\t\tout_policy: %s\n\t\t\ log.debug('encryption settings:\n\t\t\tout_policy: %s\n\t\t\
in_policy: %s\n\t\t\tlevel: %s\n\t\t\tprefer_rc4: %s", in_policy: %s\n\t\t\tlevel: %s\n\t\t\tprefer_rc4: %s',
pe_sess_settings.out_enc_policy, pe_sess_settings.out_enc_policy,
pe_sess_settings.in_enc_policy, pe_sess_settings.in_enc_policy,
pe_sess_settings.allowed_enc_level, pe_sess_settings.allowed_enc_level,
pe_sess_settings.prefer_rc4) pe_sess_settings.prefer_rc4)
def _on_set_max_connections_global(self, key, value): def _on_set_max_connections_global(self, key, value):
self.session_set_setting("connections_limit", value) self.session_set_setting('connections_limit', value)
def _on_set_max_upload_speed(self, key, value): def _on_set_max_upload_speed(self, key, value):
# We need to convert Kb/s to B/s # We need to convert Kb/s to B/s
value = -1 if value < 0 else int(value * 1024) value = -1 if value < 0 else int(value * 1024)
self.session_set_setting("upload_rate_limit", value) self.session_set_setting('upload_rate_limit', value)
def _on_set_max_download_speed(self, key, value): def _on_set_max_download_speed(self, key, value):
# We need to convert Kb/s to B/s # We need to convert Kb/s to B/s
value = -1 if value < 0 else int(value * 1024) value = -1 if value < 0 else int(value * 1024)
self.session_set_setting("download_rate_limit", value) self.session_set_setting('download_rate_limit', value)
def _on_set_max_upload_slots_global(self, key, value): def _on_set_max_upload_slots_global(self, key, value):
self.session_set_setting("unchoke_slots_limit", value) self.session_set_setting('unchoke_slots_limit', value)
def _on_set_max_half_open_connections(self, key, value): def _on_set_max_half_open_connections(self, key, value):
self.session_set_setting("half_open_limit", value) self.session_set_setting('half_open_limit', value)
def _on_set_max_connections_per_second(self, key, value): def _on_set_max_connections_per_second(self, key, value):
self.session_set_setting("connection_speed", value) self.session_set_setting('connection_speed', value)
def _on_set_ignore_limits_on_local_network(self, key, value): def _on_set_ignore_limits_on_local_network(self, key, value):
self.session_set_setting("ignore_limits_on_local_network", value) self.session_set_setting('ignore_limits_on_local_network', value)
def _on_set_share_ratio_limit(self, key, value): def _on_set_share_ratio_limit(self, key, value):
self.session_set_setting("share_ratio_limit", value) self.session_set_setting('share_ratio_limit', value)
def _on_set_seed_time_ratio_limit(self, key, value): def _on_set_seed_time_ratio_limit(self, key, value):
self.session_set_setting("seed_time_ratio_limit", value) self.session_set_setting('seed_time_ratio_limit', value)
def _on_set_seed_time_limit(self, key, value): def _on_set_seed_time_limit(self, key, value):
# This value is stored in minutes in deluge, but libtorrent wants seconds # This value is stored in minutes in deluge, but libtorrent wants seconds
self.session_set_setting("seed_time_limit", int(value * 60)) self.session_set_setting('seed_time_limit', int(value * 60))
def _on_set_max_active_downloading(self, key, value): def _on_set_max_active_downloading(self, key, value):
self.session_set_setting("active_downloads", value) self.session_set_setting('active_downloads', value)
def _on_set_max_active_seeding(self, key, value): def _on_set_max_active_seeding(self, key, value):
self.session_set_setting("active_seeds", value) self.session_set_setting('active_seeds', value)
def _on_set_max_active_limit(self, key, value): def _on_set_max_active_limit(self, key, value):
self.session_set_setting("active_limit", value) self.session_set_setting('active_limit', value)
def _on_set_dont_count_slow_torrents(self, key, value): def _on_set_dont_count_slow_torrents(self, key, value):
self.session_set_setting("dont_count_slow_torrents", value) self.session_set_setting('dont_count_slow_torrents', value)
def _on_set_send_info(self, key, value): def _on_set_send_info(self, key, value):
"""sends anonymous stats home""" """sends anonymous stats home"""
log.debug("Sending anonymous stats..") log.debug('Sending anonymous stats..')
class SendInfoThread(threading.Thread): class SendInfoThread(threading.Thread):
def __init__(self, config): def __init__(self, config):
@ -357,33 +357,33 @@ class PreferencesManager(component.Component):
import time import time
now = time.time() now = time.time()
# check if we've done this within the last week or never # check if we've done this within the last week or never
if (now - self.config["info_sent"]) >= (60 * 60 * 24 * 7): if (now - self.config['info_sent']) >= (60 * 60 * 24 * 7):
from urllib import quote_plus from urllib import quote_plus
from urllib2 import urlopen from urllib2 import urlopen
import platform import platform
try: try:
url = "http://deluge-torrent.org/stats_get.php?processor=" + \ url = 'http://deluge-torrent.org/stats_get.php?processor=' + \
platform.machine() + "&python=" + platform.python_version() \ platform.machine() + '&python=' + platform.python_version() \
+ "&deluge=" + deluge.common.get_version() \ + '&deluge=' + deluge.common.get_version() \
+ "&os=" + platform.system() \ + '&os=' + platform.system() \
+ "&plugins=" + quote_plus(":".join(self.config["enabled_plugins"])) + '&plugins=' + quote_plus(':'.join(self.config['enabled_plugins']))
urlopen(url) urlopen(url)
except IOError as ex: except IOError as ex:
log.debug("Network error while trying to send info: %s", ex) log.debug('Network error while trying to send info: %s', ex)
else: else:
self.config["info_sent"] = now self.config['info_sent'] = now
if value: if value:
SendInfoThread(self.config).start() SendInfoThread(self.config).start()
def _on_set_new_release_check(self, key, value): def _on_set_new_release_check(self, key, value):
if value: if value:
log.debug("Checking for new release..") log.debug('Checking for new release..')
threading.Thread(target=self.core.get_new_release).start() threading.Thread(target=self.core.get_new_release).start()
if self.new_release_timer and self.new_release_timer.running: if self.new_release_timer and self.new_release_timer.running:
self.new_release_timer.stop() self.new_release_timer.stop()
# Set a timer to check for a new release every 3 days # Set a timer to check for a new release every 3 days
self.new_release_timer = LoopingCall( self.new_release_timer = LoopingCall(
self._on_set_new_release_check, "new_release_check", True) self._on_set_new_release_check, 'new_release_check', True)
self.new_release_timer.start(72 * 60 * 60, False) self.new_release_timer.start(72 * 60 * 60, False)
else: else:
if self.new_release_timer and self.new_release_timer.running: if self.new_release_timer and self.new_release_timer.running:
@ -391,46 +391,46 @@ class PreferencesManager(component.Component):
def _on_set_proxy(self, key, value): def _on_set_proxy(self, key, value):
try: try:
if key == "i2p_proxy": if key == 'i2p_proxy':
self.session.apply_settings("proxy_type", lt.proxy_type("i2p_proxy")) self.session.apply_settings('proxy_type', lt.proxy_type('i2p_proxy'))
self.session.apply_settings("i2p_hostname", value["hostname"]) self.session.apply_settings('i2p_hostname', value['hostname'])
self.session.apply_settings("i2p_port", value["port"]) self.session.apply_settings('i2p_port', value['port'])
else: else:
self.session.apply_settings("proxy_type", lt.proxy_type(value["type"])) self.session.apply_settings('proxy_type', lt.proxy_type(value['type']))
self.session.apply_settings("proxy_hostname", value["hostname"]) self.session.apply_settings('proxy_hostname', value['hostname'])
self.session.apply_settings("proxy_port", value["port"]) self.session.apply_settings('proxy_port', value['port'])
self.session.apply_settings("proxy_username", value["username"]) self.session.apply_settings('proxy_username', value['username'])
self.session.apply_settings("proxy_password", value["password"]) self.session.apply_settings('proxy_password', value['password'])
self.session.apply_settings("proxy_hostnames", value["proxy_hostnames"]) self.session.apply_settings('proxy_hostnames', value['proxy_hostnames'])
self.session.apply_settings("proxy_peer_connections", value["proxy_peer_connections"]) self.session.apply_settings('proxy_peer_connections', value['proxy_peer_connections'])
self.session.apply_settings("proxy_tracker_connections", value["proxy_tracker_connections"]) self.session.apply_settings('proxy_tracker_connections', value['proxy_tracker_connections'])
except AttributeError: except AttributeError:
proxy_settings = lt.proxy_settings() proxy_settings = lt.proxy_settings()
proxy_settings.hostname = value["hostname"] proxy_settings.hostname = value['hostname']
proxy_settings.port = value["port"] proxy_settings.port = value['port']
if key == "i2p_proxy": if key == 'i2p_proxy':
try: try:
self.session.set_i2p_proxy(proxy_settings) self.session.set_i2p_proxy(proxy_settings)
except RuntimeError as ex: except RuntimeError as ex:
log.error("Unable to set I2P Proxy: %s", ex) log.error('Unable to set I2P Proxy: %s', ex)
else: else:
proxy_settings.type = lt.proxy_type(value["type"]) proxy_settings.type = lt.proxy_type(value['type'])
proxy_settings.username = value["username"] proxy_settings.username = value['username']
proxy_settings.password = value["password"] proxy_settings.password = value['password']
proxy_settings.hostname = value["hostname"] proxy_settings.hostname = value['hostname']
proxy_settings.port = value["port"] proxy_settings.port = value['port']
proxy_settings.proxy_hostnames = value["proxy_hostnames"] proxy_settings.proxy_hostnames = value['proxy_hostnames']
proxy_settings.proxy_peer_connections = value["proxy_peer_connections"] proxy_settings.proxy_peer_connections = value['proxy_peer_connections']
self.session.set_proxy(proxy_settings) self.session.set_proxy(proxy_settings)
def _on_set_i2p_proxy(self, key, value): def _on_set_i2p_proxy(self, key, value):
self._on_set_proxy(key, value) self._on_set_proxy(key, value)
def _on_set_rate_limit_ip_overhead(self, key, value): def _on_set_rate_limit_ip_overhead(self, key, value):
self.session_set_setting("rate_limit_ip_overhead", value) self.session_set_setting('rate_limit_ip_overhead', value)
def _on_set_anonymous_mode(self, key, value): def _on_set_anonymous_mode(self, key, value):
self.session_set_setting("anonymous_mode", value) self.session_set_setting('anonymous_mode', value)
def _on_set_geoip_db_location(self, key, geoipdb_path): def _on_set_geoip_db_location(self, key, geoipdb_path):
# Load the GeoIP DB for country look-ups if available # Load the GeoIP DB for country look-ups if available
@ -438,15 +438,15 @@ class PreferencesManager(component.Component):
try: try:
self.core.geoip_instance = GeoIP.open(geoipdb_path, GeoIP.GEOIP_STANDARD) self.core.geoip_instance = GeoIP.open(geoipdb_path, GeoIP.GEOIP_STANDARD)
except AttributeError: except AttributeError:
log.warning("GeoIP Unavailable") log.warning('GeoIP Unavailable')
else: else:
log.warning("Unable to find GeoIP database file: %s", geoipdb_path) log.warning('Unable to find GeoIP database file: %s', geoipdb_path)
def _on_set_cache_size(self, key, value): def _on_set_cache_size(self, key, value):
self.session_set_setting("cache_size", value) self.session_set_setting('cache_size', value)
def _on_set_cache_expiry(self, key, value): def _on_set_cache_expiry(self, key, value):
self.session_set_setting("cache_expiry", value) self.session_set_setting('cache_expiry', value)
def _on_auto_manage_prefer_seeds(self, key, value): def _on_auto_manage_prefer_seeds(self, key, value):
self.session_set_setting("auto_manage_prefer_seeds", value) self.session_set_setting('auto_manage_prefer_seeds', value)

View File

@ -49,7 +49,7 @@ def export(auth_level=AUTH_LEVEL_DEFAULT):
func._rpcserver_export = True func._rpcserver_export = True
func._rpcserver_auth_level = auth_level func._rpcserver_auth_level = auth_level
doc = func.__doc__ doc = func.__doc__
func.__doc__ = "**RPC Exported Function** (*Auth Level: %s*)\n\n" % auth_level func.__doc__ = '**RPC Exported Function** (*Auth Level: %s*)\n\n' % auth_level
if doc: if doc:
func.__doc__ += doc func.__doc__ += doc
@ -75,16 +75,16 @@ def format_request(call):
""" """
try: try:
s = call[1] + "(" s = call[1] + '('
if call[2]: if call[2]:
s += ", ".join([str(x) for x in call[2]]) s += ', '.join([str(x) for x in call[2]])
if call[3]: if call[3]:
if call[2]: if call[2]:
s += ", " s += ', '
s += ", ".join([key + "=" + str(value) for key, value in call[3].items()]) s += ', '.join([key + '=' + str(value) for key, value in call[3].items()])
s += ")" s += ')'
except UnicodeEncodeError: except UnicodeEncodeError:
return "UnicodeEncodeError, call: %s" % call return 'UnicodeEncodeError, call: %s' % call
else: else:
return s return s
@ -97,11 +97,11 @@ class ServerContextFactory(object):
This loads the servers cert/private key SSL files for use with the This loads the servers cert/private key SSL files for use with the
SSL transport. SSL transport.
""" """
ssl_dir = deluge.configmanager.get_config_dir("ssl") ssl_dir = deluge.configmanager.get_config_dir('ssl')
ctx = SSL.Context(SSL.SSLv23_METHOD) ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3) ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3)
ctx.use_certificate_file(os.path.join(ssl_dir, "daemon.cert")) ctx.use_certificate_file(os.path.join(ssl_dir, 'daemon.cert'))
ctx.use_privatekey_file(os.path.join(ssl_dir, "daemon.pkey")) ctx.use_privatekey_file(os.path.join(ssl_dir, 'daemon.pkey'))
return ctx return ctx
@ -118,17 +118,17 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
""" """
if not isinstance(request, tuple): if not isinstance(request, tuple):
log.debug("Received invalid message: type is not tuple") log.debug('Received invalid message: type is not tuple')
return return
if len(request) < 1: if len(request) < 1:
log.debug("Received invalid message: there are no items") log.debug('Received invalid message: there are no items')
return return
for call in request: for call in request:
if len(call) != 4: if len(call) != 4:
log.debug("Received invalid rpc request: number of items " log.debug('Received invalid rpc request: number of items '
"in request is %s", len(call)) 'in request is %s', len(call))
continue continue
# log.debug("RPCRequest: %s", format_request(call)) # log.debug("RPCRequest: %s", format_request(call))
reactor.callLater(0, self.dispatch, *call) reactor.callLater(0, self.dispatch, *call)
@ -145,7 +145,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
try: try:
self.transfer_message(data) self.transfer_message(data)
except Exception as ex: except Exception as ex:
log.warn("Error occurred when sending message: %s.", ex) log.warn('Error occurred when sending message: %s.', ex)
log.exception(ex) log.exception(ex)
raise raise
@ -154,7 +154,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
This method is called when a new client connects. This method is called when a new client connects.
""" """
peer = self.transport.getPeer() peer = self.transport.getPeer()
log.info("Deluge Client connection made from: %s:%s", log.info('Deluge Client connection made from: %s:%s',
peer.host, peer.port) peer.host, peer.port)
# Set the initial auth level of this session to AUTH_LEVEL_NONE # Set the initial auth level of this session to AUTH_LEVEL_NONE
self.factory.authorized_sessions[self.transport.sessionno] = AUTH_LEVEL_NONE self.factory.authorized_sessions[self.transport.sessionno] = AUTH_LEVEL_NONE
@ -175,9 +175,9 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
if self.transport.sessionno in self.factory.interested_events: if self.transport.sessionno in self.factory.interested_events:
del self.factory.interested_events[self.transport.sessionno] del self.factory.interested_events[self.transport.sessionno]
if self.factory.state == "running": if self.factory.state == 'running':
component.get("EventManager").emit(ClientDisconnectedEvent(self.factory.session_id)) component.get('EventManager').emit(ClientDisconnectedEvent(self.factory.session_id))
log.info("Deluge client disconnected: %s", reason.value) log.info('Deluge client disconnected: %s', reason.value)
def valid_session(self): def valid_session(self):
return self.transport.sessionno in self.factory.authorized_sessions return self.transport.sessionno in self.factory.authorized_sessions
@ -215,29 +215,29 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
)) ))
except AttributeError: except AttributeError:
# This is not a deluge exception (object has no attribute '_args), let's wrap it # This is not a deluge exception (object has no attribute '_args), let's wrap it
log.warning("An exception occurred while sending RPC_ERROR to " log.warning('An exception occurred while sending RPC_ERROR to '
"client. Wrapping it and resending. Error to " 'client. Wrapping it and resending. Error to '
"send(causing exception goes next):\n%s", formated_tb) 'send(causing exception goes next):\n%s', formated_tb)
try: try:
raise WrappedException(str(exceptionValue), exceptionType.__name__, formated_tb) raise WrappedException(str(exceptionValue), exceptionType.__name__, formated_tb)
except WrappedException: except WrappedException:
send_error() send_error()
except Exception as ex: except Exception as ex:
log.error("An exception occurred while sending RPC_ERROR to client: %s", ex) log.error('An exception occurred while sending RPC_ERROR to client: %s', ex)
if method == "daemon.info": if method == 'daemon.info':
# This is a special case and used in the initial connection process # This is a special case and used in the initial connection process
self.sendData((RPC_RESPONSE, request_id, deluge.common.get_version())) self.sendData((RPC_RESPONSE, request_id, deluge.common.get_version()))
return return
elif method == "daemon.login": elif method == 'daemon.login':
# This is a special case and used in the initial connection process # This is a special case and used in the initial connection process
# We need to authenticate the user here # We need to authenticate the user here
log.debug("RPC dispatch daemon.login") log.debug('RPC dispatch daemon.login')
try: try:
client_version = kwargs.pop('client_version', None) client_version = kwargs.pop('client_version', None)
if client_version is None: if client_version is None:
raise IncompatibleClient(deluge.common.get_version()) raise IncompatibleClient(deluge.common.get_version())
ret = component.get("AuthManager").authorize(*args, **kwargs) ret = component.get('AuthManager').authorize(*args, **kwargs)
if ret: if ret:
self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0]) self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
self.factory.session_protocols[self.transport.sessionno] = self self.factory.session_protocols[self.transport.sessionno] = self
@ -255,8 +255,8 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
if not self.valid_session(): if not self.valid_session():
return return
if method == "daemon.set_event_interest": if method == 'daemon.set_event_interest':
log.debug("RPC dispatch daemon.set_event_interest") log.debug('RPC dispatch daemon.set_event_interest')
# This special case is to allow clients to set which events they are # This special case is to allow clients to set which events they are
# interested in receiving. # interested in receiving.
# We are expecting a sequence from the client. # We are expecting a sequence from the client.
@ -278,13 +278,13 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
send_error() send_error()
return return
log.debug("RPC dispatch %s", method) log.debug('RPC dispatch %s', method)
try: try:
method_auth_requirement = self.factory.methods[method]._rpcserver_auth_level method_auth_requirement = self.factory.methods[method]._rpcserver_auth_level
auth_level = self.factory.authorized_sessions[self.transport.sessionno][0] auth_level = self.factory.authorized_sessions[self.transport.sessionno][0]
if auth_level < method_auth_requirement: if auth_level < method_auth_requirement:
# This session is not allowed to call this method # This session is not allowed to call this method
log.debug("Session %s is attempting an unauthorized method call!", log.debug('Session %s is attempting an unauthorized method call!',
self.transport.sessionno) self.transport.sessionno)
raise NotAuthorizedError(auth_level, method_auth_requirement) raise NotAuthorizedError(auth_level, method_auth_requirement)
# Set the session_id in the factory so that methods can know # Set the session_id in the factory so that methods can know
@ -296,7 +296,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
# Don't bother printing out DelugeErrors, because they are just # Don't bother printing out DelugeErrors, because they are just
# for the client # for the client
if not isinstance(ex, DelugeError): if not isinstance(ex, DelugeError):
log.exception("Exception calling RPC request: %s", ex) log.exception('Exception calling RPC request: %s', ex)
else: else:
# Check if the return value is a deferred, since we'll need to # Check if the return value is a deferred, since we'll need to
# wait for it to fire before sending the RPC_RESPONSE # wait for it to fire before sending the RPC_RESPONSE
@ -336,13 +336,13 @@ class RPCServer(component.Component):
:type listen: bool :type listen: bool
""" """
def __init__(self, port=58846, interface="", allow_remote=False, listen=True): def __init__(self, port=58846, interface='', allow_remote=False, listen=True):
component.Component.__init__(self, "RPCServer") component.Component.__init__(self, 'RPCServer')
self.factory = Factory() self.factory = Factory()
self.factory.protocol = DelugeRPCProtocol self.factory.protocol = DelugeRPCProtocol
self.factory.session_id = -1 self.factory.session_id = -1
self.factory.state = "running" self.factory.state = 'running'
# Holds the registered methods # Holds the registered methods
self.factory.methods = {} self.factory.methods = {}
@ -358,14 +358,14 @@ class RPCServer(component.Component):
return return
if allow_remote: if allow_remote:
hostname = "" hostname = ''
else: else:
hostname = "localhost" hostname = 'localhost'
if interface: if interface:
hostname = interface hostname = interface
log.info("Starting DelugeRPC server %s:%s", hostname, port) log.info('Starting DelugeRPC server %s:%s', hostname, port)
# Check for SSL keys and generate some if needed # Check for SSL keys and generate some if needed
check_ssl_keys() check_ssl_keys()
@ -373,7 +373,7 @@ class RPCServer(component.Component):
try: try:
reactor.listenSSL(port, self.factory, ServerContextFactory(), interface=hostname) reactor.listenSSL(port, self.factory, ServerContextFactory(), interface=hostname)
except Exception as ex: except Exception as ex:
log.info("Daemon already running or port not available.") log.info('Daemon already running or port not available.')
log.error(ex) log.error(ex)
raise raise
@ -391,11 +391,11 @@ class RPCServer(component.Component):
name = obj.__class__.__name__.lower() name = obj.__class__.__name__.lower()
for d in dir(obj): for d in dir(obj):
if d[0] == "_": if d[0] == '_':
continue continue
if getattr(getattr(obj, d), '_rpcserver_export', False): if getattr(getattr(obj, d), '_rpcserver_export', False):
log.debug("Registering method: %s", name + "." + d) log.debug('Registering method: %s', name + '.' + d)
self.factory.methods[name + "." + d] = getattr(obj, d) self.factory.methods[name + '.' + d] = getattr(obj, d)
def deregister_object(self, obj): def deregister_object(self, obj):
""" """
@ -450,13 +450,13 @@ class RPCServer(component.Component):
""" """
if not self.listen: if not self.listen:
return "localclient" return 'localclient'
session_id = self.get_session_id() session_id = self.get_session_id()
if session_id > -1 and session_id in self.factory.authorized_sessions: if session_id > -1 and session_id in self.factory.authorized_sessions:
return self.factory.authorized_sessions[session_id][1] return self.factory.authorized_sessions[session_id][1]
else: else:
# No connections made yet # No connections made yet
return "" return ''
def get_session_auth_level(self): def get_session_auth_level(self):
""" """
@ -498,11 +498,11 @@ class RPCServer(component.Component):
:param event: the event to emit :param event: the event to emit
:type event: :class:`deluge.event.DelugeEvent` :type event: :class:`deluge.event.DelugeEvent`
""" """
log.debug("intevents: %s", self.factory.interested_events) log.debug('intevents: %s', self.factory.interested_events)
# Find sessions interested in this event # Find sessions interested in this event
for session_id, interest in self.factory.interested_events.items(): for session_id, interest in self.factory.interested_events.items():
if event.name in interest: if event.name in interest:
log.debug("Emit Event: %s %s", event.name, event.args) log.debug('Emit Event: %s %s', event.name, event.args)
# This session is interested so send a RPC_EVENT # This session is interested so send a RPC_EVENT
self.factory.session_protocols[session_id].sendData( self.factory.session_protocols[session_id].sendData(
(RPC_EVENT, event.name, event.args) (RPC_EVENT, event.name, event.args)
@ -532,20 +532,20 @@ class RPCServer(component.Component):
self.factory.session_protocols[session_id].sendData((RPC_EVENT, event.name, event.args)) self.factory.session_protocols[session_id].sendData((RPC_EVENT, event.name, event.args))
def stop(self): def stop(self):
self.factory.state = "stopping" self.factory.state = 'stopping'
def check_ssl_keys(): def check_ssl_keys():
""" """
Check for SSL cert/key and create them if necessary Check for SSL cert/key and create them if necessary
""" """
ssl_dir = deluge.configmanager.get_config_dir("ssl") ssl_dir = deluge.configmanager.get_config_dir('ssl')
if not os.path.exists(ssl_dir): if not os.path.exists(ssl_dir):
# The ssl folder doesn't exist so we need to create it # The ssl folder doesn't exist so we need to create it
os.makedirs(ssl_dir) os.makedirs(ssl_dir)
generate_ssl_keys() generate_ssl_keys()
else: else:
for f in ("daemon.pkey", "daemon.cert"): for f in ('daemon.pkey', 'daemon.cert'):
if not os.path.exists(os.path.join(ssl_dir, f)): if not os.path.exists(os.path.join(ssl_dir, f)):
generate_ssl_keys() generate_ssl_keys()
break break
@ -555,7 +555,7 @@ def generate_ssl_keys():
""" """
This method generates a new SSL key/cert. This method generates a new SSL key/cert.
""" """
digest = "sha256" digest = 'sha256'
# Generate key pair # Generate key pair
pkey = crypto.PKey() pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048) pkey.generate_key(crypto.TYPE_RSA, 2048)
@ -563,7 +563,7 @@ def generate_ssl_keys():
# Generate cert request # Generate cert request
req = crypto.X509Req() req = crypto.X509Req()
subj = req.get_subject() subj = req.get_subject()
setattr(subj, "CN", "Deluge Daemon") setattr(subj, 'CN', 'Deluge Daemon')
req.set_pubkey(pkey) req.set_pubkey(pkey)
req.sign(pkey, digest) req.sign(pkey, digest)
@ -578,11 +578,11 @@ def generate_ssl_keys():
cert.sign(pkey, digest) cert.sign(pkey, digest)
# Write out files # Write out files
ssl_dir = deluge.configmanager.get_config_dir("ssl") ssl_dir = deluge.configmanager.get_config_dir('ssl')
with open(os.path.join(ssl_dir, "daemon.pkey"), "w") as _file: with open(os.path.join(ssl_dir, 'daemon.pkey'), 'w') as _file:
_file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) _file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
with open(os.path.join(ssl_dir, "daemon.cert"), "w") as _file: with open(os.path.join(ssl_dir, 'daemon.cert'), 'w') as _file:
_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) _file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
# Make the files only readable by this user # Make the files only readable by this user
for f in ("daemon.pkey", "daemon.cert"): for f in ('daemon.pkey', 'daemon.cert'):
os.chmod(os.path.join(ssl_dir, f), stat.S_IREAD | stat.S_IWRITE) os.chmod(os.path.join(ssl_dir, f), stat.S_IREAD | stat.S_IWRITE)

View File

@ -34,14 +34,14 @@ from deluge.event import TorrentFolderRenamedEvent, TorrentStateChangedEvent, To
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
LT_TORRENT_STATE_MAP = { LT_TORRENT_STATE_MAP = {
"queued_for_checking": "Checking", 'queued_for_checking': 'Checking',
"checking_files": "Checking", 'checking_files': 'Checking',
"downloading_metadata": "Downloading", 'downloading_metadata': 'Downloading',
"downloading": "Downloading", 'downloading': 'Downloading',
"finished": "Seeding", 'finished': 'Seeding',
"seeding": "Seeding", 'seeding': 'Seeding',
"allocating": "Allocating", 'allocating': 'Allocating',
"checking_resume_data": "Checking" 'checking_resume_data': 'Checking'
} }
@ -57,19 +57,19 @@ def sanitize_filepath(filepath, folder=False):
def clean_filename(filename): def clean_filename(filename):
"""Strips whitespace and discards dotted filenames""" """Strips whitespace and discards dotted filenames"""
filename = filename.strip() filename = filename.strip()
if filename.replace(".", "") == "": if filename.replace('.', '') == '':
return "" return ''
return filename return filename
if "\\" in filepath or "/" in filepath: if '\\' in filepath or '/' in filepath:
folderpath = filepath.replace("\\", "/").split("/") folderpath = filepath.replace('\\', '/').split('/')
folderpath = [clean_filename(x) for x in folderpath] folderpath = [clean_filename(x) for x in folderpath]
newfilepath = "/".join([path for path in folderpath if path]) newfilepath = '/'.join([path for path in folderpath if path])
else: else:
newfilepath = clean_filename(filepath) newfilepath = clean_filename(filepath)
if folder is True: if folder is True:
newfilepath += "/" newfilepath += '/'
return newfilepath return newfilepath
@ -95,10 +95,10 @@ def convert_lt_files(files):
filelist = [] filelist = []
for index, _file in enumerate(files): for index, _file in enumerate(files):
filelist.append({ filelist.append({
"index": index, 'index': index,
"path": _file.path.decode("utf8").replace("\\", "/"), 'path': _file.path.decode('utf8').replace('\\', '/'),
"size": _file.size, 'size': _file.size,
"offset": _file.offset 'offset': _file.offset
}) })
return filelist return filelist
@ -139,34 +139,34 @@ class TorrentOptions(dict):
""" """
def __init__(self): def __init__(self):
super(TorrentOptions, self).__init__() super(TorrentOptions, self).__init__()
config = ConfigManager("core.conf").config config = ConfigManager('core.conf').config
options_conf_map = { options_conf_map = {
"max_connections": "max_connections_per_torrent", 'max_connections': 'max_connections_per_torrent',
"max_upload_slots": "max_upload_slots_per_torrent", 'max_upload_slots': 'max_upload_slots_per_torrent',
"max_upload_speed": "max_upload_speed_per_torrent", 'max_upload_speed': 'max_upload_speed_per_torrent',
"max_download_speed": "max_download_speed_per_torrent", 'max_download_speed': 'max_download_speed_per_torrent',
"prioritize_first_last_pieces": "prioritize_first_last_pieces", 'prioritize_first_last_pieces': 'prioritize_first_last_pieces',
"sequential_download": "sequential_download", 'sequential_download': 'sequential_download',
"pre_allocate_storage": "pre_allocate_storage", 'pre_allocate_storage': 'pre_allocate_storage',
"download_location": "download_location", 'download_location': 'download_location',
"auto_managed": "auto_managed", 'auto_managed': 'auto_managed',
"stop_at_ratio": "stop_seed_at_ratio", 'stop_at_ratio': 'stop_seed_at_ratio',
"stop_ratio": "stop_seed_ratio", 'stop_ratio': 'stop_seed_ratio',
"remove_at_ratio": "remove_seed_at_ratio", 'remove_at_ratio': 'remove_seed_at_ratio',
"move_completed": "move_completed", 'move_completed': 'move_completed',
"move_completed_path": "move_completed_path", 'move_completed_path': 'move_completed_path',
"add_paused": "add_paused", 'add_paused': 'add_paused',
"shared": "shared", 'shared': 'shared',
"super_seeding": "super_seeding", 'super_seeding': 'super_seeding',
"priority": "priority", 'priority': 'priority',
} }
for opt_k, conf_k in options_conf_map.iteritems(): for opt_k, conf_k in options_conf_map.iteritems():
self[opt_k] = config[conf_k] self[opt_k] = config[conf_k]
self["file_priorities"] = [] self['file_priorities'] = []
self["mapped_files"] = {} self['mapped_files'] = {}
self["owner"] = "" self['owner'] = ''
self["name"] = "" self['name'] = ''
self["seed_mode"] = False self['seed_mode'] = False
class TorrentError(object): class TorrentError(object):
@ -216,11 +216,11 @@ class Torrent(object):
def __init__(self, handle, options, state=None, filename=None, magnet=None): def __init__(self, handle, options, state=None, filename=None, magnet=None):
self.torrent_id = str(handle.info_hash()) self.torrent_id = str(handle.info_hash())
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Creating torrent object %s", self.torrent_id) log.debug('Creating torrent object %s', self.torrent_id)
# Get the core config # Get the core config
self.config = ConfigManager("core.conf") self.config = ConfigManager('core.conf')
self.rpcserver = component.get("RPCServer") self.rpcserver = component.get('RPCServer')
self.handle = handle self.handle = handle
self.handle.resolve_countries(True) self.handle.resolve_countries(True)
@ -253,7 +253,7 @@ class Torrent(object):
self.state = None self.state = None
self.moving_storage = False self.moving_storage = False
self.moving_storage_dest_path = None self.moving_storage_dest_path = None
self.tracker_status = "" self.tracker_status = ''
self.tracker_host = None self.tracker_host = None
self.forcing_recheck = False self.forcing_recheck = False
self.forcing_recheck_paused = False self.forcing_recheck_paused = False
@ -267,13 +267,13 @@ class Torrent(object):
self.update_state() self.update_state()
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Torrent object created.") log.debug('Torrent object created.')
def on_metadata_received(self): def on_metadata_received(self):
"""Process the metadata received alert for this torrent""" """Process the metadata received alert for this torrent"""
self.has_metadata = True self.has_metadata = True
self.torrent_info = self.handle.get_torrent_info() self.torrent_info = self.handle.get_torrent_info()
if self.options["prioritize_first_last_pieces"]: if self.options['prioritize_first_last_pieces']:
self.set_prioritize_first_last_pieces(True) self.set_prioritize_first_last_pieces(True)
self.write_torrentfile() self.write_torrentfile()
@ -286,13 +286,13 @@ class Torrent(object):
""" """
# set_prioritize_first_last is called by set_file_priorities so only run if not in options # set_prioritize_first_last is called by set_file_priorities so only run if not in options
skip_func = [] skip_func = []
if "file_priorities" in options: if 'file_priorities' in options:
self.options["prioritize_first_last_pieces"] = options["prioritize_first_last_pieces"] self.options['prioritize_first_last_pieces'] = options['prioritize_first_last_pieces']
skip_func.append("prioritize_first_last_pieces") skip_func.append('prioritize_first_last_pieces')
for key, value in options.items(): for key, value in options.items():
if key in self.options: if key in self.options:
options_set_func = getattr(self, "set_" + key, None) options_set_func = getattr(self, 'set_' + key, None)
if options_set_func and key not in skip_func: if options_set_func and key not in skip_func:
options_set_func(value) options_set_func(value)
else: else:
@ -323,7 +323,7 @@ class Torrent(object):
elif max_connections == 1: elif max_connections == 1:
max_connections = 2 max_connections = 2
self.options["max_connections"] = max_connections self.options['max_connections'] = max_connections
self.handle.set_max_connections(max_connections) self.handle.set_max_connections(max_connections)
def set_max_upload_slots(self, max_slots): def set_max_upload_slots(self, max_slots):
@ -332,7 +332,7 @@ class Torrent(object):
Args: Args:
max_slots (int): Maximum upload slots max_slots (int): Maximum upload slots
""" """
self.options["max_upload_slots"] = max_slots self.options['max_upload_slots'] = max_slots
self.handle.set_max_uploads(max_slots) self.handle.set_max_uploads(max_slots)
def set_max_upload_speed(self, m_up_speed): def set_max_upload_speed(self, m_up_speed):
@ -341,7 +341,7 @@ class Torrent(object):
Args: Args:
m_up_speed (float): Maximum upload speed in KiB/s. m_up_speed (float): Maximum upload speed in KiB/s.
""" """
self.options["max_upload_speed"] = m_up_speed self.options['max_upload_speed'] = m_up_speed
if m_up_speed < 0: if m_up_speed < 0:
value = -1 value = -1
else: else:
@ -354,7 +354,7 @@ class Torrent(object):
Args: Args:
m_up_speed (float): Maximum download speed in KiB/s. m_up_speed (float): Maximum download speed in KiB/s.
""" """
self.options["max_download_speed"] = m_down_speed self.options['max_download_speed'] = m_down_speed
if m_down_speed < 0: if m_down_speed < 0:
value = -1 value = -1
else: else:
@ -374,11 +374,11 @@ class Torrent(object):
Returns: Returns:
tuple of lists: The prioritized pieces and the torrent piece priorities. tuple of lists: The prioritized pieces and the torrent piece priorities.
""" """
self.options["prioritize_first_last_pieces"] = prioritize self.options['prioritize_first_last_pieces'] = prioritize
if not prioritize: if not prioritize:
# If we are turning off this option, call set_file_priorities to # If we are turning off this option, call set_file_priorities to
# reset all the piece priorities # reset all the piece priorities
self.set_file_priorities(self.options["file_priorities"]) self.set_file_priorities(self.options['file_priorities'])
return None, None return None, None
if not self.has_metadata: if not self.has_metadata:
return None, None return None, None
@ -414,7 +414,7 @@ class Torrent(object):
Args: Args:
set_sequencial (bool): Enable sequencial downloading. set_sequencial (bool): Enable sequencial downloading.
""" """
self.options["sequential_download"] = set_sequencial self.options['sequential_download'] = set_sequencial
self.handle.set_sequential_download(set_sequencial) self.handle.set_sequential_download(set_sequencial)
def set_auto_managed(self, auto_managed): def set_auto_managed(self, auto_managed):
@ -423,7 +423,7 @@ class Torrent(object):
Args: Args:
auto_managed (bool): Enable auto managed. auto_managed (bool): Enable auto managed.
""" """
self.options["auto_managed"] = auto_managed self.options['auto_managed'] = auto_managed
if not (self.status.paused and not self.status.auto_managed): if not (self.status.paused and not self.status.auto_managed):
self.handle.auto_managed(auto_managed) self.handle.auto_managed(auto_managed)
self.update_state() self.update_state()
@ -435,10 +435,10 @@ class Torrent(object):
super_seeding (bool): Enable super seeding. super_seeding (bool): Enable super seeding.
""" """
if self.status.is_seeding: if self.status.is_seeding:
self.options["super_seeding"] = super_seeding self.options['super_seeding'] = super_seeding
self.handle.super_seeding(super_seeding) self.handle.super_seeding(super_seeding)
else: else:
self.options["super_seeding"] = False self.options['super_seeding'] = False
def set_stop_ratio(self, stop_ratio): def set_stop_ratio(self, stop_ratio):
"""The seeding ratio to stop (or remove) the torrent at. """The seeding ratio to stop (or remove) the torrent at.
@ -446,7 +446,7 @@ class Torrent(object):
Args: Args:
stop_ratio (float): The seeding ratio. stop_ratio (float): The seeding ratio.
""" """
self.options["stop_ratio"] = stop_ratio self.options['stop_ratio'] = stop_ratio
def set_stop_at_ratio(self, stop_at_ratio): def set_stop_at_ratio(self, stop_at_ratio):
"""Stop the torrent when it has reached stop_ratio. """Stop the torrent when it has reached stop_ratio.
@ -454,7 +454,7 @@ class Torrent(object):
Args: Args:
stop_at_ratio (bool): Stop the torrent. stop_at_ratio (bool): Stop the torrent.
""" """
self.options["stop_at_ratio"] = stop_at_ratio self.options['stop_at_ratio'] = stop_at_ratio
def set_remove_at_ratio(self, remove_at_ratio): def set_remove_at_ratio(self, remove_at_ratio):
"""Remove the torrent when it has reached the stop_ratio. """Remove the torrent when it has reached the stop_ratio.
@ -462,7 +462,7 @@ class Torrent(object):
Args: Args:
remove_at_ratio (bool): Remove the torrent. remove_at_ratio (bool): Remove the torrent.
""" """
self.options["remove_at_ratio"] = remove_at_ratio self.options['remove_at_ratio'] = remove_at_ratio
def set_move_completed(self, move_completed): def set_move_completed(self, move_completed):
"""Set whether to move the torrent when downloading has finished. """Set whether to move the torrent when downloading has finished.
@ -471,7 +471,7 @@ class Torrent(object):
move_completed (bool): Move the torrent. move_completed (bool): Move the torrent.
""" """
self.options["move_completed"] = move_completed self.options['move_completed'] = move_completed
def set_move_completed_path(self, move_completed_path): def set_move_completed_path(self, move_completed_path):
"""Set the path to move torrent to when downloading has finished. """Set the path to move torrent to when downloading has finished.
@ -479,7 +479,7 @@ class Torrent(object):
Args: Args:
move_completed_path (str): The move path. move_completed_path (str): The move path.
""" """
self.options["move_completed_path"] = move_completed_path self.options['move_completed_path'] = move_completed_path
def set_file_priorities(self, file_priorities): def set_file_priorities(self, file_priorities):
"""Sets the file priotities. """Sets the file priotities.
@ -490,8 +490,8 @@ class Torrent(object):
if not self.has_metadata: if not self.has_metadata:
return return
if len(file_priorities) != self.torrent_info.num_files(): if len(file_priorities) != self.torrent_info.num_files():
log.debug("file_priorities len != num_files") log.debug('file_priorities len != num_files')
self.options["file_priorities"] = self.handle.file_priorities() self.options['file_priorities'] = self.handle.file_priorities()
return return
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
@ -499,10 +499,10 @@ class Torrent(object):
self.handle.prioritize_files(file_priorities) self.handle.prioritize_files(file_priorities)
if 0 in self.options["file_priorities"]: if 0 in self.options['file_priorities']:
# We have previously marked a file 'Do Not Download' # We have previously marked a file 'Do Not Download'
# Check to see if we have changed any 0's to >0 and change state accordingly # Check to see if we have changed any 0's to >0 and change state accordingly
for index, priority in enumerate(self.options["file_priorities"]): for index, priority in enumerate(self.options['file_priorities']):
if priority == 0 and file_priorities[index] > 0: if priority == 0 and file_priorities[index] > 0:
# We have a changed 'Do Not Download' to a download priority # We have a changed 'Do Not Download' to a download priority
self.is_finished = False self.is_finished = False
@ -511,11 +511,11 @@ class Torrent(object):
# In case values in file_priorities were faulty (old state?) # In case values in file_priorities were faulty (old state?)
# we make sure the stored options are in sync # we make sure the stored options are in sync
self.options["file_priorities"] = self.handle.file_priorities() self.options['file_priorities'] = self.handle.file_priorities()
# Set the first/last priorities if needed # Set the first/last priorities if needed
if self.options["prioritize_first_last_pieces"]: if self.options['prioritize_first_last_pieces']:
self.set_prioritize_first_last_pieces(self.options["prioritize_first_last_pieces"]) self.set_prioritize_first_last_pieces(self.options['prioritize_first_last_pieces'])
def set_save_path(self, download_location): def set_save_path(self, download_location):
"""Deprecated, use set_download_location.""" """Deprecated, use set_download_location."""
@ -523,7 +523,7 @@ class Torrent(object):
def set_download_location(self, download_location): def set_download_location(self, download_location):
"""The location for downloading torrent data.""" """The location for downloading torrent data."""
self.options["download_location"] = download_location self.options['download_location'] = download_location
def set_priority(self, priority): def set_priority(self, priority):
"""Sets the bandwidth priority of this torrent. """Sets the bandwidth priority of this torrent.
@ -537,10 +537,10 @@ class Torrent(object):
ValueError: If value of priority is not in range [0..255] ValueError: If value of priority is not in range [0..255]
""" """
if 0 <= priority <= 255: if 0 <= priority <= 255:
self.options["priority"] = priority self.options['priority'] = priority
return self.handle.set_priority(priority) return self.handle.set_priority(priority)
else: else:
raise ValueError("Torrent priority, %s, is invalid, should be [0..255]", priority) raise ValueError('Torrent priority, %s, is invalid, should be [0..255]', priority)
def set_owner(self, account): def set_owner(self, account):
"""Sets the owner of this torrent. """Sets the owner of this torrent.
@ -548,7 +548,7 @@ class Torrent(object):
Only a user with admin level auth can change this value. Only a user with admin level auth can change this value.
""" """
if self.rpcserver.get_session_auth_level() == AUTH_LEVEL_ADMIN: if self.rpcserver.get_session_auth_level() == AUTH_LEVEL_ADMIN:
self.options["owner"] = account self.options['owner'] = account
# End Options methods # # End Options methods #
@ -564,21 +564,21 @@ class Torrent(object):
return return
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Setting trackers for %s: %s", self.torrent_id, trackers) log.debug('Setting trackers for %s: %s', self.torrent_id, trackers)
tracker_list = [] tracker_list = []
for tracker in trackers: for tracker in trackers:
new_entry = lt.announce_entry(str(tracker["url"])) new_entry = lt.announce_entry(str(tracker['url']))
new_entry.tier = tracker["tier"] new_entry.tier = tracker['tier']
tracker_list.append(new_entry) tracker_list.append(new_entry)
self.handle.replace_trackers(tracker_list) self.handle.replace_trackers(tracker_list)
# Print out the trackers # Print out the trackers
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Trackers set for %s:", self.torrent_id) log.debug('Trackers set for %s:', self.torrent_id)
for tracker in self.handle.trackers(): for tracker in self.handle.trackers():
log.debug(" [tier %s]: %s", tracker["tier"], tracker["url"]) log.debug(' [tier %s]: %s', tracker['tier'], tracker['url'])
# Set the tracker list in the torrent object # Set the tracker list in the torrent object
self.trackers = trackers self.trackers = trackers
if len(trackers) > 0: if len(trackers) > 0:
@ -601,26 +601,26 @@ class Torrent(object):
if self.tracker_status != status: if self.tracker_status != status:
self.tracker_status = status self.tracker_status = status
component.get("EventManager").emit(TorrentTrackerStatusEvent(self.torrent_id, self.tracker_status)) component.get('EventManager').emit(TorrentTrackerStatusEvent(self.torrent_id, self.tracker_status))
def merge_trackers(self, torrent_info): def merge_trackers(self, torrent_info):
"""Merges new trackers in torrent_info into torrent""" """Merges new trackers in torrent_info into torrent"""
log.info("Adding any new trackers to torrent (%s) already in session...", self.torrent_id) log.info('Adding any new trackers to torrent (%s) already in session...', self.torrent_id)
if not torrent_info: if not torrent_info:
return return
# Don't merge trackers if either torrent has private flag set. # Don't merge trackers if either torrent has private flag set.
if torrent_info.priv() or self.get_status(["private"])["private"]: if torrent_info.priv() or self.get_status(['private'])['private']:
log.info("Adding trackers aborted: Torrent has private flag set.") log.info('Adding trackers aborted: Torrent has private flag set.')
else: else:
for tracker in torrent_info.trackers(): for tracker in torrent_info.trackers():
self.handle.add_tracker({"url": tracker.url, "tier": tracker.tier}) self.handle.add_tracker({'url': tracker.url, 'tier': tracker.tier})
# Update torrent.trackers from libtorrent handle. # Update torrent.trackers from libtorrent handle.
self.set_trackers() self.set_trackers()
def update_state(self): def update_state(self):
"""Updates the state, based on libtorrent's torrent state""" """Updates the state, based on libtorrent's torrent state"""
status = self.handle.status() status = self.handle.status()
session_paused = component.get("Core").session.is_paused() session_paused = component.get('Core').session.is_paused()
old_state = self.state old_state = self.state
self.set_status_message() self.set_status_message()
try: try:
@ -630,30 +630,30 @@ class Torrent(object):
status_error = status.error status_error = status.error
if self.forced_error: if self.forced_error:
self.state = "Error" self.state = 'Error'
self.set_status_message(self.forced_error.error_message) self.set_status_message(self.forced_error.error_message)
elif status_error: elif status_error:
self.state = "Error" self.state = 'Error'
# auto-manage status will be reverted upon resuming. # auto-manage status will be reverted upon resuming.
self.handle.auto_managed(False) self.handle.auto_managed(False)
self.set_status_message(decode_string(status_error)) self.set_status_message(decode_string(status_error))
elif self.moving_storage: elif self.moving_storage:
self.state = "Moving" self.state = 'Moving'
elif not session_paused and status.paused and status.auto_managed: elif not session_paused and status.paused and status.auto_managed:
self.state = "Queued" self.state = 'Queued'
elif session_paused or status.paused: elif session_paused or status.paused:
self.state = "Paused" self.state = 'Paused'
else: else:
self.state = LT_TORRENT_STATE_MAP.get(str(status.state), str(status.state)) self.state = LT_TORRENT_STATE_MAP.get(str(status.state), str(status.state))
if self.state != old_state: if self.state != old_state:
component.get("EventManager").emit(TorrentStateChangedEvent(self.torrent_id, self.state)) component.get('EventManager').emit(TorrentStateChangedEvent(self.torrent_id, self.state))
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("State from lt was: %s | Session is paused: %s\nTorrent state set from '%s' to '%s' (%s)", log.debug("State from lt was: %s | Session is paused: %s\nTorrent state set from '%s' to '%s' (%s)",
"error" if status_error else status.state, session_paused, old_state, self.state, self.torrent_id) 'error' if status_error else status.state, session_paused, old_state, self.state, self.torrent_id)
if self.forced_error: if self.forced_error:
log.debug("Torrent Error state message: %s", self.forced_error.error_message) log.debug('Torrent Error state message: %s', self.forced_error.error_message)
def set_status_message(self, message=None): def set_status_message(self, message=None):
"""Sets the torrent status message. """Sets the torrent status message.
@ -665,7 +665,7 @@ class Torrent(object):
""" """
if not message: if not message:
message = "OK" message = 'OK'
self.statusmsg = message self.statusmsg = message
def force_error_state(self, message, restart_to_resume=True): def force_error_state(self, message, restart_to_resume=True):
@ -690,12 +690,12 @@ class Torrent(object):
return return
if self.forced_error.restart_to_resume: if self.forced_error.restart_to_resume:
log.error("Restart deluge to clear this torrent error") log.error('Restart deluge to clear this torrent error')
if not self.forced_error.was_paused and self.options["auto_managed"]: if not self.forced_error.was_paused and self.options['auto_managed']:
self.handle.auto_managed(True) self.handle.auto_managed(True)
self.forced_error = None self.forced_error = None
self.set_status_message("OK") self.set_status_message('OK')
if update_state: if update_state:
self.update_state() self.update_state()
@ -708,9 +708,9 @@ class Torrent(object):
""" """
status = self.status status = self.status
eta = 0 eta = 0
if self.is_finished and self.options["stop_at_ratio"] and status.upload_payload_rate: if self.is_finished and self.options['stop_at_ratio'] and status.upload_payload_rate:
# We're a seed, so calculate the time to the 'stop_share_ratio' # We're a seed, so calculate the time to the 'stop_share_ratio'
eta = ((status.all_time_download * self.options["stop_ratio"]) - eta = ((status.all_time_download * self.options['stop_ratio']) -
status.all_time_upload) // status.upload_payload_rate status.all_time_upload) // status.upload_payload_rate
elif status.download_payload_rate: elif status.download_payload_rate:
left = status.total_wanted - status.total_wanted_done left = status.total_wanted - status.total_wanted_done
@ -788,20 +788,20 @@ class Torrent(object):
client = decode_string(peer.client) client = decode_string(peer.client)
try: try:
country = component.get("Core").geoip_instance.country_code_by_addr(peer.ip[0]) country = component.get('Core').geoip_instance.country_code_by_addr(peer.ip[0])
except AttributeError: except AttributeError:
country = "" country = ''
else: else:
country = "".join([char if char.isalpha() else " " for char in country]) country = ''.join([char if char.isalpha() else ' ' for char in country])
ret.append({ ret.append({
"client": client, 'client': client,
"country": country, 'country': country,
"down_speed": peer.payload_down_speed, 'down_speed': peer.payload_down_speed,
"ip": "%s:%s" % (peer.ip[0], peer.ip[1]), 'ip': '%s:%s' % (peer.ip[0], peer.ip[1]),
"progress": peer.progress, 'progress': peer.progress,
"seed": peer.flags & peer.seed, 'seed': peer.flags & peer.seed,
"up_speed": peer.payload_up_speed, 'up_speed': peer.payload_up_speed,
}) })
return ret return ret
@ -838,12 +838,12 @@ class Torrent(object):
tracker = self.status.current_tracker tracker = self.status.current_tracker
if not tracker and self.trackers: if not tracker and self.trackers:
tracker = self.trackers[0]["url"] tracker = self.trackers[0]['url']
if tracker: if tracker:
url = urlparse(tracker.replace("udp://", "http://")) url = urlparse(tracker.replace('udp://', 'http://'))
if hasattr(url, "hostname"): if hasattr(url, 'hostname'):
host = (url.hostname or "DHT") host = (url.hostname or 'DHT')
# Check if hostname is an IP address and just return it if that's the case # Check if hostname is an IP address and just return it if that's the case
try: try:
socket.inet_aton(host) socket.inet_aton(host)
@ -853,15 +853,15 @@ class Torrent(object):
# This is an IP address because an exception wasn't raised # This is an IP address because an exception wasn't raised
return url.hostname return url.hostname
parts = host.split(".") parts = host.split('.')
if len(parts) > 2: if len(parts) > 2:
if parts[-2] in ("co", "com", "net", "org") or parts[-1] == "uk": if parts[-2] in ('co', 'com', 'net', 'org') or parts[-1] == 'uk':
host = ".".join(parts[-3:]) host = '.'.join(parts[-3:])
else: else:
host = ".".join(parts[-2:]) host = '.'.join(parts[-2:])
self.tracker_host = host self.tracker_host = host
return host return host
return "" return ''
def get_magnet_uri(self): def get_magnet_uri(self):
"""Returns a magnet uri for this torrent""" """Returns a magnet uri for this torrent"""
@ -878,14 +878,14 @@ class Torrent(object):
str: the name of the torrent. str: the name of the torrent.
""" """
if not self.options["name"]: if not self.options['name']:
handle_name = self.handle.name() handle_name = self.handle.name()
if handle_name: if handle_name:
name = decode_string(handle_name) name = decode_string(handle_name)
else: else:
name = self.torrent_id name = self.torrent_id
else: else:
name = self.options["name"] name = self.options['name']
return name return name
@ -902,12 +902,12 @@ class Torrent(object):
files = [os.path.join(path, f) for f in files] files = [os.path.join(path, f) for f in files]
return sum(os.stat(f).st_size for f in files if os.path.exists(f)) return sum(os.stat(f).st_size for f in files if os.path.exists(f))
if self.state == "Error": if self.state == 'Error':
progress = 100.0 progress = 100.0
elif self.moving_storage: elif self.moving_storage:
# Check if torrent has downloaded any data yet. # Check if torrent has downloaded any data yet.
if self.status.total_done: if self.status.total_done:
torrent_files = [f["path"] for f in self.get_files()] torrent_files = [f['path'] for f in self.get_files()]
dest_path_size = get_size(torrent_files, self.moving_storage_dest_path) dest_path_size = get_size(torrent_files, self.moving_storage_dest_path)
progress = dest_path_size / self.status.total_done * 100 progress = dest_path_size / self.status.total_done * 100
else: else:
@ -972,81 +972,81 @@ class Torrent(object):
def _create_status_funcs(self): def _create_status_funcs(self):
"""Creates the functions for getting torrent status""" """Creates the functions for getting torrent status"""
self.status_funcs = { self.status_funcs = {
"active_time": lambda: self.status.active_time, 'active_time': lambda: self.status.active_time,
"seeding_time": lambda: self.status.seeding_time, 'seeding_time': lambda: self.status.seeding_time,
"finished_time": lambda: self.status.finished_time, 'finished_time': lambda: self.status.finished_time,
"all_time_download": lambda: self.status.all_time_download, 'all_time_download': lambda: self.status.all_time_download,
"storage_mode": lambda: self.status.storage_mode.name.split("_")[2], # sparse or allocate 'storage_mode': lambda: self.status.storage_mode.name.split('_')[2], # sparse or allocate
"distributed_copies": lambda: max(0.0, self.status.distributed_copies), 'distributed_copies': lambda: max(0.0, self.status.distributed_copies),
"download_payload_rate": lambda: self.status.download_payload_rate, 'download_payload_rate': lambda: self.status.download_payload_rate,
"file_priorities": lambda: self.options["file_priorities"], 'file_priorities': lambda: self.options['file_priorities'],
"hash": lambda: self.torrent_id, 'hash': lambda: self.torrent_id,
"is_auto_managed": lambda: self.options["auto_managed"], 'is_auto_managed': lambda: self.options['auto_managed'],
"is_finished": lambda: self.is_finished, 'is_finished': lambda: self.is_finished,
"max_connections": lambda: self.options["max_connections"], 'max_connections': lambda: self.options['max_connections'],
"max_download_speed": lambda: self.options["max_download_speed"], 'max_download_speed': lambda: self.options['max_download_speed'],
"max_upload_slots": lambda: self.options["max_upload_slots"], 'max_upload_slots': lambda: self.options['max_upload_slots'],
"max_upload_speed": lambda: self.options["max_upload_speed"], 'max_upload_speed': lambda: self.options['max_upload_speed'],
"message": lambda: self.statusmsg, 'message': lambda: self.statusmsg,
"move_on_completed_path": lambda: self.options["move_completed_path"], # Depr, use move_completed_path 'move_on_completed_path': lambda: self.options['move_completed_path'], # Depr, use move_completed_path
"move_on_completed": lambda: self.options["move_completed"], # Deprecated, use move_completed 'move_on_completed': lambda: self.options['move_completed'], # Deprecated, use move_completed
"move_completed_path": lambda: self.options["move_completed_path"], 'move_completed_path': lambda: self.options['move_completed_path'],
"move_completed": lambda: self.options["move_completed"], 'move_completed': lambda: self.options['move_completed'],
"next_announce": lambda: self.status.next_announce.seconds, 'next_announce': lambda: self.status.next_announce.seconds,
"num_peers": lambda: self.status.num_peers - self.status.num_seeds, 'num_peers': lambda: self.status.num_peers - self.status.num_seeds,
"num_seeds": lambda: self.status.num_seeds, 'num_seeds': lambda: self.status.num_seeds,
"owner": lambda: self.options["owner"], 'owner': lambda: self.options['owner'],
"paused": lambda: self.status.paused, 'paused': lambda: self.status.paused,
"prioritize_first_last": lambda: self.options["prioritize_first_last_pieces"], 'prioritize_first_last': lambda: self.options['prioritize_first_last_pieces'],
"sequential_download": lambda: self.options["sequential_download"], 'sequential_download': lambda: self.options['sequential_download'],
"progress": self.get_progress, 'progress': self.get_progress,
"shared": lambda: self.options["shared"], 'shared': lambda: self.options['shared'],
"remove_at_ratio": lambda: self.options["remove_at_ratio"], 'remove_at_ratio': lambda: self.options['remove_at_ratio'],
"save_path": lambda: self.options["download_location"], # Deprecated, use download_location 'save_path': lambda: self.options['download_location'], # Deprecated, use download_location
"download_location": lambda: self.options["download_location"], 'download_location': lambda: self.options['download_location'],
"seeds_peers_ratio": lambda: -1.0 if self.status.num_incomplete == 0 else ( # Use -1.0 to signify infinity 'seeds_peers_ratio': lambda: -1.0 if self.status.num_incomplete == 0 else ( # Use -1.0 to signify infinity
self.status.num_complete / self.status.num_incomplete), self.status.num_complete / self.status.num_incomplete),
"seed_rank": lambda: self.status.seed_rank, 'seed_rank': lambda: self.status.seed_rank,
"state": lambda: self.state, 'state': lambda: self.state,
"stop_at_ratio": lambda: self.options["stop_at_ratio"], 'stop_at_ratio': lambda: self.options['stop_at_ratio'],
"stop_ratio": lambda: self.options["stop_ratio"], 'stop_ratio': lambda: self.options['stop_ratio'],
"time_added": lambda: self.status.added_time, 'time_added': lambda: self.status.added_time,
"total_done": lambda: self.status.total_done, 'total_done': lambda: self.status.total_done,
"total_payload_download": lambda: self.status.total_payload_download, 'total_payload_download': lambda: self.status.total_payload_download,
"total_payload_upload": lambda: self.status.total_payload_upload, 'total_payload_upload': lambda: self.status.total_payload_upload,
"total_peers": lambda: self.status.num_incomplete, 'total_peers': lambda: self.status.num_incomplete,
"total_seeds": lambda: self.status.num_complete, 'total_seeds': lambda: self.status.num_complete,
"total_uploaded": lambda: self.status.all_time_upload, 'total_uploaded': lambda: self.status.all_time_upload,
"total_wanted": lambda: self.status.total_wanted, 'total_wanted': lambda: self.status.total_wanted,
"total_remaining": lambda: self.status.total_wanted - self.status.total_wanted_done, 'total_remaining': lambda: self.status.total_wanted - self.status.total_wanted_done,
"tracker": lambda: self.status.current_tracker, 'tracker': lambda: self.status.current_tracker,
"tracker_host": self.get_tracker_host, 'tracker_host': self.get_tracker_host,
"trackers": lambda: self.trackers, 'trackers': lambda: self.trackers,
"tracker_status": lambda: self.tracker_status, 'tracker_status': lambda: self.tracker_status,
"upload_payload_rate": lambda: self.status.upload_payload_rate, 'upload_payload_rate': lambda: self.status.upload_payload_rate,
"comment": lambda: decode_string(self.torrent_info.comment()) if self.has_metadata else "", 'comment': lambda: decode_string(self.torrent_info.comment()) if self.has_metadata else '',
"num_files": lambda: self.torrent_info.num_files() if self.has_metadata else 0, 'num_files': lambda: self.torrent_info.num_files() if self.has_metadata else 0,
"num_pieces": lambda: self.torrent_info.num_pieces() if self.has_metadata else 0, 'num_pieces': lambda: self.torrent_info.num_pieces() if self.has_metadata else 0,
"piece_length": lambda: self.torrent_info.piece_length() if self.has_metadata else 0, 'piece_length': lambda: self.torrent_info.piece_length() if self.has_metadata else 0,
"private": lambda: self.torrent_info.priv() if self.has_metadata else False, 'private': lambda: self.torrent_info.priv() if self.has_metadata else False,
"total_size": lambda: self.torrent_info.total_size() if self.has_metadata else 0, 'total_size': lambda: self.torrent_info.total_size() if self.has_metadata else 0,
"eta": self.get_eta, 'eta': self.get_eta,
"file_progress": self.get_file_progress, 'file_progress': self.get_file_progress,
"files": self.get_files, 'files': self.get_files,
"orig_files": self.get_orig_files, 'orig_files': self.get_orig_files,
"is_seed": lambda: self.status.is_seeding, 'is_seed': lambda: self.status.is_seeding,
"peers": self.get_peers, 'peers': self.get_peers,
"queue": lambda: self.status.queue_position, 'queue': lambda: self.status.queue_position,
"ratio": self.get_ratio, 'ratio': self.get_ratio,
"completed_time": lambda: self.status.completed_time, 'completed_time': lambda: self.status.completed_time,
"last_seen_complete": lambda: self.status.last_seen_complete, 'last_seen_complete': lambda: self.status.last_seen_complete,
"name": self.get_name, 'name': self.get_name,
"pieces": self._get_pieces_info, 'pieces': self._get_pieces_info,
"seed_mode": lambda: self.status.seed_mode, 'seed_mode': lambda: self.status.seed_mode,
"super_seeding": lambda: self.status.super_seeding, 'super_seeding': lambda: self.status.super_seeding,
"time_since_download": lambda: self.status.time_since_download, 'time_since_download': lambda: self.status.time_since_download,
"time_since_upload": lambda: self.status.time_since_upload, 'time_since_upload': lambda: self.status.time_since_upload,
"priority": lambda: self.status.priority, 'priority': lambda: self.status.priority,
} }
def pause(self): def pause(self):
@ -1058,7 +1058,7 @@ class Torrent(object):
""" """
# Turn off auto-management so the torrent will not be unpaused by lt queueing # Turn off auto-management so the torrent will not be unpaused by lt queueing
self.handle.auto_managed(False) self.handle.auto_managed(False)
if self.state == "Error": if self.state == 'Error':
return False return False
elif self.status.paused: elif self.status.paused:
# This torrent was probably paused due to being auto managed by lt # This torrent was probably paused due to being auto managed by lt
@ -1066,37 +1066,37 @@ class Torrent(object):
# show it as 'Paused'. We need to emit a torrent_paused signal because # show it as 'Paused'. We need to emit a torrent_paused signal because
# the torrent_paused alert from libtorrent will not be generated. # the torrent_paused alert from libtorrent will not be generated.
self.update_state() self.update_state()
component.get("EventManager").emit(TorrentStateChangedEvent(self.torrent_id, "Paused")) component.get('EventManager').emit(TorrentStateChangedEvent(self.torrent_id, 'Paused'))
else: else:
try: try:
self.handle.pause() self.handle.pause()
except RuntimeError as ex: except RuntimeError as ex:
log.debug("Unable to pause torrent: %s", ex) log.debug('Unable to pause torrent: %s', ex)
return False return False
return True return True
def resume(self): def resume(self):
"""Resumes this torrent.""" """Resumes this torrent."""
if self.status.paused and self.status.auto_managed: if self.status.paused and self.status.auto_managed:
log.debug("Resume not possible for auto-managed torrent!") log.debug('Resume not possible for auto-managed torrent!')
elif self.forced_error and self.forced_error.was_paused: elif self.forced_error and self.forced_error.was_paused:
log.debug("Resume skipped for error'd torrent as it was originally paused.") log.debug("Resume skipped for error'd torrent as it was originally paused.")
elif (self.status.is_finished and self.options["stop_at_ratio"] and elif (self.status.is_finished and self.options['stop_at_ratio'] and
self.get_ratio() >= self.options["stop_ratio"]): self.get_ratio() >= self.options['stop_ratio']):
log.debug("Resume skipped for torrent as it has reached 'stop_seed_ratio'.") log.debug("Resume skipped for torrent as it has reached 'stop_seed_ratio'.")
else: else:
# Check if torrent was originally being auto-managed. # Check if torrent was originally being auto-managed.
if self.options["auto_managed"]: if self.options['auto_managed']:
self.handle.auto_managed(True) self.handle.auto_managed(True)
try: try:
self.handle.resume() self.handle.resume()
except RuntimeError as ex: except RuntimeError as ex:
log.debug("Unable to resume torrent: %s", ex) log.debug('Unable to resume torrent: %s', ex)
# Clear torrent error state. # Clear torrent error state.
if self.forced_error and not self.forced_error.restart_to_resume: if self.forced_error and not self.forced_error.restart_to_resume:
self.clear_forced_error_state() self.clear_forced_error_state()
elif self.state == "Error" and not self.forced_error: elif self.state == 'Error' and not self.forced_error:
self.handle.clear_error() self.handle.clear_error()
def connect_peer(self, peer_ip, peer_port): def connect_peer(self, peer_ip, peer_port):
@ -1112,7 +1112,7 @@ class Torrent(object):
try: try:
self.handle.connect_peer((peer_ip, peer_port), 0) self.handle.connect_peer((peer_ip, peer_port), 0)
except RuntimeError as ex: except RuntimeError as ex:
log.debug("Unable to connect to peer: %s", ex) log.debug('Unable to connect to peer: %s', ex)
return False return False
return True return True
@ -1132,8 +1132,8 @@ class Torrent(object):
try: try:
os.makedirs(dest) os.makedirs(dest)
except OSError as ex: except OSError as ex:
log.error("Could not move storage for torrent %s since %s does " log.error('Could not move storage for torrent %s since %s does '
"not exist and could not create the directory: %s", 'not exist and could not create the directory: %s',
self.torrent_id, dest, ex) self.torrent_id, dest, ex)
return False return False
@ -1145,7 +1145,7 @@ class Torrent(object):
except TypeError: except TypeError:
self.handle.move_storage(utf8_encoded(dest), flags=1) self.handle.move_storage(utf8_encoded(dest), flags=1)
except RuntimeError as ex: except RuntimeError as ex:
log.error("Error calling libtorrent move_storage: %s", ex) log.error('Error calling libtorrent move_storage: %s', ex)
return False return False
self.moving_storage = True self.moving_storage = True
self.moving_storage_dest_path = dest self.moving_storage_dest_path = dest
@ -1164,12 +1164,12 @@ class Torrent(object):
""" """
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Requesting save_resume_data for torrent: %s", self.torrent_id) log.debug('Requesting save_resume_data for torrent: %s', self.torrent_id)
flags = lt.save_resume_flags_t.flush_disk_cache if flush_disk_cache else 0 flags = lt.save_resume_flags_t.flush_disk_cache if flush_disk_cache else 0
# Don't generate fastresume data if torrent is in a Deluge Error state. # Don't generate fastresume data if torrent is in a Deluge Error state.
if self.forced_error: if self.forced_error:
component.get("TorrentManager").waiting_on_resume_data[self.torrent_id].errback( component.get('TorrentManager').waiting_on_resume_data[self.torrent_id].errback(
UserWarning("Skipped creating resume_data while in Error state")) UserWarning('Skipped creating resume_data while in Error state'))
else: else:
self.handle.save_resume_data(flags) self.handle.save_resume_data(flags)
@ -1183,48 +1183,48 @@ class Torrent(object):
def write_file(filepath, filedump): def write_file(filepath, filedump):
"""Write out the torrent file""" """Write out the torrent file"""
log.debug("Writing torrent file to: %s", filepath) log.debug('Writing torrent file to: %s', filepath)
try: try:
with open(filepath, "wb") as save_file: with open(filepath, 'wb') as save_file:
save_file.write(filedump) save_file.write(filedump)
except IOError as ex: except IOError as ex:
log.error("Unable to save torrent file to: %s", ex) log.error('Unable to save torrent file to: %s', ex)
filepath = os.path.join(get_config_dir(), "state", self.torrent_id + ".torrent") filepath = os.path.join(get_config_dir(), 'state', self.torrent_id + '.torrent')
# Regenerate the file priorities # Regenerate the file priorities
self.set_file_priorities([]) self.set_file_priorities([])
if filedump is None: if filedump is None:
metadata = lt.bdecode(self.torrent_info.metadata()) metadata = lt.bdecode(self.torrent_info.metadata())
torrent_file = {"info": metadata} torrent_file = {'info': metadata}
filedump = lt.bencode(torrent_file) filedump = lt.bencode(torrent_file)
write_file(filepath, filedump) write_file(filepath, filedump)
# If the user has requested a copy of the torrent be saved elsewhere we need to do that. # If the user has requested a copy of the torrent be saved elsewhere we need to do that.
if self.config["copy_torrent_file"]: if self.config['copy_torrent_file']:
if not self.filename: if not self.filename:
self.filename = self.get_name() + ".torrent" self.filename = self.get_name() + '.torrent'
filepath = os.path.join(self.config["torrentfiles_location"], self.filename) filepath = os.path.join(self.config['torrentfiles_location'], self.filename)
write_file(filepath, filedump) write_file(filepath, filedump)
def delete_torrentfile(self, delete_copies=False): def delete_torrentfile(self, delete_copies=False):
"""Deletes the .torrent file in the state directory in config""" """Deletes the .torrent file in the state directory in config"""
torrent_files = [os.path.join(get_config_dir(), "state", self.torrent_id + ".torrent")] torrent_files = [os.path.join(get_config_dir(), 'state', self.torrent_id + '.torrent')]
if delete_copies: if delete_copies:
torrent_files.append(os.path.join(self.config["torrentfiles_location"], self.filename)) torrent_files.append(os.path.join(self.config['torrentfiles_location'], self.filename))
for torrent_file in torrent_files: for torrent_file in torrent_files:
log.debug("Deleting torrent file: %s", torrent_file) log.debug('Deleting torrent file: %s', torrent_file)
try: try:
os.remove(torrent_file) os.remove(torrent_file)
except OSError as ex: except OSError as ex:
log.warning("Unable to delete the torrent file: %s", ex) log.warning('Unable to delete the torrent file: %s', ex)
def force_reannounce(self): def force_reannounce(self):
"""Force a tracker reannounce""" """Force a tracker reannounce"""
try: try:
self.handle.force_reannounce() self.handle.force_reannounce()
except RuntimeError as ex: except RuntimeError as ex:
log.debug("Unable to force reannounce: %s", ex) log.debug('Unable to force reannounce: %s', ex)
return False return False
return True return True
@ -1237,7 +1237,7 @@ class Torrent(object):
try: try:
self.handle.scrape_tracker() self.handle.scrape_tracker()
except RuntimeError as ex: except RuntimeError as ex:
log.debug("Unable to scrape tracker: %s", ex) log.debug('Unable to scrape tracker: %s', ex)
return False return False
return True return True
@ -1254,7 +1254,7 @@ class Torrent(object):
self.handle.resume() self.handle.resume()
self.forcing_recheck = True self.forcing_recheck = True
except RuntimeError as ex: except RuntimeError as ex:
log.debug("Unable to force recheck: %s", ex) log.debug('Unable to force recheck: %s', ex)
self.forcing_recheck = False self.forcing_recheck = False
return self.forcing_recheck return self.forcing_recheck
@ -1285,7 +1285,7 @@ class Torrent(object):
Returns: Returns:
twisted.internet.defer.Deferred: A deferred which fires when the rename is complete twisted.internet.defer.Deferred: A deferred which fires when the rename is complete
""" """
log.debug("Attempting to rename folder: %s to %s", folder, new_folder) log.debug('Attempting to rename folder: %s to %s', folder, new_folder)
# Empty string means remove the dir and move its content to the parent # Empty string means remove the dir and move its content to the parent
if len(new_folder) > 0: if len(new_folder) > 0:
@ -1298,24 +1298,24 @@ class Torrent(object):
wait_on_folder = {} wait_on_folder = {}
self.waiting_on_folder_rename.append(wait_on_folder) self.waiting_on_folder_rename.append(wait_on_folder)
for _file in self.get_files(): for _file in self.get_files():
if _file["path"].startswith(folder): if _file['path'].startswith(folder):
# Keep track of filerenames we're waiting on # Keep track of filerenames we're waiting on
wait_on_folder[_file["index"]] = Deferred().addBoth( wait_on_folder[_file['index']] = Deferred().addBoth(
on_file_rename_complete, wait_on_folder, _file["index"] on_file_rename_complete, wait_on_folder, _file['index']
) )
new_path = _file["path"].replace(folder, new_folder, 1) new_path = _file['path'].replace(folder, new_folder, 1)
try: try:
self.handle.rename_file(_file["index"], new_path) self.handle.rename_file(_file['index'], new_path)
except TypeError: except TypeError:
self.handle.rename_file(_file["index"], utf8_encoded(new_path)) self.handle.rename_file(_file['index'], utf8_encoded(new_path))
def on_folder_rename_complete(dummy_result, torrent, folder, new_folder): def on_folder_rename_complete(dummy_result, torrent, folder, new_folder):
"""Folder rename complete""" """Folder rename complete"""
component.get("EventManager").emit(TorrentFolderRenamedEvent(torrent.torrent_id, folder, new_folder)) component.get('EventManager').emit(TorrentFolderRenamedEvent(torrent.torrent_id, folder, new_folder))
# Empty folders are removed after libtorrent folder renames # Empty folders are removed after libtorrent folder renames
self.remove_empty_folders(folder) self.remove_empty_folders(folder)
torrent.waiting_on_folder_rename = [_dir for _dir in torrent.waiting_on_folder_rename if _dir] 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,)) component.get('TorrentManager').save_resume_data((self.torrent_id,))
d = DeferredList(wait_on_folder.values()) d = DeferredList(wait_on_folder.values())
d.addBoth(on_folder_rename_complete, self, folder, new_folder) d.addBoth(on_folder_rename_complete, self, folder, new_folder)
@ -1330,24 +1330,24 @@ class Torrent(object):
folder (str): The folder to recursively check folder (str): The folder to recursively check
""" """
# Removes leading slashes that can cause join to ignore download_location # Removes leading slashes that can cause join to ignore download_location
download_location = self.options["download_location"] download_location = self.options['download_location']
folder_full_path = os.path.normpath(os.path.join(download_location, folder.lstrip("\\/"))) folder_full_path = os.path.normpath(os.path.join(download_location, folder.lstrip('\\/')))
try: try:
if not os.listdir(folder_full_path): if not os.listdir(folder_full_path):
os.removedirs(folder_full_path) os.removedirs(folder_full_path)
log.debug("Removed Empty Folder %s", folder_full_path) log.debug('Removed Empty Folder %s', folder_full_path)
else: else:
for root, dirs, dummy_files in os.walk(folder_full_path, topdown=False): for root, dirs, dummy_files in os.walk(folder_full_path, topdown=False):
for name in dirs: for name in dirs:
try: try:
os.removedirs(os.path.join(root, name)) os.removedirs(os.path.join(root, name))
log.debug("Removed Empty Folder %s", os.path.join(root, name)) log.debug('Removed Empty Folder %s', os.path.join(root, name))
except OSError as ex: except OSError as ex:
log.debug(ex) log.debug(ex)
except OSError as ex: except OSError as ex:
log.debug("Cannot Remove Folder: %s", ex) log.debug('Cannot Remove Folder: %s', ex)
def cleanup_prev_status(self): def cleanup_prev_status(self):
"""Checks the validity of the keys in the prev_status dict. """Checks the validity of the keys in the prev_status dict.

View File

@ -46,7 +46,7 @@ class TorrentState: # pylint: disable=old-style-class
torrent_id=None, torrent_id=None,
filename=None, filename=None,
trackers=None, trackers=None,
storage_mode="sparse", storage_mode='sparse',
paused=False, paused=False,
save_path=None, save_path=None,
max_connections=-1, max_connections=-1,
@ -72,7 +72,7 @@ class TorrentState: # pylint: disable=old-style-class
name=None): name=None):
# Build the class atrribute list from args # Build the class atrribute list from args
for key, value in locals().items(): for key, value in locals().items():
if key == "self": if key == 'self':
continue continue
setattr(self, key, value) setattr(self, key, value)
@ -96,21 +96,21 @@ class TorrentManager(component.Component):
""" """
def __init__(self): def __init__(self):
component.Component.__init__(self, "TorrentManager", interval=5, component.Component.__init__(self, 'TorrentManager', interval=5,
depend=["CorePluginManager", "AlertManager"]) depend=['CorePluginManager', 'AlertManager'])
log.debug("TorrentManager init...") log.debug('TorrentManager init...')
# Set the libtorrent session # Set the libtorrent session
self.session = component.get("Core").session self.session = component.get('Core').session
# Set the alertmanager # Set the alertmanager
self.alerts = component.get("AlertManager") self.alerts = component.get('AlertManager')
# Get the core config # Get the core config
self.config = ConfigManager("core.conf") self.config = ConfigManager('core.conf')
# Make sure the state folder has been created # Make sure the state folder has been created
self.state_dir = os.path.join(get_config_dir(), "state") self.state_dir = os.path.join(get_config_dir(), 'state')
if not os.path.exists(self.state_dir): if not os.path.exists(self.state_dir):
os.makedirs(self.state_dir) os.makedirs(self.state_dir)
self.temp_file = os.path.join(self.state_dir, ".safe_state_check") self.temp_file = os.path.join(self.state_dir, '.safe_state_check')
# Create the torrents dict { torrent_id: Torrent } # Create the torrents dict { torrent_id: Torrent }
self.torrents = {} self.torrents = {}
@ -134,38 +134,38 @@ class TorrentManager(component.Component):
self.last_state_update_alert_ts = 0 self.last_state_update_alert_ts = 0
# Register set functions # Register set functions
self.config.register_set_function("max_connections_per_torrent", self.config.register_set_function('max_connections_per_torrent',
self.on_set_max_connections_per_torrent) self.on_set_max_connections_per_torrent)
self.config.register_set_function("max_upload_slots_per_torrent", self.config.register_set_function('max_upload_slots_per_torrent',
self.on_set_max_upload_slots_per_torrent) self.on_set_max_upload_slots_per_torrent)
self.config.register_set_function("max_upload_speed_per_torrent", self.config.register_set_function('max_upload_speed_per_torrent',
self.on_set_max_upload_speed_per_torrent) self.on_set_max_upload_speed_per_torrent)
self.config.register_set_function("max_download_speed_per_torrent", self.config.register_set_function('max_download_speed_per_torrent',
self.on_set_max_download_speed_per_torrent) self.on_set_max_download_speed_per_torrent)
# Register alert functions # Register alert functions
self.alerts.register_handler("torrent_finished_alert", self.on_alert_torrent_finished) self.alerts.register_handler('torrent_finished_alert', self.on_alert_torrent_finished)
self.alerts.register_handler("torrent_paused_alert", self.on_alert_torrent_paused) self.alerts.register_handler('torrent_paused_alert', self.on_alert_torrent_paused)
self.alerts.register_handler("torrent_checked_alert", self.on_alert_torrent_checked) self.alerts.register_handler('torrent_checked_alert', self.on_alert_torrent_checked)
self.alerts.register_handler("tracker_reply_alert", self.on_alert_tracker_reply) self.alerts.register_handler('tracker_reply_alert', self.on_alert_tracker_reply)
self.alerts.register_handler("tracker_announce_alert", self.on_alert_tracker_announce) self.alerts.register_handler('tracker_announce_alert', self.on_alert_tracker_announce)
self.alerts.register_handler("tracker_warning_alert", self.on_alert_tracker_warning) self.alerts.register_handler('tracker_warning_alert', self.on_alert_tracker_warning)
self.alerts.register_handler("tracker_error_alert", self.on_alert_tracker_error) self.alerts.register_handler('tracker_error_alert', self.on_alert_tracker_error)
self.alerts.register_handler("storage_moved_alert", self.on_alert_storage_moved) self.alerts.register_handler('storage_moved_alert', self.on_alert_storage_moved)
self.alerts.register_handler("storage_moved_failed_alert", self.on_alert_storage_moved_failed) self.alerts.register_handler('storage_moved_failed_alert', self.on_alert_storage_moved_failed)
self.alerts.register_handler("torrent_resumed_alert", self.on_alert_torrent_resumed) self.alerts.register_handler('torrent_resumed_alert', self.on_alert_torrent_resumed)
self.alerts.register_handler("state_changed_alert", self.on_alert_state_changed) self.alerts.register_handler('state_changed_alert', self.on_alert_state_changed)
self.alerts.register_handler("save_resume_data_alert", self.on_alert_save_resume_data) self.alerts.register_handler('save_resume_data_alert', self.on_alert_save_resume_data)
self.alerts.register_handler("save_resume_data_failed_alert", self.on_alert_save_resume_data_failed) self.alerts.register_handler('save_resume_data_failed_alert', self.on_alert_save_resume_data_failed)
self.alerts.register_handler("file_renamed_alert", self.on_alert_file_renamed) self.alerts.register_handler('file_renamed_alert', self.on_alert_file_renamed)
self.alerts.register_handler("metadata_received_alert", self.on_alert_metadata_received) self.alerts.register_handler('metadata_received_alert', self.on_alert_metadata_received)
self.alerts.register_handler("file_error_alert", self.on_alert_file_error) self.alerts.register_handler('file_error_alert', self.on_alert_file_error)
self.alerts.register_handler("file_completed_alert", self.on_alert_file_completed) self.alerts.register_handler('file_completed_alert', self.on_alert_file_completed)
self.alerts.register_handler("state_update_alert", self.on_alert_state_update) self.alerts.register_handler('state_update_alert', self.on_alert_state_update)
self.alerts.register_handler("external_ip_alert", self.on_alert_external_ip) self.alerts.register_handler('external_ip_alert', self.on_alert_external_ip)
self.alerts.register_handler("performance_alert", self.on_alert_performance) self.alerts.register_handler('performance_alert', self.on_alert_performance)
self.alerts.register_handler("fastresume_rejected_alert", self.on_alert_fastresume_rejected) self.alerts.register_handler('fastresume_rejected_alert', self.on_alert_fastresume_rejected)
self.alerts.register_handler("add_torrent_alert", self.on_add_torrent_alert) self.alerts.register_handler('add_torrent_alert', self.on_add_torrent_alert)
# Define timers # Define timers
self.save_state_timer = LoopingCall(self.save_state) self.save_state_timer = LoopingCall(self.save_state)
@ -178,24 +178,24 @@ class TorrentManager(component.Component):
def archive_file(filename): def archive_file(filename):
"""Archives the file in 'archive' sub-directory with timestamp appended""" """Archives the file in 'archive' sub-directory with timestamp appended"""
filepath = os.path.join(self.state_dir, filename) filepath = os.path.join(self.state_dir, filename)
filepath_bak = filepath + ".bak" filepath_bak = filepath + '.bak'
archive_dir = os.path.join(get_config_dir(), "archive") archive_dir = os.path.join(get_config_dir(), 'archive')
if not os.path.exists(archive_dir): if not os.path.exists(archive_dir):
os.makedirs(archive_dir) os.makedirs(archive_dir)
for _filepath in (filepath, filepath_bak): for _filepath in (filepath, filepath_bak):
timestamp = datetime.datetime.now().replace(microsecond=0).isoformat().replace(':', '-') timestamp = datetime.datetime.now().replace(microsecond=0).isoformat().replace(':', '-')
archive_filepath = os.path.join(archive_dir, filename + "-" + timestamp) archive_filepath = os.path.join(archive_dir, filename + '-' + timestamp)
try: try:
shutil.copy2(_filepath, archive_filepath) shutil.copy2(_filepath, archive_filepath)
except IOError: except IOError:
log.error("Unable to archive: %s", filename) log.error('Unable to archive: %s', filename)
else: else:
log.info("Archive of %s successful: %s", filename, archive_filepath) log.info('Archive of %s successful: %s', filename, archive_filepath)
log.warning("Potential bad shutdown of Deluge detected, archiving torrent state files...") log.warning('Potential bad shutdown of Deluge detected, archiving torrent state files...')
archive_file("torrents.state") archive_file('torrents.state')
archive_file("torrents.fastresume") archive_file('torrents.fastresume')
else: else:
with open(self.temp_file, 'a'): with open(self.temp_file, 'a'):
os.utime(self.temp_file, None) os.utime(self.temp_file, None)
@ -233,15 +233,15 @@ class TorrentManager(component.Component):
def update(self): def update(self):
for torrent_id, torrent in self.torrents.items(): for torrent_id, torrent in self.torrents.items():
# XXX: Should the state check be those that _can_ be stopped at ratio # XXX: Should the state check be those that _can_ be stopped at ratio
if torrent.options["stop_at_ratio"] and torrent.state not in ( if torrent.options['stop_at_ratio'] and torrent.state not in (
"Checking", "Allocating", "Paused", "Queued"): 'Checking', 'Allocating', 'Paused', 'Queued'):
# If the global setting is set, but the per-torrent isn't... # If the global setting is set, but the per-torrent isn't...
# Just skip to the next torrent. # Just skip to the next torrent.
# This is so that a user can turn-off the stop at ratio option on a per-torrent basis # This is so that a user can turn-off the stop at ratio option on a per-torrent basis
if not torrent.options["stop_at_ratio"]: if not torrent.options['stop_at_ratio']:
continue continue
if torrent.get_ratio() >= torrent.options["stop_ratio"] and torrent.is_finished: if torrent.get_ratio() >= torrent.options['stop_ratio'] and torrent.is_finished:
if torrent.options["remove_at_ratio"]: if torrent.options['remove_at_ratio']:
self.remove(torrent_id) self.remove(torrent_id)
break break
if not torrent.handle.status().paused: if not torrent.handle.status().paused:
@ -267,13 +267,13 @@ class TorrentManager(component.Component):
""" """
torrent_ids = self.torrents.keys() torrent_ids = self.torrents.keys()
if component.get("RPCServer").get_session_auth_level() == AUTH_LEVEL_ADMIN: if component.get('RPCServer').get_session_auth_level() == AUTH_LEVEL_ADMIN:
return torrent_ids return torrent_ids
current_user = component.get("RPCServer").get_session_user() current_user = component.get('RPCServer').get_session_user()
for torrent_id in torrent_ids[:]: for torrent_id in torrent_ids[:]:
torrent_status = self.torrents[torrent_id].get_status(["owner", "shared"]) torrent_status = self.torrents[torrent_id].get_status(['owner', 'shared'])
if torrent_status["owner"] != current_user and not torrent_status["shared"]: if torrent_status['owner'] != current_user and not torrent_status['shared']:
torrent_ids.pop(torrent_ids.index(torrent_id)) torrent_ids.pop(torrent_ids.index(torrent_id))
return torrent_ids return torrent_ids
@ -289,11 +289,11 @@ class TorrentManager(component.Component):
""" """
# Get the torrent data from the torrent file # Get the torrent data from the torrent file
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Attempting to extract torrent_info from %s", filepath) log.debug('Attempting to extract torrent_info from %s', filepath)
try: try:
torrent_info = lt.torrent_info(filepath) torrent_info = lt.torrent_info(filepath)
except RuntimeError as ex: except RuntimeError as ex:
log.warning("Unable to open torrent file %s: %s", filepath, ex) log.warning('Unable to open torrent file %s: %s', filepath, ex)
else: else:
return torrent_info return torrent_info
@ -319,39 +319,39 @@ class TorrentManager(component.Component):
""" """
if not torrent_info and not filedump and not magnet: if not torrent_info and not filedump and not magnet:
raise AddTorrentError("You must specify a valid torrent_info, torrent state or magnet.") raise AddTorrentError('You must specify a valid torrent_info, torrent state or magnet.')
if filedump: if filedump:
try: try:
torrent_info = lt.torrent_info(lt.bdecode(filedump)) torrent_info = lt.torrent_info(lt.bdecode(filedump))
except RuntimeError as ex: except RuntimeError as ex:
raise AddTorrentError("Unable to add torrent, decoding filedump failed: %s" % ex) raise AddTorrentError('Unable to add torrent, decoding filedump failed: %s' % ex)
add_torrent_params = {} add_torrent_params = {}
if torrent_info: if torrent_info:
add_torrent_params["ti"] = torrent_info add_torrent_params['ti'] = torrent_info
name = torrent_info.name() name = torrent_info.name()
if not name: if not name:
name = torrent_info.file_at(0).path.replace("\\", "/", 1).split("/", 1)[0] name = torrent_info.file_at(0).path.replace('\\', '/', 1).split('/', 1)[0]
add_torrent_params["name"] = name add_torrent_params['name'] = name
torrent_id = str(torrent_info.info_hash()) torrent_id = str(torrent_info.info_hash())
elif magnet: elif magnet:
magnet = utf8_encoded(magnet) magnet = utf8_encoded(magnet)
magnet_info = get_magnet_info(magnet) magnet_info = get_magnet_info(magnet)
if magnet_info: if magnet_info:
add_torrent_params["url"] = magnet add_torrent_params['url'] = magnet
add_torrent_params["name"] = magnet_info["name"] add_torrent_params['name'] = magnet_info['name']
torrent_id = magnet_info["info_hash"] torrent_id = magnet_info['info_hash']
else: else:
raise AddTorrentError("Unable to add magnet, invalid magnet info: %s" % magnet) raise AddTorrentError('Unable to add magnet, invalid magnet info: %s' % magnet)
# Check for existing torrent in session. # Check for existing torrent in session.
if torrent_id in self.get_torrent_list(): if torrent_id in self.get_torrent_list():
# Attempt merge trackers before returning. # Attempt merge trackers before returning.
self.torrents[torrent_id].merge_trackers(torrent_info) self.torrents[torrent_id].merge_trackers(torrent_info)
raise AddTorrentError("Torrent already in session (%s)." % torrent_id) raise AddTorrentError('Torrent already in session (%s).' % torrent_id)
elif torrent_id in self.torrents_loading: elif torrent_id in self.torrents_loading:
raise AddTorrentError("Torrent already being added (%s)." % torrent_id) raise AddTorrentError('Torrent already being added (%s).' % torrent_id)
# Load default options and update if needed. # Load default options and update if needed.
_options = TorrentOptions() _options = TorrentOptions()
@ -360,63 +360,63 @@ class TorrentManager(component.Component):
options = _options options = _options
# Check for renamed files and if so, rename them in the torrent_info before adding. # Check for renamed files and if so, rename them in the torrent_info before adding.
if options["mapped_files"] and torrent_info: if options['mapped_files'] and torrent_info:
for index, fname in options["mapped_files"].items(): for index, fname in options['mapped_files'].items():
fname = sanitize_filepath(decode_string(fname)) fname = sanitize_filepath(decode_string(fname))
log.debug("renaming file index %s to %s", index, fname) log.debug('renaming file index %s to %s', index, fname)
try: try:
torrent_info.rename_file(index, fname) torrent_info.rename_file(index, fname)
except TypeError: except TypeError:
torrent_info.rename_file(index, utf8_encoded(fname)) torrent_info.rename_file(index, utf8_encoded(fname))
add_torrent_params["ti"] = torrent_info add_torrent_params['ti'] = torrent_info
if not options["owner"]: if not options['owner']:
options["owner"] = component.get("RPCServer").get_session_user() options['owner'] = component.get('RPCServer').get_session_user()
if not component.get("AuthManager").has_account(options["owner"]): if not component.get('AuthManager').has_account(options['owner']):
options["owner"] = "localclient" options['owner'] = 'localclient'
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("options: %s", options) log.debug('options: %s', options)
# Fill in the rest of the add_torrent_params dictionary. # Fill in the rest of the add_torrent_params dictionary.
add_torrent_params["save_path"] = utf8_encoded(options["download_location"]) add_torrent_params['save_path'] = utf8_encoded(options['download_location'])
if options["name"]: if options['name']:
add_torrent_params["name"] = options["name"] add_torrent_params['name'] = options['name']
if options["pre_allocate_storage"]: if options['pre_allocate_storage']:
add_torrent_params["storage_mode"] = lt.storage_mode_t.storage_mode_allocate add_torrent_params['storage_mode'] = lt.storage_mode_t.storage_mode_allocate
if resume_data: if resume_data:
add_torrent_params["resume_data"] = resume_data add_torrent_params['resume_data'] = resume_data
default_flags = (lt.add_torrent_params_flags_t.flag_paused | default_flags = (lt.add_torrent_params_flags_t.flag_paused |
lt.add_torrent_params_flags_t.flag_auto_managed | lt.add_torrent_params_flags_t.flag_auto_managed |
lt.add_torrent_params_flags_t.flag_update_subscribe | lt.add_torrent_params_flags_t.flag_update_subscribe |
lt.add_torrent_params_flags_t.flag_apply_ip_filter) lt.add_torrent_params_flags_t.flag_apply_ip_filter)
# Set flags: enable duplicate_is_error & override_resume_data, disable auto_managed. # Set flags: enable duplicate_is_error & override_resume_data, disable auto_managed.
add_torrent_params["flags"] = ((default_flags | add_torrent_params['flags'] = ((default_flags |
lt.add_torrent_params_flags_t.flag_duplicate_is_error | lt.add_torrent_params_flags_t.flag_duplicate_is_error |
lt.add_torrent_params_flags_t.flag_override_resume_data) ^ lt.add_torrent_params_flags_t.flag_override_resume_data) ^
lt.add_torrent_params_flags_t.flag_auto_managed) lt.add_torrent_params_flags_t.flag_auto_managed)
if options["seed_mode"]: if options['seed_mode']:
add_torrent_params["flags"] |= lt.add_torrent_params_flags_t.flag_seed_mode add_torrent_params['flags'] |= lt.add_torrent_params_flags_t.flag_seed_mode
d = Deferred() d = Deferred()
try: try:
self.torrents_loading[torrent_id] = (d, options, state, filename, magnet, resume_data, filedump, save_state) self.torrents_loading[torrent_id] = (d, options, state, filename, magnet, resume_data, filedump, save_state)
self.session.async_add_torrent(add_torrent_params) self.session.async_add_torrent(add_torrent_params)
except RuntimeError as ex: except RuntimeError as ex:
raise AddTorrentError("Unable to add torrent to session: %s" % ex) raise AddTorrentError('Unable to add torrent to session: %s' % ex)
return d return d
def on_add_torrent_alert(self, alert): def on_add_torrent_alert(self, alert):
"""Alert handler for libtorrent add_torrent_alert""" """Alert handler for libtorrent add_torrent_alert"""
if not alert.handle.is_valid(): if not alert.handle.is_valid():
log.warn("Torrent handle is invalid!") log.warn('Torrent handle is invalid!')
return return
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
except RuntimeError as ex: except RuntimeError as ex:
log.warn("Failed to get torrent id from handle: %s", ex) log.warn('Failed to get torrent id from handle: %s', ex)
return return
d, options, state, filename, magnet, resume_data, filedump, save_state = self.torrents_loading.pop(torrent_id) d, options, state, filename, magnet, resume_data, filedump, save_state = self.torrents_loading.pop(torrent_id)
@ -431,25 +431,25 @@ class TorrentManager(component.Component):
# Add to queued torrents set. # Add to queued torrents set.
self.queued_torrents.add(torrent.torrent_id) self.queued_torrents.add(torrent.torrent_id)
if self.config["queue_new_to_top"]: if self.config['queue_new_to_top']:
self.queue_top(torrent.torrent_id) self.queue_top(torrent.torrent_id)
# Resume the torrent if needed. # Resume the torrent if needed.
if not options["add_paused"]: if not options['add_paused']:
torrent.resume() torrent.resume()
# Emit torrent_added signal. # Emit torrent_added signal.
from_state = state is not None from_state = state is not None
component.get("EventManager").emit(TorrentAddedEvent(torrent.torrent_id, from_state)) component.get('EventManager').emit(TorrentAddedEvent(torrent.torrent_id, from_state))
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Torrent added: %s", str(alert.handle.info_hash())) log.debug('Torrent added: %s', str(alert.handle.info_hash()))
if log.isEnabledFor(logging.INFO): if log.isEnabledFor(logging.INFO):
name_and_owner = torrent.get_status(["name", "owner"]) name_and_owner = torrent.get_status(['name', 'owner'])
log.info("Torrent %s from user \"%s\" %s", log.info("Torrent %s from user \"%s\" %s",
name_and_owner["name"], name_and_owner['name'],
name_and_owner["owner"], name_and_owner['owner'],
from_state and "loaded" or "added") from_state and 'loaded' or 'added')
# Write the .torrent file to the state directory. # Write the .torrent file to the state directory.
if filedump: if filedump:
@ -485,22 +485,22 @@ class TorrentManager(component.Component):
except KeyError: except KeyError:
raise InvalidTorrentError("torrent_id '%s' not in session." % torrent_id) raise InvalidTorrentError("torrent_id '%s' not in session." % torrent_id)
torrent_name = torrent.get_status(["name"])["name"] torrent_name = torrent.get_status(['name'])['name']
# Emit the signal to the clients # Emit the signal to the clients
component.get("EventManager").emit(PreTorrentRemovedEvent(torrent_id)) component.get('EventManager').emit(PreTorrentRemovedEvent(torrent_id))
try: try:
self.session.remove_torrent(torrent.handle, 1 if remove_data else 0) self.session.remove_torrent(torrent.handle, 1 if remove_data else 0)
except RuntimeError as ex: except RuntimeError as ex:
log.warning("Error removing torrent: %s", ex) log.warning('Error removing torrent: %s', ex)
return False return False
# Remove fastresume data if it is exists # Remove fastresume data if it is exists
self.resume_data.pop(torrent_id, None) self.resume_data.pop(torrent_id, None)
# Remove the .torrent file in the state and copy location, if user requested. # Remove the .torrent file in the state and copy location, if user requested.
delete_copies = self.config["copy_torrent_file"] and self.config["del_copy_torrent_file"] delete_copies = self.config['copy_torrent_file'] and self.config['del_copy_torrent_file']
torrent.delete_torrentfile(delete_copies) torrent.delete_torrentfile(delete_copies)
# Remove from set if it wasn't finished # Remove from set if it wasn't finished
@ -518,8 +518,8 @@ class TorrentManager(component.Component):
self.save_state() self.save_state()
# Emit the signal to the clients # Emit the signal to the clients
component.get("EventManager").emit(TorrentRemovedEvent(torrent_id)) component.get('EventManager').emit(TorrentRemovedEvent(torrent_id))
log.info("Torrent %s removed by user: %s", torrent_name, component.get("RPCServer").get_session_user()) log.info('Torrent %s removed by user: %s', torrent_name, component.get('RPCServer').get_session_user())
return True return True
def fixup_state(self, state): def fixup_state(self, state):
@ -540,7 +540,7 @@ class TorrentManager(component.Component):
for t_state in state.torrents: for t_state in state.torrents:
setattr(t_state, attr, getattr(t_state_tmp, attr, None)) setattr(t_state, attr, getattr(t_state_tmp, attr, None))
except AttributeError as ex: except AttributeError as ex:
log.error("Unable to update state file to a compatible version: %s", ex) log.error('Unable to update state file to a compatible version: %s', ex)
return state return state
def open_state(self): def open_state(self):
@ -550,17 +550,17 @@ class TorrentManager(component.Component):
TorrentManagerState: The TorrentManager state. TorrentManagerState: The TorrentManager state.
""" """
torrents_state = os.path.join(self.state_dir, "torrents.state") torrents_state = os.path.join(self.state_dir, 'torrents.state')
for filepath in (torrents_state, torrents_state + ".bak"): for filepath in (torrents_state, torrents_state + '.bak'):
log.info("Loading torrent state: %s", filepath) log.info('Loading torrent state: %s', filepath)
try: try:
with open(filepath, "rb") as _file: with open(filepath, 'rb') as _file:
state = cPickle.load(_file) state = cPickle.load(_file)
except (IOError, EOFError, cPickle.UnpicklingError) as ex: except (IOError, EOFError, cPickle.UnpicklingError) as ex:
log.warning("Unable to load %s: %s", filepath, ex) log.warning('Unable to load %s: %s', filepath, ex)
state = None state = None
else: else:
log.info("Successfully loaded %s", filepath) log.info('Successfully loaded %s', filepath)
break break
if state is None: if state is None:
@ -579,7 +579,7 @@ class TorrentManager(component.Component):
state = self.fixup_state(state) state = self.fixup_state(state)
# Reorder the state.torrents list to add torrents in the correct queue order. # Reorder the state.torrents list to add torrents in the correct queue order.
state.torrents.sort(key=operator.attrgetter("queue"), reverse=self.config["queue_new_to_top"]) state.torrents.sort(key=operator.attrgetter('queue'), reverse=self.config['queue_new_to_top'])
resume_data = self.load_resume_data_file() resume_data = self.load_resume_data_file()
deferreds = [] deferreds = []
@ -592,14 +592,14 @@ class TorrentManager(component.Component):
except AttributeError: except AttributeError:
pass pass
# Manually update unmatched attributes # Manually update unmatched attributes
options["download_location"] = t_state.save_path options['download_location'] = t_state.save_path
options["pre_allocate_storage"] = t_state.storage_mode == "allocate" options['pre_allocate_storage'] = t_state.storage_mode == 'allocate'
options["prioritize_first_last_pieces"] = t_state.prioritize_first_last options['prioritize_first_last_pieces'] = t_state.prioritize_first_last
options["add_paused"] = t_state.paused options['add_paused'] = t_state.paused
magnet = t_state.magnet magnet = t_state.magnet
torrent_info = self.get_torrent_info_from_file( torrent_info = self.get_torrent_info_from_file(
os.path.join(self.state_dir, t_state.torrent_id + ".torrent")) os.path.join(self.state_dir, t_state.torrent_id + '.torrent'))
if torrent_info: if torrent_info:
magnet = None magnet = None
@ -614,8 +614,8 @@ class TorrentManager(component.Component):
deferred_list = DeferredList(deferreds, consumeErrors=False) deferred_list = DeferredList(deferreds, consumeErrors=False)
def on_complete(result): def on_complete(result):
log.info("Finished loading %d torrents in %s", len(state.torrents), str(datetime.datetime.now() - start)) log.info('Finished loading %d torrents in %s', len(state.torrents), str(datetime.datetime.now() - start))
component.get("EventManager").emit(SessionStartedEvent()) component.get('EventManager').emit(SessionStartedEvent())
deferred_list.addCallback(on_complete) deferred_list.addCallback(on_complete)
def create_state(self): def create_state(self):
@ -632,7 +632,7 @@ class TorrentManager(component.Component):
paused = torrent.handle.is_paused() paused = torrent.handle.is_paused()
elif torrent.forced_error: elif torrent.forced_error:
paused = torrent.forced_error.was_paused paused = torrent.forced_error.was_paused
elif torrent.state == "Paused": elif torrent.state == 'Paused':
paused = True paused = True
else: else:
paused = False paused = False
@ -641,30 +641,30 @@ class TorrentManager(component.Component):
torrent.torrent_id, torrent.torrent_id,
torrent.filename, torrent.filename,
torrent.trackers, torrent.trackers,
torrent.get_status(["storage_mode"])["storage_mode"], torrent.get_status(['storage_mode'])['storage_mode'],
paused, paused,
torrent.options["download_location"], torrent.options['download_location'],
torrent.options["max_connections"], torrent.options['max_connections'],
torrent.options["max_upload_slots"], torrent.options['max_upload_slots'],
torrent.options["max_upload_speed"], torrent.options['max_upload_speed'],
torrent.options["max_download_speed"], torrent.options['max_download_speed'],
torrent.options["prioritize_first_last_pieces"], torrent.options['prioritize_first_last_pieces'],
torrent.options["sequential_download"], torrent.options['sequential_download'],
torrent.options["file_priorities"], torrent.options['file_priorities'],
torrent.get_queue_position(), torrent.get_queue_position(),
torrent.options["auto_managed"], torrent.options['auto_managed'],
torrent.is_finished, torrent.is_finished,
torrent.options["stop_ratio"], torrent.options['stop_ratio'],
torrent.options["stop_at_ratio"], torrent.options['stop_at_ratio'],
torrent.options["remove_at_ratio"], torrent.options['remove_at_ratio'],
torrent.options["move_completed"], torrent.options['move_completed'],
torrent.options["move_completed_path"], torrent.options['move_completed_path'],
torrent.magnet, torrent.magnet,
torrent.options["owner"], torrent.options['owner'],
torrent.options["shared"], torrent.options['shared'],
torrent.options["super_seeding"], torrent.options['super_seeding'],
torrent.options["priority"], torrent.options['priority'],
torrent.options["name"] torrent.options['name']
) )
state.torrents.append(torrent_state) state.torrents.append(torrent_state)
return state return state
@ -692,41 +692,41 @@ class TorrentManager(component.Component):
"""Save the state of the TorrentManager to the torrents.state file.""" """Save the state of the TorrentManager to the torrents.state file."""
state = self.create_state() state = self.create_state()
if not state.torrents: if not state.torrents:
log.debug("Skipping saving state with no torrents loaded") log.debug('Skipping saving state with no torrents loaded')
return return
filename = "torrents.state" filename = 'torrents.state'
filepath = os.path.join(self.state_dir, filename) filepath = os.path.join(self.state_dir, filename)
filepath_bak = filepath + ".bak" filepath_bak = filepath + '.bak'
filepath_tmp = filepath + ".tmp" filepath_tmp = filepath + '.tmp'
try: try:
log.debug("Creating the temporary file: %s", filepath_tmp) log.debug('Creating the temporary file: %s', filepath_tmp)
with open(filepath_tmp, "wb", 0) as _file: with open(filepath_tmp, 'wb', 0) as _file:
cPickle.dump(state, _file) cPickle.dump(state, _file)
_file.flush() _file.flush()
os.fsync(_file.fileno()) os.fsync(_file.fileno())
except (OSError, cPickle.PicklingError) as ex: except (OSError, cPickle.PicklingError) as ex:
log.error("Unable to save %s: %s", filename, ex) log.error('Unable to save %s: %s', filename, ex)
return return
try: try:
log.debug("Creating backup of %s at: %s", filename, filepath_bak) log.debug('Creating backup of %s at: %s', filename, filepath_bak)
if os.path.isfile(filepath_bak): if os.path.isfile(filepath_bak):
os.remove(filepath_bak) os.remove(filepath_bak)
if os.path.isfile(filepath): if os.path.isfile(filepath):
os.rename(filepath, filepath_bak) os.rename(filepath, filepath_bak)
except OSError as ex: except OSError as ex:
log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex) log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
return return
try: try:
log.debug("Saving %s to: %s", filename, filepath) log.debug('Saving %s to: %s', filename, filepath)
os.rename(filepath_tmp, filepath) os.rename(filepath_tmp, filepath)
except OSError as ex: except OSError as ex:
log.error("Failed to set new state file %s: %s", filepath, ex) log.error('Failed to set new state file %s: %s', filepath, ex)
if os.path.isfile(filepath_bak): if os.path.isfile(filepath_bak):
log.info("Restoring backup of state from: %s", filepath_bak) log.info('Restoring backup of state from: %s', filepath_bak)
os.rename(filepath_bak, filepath) os.rename(filepath_bak, filepath)
def save_resume_data(self, torrent_ids=None, flush_disk_cache=False): def save_resume_data(self, torrent_ids=None, flush_disk_cache=False):
@ -781,22 +781,22 @@ class TorrentManager(component.Component):
dict: A dict of torrents and their resume_data. dict: A dict of torrents and their resume_data.
""" """
filename = "torrents.fastresume" filename = 'torrents.fastresume'
filepath = os.path.join(self.state_dir, filename) filepath = os.path.join(self.state_dir, filename)
filepath_bak = filepath + ".bak" filepath_bak = filepath + '.bak'
old_data_filepath = os.path.join(get_config_dir(), filename) old_data_filepath = os.path.join(get_config_dir(), filename)
for _filepath in (filepath, filepath_bak, old_data_filepath): for _filepath in (filepath, filepath_bak, old_data_filepath):
log.info("Opening %s for load: %s", filename, _filepath) log.info('Opening %s for load: %s', filename, _filepath)
try: try:
with open(_filepath, "rb") as _file: with open(_filepath, 'rb') as _file:
resume_data = lt.bdecode(_file.read()) resume_data = lt.bdecode(_file.read())
except (IOError, EOFError, RuntimeError) as ex: except (IOError, EOFError, RuntimeError) as ex:
if self.torrents: if self.torrents:
log.warning("Unable to load %s: %s", _filepath, ex) log.warning('Unable to load %s: %s', _filepath, ex)
resume_data = None resume_data = None
else: else:
log.info("Successfully loaded %s: %s", filename, _filepath) log.info('Successfully loaded %s: %s', filename, _filepath)
break break
# If the libtorrent bdecode doesn't happen properly, it will return None # If the libtorrent bdecode doesn't happen properly, it will return None
# so we need to make sure we return a {} # so we need to make sure we return a {}
@ -836,38 +836,38 @@ class TorrentManager(component.Component):
if not self.resume_data: if not self.resume_data:
return True return True
filename = "torrents.fastresume" filename = 'torrents.fastresume'
filepath = os.path.join(self.state_dir, filename) filepath = os.path.join(self.state_dir, filename)
filepath_bak = filepath + ".bak" filepath_bak = filepath + '.bak'
filepath_tmp = filepath + ".tmp" filepath_tmp = filepath + '.tmp'
try: try:
log.debug("Creating the temporary file: %s", filepath_tmp) log.debug('Creating the temporary file: %s', filepath_tmp)
with open(filepath_tmp, "wb", 0) as _file: with open(filepath_tmp, 'wb', 0) as _file:
_file.write(lt.bencode(self.resume_data)) _file.write(lt.bencode(self.resume_data))
_file.flush() _file.flush()
os.fsync(_file.fileno()) os.fsync(_file.fileno())
except (OSError, EOFError) as ex: except (OSError, EOFError) as ex:
log.error("Unable to save %s: %s", filename, ex) log.error('Unable to save %s: %s', filename, ex)
return False return False
try: try:
log.debug("Creating backup of %s at: %s", filename, filepath_bak) log.debug('Creating backup of %s at: %s', filename, filepath_bak)
if os.path.isfile(filepath_bak): if os.path.isfile(filepath_bak):
os.remove(filepath_bak) os.remove(filepath_bak)
if os.path.isfile(filepath): if os.path.isfile(filepath):
os.rename(filepath, filepath_bak) os.rename(filepath, filepath_bak)
except OSError as ex: except OSError as ex:
log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex) log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
return False return False
try: try:
log.debug("Saving %s to: %s", filename, filepath) log.debug('Saving %s to: %s', filename, filepath)
os.rename(filepath_tmp, filepath) os.rename(filepath_tmp, filepath)
except OSError as ex: except OSError as ex:
log.error("Failed to set new file %s: %s", filepath, ex) log.error('Failed to set new file %s: %s', filepath, ex)
if os.path.isfile(filepath_bak): if os.path.isfile(filepath_bak):
log.info("Restoring backup from: %s", filepath_bak) log.info('Restoring backup from: %s', filepath_bak)
os.rename(filepath_bak, filepath) os.rename(filepath_bak, filepath)
else: else:
# Sync the rename operations for the directory # Sync the rename operations for the directory
@ -920,58 +920,58 @@ class TorrentManager(component.Component):
def on_set_max_connections_per_torrent(self, key, value): def on_set_max_connections_per_torrent(self, key, value):
"""Sets the per-torrent connection limit""" """Sets the per-torrent connection limit"""
log.debug("max_connections_per_torrent set to %s...", value) log.debug('max_connections_per_torrent set to %s...', value)
for key in self.torrents: for key in self.torrents:
self.torrents[key].set_max_connections(value) self.torrents[key].set_max_connections(value)
def on_set_max_upload_slots_per_torrent(self, key, value): def on_set_max_upload_slots_per_torrent(self, key, value):
"""Sets the per-torrent upload slot limit""" """Sets the per-torrent upload slot limit"""
log.debug("max_upload_slots_per_torrent set to %s...", value) log.debug('max_upload_slots_per_torrent set to %s...', value)
for key in self.torrents: for key in self.torrents:
self.torrents[key].set_max_upload_slots(value) self.torrents[key].set_max_upload_slots(value)
def on_set_max_upload_speed_per_torrent(self, key, value): def on_set_max_upload_speed_per_torrent(self, key, value):
"""Sets the per-torrent upload speed limit""" """Sets the per-torrent upload speed limit"""
log.debug("max_upload_speed_per_torrent set to %s...", value) log.debug('max_upload_speed_per_torrent set to %s...', value)
for key in self.torrents: for key in self.torrents:
self.torrents[key].set_max_upload_speed(value) self.torrents[key].set_max_upload_speed(value)
def on_set_max_download_speed_per_torrent(self, key, value): def on_set_max_download_speed_per_torrent(self, key, value):
"""Sets the per-torrent download speed limit""" """Sets the per-torrent download speed limit"""
log.debug("max_download_speed_per_torrent set to %s...", value) log.debug('max_download_speed_per_torrent set to %s...', value)
for key in self.torrents: for key in self.torrents:
self.torrents[key].set_max_download_speed(value) self.torrents[key].set_max_download_speed(value)
# --- Alert handlers --- # --- Alert handlers ---
def on_alert_torrent_finished(self, alert): def on_alert_torrent_finished(self, alert):
"""Alert handler for libtorrent torrent_finished_alert""" """Alert handler for libtorrent torrent_finished_alert"""
log.debug("on_alert_torrent_finished") log.debug('on_alert_torrent_finished')
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
return return
log.debug("Finished %s ", torrent_id) log.debug('Finished %s ', torrent_id)
# If total_download is 0, do not move, it's likely the torrent wasn't downloaded, but just added. # If total_download is 0, do not move, it's likely the torrent wasn't downloaded, but just added.
# Get fresh data from libtorrent, the cache isn't always up to date # Get fresh data from libtorrent, the cache isn't always up to date
total_download = torrent.get_status(["total_payload_download"], update=True)["total_payload_download"] total_download = torrent.get_status(['total_payload_download'], update=True)['total_payload_download']
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("Torrent settings: is_finished: %s, total_download: %s, move_completed: %s, move_path: %s", log.debug('Torrent settings: is_finished: %s, total_download: %s, move_completed: %s, move_path: %s',
torrent.is_finished, total_download, torrent.options["move_completed"], torrent.is_finished, total_download, torrent.options['move_completed'],
torrent.options["move_completed_path"]) torrent.options['move_completed_path'])
torrent.update_state() torrent.update_state()
if not torrent.is_finished and total_download: if not torrent.is_finished and total_download:
# Move completed download to completed folder if needed # Move completed download to completed folder if needed
if torrent.options["move_completed"] and \ if torrent.options['move_completed'] and \
torrent.options["download_location"] != torrent.options["move_completed_path"]: torrent.options['download_location'] != torrent.options['move_completed_path']:
self.waiting_on_finish_moving.append(torrent_id) self.waiting_on_finish_moving.append(torrent_id)
torrent.move_storage(torrent.options["move_completed_path"]) torrent.move_storage(torrent.options['move_completed_path'])
else: else:
torrent.is_finished = True torrent.is_finished = True
component.get("EventManager").emit(TorrentFinishedEvent(torrent_id)) component.get('EventManager').emit(TorrentFinishedEvent(torrent_id))
else: else:
torrent.is_finished = True torrent.is_finished = True
@ -994,7 +994,7 @@ class TorrentManager(component.Component):
def on_alert_torrent_paused(self, alert): def on_alert_torrent_paused(self, alert):
"""Alert handler for libtorrent torrent_paused_alert""" """Alert handler for libtorrent torrent_paused_alert"""
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("on_alert_torrent_paused") log.debug('on_alert_torrent_paused')
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
@ -1008,7 +1008,7 @@ class TorrentManager(component.Component):
def on_alert_torrent_checked(self, alert): def on_alert_torrent_checked(self, alert):
"""Alert handler for libtorrent torrent_checked_alert""" """Alert handler for libtorrent torrent_checked_alert"""
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("on_alert_torrent_checked") log.debug('on_alert_torrent_checked')
try: try:
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
@ -1025,14 +1025,14 @@ class TorrentManager(component.Component):
def on_alert_tracker_reply(self, alert): def on_alert_tracker_reply(self, alert):
"""Alert handler for libtorrent tracker_reply_alert""" """Alert handler for libtorrent tracker_reply_alert"""
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("on_alert_tracker_reply: %s", decode_string(alert.message())) log.debug('on_alert_tracker_reply: %s', decode_string(alert.message()))
try: try:
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
return return
# Set the tracker status for the torrent # Set the tracker status for the torrent
torrent.set_tracker_status("Announce OK") torrent.set_tracker_status('Announce OK')
# Check for peer information from the tracker, if none then send a scrape request. # Check for peer information from the tracker, if none then send a scrape request.
if alert.handle.status().num_complete == -1 or alert.handle.status().num_incomplete == -1: if alert.handle.status().num_complete == -1 or alert.handle.status().num_incomplete == -1:
@ -1041,24 +1041,24 @@ class TorrentManager(component.Component):
def on_alert_tracker_announce(self, alert): def on_alert_tracker_announce(self, alert):
"""Alert handler for libtorrent tracker_announce_alert""" """Alert handler for libtorrent tracker_announce_alert"""
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("on_alert_tracker_announce") log.debug('on_alert_tracker_announce')
try: try:
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
return return
# Set the tracker status for the torrent # Set the tracker status for the torrent
torrent.set_tracker_status("Announce Sent") torrent.set_tracker_status('Announce Sent')
def on_alert_tracker_warning(self, alert): def on_alert_tracker_warning(self, alert):
"""Alert handler for libtorrent tracker_warning_alert""" """Alert handler for libtorrent tracker_warning_alert"""
log.debug("on_alert_tracker_warning") log.debug('on_alert_tracker_warning')
try: try:
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
return return
# Set the tracker status for the torrent # Set the tracker status for the torrent
torrent.set_tracker_status("Warning: %s" % decode_string(alert.message())) torrent.set_tracker_status('Warning: %s' % decode_string(alert.message()))
def on_alert_tracker_error(self, alert): def on_alert_tracker_error(self, alert):
"""Alert handler for libtorrent tracker_error_alert""" """Alert handler for libtorrent tracker_error_alert"""
@ -1071,17 +1071,17 @@ class TorrentManager(component.Component):
# cannot be replaced by a.e.message because the code is included in the string (for non-'-1'). # cannot be replaced by a.e.message because the code is included in the string (for non-'-1').
if not error_message: if not error_message:
error_message = decode_string(alert.error.message()) error_message = decode_string(alert.error.message())
log.debug("Tracker Error Alert: %s [%s]", decode_string(alert.message()), error_message) log.debug('Tracker Error Alert: %s [%s]', decode_string(alert.message()), error_message)
try: try:
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
return return
torrent.set_tracker_status("Error: " + error_message) torrent.set_tracker_status('Error: ' + error_message)
def on_alert_storage_moved(self, alert): def on_alert_storage_moved(self, alert):
"""Alert handler for libtorrent storage_moved_alert""" """Alert handler for libtorrent storage_moved_alert"""
log.debug("on_alert_storage_moved") log.debug('on_alert_storage_moved')
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
@ -1100,11 +1100,11 @@ class TorrentManager(component.Component):
if torrent_id in self.waiting_on_finish_moving: if torrent_id in self.waiting_on_finish_moving:
self.waiting_on_finish_moving.remove(torrent_id) self.waiting_on_finish_moving.remove(torrent_id)
torrent.is_finished = True torrent.is_finished = True
component.get("EventManager").emit(TorrentFinishedEvent(torrent_id)) component.get('EventManager').emit(TorrentFinishedEvent(torrent_id))
def on_alert_storage_moved_failed(self, alert): def on_alert_storage_moved_failed(self, alert):
"""Alert handler for libtorrent storage_moved_failed_alert""" """Alert handler for libtorrent storage_moved_failed_alert"""
log.warning("on_alert_storage_moved_failed: %s", decode_string(alert.message())) log.warning('on_alert_storage_moved_failed: %s', decode_string(alert.message()))
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
@ -1113,23 +1113,23 @@ class TorrentManager(component.Component):
# Set an Error message and pause the torrent # Set an Error message and pause the torrent
alert_msg = decode_string(alert.message()).split(':', 1)[1].strip() alert_msg = decode_string(alert.message()).split(':', 1)[1].strip()
torrent.moving_storage = False torrent.moving_storage = False
torrent.force_error_state("Failed to move download folder: %s" % alert_msg) torrent.force_error_state('Failed to move download folder: %s' % alert_msg)
if torrent_id in self.waiting_on_finish_moving: if torrent_id in self.waiting_on_finish_moving:
self.waiting_on_finish_moving.remove(torrent_id) self.waiting_on_finish_moving.remove(torrent_id)
torrent.is_finished = True torrent.is_finished = True
component.get("EventManager").emit(TorrentFinishedEvent(torrent_id)) component.get('EventManager').emit(TorrentFinishedEvent(torrent_id))
def on_alert_torrent_resumed(self, alert): def on_alert_torrent_resumed(self, alert):
"""Alert handler for libtorrent torrent_resumed_alert""" """Alert handler for libtorrent torrent_resumed_alert"""
log.debug("on_alert_torrent_resumed") log.debug('on_alert_torrent_resumed')
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
return return
torrent.update_state() torrent.update_state()
component.get("EventManager").emit(TorrentResumedEvent(torrent_id)) component.get('EventManager').emit(TorrentResumedEvent(torrent_id))
def on_alert_state_changed(self, alert): def on_alert_state_changed(self, alert):
"""Alert handler for libtorrent state_changed_alert. """Alert handler for libtorrent state_changed_alert.
@ -1139,7 +1139,7 @@ class TorrentManager(component.Component):
""" """
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("on_alert_state_changed") log.debug('on_alert_state_changed')
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
@ -1155,7 +1155,7 @@ class TorrentManager(component.Component):
def on_alert_save_resume_data(self, alert): def on_alert_save_resume_data(self, alert):
"""Alert handler for libtorrent save_resume_data_alert""" """Alert handler for libtorrent save_resume_data_alert"""
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.debug("on_alert_save_resume_data") log.debug('on_alert_save_resume_data')
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
except RuntimeError: except RuntimeError:
@ -1169,7 +1169,7 @@ class TorrentManager(component.Component):
def on_alert_save_resume_data_failed(self, alert): def on_alert_save_resume_data_failed(self, alert):
"""Alert handler for libtorrent save_resume_data_failed_alert""" """Alert handler for libtorrent save_resume_data_failed_alert"""
log.debug("on_alert_save_resume_data_failed: %s", decode_string(alert.message())) log.debug('on_alert_save_resume_data_failed: %s', decode_string(alert.message()))
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
except RuntimeError: except RuntimeError:
@ -1181,7 +1181,7 @@ class TorrentManager(component.Component):
def on_alert_fastresume_rejected(self, alert): def on_alert_fastresume_rejected(self, alert):
"""Alert handler for libtorrent fastresume_rejected_alert""" """Alert handler for libtorrent fastresume_rejected_alert"""
alert_msg = decode_string(alert.message()) alert_msg = decode_string(alert.message())
log.error("on_alert_fastresume_rejected: %s", alert_msg) log.error('on_alert_fastresume_rejected: %s', alert_msg)
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
@ -1189,12 +1189,12 @@ class TorrentManager(component.Component):
return return
if alert.error.value() == 134: if alert.error.value() == 134:
if not os.path.isdir(torrent.options["download_location"]): if not os.path.isdir(torrent.options['download_location']):
error_msg = "Unable to locate Download Folder!" error_msg = 'Unable to locate Download Folder!'
else: else:
error_msg = "Missing or invalid torrent data!" error_msg = 'Missing or invalid torrent data!'
else: else:
error_msg = "Problem with resume data: %s" % alert_msg.split(":", 1)[1].strip() error_msg = 'Problem with resume data: %s' % alert_msg.split(':', 1)[1].strip()
torrent.force_error_state(error_msg, restart_to_resume=True) torrent.force_error_state(error_msg, restart_to_resume=True)
def on_alert_file_renamed(self, alert): def on_alert_file_renamed(self, alert):
@ -1204,13 +1204,13 @@ class TorrentManager(component.Component):
TorrentFileRenamedEvent: Files in the torrent have been renamed. TorrentFileRenamedEvent: Files in the torrent have been renamed.
""" """
log.debug("on_alert_file_renamed") log.debug('on_alert_file_renamed')
try: try:
new_name = decode_string(alert.new_name) new_name = decode_string(alert.new_name)
except AttributeError: except AttributeError:
# Deprecated in libtorrent 1.1 # Deprecated in libtorrent 1.1
new_name = decode_string(alert.name) new_name = decode_string(alert.name)
log.debug("index: %s name: %s", alert.index, new_name) log.debug('index: %s name: %s', alert.index, new_name)
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
@ -1224,12 +1224,12 @@ class TorrentManager(component.Component):
break break
else: else:
# This is just a regular file rename so send the signal # This is just a regular file rename so send the signal
component.get("EventManager").emit(TorrentFileRenamedEvent(torrent_id, alert.index, new_name)) component.get('EventManager').emit(TorrentFileRenamedEvent(torrent_id, alert.index, new_name))
self.save_resume_data((torrent_id,)) self.save_resume_data((torrent_id,))
def on_alert_metadata_received(self, alert): def on_alert_metadata_received(self, alert):
"""Alert handler for libtorrent metadata_received_alert""" """Alert handler for libtorrent metadata_received_alert"""
log.debug("on_alert_metadata_received") log.debug('on_alert_metadata_received')
try: try:
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
@ -1238,7 +1238,7 @@ class TorrentManager(component.Component):
def on_alert_file_error(self, alert): def on_alert_file_error(self, alert):
"""Alert handler for libtorrent file_error_alert""" """Alert handler for libtorrent file_error_alert"""
log.debug("on_alert_file_error: %s", decode_string(alert.message())) log.debug('on_alert_file_error: %s', decode_string(alert.message()))
try: try:
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
except (RuntimeError, KeyError): except (RuntimeError, KeyError):
@ -1252,13 +1252,13 @@ class TorrentManager(component.Component):
TorrentFileCompletedEvent: When an individual file completes downloading. TorrentFileCompletedEvent: When an individual file completes downloading.
""" """
log.debug("file_completed_alert: %s", decode_string(alert.message())) log.debug('file_completed_alert: %s', decode_string(alert.message()))
try: try:
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
except RuntimeError: except RuntimeError:
return return
if torrent_id in self.torrents: if torrent_id in self.torrents:
component.get("EventManager").emit(TorrentFileCompletedEvent(torrent_id, alert.index)) component.get('EventManager').emit(TorrentFileCompletedEvent(torrent_id, alert.index))
def on_alert_state_update(self, alert): def on_alert_state_update(self, alert):
"""Alert handler for libtorrent state_update_alert """Alert handler for libtorrent state_update_alert
@ -1267,7 +1267,7 @@ class TorrentManager(component.Component):
of all torrents that changed since last time this was posted. of all torrents that changed since last time this was posted.
""" """
log.debug("on_status_notification: %s", decode_string(alert.message())) log.debug('on_status_notification: %s', decode_string(alert.message()))
self.last_state_update_alert_ts = time.time() self.last_state_update_alert_ts = time.time()
for t_status in alert.status: for t_status in alert.status:
@ -1291,24 +1291,24 @@ class TorrentManager(component.Component):
""" """
external_ip = decode_string(alert.message()).split(' ')[-1] external_ip = decode_string(alert.message()).split(' ')[-1]
log.info("on_alert_external_ip: %s", external_ip) log.info('on_alert_external_ip: %s', external_ip)
component.get("EventManager").emit(ExternalIPEvent(external_ip)) component.get('EventManager').emit(ExternalIPEvent(external_ip))
def on_alert_performance(self, alert): def on_alert_performance(self, alert):
"""Alert handler for libtorrent performance_alert""" """Alert handler for libtorrent performance_alert"""
log.warning("on_alert_performance: %s, %s", decode_string(alert.message()), alert.warning_code) log.warning('on_alert_performance: %s, %s', decode_string(alert.message()), alert.warning_code)
if alert.warning_code == lt.performance_warning_t.send_buffer_watermark_too_low: if alert.warning_code == lt.performance_warning_t.send_buffer_watermark_too_low:
max_send_buffer_watermark = 3 * 1024 * 1024 # 3MiB max_send_buffer_watermark = 3 * 1024 * 1024 # 3MiB
settings = self.session.get_settings() settings = self.session.get_settings()
send_buffer_watermark = settings["send_buffer_watermark"] send_buffer_watermark = settings['send_buffer_watermark']
# If send buffer is too small, try increasing its size by 512KiB (up to max_send_buffer_watermark) # If send buffer is too small, try increasing its size by 512KiB (up to max_send_buffer_watermark)
if send_buffer_watermark < max_send_buffer_watermark: if send_buffer_watermark < max_send_buffer_watermark:
value = send_buffer_watermark + (500 * 1024) value = send_buffer_watermark + (500 * 1024)
log.info("Increasing send_buffer_watermark from %s to %s Bytes", send_buffer_watermark, value) log.info('Increasing send_buffer_watermark from %s to %s Bytes', send_buffer_watermark, value)
component.get("Core").apply_session_setting("send_buffer_watermark", value) component.get('Core').apply_session_setting('send_buffer_watermark', value)
else: else:
log.warning("send_buffer_watermark reached maximum value: %s Bytes", max_send_buffer_watermark) log.warning('send_buffer_watermark reached maximum value: %s Bytes', max_send_buffer_watermark)
def separate_keys(self, keys, torrent_ids): def separate_keys(self, keys, torrent_ids):
"""Separates the input keys into torrent class keys and plugins keys""" """Separates the input keys into torrent class keys and plugins keys"""

View File

@ -89,7 +89,7 @@ def _overrides(stack, method, explicit_base_classes=None):
if explicit_base_classes: if explicit_base_classes:
# One or more base classes are explicitly given, check only those classes # One or more base classes are explicitly given, check only those classes
override_classes = re.search(r'\s*@overrides\((.+)\)\s*', stack[1][4][0]).group(1) override_classes = re.search(r'\s*@overrides\((.+)\)\s*', stack[1][4][0]).group(1)
override_classes = [c.strip() for c in override_classes.split(",")] override_classes = [c.strip() for c in override_classes.split(',')]
check_classes = override_classes check_classes = override_classes
for c in base_classes + check_classes: for c in base_classes + check_classes:
@ -108,9 +108,9 @@ def _overrides(stack, method, explicit_base_classes=None):
for cls in check_classes: for cls in check_classes:
if not hasattr(classes[cls], method.__name__): if not hasattr(classes[cls], method.__name__):
raise Exception("Function override '%s' not found in superclass: '%s'\n%s" raise Exception("Function override '%s' not found in superclass: '%s'\n%s"
% (method.__name__, cls, "File: %s:%s" % (stack[1][1], stack[1][2]))) % (method.__name__, cls, 'File: %s:%s' % (stack[1][1], stack[1][2])))
if not any(hasattr(classes[cls], method.__name__) for cls in check_classes): if not any(hasattr(classes[cls], method.__name__) for cls in check_classes):
raise Exception("Function override '%s' not found in any superclass: '%s'\n%s" raise Exception("Function override '%s' not found in any superclass: '%s'\n%s"
% (method.__name__, check_classes, "File: %s:%s" % (stack[1][1], stack[1][2]))) % (method.__name__, check_classes, 'File: %s:%s' % (stack[1][1], stack[1][2])))
return method return method

View File

@ -49,7 +49,7 @@ class WrappedException(DelugeError):
self.traceback = traceback self.traceback = traceback
def __str__(self): def __str__(self):
return "%s\n%s" % (self.message, self.traceback) return '%s\n%s' % (self.message, self.traceback)
class _ClientSideRecreateError(DelugeError): class _ClientSideRecreateError(DelugeError):
@ -60,8 +60,8 @@ class IncompatibleClient(_ClientSideRecreateError):
def __init__(self, daemon_version): def __init__(self, daemon_version):
self.daemon_version = daemon_version self.daemon_version = daemon_version
msg = "Your deluge client is not compatible with the daemon. "\ msg = 'Your deluge client is not compatible with the daemon. '\
"Please upgrade your client to %(daemon_version)s" % \ 'Please upgrade your client to %(daemon_version)s' % \
dict(daemon_version=self.daemon_version) dict(daemon_version=self.daemon_version)
super(IncompatibleClient, self).__init__(message=msg) super(IncompatibleClient, self).__init__(message=msg)
@ -69,7 +69,7 @@ class IncompatibleClient(_ClientSideRecreateError):
class NotAuthorizedError(_ClientSideRecreateError): class NotAuthorizedError(_ClientSideRecreateError):
def __init__(self, current_level, required_level): def __init__(self, current_level, required_level):
msg = "Auth level too low: %(current_level)s < %(required_level)s" % \ msg = 'Auth level too low: %(current_level)s < %(required_level)s' % \
dict(current_level=current_level, required_level=required_level) dict(current_level=current_level, required_level=required_level)
super(NotAuthorizedError, self).__init__(message=msg) super(NotAuthorizedError, self).__init__(message=msg)
self.current_level = current_level self.current_level = current_level

View File

@ -24,7 +24,7 @@ class DelugeEventMetaClass(type):
""" """
def __init__(self, name, bases, dct): # pylint: disable=bad-mcs-method-argument def __init__(self, name, bases, dct): # pylint: disable=bad-mcs-method-argument
super(DelugeEventMetaClass, self).__init__(name, bases, dct) super(DelugeEventMetaClass, self).__init__(name, bases, dct)
if name != "DelugeEvent": if name != 'DelugeEvent':
known_events[name] = self known_events[name] = self
@ -44,7 +44,7 @@ class DelugeEvent(object):
return self.__class__.__name__ return self.__class__.__name__
def _get_args(self): def _get_args(self):
if not hasattr(self, "_args"): if not hasattr(self, '_args'):
return [] return []
return self._args return self._args

View File

@ -49,7 +49,7 @@ class HTTPDownloader(client.HTTPDownloader):
self.force_filename = force_filename self.force_filename = force_filename
self.allow_compression = allow_compression self.allow_compression = allow_compression
self.code = None self.code = None
agent = "Deluge/%s (http://deluge-torrent.org)" % get_version() agent = 'Deluge/%s (http://deluge-torrent.org)' % get_version()
client.HTTPDownloader.__init__(self, url, filename, headers=headers, agent=agent) client.HTTPDownloader.__init__(self, url, filename, headers=headers, agent=agent)
def gotStatus(self, version, status, message): # NOQA def gotStatus(self, version, status, message): # NOQA
@ -58,19 +58,19 @@ class HTTPDownloader(client.HTTPDownloader):
def gotHeaders(self, headers): # NOQA def gotHeaders(self, headers): # NOQA
if self.code == http.OK: if self.code == http.OK:
if "content-length" in headers: if 'content-length' in headers:
self.total_length = int(headers["content-length"][0]) self.total_length = int(headers['content-length'][0])
else: else:
self.total_length = 0 self.total_length = 0
if self.allow_compression and "content-encoding" in headers and \ if self.allow_compression and 'content-encoding' in headers and \
headers["content-encoding"][0] in ("gzip", "x-gzip", "deflate"): headers['content-encoding'][0] in ('gzip', 'x-gzip', 'deflate'):
# Adding 32 to the wbits enables gzip & zlib decoding (with automatic header detection) # Adding 32 to the wbits enables gzip & zlib decoding (with automatic header detection)
# Adding 16 just enables gzip decoding (no zlib) # Adding 16 just enables gzip decoding (no zlib)
self.decoder = zlib.decompressobj(zlib.MAX_WBITS + 32) self.decoder = zlib.decompressobj(zlib.MAX_WBITS + 32)
if "content-disposition" in headers and not self.force_filename: if 'content-disposition' in headers and not self.force_filename:
new_file_name = str(headers["content-disposition"][0]).split(";")[1].split("=")[1] new_file_name = str(headers['content-disposition'][0]).split(';')[1].split('=')[1]
new_file_name = sanitise_filename(new_file_name) new_file_name = sanitise_filename(new_file_name)
new_file_name = os.path.join(os.path.split(self.value)[0], new_file_name) new_file_name = os.path.join(os.path.split(self.value)[0], new_file_name)
@ -79,14 +79,14 @@ class HTTPDownloader(client.HTTPDownloader):
fileext = os.path.splitext(new_file_name)[1] fileext = os.path.splitext(new_file_name)[1]
while os.path.isfile(new_file_name): while os.path.isfile(new_file_name):
# Increment filename if already exists # Increment filename if already exists
new_file_name = "%s-%s%s" % (fileroot, count, fileext) new_file_name = '%s-%s%s' % (fileroot, count, fileext)
count += 1 count += 1
self.fileName = new_file_name self.fileName = new_file_name
self.value = new_file_name self.value = new_file_name
elif self.code in (http.MOVED_PERMANENTLY, http.FOUND, http.SEE_OTHER, http.TEMPORARY_REDIRECT): elif self.code in (http.MOVED_PERMANENTLY, http.FOUND, http.SEE_OTHER, http.TEMPORARY_REDIRECT):
location = headers["location"][0] location = headers['location'][0]
error = PageRedirect(self.code, location=location) error = PageRedirect(self.code, location=location)
self.noPage(Failure(error)) self.noPage(Failure(error))
@ -133,7 +133,7 @@ def sanitise_filename(filename):
filename = os.path.basename(filename) filename = os.path.basename(filename)
filename = filename.strip() filename = filename.strip()
if filename.startswith(".") or ";" in filename or "|" in filename: if filename.startswith('.') or ';' in filename or '|' in filename:
# Dodgy server, log it # Dodgy server, log it
log.warning("Potentially malicious server: trying to write to file '%s'", filename) log.warning("Potentially malicious server: trying to write to file '%s'", filename)
@ -172,11 +172,11 @@ def _download_file(url, filename, callback=None, headers=None, force_filename=Fa
if allow_compression: if allow_compression:
if not headers: if not headers:
headers = {} headers = {}
headers["accept-encoding"] = "deflate, gzip, x-gzip" headers['accept-encoding'] = 'deflate, gzip, x-gzip'
# In Twisted 13.1.0 _parse() function replaced by _URI class. # In Twisted 13.1.0 _parse() function replaced by _URI class.
# In Twisted 15.0.0 _URI class renamed to URI. # In Twisted 15.0.0 _URI class renamed to URI.
if hasattr(client, "_parse"): if hasattr(client, '_parse'):
scheme, host, port, dummy_path = client._parse(url) scheme, host, port, dummy_path = client._parse(url)
else: else:
try: try:
@ -190,7 +190,7 @@ def _download_file(url, filename, callback=None, headers=None, force_filename=Fa
port = uri.port port = uri.port
factory = HTTPDownloader(url, filename, callback, headers, force_filename, allow_compression) factory = HTTPDownloader(url, filename, callback, headers, force_filename, allow_compression)
if scheme == "https": if scheme == 'https':
from twisted.internet import ssl from twisted.internet import ssl
# ClientTLSOptions in Twisted >= 14, see ticket #2765 for details on this addition. # ClientTLSOptions in Twisted >= 14, see ticket #2765 for details on this addition.
try: try:
@ -241,12 +241,12 @@ def download_file(url, filename, callback=None, headers=None, force_filename=Fal
""" """
def on_download_success(result): def on_download_success(result):
log.debug("Download success!") log.debug('Download success!')
return result return result
def on_download_fail(failure): def on_download_fail(failure):
if failure.check(PageRedirect) and handle_redirects: if failure.check(PageRedirect) and handle_redirects:
new_url = urljoin(url, failure.getErrorMessage().split(" to ")[1]) new_url = urljoin(url, failure.getErrorMessage().split(' to ')[1])
result = _download_file(new_url, filename, callback=callback, headers=headers, result = _download_file(new_url, filename, callback=callback, headers=headers,
force_filename=force_filename, force_filename=force_filename,
allow_compression=allow_compression) allow_compression=allow_compression)

View File

@ -21,14 +21,14 @@ from twisted.python.log import PythonLoggingObserver
from deluge import common from deluge import common
__all__ = ("setup_logger", "set_logger_level", "get_plugin_logger", "LOG") __all__ = ('setup_logger', 'set_logger_level', 'get_plugin_logger', 'LOG')
LoggingLoggerClass = logging.getLoggerClass() LoggingLoggerClass = logging.getLoggerClass()
if "dev" in common.get_version(): if 'dev' in common.get_version():
DEFAULT_LOGGING_FORMAT = "%%(asctime)s.%%(msecs)03.0f [%%(levelname)-8s][%%(name)-%ds:%%(lineno)-4d] %%(message)s" DEFAULT_LOGGING_FORMAT = '%%(asctime)s.%%(msecs)03.0f [%%(levelname)-8s][%%(name)-%ds:%%(lineno)-4d] %%(message)s'
else: else:
DEFAULT_LOGGING_FORMAT = "%%(asctime)s [%%(levelname)-8s][%%(name)-%ds:%%(lineno)-4d] %%(message)s" DEFAULT_LOGGING_FORMAT = '%%(asctime)s [%%(levelname)-8s][%%(name)-%ds:%%(lineno)-4d] %%(message)s'
MAX_LOGGER_NAME_LENGTH = 10 MAX_LOGGER_NAME_LENGTH = 10
@ -44,7 +44,7 @@ class Logging(LoggingLoggerClass):
for handler in logging.getLogger().handlers: for handler in logging.getLogger().handlers:
handler.setFormatter(logging.Formatter( handler.setFormatter(logging.Formatter(
DEFAULT_LOGGING_FORMAT % MAX_LOGGER_NAME_LENGTH, DEFAULT_LOGGING_FORMAT % MAX_LOGGER_NAME_LENGTH,
datefmt="%H:%M:%S" datefmt='%H:%M:%S'
)) ))
@defer.inlineCallbacks @defer.inlineCallbacks
@ -83,12 +83,12 @@ class Logging(LoggingLoggerClass):
def findCaller(self): # NOQA def findCaller(self): # NOQA
f = logging.currentframe().f_back f = logging.currentframe().f_back
rv = "(unknown file)", 0, "(unknown function)" rv = '(unknown file)', 0, '(unknown function)'
while hasattr(f, "f_code"): while hasattr(f, 'f_code'):
co = f.f_code co = f.f_code
filename = os.path.normcase(co.co_filename) filename = os.path.normcase(co.co_filename)
if filename in (__file__.replace(".pyc", ".py"), if filename in (__file__.replace('.pyc', '.py'),
defer.__file__.replace(".pyc", ".py")): defer.__file__.replace('.pyc', '.py')):
f = f.f_back f = f.f_back
continue continue
rv = (filename, f.f_lineno, co.co_name) rv = (filename, f.f_lineno, co.co_name)
@ -96,18 +96,18 @@ class Logging(LoggingLoggerClass):
return rv return rv
levels = { levels = {
"info": logging.INFO, 'info': logging.INFO,
"warn": logging.WARNING, 'warn': logging.WARNING,
"warning": logging.WARNING, 'warning': logging.WARNING,
"error": logging.ERROR, 'error': logging.ERROR,
"none": logging.CRITICAL, 'none': logging.CRITICAL,
"debug": logging.DEBUG, 'debug': logging.DEBUG,
"trace": 5, 'trace': 5,
"garbage": 1 'garbage': 1
} }
def setup_logger(level="error", filename=None, filemode="w", logrotate=None, def setup_logger(level='error', filename=None, filemode='w', logrotate=None,
output_stream=sys.stdout, twisted_observer=True): output_stream=sys.stdout, twisted_observer=True):
""" """
Sets up the basic logger and if `:param:filename` is set, then it will log Sets up the basic logger and if `:param:filename` is set, then it will log
@ -125,8 +125,8 @@ def setup_logger(level="error", filename=None, filemode="w", logrotate=None,
""" """
if logging.getLoggerClass() is not Logging: if logging.getLoggerClass() is not Logging:
logging.setLoggerClass(Logging) logging.setLoggerClass(Logging)
logging.addLevelName(5, "TRACE") logging.addLevelName(5, 'TRACE')
logging.addLevelName(1, "GARBAGE") logging.addLevelName(1, 'GARBAGE')
level = levels.get(level, logging.ERROR) level = levels.get(level, logging.ERROR)
@ -135,13 +135,13 @@ def setup_logger(level="error", filename=None, filemode="w", logrotate=None,
if filename and logrotate: if filename and logrotate:
handler = logging.handlers.RotatingFileHandler( handler = logging.handlers.RotatingFileHandler(
filename, maxBytes=logrotate, filename, maxBytes=logrotate,
backupCount=5, encoding="utf-8" backupCount=5, encoding='utf-8'
) )
elif filename and filemode == "w": elif filename and filemode == 'w':
handler_cls = logging.FileHandler handler_cls = logging.FileHandler
if not common.windows_check(): if not common.windows_check():
handler_cls = getattr(logging.handlers, "WatchedFileHandler", logging.FileHandler) handler_cls = getattr(logging.handlers, 'WatchedFileHandler', logging.FileHandler)
handler = handler_cls(filename, mode=filemode, encoding="utf-8") handler = handler_cls(filename, mode=filemode, encoding='utf-8')
else: else:
handler = logging.StreamHandler(stream=output_stream) handler = logging.StreamHandler(stream=output_stream)
@ -149,7 +149,7 @@ def setup_logger(level="error", filename=None, filemode="w", logrotate=None,
formatter = logging.Formatter( formatter = logging.Formatter(
DEFAULT_LOGGING_FORMAT % MAX_LOGGER_NAME_LENGTH, DEFAULT_LOGGING_FORMAT % MAX_LOGGER_NAME_LENGTH,
datefmt="%H:%M:%S" datefmt='%H:%M:%S'
) )
handler.setFormatter(formatter) handler.setFormatter(formatter)
@ -182,9 +182,9 @@ class TwistedLoggingObserver(PythonLoggingObserver):
def emit(self, event_dict): def emit(self, event_dict):
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
if "log_failure" in event_dict: if 'log_failure' in event_dict:
fmt = "%(log_namespace)s \n%(log_failure)s" fmt = '%(log_namespace)s \n%(log_failure)s'
getattr(LoggingLoggerClass, event_dict["log_level"].name)(log, fmt % (event_dict)) getattr(LoggingLoggerClass, event_dict['log_level'].name)(log, fmt % (event_dict))
else: else:
PythonLoggingObserver.emit(self, event_dict) PythonLoggingObserver.emit(self, event_dict)
@ -208,17 +208,17 @@ def tweak_logging_levels():
the command line. the command line.
""" """
from deluge import configmanager from deluge import configmanager
logging_config_file = os.path.join(configmanager.get_config_dir(), "logging.conf") logging_config_file = os.path.join(configmanager.get_config_dir(), 'logging.conf')
if not os.path.isfile(logging_config_file): if not os.path.isfile(logging_config_file):
return return
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
log.warn("logging.conf found! tweaking logging levels from %s", log.warn('logging.conf found! tweaking logging levels from %s',
logging_config_file) logging_config_file)
with open(logging_config_file, "r") as _file: with open(logging_config_file, 'r') as _file:
for line in _file: for line in _file:
if line.strip().startswith("#"): if line.strip().startswith('#'):
continue continue
name, level = line.strip().split(":") name, level = line.strip().split(':')
if level not in levels: if level not in levels:
continue continue
@ -236,7 +236,7 @@ def set_logger_level(level, logger_name=None):
tweak the root logger level. tweak the root logger level.
""" """
logging.getLogger(logger_name).setLevel(levels.get(level, "error")) logging.getLogger(logger_name).setLevel(levels.get(level, 'error'))
def get_plugin_logger(logger_name): def get_plugin_logger(logger_name):
@ -246,14 +246,14 @@ def get_plugin_logger(logger_name):
module_stack = stack.pop(0) # The module that called the log function module_stack = stack.pop(0) # The module that called the log function
caller_module = inspect.getmodule(module_stack[0]) caller_module = inspect.getmodule(module_stack[0])
# In some weird cases caller_module might be None, try to continue # In some weird cases caller_module might be None, try to continue
caller_module_name = getattr(caller_module, "__name__", "") caller_module_name = getattr(caller_module, '__name__', '')
warnings.warn_explicit(DEPRECATION_WARNING, DeprecationWarning, warnings.warn_explicit(DEPRECATION_WARNING, DeprecationWarning,
module_stack[1], module_stack[2], module_stack[1], module_stack[2],
caller_module_name) caller_module_name)
if "deluge.plugins." in logger_name: if 'deluge.plugins.' in logger_name:
return logging.getLogger(logger_name) return logging.getLogger(logger_name)
return logging.getLogger("deluge.plugin.%s" % logger_name) return logging.getLogger('deluge.plugin.%s' % logger_name)
DEPRECATION_WARNING = """You seem to be using old style logging on your code, ie: DEPRECATION_WARNING = """You seem to be using old style logging on your code, ie:
@ -282,13 +282,13 @@ Triggering code:"""
class _BackwardsCompatibleLOG(object): class _BackwardsCompatibleLOG(object):
def __getattribute__(self, name): def __getattribute__(self, name):
import warnings import warnings
logger_name = "deluge" logger_name = 'deluge'
stack = inspect.stack() stack = inspect.stack()
stack.pop(0) # The logging call from this module stack.pop(0) # The logging call from this module
module_stack = stack.pop(0) # The module that called the log function module_stack = stack.pop(0) # The module that called the log function
caller_module = inspect.getmodule(module_stack[0]) caller_module = inspect.getmodule(module_stack[0])
# In some weird cases caller_module might be None, try to continue # In some weird cases caller_module might be None, try to continue
caller_module_name = getattr(caller_module, "__name__", "") caller_module_name = getattr(caller_module, '__name__', '')
warnings.warn_explicit(DEPRECATION_WARNING, DeprecationWarning, warnings.warn_explicit(DEPRECATION_WARNING, DeprecationWarning,
module_stack[1], module_stack[2], module_stack[1], module_stack[2],
caller_module_name) caller_module_name)
@ -297,16 +297,16 @@ class _BackwardsCompatibleLOG(object):
module = inspect.getmodule(member[0]) module = inspect.getmodule(member[0])
if not module: if not module:
continue continue
if module.__name__ in ("deluge.plugins.pluginbase", if module.__name__ in ('deluge.plugins.pluginbase',
"deluge.plugins.init"): 'deluge.plugins.init'):
logger_name += ".plugin.%s" % caller_module_name logger_name += '.plugin.%s' % caller_module_name
# Monkey Patch The Plugin Module # Monkey Patch The Plugin Module
caller_module.log = logging.getLogger(logger_name) caller_module.log = logging.getLogger(logger_name)
break break
else: else:
logging.getLogger(logger_name).warning( logging.getLogger(logger_name).warning(
"Unable to monkey-patch the calling module's `log` attribute! " "Unable to monkey-patch the calling module's `log` attribute! "
"You should really update and rebuild your plugins..." 'You should really update and rebuild your plugins...'
) )
return getattr(logging.getLogger(logger_name), name) return getattr(logging.getLogger(logger_name), name)

View File

@ -46,7 +46,7 @@ class TorrentMetadata(object):
def __init__(self): def __init__(self):
self.__data_path = None self.__data_path = None
self.__piece_size = 0 self.__piece_size = 0
self.__comment = "" self.__comment = ''
self.__private = False self.__private = False
self.__trackers = [] self.__trackers = []
self.__webseeds = [] self.__webseeds = []
@ -65,37 +65,37 @@ class TorrentMetadata(object):
""" """
if not self.data_path: if not self.data_path:
raise InvalidPath("Need to set a data_path!") raise InvalidPath('Need to set a data_path!')
torrent = { torrent = {
"info": {} 'info': {}
} }
if self.comment: if self.comment:
torrent["comment"] = self.comment.encode("UTF-8") torrent['comment'] = self.comment.encode('UTF-8')
if self.private: if self.private:
torrent["info"]["private"] = True torrent['info']['private'] = True
if self.trackers: if self.trackers:
torrent["announce"] = self.trackers[0][0] torrent['announce'] = self.trackers[0][0]
torrent["announce-list"] = self.trackers torrent['announce-list'] = self.trackers
else: else:
torrent["announce"] = "" torrent['announce'] = ''
if self.webseeds: if self.webseeds:
httpseeds = [] httpseeds = []
webseeds = [] webseeds = []
for w in self.webseeds: for w in self.webseeds:
if w.endswith(".php"): if w.endswith('.php'):
httpseeds.append(w) httpseeds.append(w)
else: else:
webseeds.append(w) webseeds.append(w)
if httpseeds: if httpseeds:
torrent["httpseeds"] = httpseeds torrent['httpseeds'] = httpseeds
if webseeds: if webseeds:
torrent["url-list"] = webseeds torrent['url-list'] = webseeds
datasize = get_path_size(self.data_path) datasize = get_path_size(self.data_path)
@ -112,11 +112,11 @@ class TorrentMetadata(object):
if datasize % piece_size: if datasize % piece_size:
num_pieces += 1 num_pieces += 1
torrent["info"]["piece length"] = piece_size torrent['info']['piece length'] = piece_size
# Create the info # Create the info
if os.path.isdir(self.data_path): if os.path.isdir(self.data_path):
torrent["info"]["name"] = os.path.split(self.data_path)[1] torrent['info']['name'] = os.path.split(self.data_path)[1]
files = [] files = []
padding_count = 0 padding_count = 0
# Collect a list of file paths and add padding files if necessary # Collect a list of file paths and add padding files if necessary
@ -124,8 +124,8 @@ class TorrentMetadata(object):
for index, filename in enumerate(filenames): for index, filename in enumerate(filenames):
size = get_path_size(os.path.join(self.data_path, dirpath, filename)) size = get_path_size(os.path.join(self.data_path, dirpath, filename))
p = dirpath[len(self.data_path):] p = dirpath[len(self.data_path):]
p = p.lstrip("/") p = p.lstrip('/')
p = p.split("/") p = p.split('/')
if p[0]: if p[0]:
p += [filename] p += [filename]
else: else:
@ -136,7 +136,7 @@ class TorrentMetadata(object):
left = size % piece_size left = size % piece_size
if left: if left:
p = list(p) p = list(p)
p[-1] = "_____padding_file_" + str(padding_count) p[-1] = '_____padding_file_' + str(padding_count)
files.append((piece_size - left, p)) files.append((piece_size - left, p))
padding_count += 1 padding_count += 1
@ -147,17 +147,17 @@ class TorrentMetadata(object):
fs = [] fs = []
pieces = [] pieces = []
# Create the piece hashes # Create the piece hashes
buf = "" buf = ''
for size, path in files: for size, path in files:
path = [s.decode(sys.getfilesystemencoding()).encode("UTF-8") for s in path] path = [s.decode(sys.getfilesystemencoding()).encode('UTF-8') for s in path]
fs.append({"length": size, "path": path}) fs.append({'length': size, 'path': path})
if path[-1].startswith("_____padding_file_"): if path[-1].startswith('_____padding_file_'):
buf += "\0" * size buf += '\0' * size
pieces.append(sha(buf).digest()) pieces.append(sha(buf).digest())
buf = "" buf = ''
fs[-1]["attr"] = "p" fs[-1]['attr'] = 'p'
else: else:
with open(os.path.join(self.data_path, *path), "rb") as _file: with open(os.path.join(self.data_path, *path), 'rb') as _file:
r = _file.read(piece_size - len(buf)) r = _file.read(piece_size - len(buf))
while r: while r:
buf += r buf += r
@ -166,7 +166,7 @@ class TorrentMetadata(object):
# Run the progress function if necessary # Run the progress function if necessary
if progress: if progress:
progress(len(pieces), num_pieces) progress(len(pieces), num_pieces)
buf = "" buf = ''
else: else:
break break
r = _file.read(piece_size - len(buf)) r = _file.read(piece_size - len(buf))
@ -175,17 +175,17 @@ class TorrentMetadata(object):
pieces.append(sha(buf).digest()) pieces.append(sha(buf).digest())
if progress: if progress:
progress(len(pieces), num_pieces) progress(len(pieces), num_pieces)
buf = "" buf = ''
torrent["info"]["pieces"] = "".join(pieces) torrent['info']['pieces'] = ''.join(pieces)
torrent["info"]["files"] = fs torrent['info']['files'] = fs
elif os.path.isfile(self.data_path): elif os.path.isfile(self.data_path):
torrent["info"]["name"] = os.path.split(self.data_path)[1] torrent['info']['name'] = os.path.split(self.data_path)[1]
torrent["info"]["length"] = get_path_size(self.data_path) torrent['info']['length'] = get_path_size(self.data_path)
pieces = [] pieces = []
with open(self.data_path, "rb") as _file: with open(self.data_path, 'rb') as _file:
r = _file.read(piece_size) r = _file.read(piece_size)
while r: while r:
pieces.append(sha(r).digest()) pieces.append(sha(r).digest())
@ -194,10 +194,10 @@ class TorrentMetadata(object):
r = _file.read(piece_size) r = _file.read(piece_size)
torrent["info"]["pieces"] = "".join(pieces) torrent['info']['pieces'] = ''.join(pieces)
# Write out the torrent file # Write out the torrent file
with open(torrent_path, "wb") as _file: with open(torrent_path, 'wb') as _file:
_file.write(bencode(torrent)) _file.write(bencode(torrent))
def get_data_path(self): def get_data_path(self):
@ -228,7 +228,7 @@ class TorrentMetadata(object):
if os.path.exists(path) and (os.path.isdir(path) or os.path.isfile(path)): if os.path.exists(path) and (os.path.isdir(path) or os.path.isfile(path)):
self.__data_path = os.path.abspath(path) self.__data_path = os.path.abspath(path)
else: else:
raise InvalidPath("No such file or directory: %s" % path) raise InvalidPath('No such file or directory: %s' % path)
def get_piece_size(self): def get_piece_size(self):
"""The size of the pieces. """The size of the pieces.
@ -254,7 +254,7 @@ class TorrentMetadata(object):
""" """
if size % 16 and size: if size % 16 and size:
raise InvalidPieceSize("Piece size must be a multiple of 16 KiB") raise InvalidPieceSize('Piece size must be a multiple of 16 KiB')
self.__piece_size = size self.__piece_size = size
def get_comment(self): def get_comment(self):

View File

@ -47,10 +47,10 @@ def get_filesystem_encoding():
def decode_from_filesystem(path): def decode_from_filesystem(path):
encoding = get_filesystem_encoding() encoding = get_filesystem_encoding()
if encoding is None: if encoding is None:
assert isinstance(path, unicode), "Path should be unicode not %s" % type(path) assert isinstance(path, unicode), 'Path should be unicode not %s' % type(path)
decoded_path = path decoded_path = path
else: else:
assert isinstance(path, str), "Path should be str not %s" % type(path) assert isinstance(path, str), 'Path should be str not %s' % type(path)
decoded_path = path.decode(encoding) decoded_path = path.decode(encoding)
return decoded_path return decoded_path
@ -65,7 +65,7 @@ class RemoteFileProgress(object):
self.session_id = session_id self.session_id = session_id
def __call__(self, piece_count, num_pieces): def __call__(self, piece_count, num_pieces):
component.get("RPCServer").emit_event_for_session_id( component.get('RPCServer').emit_event_for_session_id(
self.session_id, CreateTorrentProgressEvent(piece_count, num_pieces) self.session_id, CreateTorrentProgressEvent(piece_count, num_pieces)
) )
@ -86,11 +86,11 @@ def make_meta_file(path, url, piece_length, progress=None, title=None, comment=N
f = target f = target
if progress is None: if progress is None:
session_id = component.get("RPCServer").get_session_id() session_id = component.get('RPCServer').get_session_id()
if not session_id: if not session_id:
progress = dummy progress = dummy
else: else:
progress = RemoteFileProgress(component.get("RPCServer").get_session_id()) progress = RemoteFileProgress(component.get('RPCServer').get_session_id())
info = makeinfo(path, piece_length, progress, name, content_type, private) info = makeinfo(path, piece_length, progress, name, content_type, private)
@ -99,18 +99,18 @@ def make_meta_file(path, url, piece_length, progress=None, title=None, comment=N
data['info'] = info data['info'] = info
if title: if title:
data['title'] = title.encode("utf8") data['title'] = title.encode('utf8')
if comment: if comment:
data['comment'] = comment.encode("utf8") data['comment'] = comment.encode('utf8')
if safe: if safe:
data['safe'] = safe.encode("utf8") data['safe'] = safe.encode('utf8')
httpseeds = [] httpseeds = []
url_list = [] url_list = []
if webseeds: if webseeds:
for webseed in webseeds: for webseed in webseeds:
if webseed.endswith(".php"): if webseed.endswith('.php'):
httpseeds.append(webseed) httpseeds.append(webseed)
else: else:
url_list.append(webseed) url_list.append(webseed)
@ -120,12 +120,12 @@ def make_meta_file(path, url, piece_length, progress=None, title=None, comment=N
if httpseeds: if httpseeds:
data['httpseeds'] = httpseeds data['httpseeds'] = httpseeds
if created_by: if created_by:
data['created by'] = created_by.encode("utf8") data['created by'] = created_by.encode('utf8')
if trackers and (len(trackers[0]) > 1 or len(trackers) > 1): if trackers and (len(trackers[0]) > 1 or len(trackers) > 1):
data['announce-list'] = trackers data['announce-list'] = trackers
data["encoding"] = "UTF-8" data['encoding'] = 'UTF-8'
h.write(bencode(data)) h.write(bencode(data))
h.close() h.close()

View File

@ -41,9 +41,9 @@ def get_completion_paths(args):
:rtype: list :rtype: list
""" """
args["paths"] = [] args['paths'] = []
path_value = args["completion_text"] path_value = args['completion_text']
hidden_files = args["show_hidden_files"] hidden_files = args['show_hidden_files']
def get_subdirs(dirname): def get_subdirs(dirname):
try: try:
@ -78,5 +78,5 @@ def get_completion_paths(args):
p += os.path.sep p += os.path.sep
matching_dirs.append(p) matching_dirs.append(p)
args["paths"] = sorted(matching_dirs) args['paths'] = sorted(matching_dirs)
return args return args

View File

@ -24,15 +24,15 @@ import deluge.configmanager
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
METADATA_KEYS = [ METADATA_KEYS = [
"Name", 'Name',
"License", 'License',
"Author", 'Author',
"Home-page", 'Home-page',
"Summary", 'Summary',
"Platform", 'Platform',
"Version", 'Version',
"Author-email", 'Author-email',
"Description", 'Description',
] ]
DEPRECATION_WARNING = """ DEPRECATION_WARNING = """
@ -50,13 +50,13 @@ class PluginManagerBase(object):
"""PluginManagerBase is a base class for PluginManagers to inherit""" """PluginManagerBase is a base class for PluginManagers to inherit"""
def __init__(self, config_file, entry_name): def __init__(self, config_file, entry_name):
log.debug("Plugin manager init..") log.debug('Plugin manager init..')
self.config = deluge.configmanager.ConfigManager(config_file) self.config = deluge.configmanager.ConfigManager(config_file)
# Create the plugins folder if it doesn't exist # Create the plugins folder if it doesn't exist
if not os.path.exists(os.path.join(deluge.configmanager.get_config_dir(), "plugins")): if not os.path.exists(os.path.join(deluge.configmanager.get_config_dir(), 'plugins')):
os.mkdir(os.path.join(deluge.configmanager.get_config_dir(), "plugins")) os.mkdir(os.path.join(deluge.configmanager.get_config_dir(), 'plugins'))
# This is the entry we want to load.. # This is the entry we want to load..
self.entry_name = entry_name self.entry_name = entry_name
@ -69,7 +69,7 @@ class PluginManagerBase(object):
def enable_plugins(self): def enable_plugins(self):
# Load plugins that are enabled in the config. # Load plugins that are enabled in the config.
for name in self.config["enabled_plugins"]: for name in self.config['enabled_plugins']:
self.enable_plugin(name) self.enable_plugin(name)
def disable_plugins(self): def disable_plugins(self):
@ -91,9 +91,9 @@ class PluginManagerBase(object):
def scan_for_plugins(self): def scan_for_plugins(self):
"""Scans for available plugins""" """Scans for available plugins"""
base_plugin_dir = deluge.common.resource_filename("deluge", "plugins") base_plugin_dir = deluge.common.resource_filename('deluge', 'plugins')
pkg_resources.working_set.add_entry(base_plugin_dir) pkg_resources.working_set.add_entry(base_plugin_dir)
user_plugin_dir = os.path.join(deluge.configmanager.get_config_dir(), "plugins") user_plugin_dir = os.path.join(deluge.configmanager.get_config_dir(), 'plugins')
plugins_dirs = [base_plugin_dir] plugins_dirs = [base_plugin_dir]
for dirname in os.listdir(base_plugin_dir): for dirname in os.listdir(base_plugin_dir):
@ -107,7 +107,7 @@ class PluginManagerBase(object):
self.available_plugins = [] self.available_plugins = []
for name in self.pkg_env: for name in self.pkg_env:
log.debug("Found plugin: %s %s at %s", log.debug('Found plugin: %s %s at %s',
self.pkg_env[name][0].project_name, self.pkg_env[name][0].project_name,
self.pkg_env[name][0].version, self.pkg_env[name][0].version,
self.pkg_env[name][0].location) self.pkg_env[name][0].location)
@ -125,14 +125,14 @@ class PluginManagerBase(object):
""" """
if plugin_name not in self.available_plugins: if plugin_name not in self.available_plugins:
log.warning("Cannot enable non-existant plugin %s", plugin_name) log.warning('Cannot enable non-existant plugin %s', plugin_name)
return defer.succeed(False) return defer.succeed(False)
if plugin_name in self.plugins: if plugin_name in self.plugins:
log.warning("Cannot enable already enabled plugin %s", plugin_name) log.warning('Cannot enable already enabled plugin %s', plugin_name)
return defer.succeed(True) return defer.succeed(True)
plugin_name = plugin_name.replace(" ", "-") plugin_name = plugin_name.replace(' ', '-')
egg = self.pkg_env[plugin_name][0] egg = self.pkg_env[plugin_name][0]
egg.activate() egg.activate()
return_d = defer.succeed(True) return_d = defer.succeed(True)
@ -141,12 +141,12 @@ class PluginManagerBase(object):
entry_point = egg.get_entry_info(self.entry_name, name) entry_point = egg.get_entry_info(self.entry_name, name)
try: try:
cls = entry_point.load() cls = entry_point.load()
instance = cls(plugin_name.replace("-", "_")) instance = cls(plugin_name.replace('-', '_'))
except component.ComponentAlreadyRegistered as ex: except component.ComponentAlreadyRegistered as ex:
log.error(ex) log.error(ex)
return defer.succeed(False) return defer.succeed(False)
except Exception as ex: except Exception as ex:
log.error("Unable to instantiate plugin %r from %r!", name, egg.location) log.error('Unable to instantiate plugin %r from %r!', name, egg.location)
log.exception(ex) log.exception(ex)
continue continue
try: try:
@ -156,25 +156,25 @@ class PluginManagerBase(object):
log.exception(ex) log.exception(ex)
return_d = defer.fail(False) return_d = defer.fail(False)
if not instance.__module__.startswith("deluge.plugins."): if not instance.__module__.startswith('deluge.plugins.'):
import warnings import warnings
warnings.warn_explicit( warnings.warn_explicit(
DEPRECATION_WARNING % name, DEPRECATION_WARNING % name,
DeprecationWarning, DeprecationWarning,
instance.__module__, 0 instance.__module__, 0
) )
if self._component_state == "Started": if self._component_state == 'Started':
def on_enabled(result, instance): def on_enabled(result, instance):
return component.start([instance.plugin._component_name]) return component.start([instance.plugin._component_name])
return_d.addCallback(on_enabled, instance) return_d.addCallback(on_enabled, instance)
def on_started(result, instance): def on_started(result, instance):
plugin_name_space = plugin_name.replace("-", " ") plugin_name_space = plugin_name.replace('-', ' ')
self.plugins[plugin_name_space] = instance self.plugins[plugin_name_space] = instance
if plugin_name_space not in self.config["enabled_plugins"]: if plugin_name_space not in self.config['enabled_plugins']:
log.debug("Adding %s to enabled_plugins list in config", plugin_name_space) log.debug('Adding %s to enabled_plugins list in config', plugin_name_space)
self.config["enabled_plugins"].append(plugin_name_space) self.config['enabled_plugins'].append(plugin_name_space)
log.info("Plugin %s enabled..", plugin_name_space) log.info('Plugin %s enabled..', plugin_name_space)
return True return True
def on_started_error(result, instance): def on_started_error(result, instance):
@ -218,13 +218,13 @@ class PluginManagerBase(object):
try: try:
component.deregister(self.plugins[name].plugin) component.deregister(self.plugins[name].plugin)
del self.plugins[name] del self.plugins[name]
self.config["enabled_plugins"].remove(name) self.config['enabled_plugins'].remove(name)
except Exception as ex: except Exception as ex:
log.error("Unable to disable plugin '%s'!", name) log.error("Unable to disable plugin '%s'!", name)
log.exception(ex) log.exception(ex)
ret = False ret = False
else: else:
log.info("Plugin %s disabled..", name) log.info('Plugin %s disabled..', name)
return ret return ret
d.addBoth(on_disabled) d.addBoth(on_disabled)
@ -233,25 +233,25 @@ class PluginManagerBase(object):
def get_plugin_info(self, name): def get_plugin_info(self, name):
"""Returns a dictionary of plugin info from the metadata""" """Returns a dictionary of plugin info from the metadata"""
info = {}.fromkeys(METADATA_KEYS) info = {}.fromkeys(METADATA_KEYS)
last_header = "" last_header = ''
cont_lines = [] cont_lines = []
# Missing plugin info # Missing plugin info
if not self.pkg_env[name]: if not self.pkg_env[name]:
log.warn("Failed to retrive info for plugin '%s'", name) log.warn("Failed to retrive info for plugin '%s'", name)
for k in info: for k in info:
info[k] = "not available" info[k] = 'not available'
return info return info
for line in self.pkg_env[name][0].get_metadata("PKG-INFO").splitlines(): for line in self.pkg_env[name][0].get_metadata('PKG-INFO').splitlines():
if not line: if not line:
continue 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 info.keys()):
# This is a continuation # This is a continuation
cont_lines.append(line.strip()) cont_lines.append(line.strip())
else: else:
if cont_lines: if cont_lines:
info[last_header] = "\n".join(cont_lines).strip() info[last_header] = '\n'.join(cont_lines).strip()
cont_lines = [] cont_lines = []
if line.split(":", 1)[0] in info.keys(): if line.split(':', 1)[0] in info.keys():
last_header = line.split(":", 1)[0] last_header = line.split(':', 1)[0]
info[last_header] = line.split(":", 1)[1].strip() info[last_header] = line.split(':', 1)[1].strip()
return info return info

View File

@ -18,4 +18,4 @@ import pkg_resources
def get_resource(filename): def get_resource(filename):
return pkg_resources.resource_filename("deluge.plugins.autoadd", os.path.join("data", filename)) return pkg_resources.resource_filename('deluge.plugins.autoadd', os.path.join('data', filename))

View File

@ -33,35 +33,35 @@ log = logging.getLogger(__name__)
DEFAULT_PREFS = { DEFAULT_PREFS = {
"watchdirs": {}, 'watchdirs': {},
"next_id": 1 'next_id': 1
} }
OPTIONS_AVAILABLE = { # option: builtin OPTIONS_AVAILABLE = { # option: builtin
"enabled": False, 'enabled': False,
"path": False, 'path': False,
"append_extension": False, 'append_extension': False,
"copy_torrent": False, 'copy_torrent': False,
"delete_copy_torrent_toggle": False, 'delete_copy_torrent_toggle': False,
"abspath": False, 'abspath': False,
"download_location": True, 'download_location': True,
"max_download_speed": True, 'max_download_speed': True,
"max_upload_speed": True, 'max_upload_speed': True,
"max_connections": True, 'max_connections': True,
"max_upload_slots": True, 'max_upload_slots': True,
"prioritize_first_last": True, 'prioritize_first_last': True,
"auto_managed": True, 'auto_managed': True,
"stop_at_ratio": True, 'stop_at_ratio': True,
"stop_ratio": True, 'stop_ratio': True,
"remove_at_ratio": True, 'remove_at_ratio': True,
"move_completed": True, 'move_completed': True,
"move_completed_path": True, 'move_completed_path': True,
"label": False, 'label': False,
"add_paused": True, 'add_paused': True,
"queue_to_top": False, 'queue_to_top': False,
"owner": True, 'owner': True,
"seed_mode": True 'seed_mode': True
} }
MAX_NUM_ATTEMPTS = 10 MAX_NUM_ATTEMPTS = 10
@ -82,13 +82,13 @@ class Core(CorePluginBase):
def enable(self): def enable(self):
# reduce typing, assigning some values to self... # reduce typing, assigning some values to self...
self.config = deluge.configmanager.ConfigManager("autoadd.conf", DEFAULT_PREFS) self.config = deluge.configmanager.ConfigManager('autoadd.conf', DEFAULT_PREFS)
self.config.run_converter((0, 1), 2, self.__migrate_config_1_to_2) self.config.run_converter((0, 1), 2, self.__migrate_config_1_to_2)
self.config.save() self.config.save()
self.watchdirs = self.config["watchdirs"] self.watchdirs = self.config['watchdirs']
component.get("EventManager").register_event_handler( component.get('EventManager').register_event_handler(
"PreTorrentRemovedEvent", self.__on_pre_torrent_removed 'PreTorrentRemovedEvent', self.__on_pre_torrent_removed
) )
# Dict of Filename:Attempts # Dict of Filename:Attempts
@ -100,13 +100,13 @@ class Core(CorePluginBase):
def enable_looping(self): def enable_looping(self):
# Enable all looping calls for enabled watchdirs here # Enable all looping calls for enabled watchdirs here
for watchdir_id, watchdir in self.watchdirs.iteritems(): for watchdir_id, watchdir in self.watchdirs.iteritems():
if watchdir["enabled"]: if watchdir['enabled']:
self.enable_watchdir(watchdir_id) self.enable_watchdir(watchdir_id)
def disable(self): def disable(self):
# disable all running looping calls # disable all running looping calls
component.get("EventManager").deregister_event_handler( component.get('EventManager').deregister_event_handler(
"PreTorrentRemovedEvent", self.__on_pre_torrent_removed 'PreTorrentRemovedEvent', self.__on_pre_torrent_removed
) )
for loopingcall in self.update_timers.itervalues(): for loopingcall in self.update_timers.itervalues():
loopingcall.stop() loopingcall.stop()
@ -121,45 +121,45 @@ class Core(CorePluginBase):
watchdir_id = str(watchdir_id) watchdir_id = str(watchdir_id)
options = self._make_unicode(options) options = self._make_unicode(options)
check_input( check_input(
watchdir_id in self.watchdirs, _("Watch folder does not exist.") watchdir_id in self.watchdirs, _('Watch folder does not exist.')
) )
if "path" in options: if 'path' in options:
options["abspath"] = os.path.abspath(options["path"]) options['abspath'] = os.path.abspath(options['path'])
check_input( check_input(
os.path.isdir(options["abspath"]), _("Path does not exist.") os.path.isdir(options['abspath']), _('Path does not exist.')
) )
for w_id, w in self.watchdirs.iteritems(): for w_id, w in self.watchdirs.iteritems():
if options["abspath"] == w["abspath"] and watchdir_id != w_id: if options['abspath'] == w['abspath'] and watchdir_id != w_id:
raise Exception("Path is already being watched.") raise Exception('Path is already being watched.')
for key in options: for key in options:
if key not in OPTIONS_AVAILABLE: 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.iterkeys()]:
raise Exception("autoadd: Invalid options key:%s" % key) raise Exception('autoadd: Invalid options key:%s' % key)
# disable the watch loop if it was active # disable the watch loop if it was active
if watchdir_id in self.update_timers: if watchdir_id in self.update_timers:
self.disable_watchdir(watchdir_id) self.disable_watchdir(watchdir_id)
self.watchdirs[watchdir_id].update(options) self.watchdirs[watchdir_id].update(options)
# re-enable watch loop if appropriate # re-enable watch loop if appropriate
if self.watchdirs[watchdir_id]["enabled"]: if self.watchdirs[watchdir_id]['enabled']:
self.enable_watchdir(watchdir_id) self.enable_watchdir(watchdir_id)
self.config.save() self.config.save()
component.get("EventManager").emit(AutoaddOptionsChangedEvent()) component.get('EventManager').emit(AutoaddOptionsChangedEvent())
def load_torrent(self, filename, magnet): def load_torrent(self, filename, magnet):
try: try:
log.debug("Attempting to open %s for add.", filename) log.debug('Attempting to open %s for add.', filename)
if magnet: if magnet:
with open(filename, "r") as _file: with open(filename, 'r') as _file:
filedump = _file.read() filedump = _file.read()
else: else:
with open(filename, "rb") as _file: with open(filename, 'rb') as _file:
filedump = _file.read() filedump = _file.read()
if not filedump: if not filedump:
raise RuntimeError("Torrent is 0 bytes!") raise RuntimeError('Torrent is 0 bytes!')
except IOError as ex: except IOError as ex:
log.warning("Unable to open %s: %s", filename, ex) log.warning('Unable to open %s: %s', filename, ex)
raise ex raise ex
# Get the info to see if any exceptions are raised # Get the info to see if any exceptions are raised
@ -169,16 +169,16 @@ class Core(CorePluginBase):
return base64.encodestring(filedump) return base64.encodestring(filedump)
def split_magnets(self, filename): def split_magnets(self, filename):
log.debug("Attempting to open %s for splitting magnets.", filename) log.debug('Attempting to open %s for splitting magnets.', filename)
magnets = [] magnets = []
try: try:
with open(filename, "r") as _file: with open(filename, 'r') as _file:
for line in _file: for line in _file:
line = line.strip() line = line.strip()
if line: if line:
magnets.append(line) magnets.append(line)
except IOError as ex: except IOError as ex:
log.warning("Unable to open %s: %s", filename, ex) log.warning('Unable to open %s: %s', filename, ex)
if len(magnets) < 2: if len(magnets) < 2:
return [] return []
@ -186,79 +186,79 @@ class Core(CorePluginBase):
n = 0 n = 0
path = filename.rsplit(os.sep, 1)[0] path = filename.rsplit(os.sep, 1)[0]
for magnet in magnets: for magnet in magnets:
for part in magnet.split("&"): for part in magnet.split('&'):
if part.startswith("dn="): if part.startswith('dn='):
mname = os.sep.join([path, part[3:] + ".magnet"]) mname = os.sep.join([path, part[3:] + '.magnet'])
break break
else: else:
mname = ".".join([filename, str(n), "magnet"]) mname = '.'.join([filename, str(n), 'magnet'])
n += 1 n += 1
try: try:
with open(mname, "w") as _mfile: with open(mname, 'w') as _mfile:
_mfile.write(magnet) _mfile.write(magnet)
except IOError as ex: except IOError as ex:
log.warning("Unable to open %s: %s", mname, ex) log.warning('Unable to open %s: %s', mname, ex)
return magnets return magnets
def update_watchdir(self, watchdir_id): def update_watchdir(self, watchdir_id):
"""Check the watch folder for new torrents to add.""" """Check the watch folder for new torrents to add."""
log.trace("Updating watchdir id: %s", watchdir_id) log.trace('Updating watchdir id: %s', watchdir_id)
watchdir_id = str(watchdir_id) watchdir_id = str(watchdir_id)
watchdir = self.watchdirs[watchdir_id] watchdir = self.watchdirs[watchdir_id]
if not watchdir["enabled"]: if not watchdir['enabled']:
# We shouldn't be updating because this watchdir is not enabled # We shouldn't be updating because this watchdir is not enabled
log.debug("Watchdir id %s is not enabled. Disabling it.", log.debug('Watchdir id %s is not enabled. Disabling it.',
watchdir_id) watchdir_id)
self.disable_watchdir(watchdir_id) self.disable_watchdir(watchdir_id)
return return
if not os.path.isdir(watchdir["abspath"]): if not os.path.isdir(watchdir['abspath']):
log.warning("Invalid AutoAdd folder: %s", watchdir["abspath"]) log.warning('Invalid AutoAdd folder: %s', watchdir['abspath'])
self.disable_watchdir(watchdir_id) self.disable_watchdir(watchdir_id)
return return
# Generate options dict for watchdir # Generate options dict for watchdir
opts = {} opts = {}
if "stop_at_ratio_toggle" in watchdir: if 'stop_at_ratio_toggle' in watchdir:
watchdir["stop_ratio_toggle"] = watchdir["stop_at_ratio_toggle"] watchdir['stop_ratio_toggle'] = watchdir['stop_at_ratio_toggle']
# We default to True when reading _toggle values, so a config # We default to True when reading _toggle values, so a config
# without them is valid, and applies all its settings. # without them is valid, and applies all its settings.
for option, value in watchdir.iteritems(): for option, value in watchdir.iteritems():
if OPTIONS_AVAILABLE.get(option): if OPTIONS_AVAILABLE.get(option):
if watchdir.get(option + "_toggle", True) or option in ["owner", "seed_mode"]: if watchdir.get(option + '_toggle', True) or option in ['owner', 'seed_mode']:
opts[option] = value opts[option] = value
# Check for .magnet files containing multiple magnet links and # Check for .magnet files containing multiple magnet links and
# create a new .magnet file for each of them. # create a new .magnet file for each of them.
for filename in os.listdir(watchdir["abspath"]): for filename in os.listdir(watchdir['abspath']):
try: try:
filepath = os.path.join(watchdir["abspath"], filename) filepath = os.path.join(watchdir['abspath'], filename)
except UnicodeDecodeError as ex: except UnicodeDecodeError as ex:
log.error("Unable to auto add torrent due to improper filename encoding: %s", ex) log.error('Unable to auto add torrent due to improper filename encoding: %s', ex)
continue continue
if os.path.isdir(filepath): if os.path.isdir(filepath):
# Skip directories # Skip directories
continue continue
elif os.path.splitext(filename)[1] == ".magnet" and self.split_magnets(filepath): elif os.path.splitext(filename)[1] == '.magnet' and self.split_magnets(filepath):
os.remove(filepath) os.remove(filepath)
for filename in os.listdir(watchdir["abspath"]): for filename in os.listdir(watchdir['abspath']):
try: try:
filepath = os.path.join(watchdir["abspath"], filename) filepath = os.path.join(watchdir['abspath'], filename)
except UnicodeDecodeError as ex: except UnicodeDecodeError as ex:
log.error("Unable to auto add torrent due to improper filename encoding: %s", ex) log.error('Unable to auto add torrent due to improper filename encoding: %s', ex)
continue continue
if os.path.isdir(filepath): if os.path.isdir(filepath):
# Skip directories # Skip directories
continue continue
else: else:
ext = os.path.splitext(filename)[1].lower() ext = os.path.splitext(filename)[1].lower()
if ext == ".torrent": if ext == '.torrent':
magnet = False magnet = False
elif ext == ".magnet": elif ext == '.magnet':
magnet = True magnet = True
else: else:
log.debug("File checked for auto-loading is invalid: %s", filename) log.debug('File checked for auto-loading is invalid: %s', filename)
continue continue
try: try:
filedump = self.load_torrent(filepath, magnet) filedump = self.load_torrent(filepath, magnet)
@ -266,15 +266,15 @@ class Core(CorePluginBase):
# If the torrent is invalid, we keep track of it so that we # If the torrent is invalid, we keep track of it so that we
# can try again on the next pass. This is because some # can try again on the next pass. This is because some
# torrents may not be fully saved during the pass. # torrents may not be fully saved during the pass.
log.debug("Torrent is invalid: %s", ex) log.debug('Torrent is invalid: %s', ex)
if filename in self.invalid_torrents: if filename in self.invalid_torrents:
self.invalid_torrents[filename] += 1 self.invalid_torrents[filename] += 1
if self.invalid_torrents[filename] >= MAX_NUM_ATTEMPTS: if self.invalid_torrents[filename] >= MAX_NUM_ATTEMPTS:
log.warning( log.warning(
"Maximum attempts reached while trying to add the " 'Maximum attempts reached while trying to add the '
"torrent file with the path %s", filepath 'torrent file with the path %s', filepath
) )
os.rename(filepath, filepath + ".invalid") os.rename(filepath, filepath + '.invalid')
del self.invalid_torrents[filename] del self.invalid_torrents[filename]
else: else:
self.invalid_torrents[filename] = 1 self.invalid_torrents[filename] = 1
@ -282,37 +282,37 @@ class Core(CorePluginBase):
# The torrent looks good, so lets add it to the session. # The torrent looks good, so lets add it to the session.
if magnet: if magnet:
torrent_id = component.get("Core").add_torrent_magnet(filedump, opts) torrent_id = component.get('Core').add_torrent_magnet(filedump, opts)
else: else:
torrent_id = component.get("Core").add_torrent_file(filename, filedump, opts) torrent_id = component.get('Core').add_torrent_file(filename, filedump, opts)
# If the torrent added successfully, set the extra options. # If the torrent added successfully, set the extra options.
if torrent_id: if torrent_id:
if "Label" in component.get("CorePluginManager").get_enabled_plugins(): if 'Label' in component.get('CorePluginManager').get_enabled_plugins():
if watchdir.get("label_toggle", True) and watchdir.get("label"): if watchdir.get('label_toggle', True) and watchdir.get('label'):
label = component.get("CorePlugin.Label") label = component.get('CorePlugin.Label')
if not watchdir["label"] in label.get_labels(): if not watchdir['label'] in label.get_labels():
label.add(watchdir["label"]) label.add(watchdir['label'])
label.set_torrent(torrent_id, watchdir["label"]) label.set_torrent(torrent_id, watchdir['label'])
if watchdir.get("queue_to_top_toggle", True) and "queue_to_top" in watchdir: if watchdir.get('queue_to_top_toggle', True) and 'queue_to_top' in watchdir:
if watchdir["queue_to_top"]: if watchdir['queue_to_top']:
component.get("TorrentManager").queue_top(torrent_id) component.get('TorrentManager').queue_top(torrent_id)
else: else:
component.get("TorrentManager").queue_bottom(torrent_id) component.get('TorrentManager').queue_bottom(torrent_id)
else: else:
# torrent handle is invalid and so is the magnet link # torrent handle is invalid and so is the magnet link
if magnet: if magnet:
log.debug("invalid magnet link") log.debug('invalid magnet link')
os.rename(filepath, filepath + ".invalid") os.rename(filepath, filepath + '.invalid')
continue continue
# Rename, copy or delete the torrent once added to deluge. # Rename, copy or delete the torrent once added to deluge.
if watchdir.get("append_extension_toggle"): if watchdir.get('append_extension_toggle'):
if not watchdir.get("append_extension"): if not watchdir.get('append_extension'):
watchdir["append_extension"] = ".added" watchdir['append_extension'] = '.added'
os.rename(filepath, filepath + watchdir["append_extension"]) os.rename(filepath, filepath + watchdir['append_extension'])
elif watchdir.get("copy_torrent_toggle"): elif watchdir.get('copy_torrent_toggle'):
copy_torrent_path = watchdir["copy_torrent"] copy_torrent_path = watchdir['copy_torrent']
copy_torrent_file = os.path.join(copy_torrent_path, filename) copy_torrent_file = os.path.join(copy_torrent_path, filename)
log.debug("Moving added torrent file \"%s\" to \"%s\"", log.debug("Moving added torrent file \"%s\" to \"%s\"",
os.path.basename(filepath), copy_torrent_path) os.path.basename(filepath), copy_torrent_path)
@ -325,7 +325,7 @@ class Core(CorePluginBase):
"""Disables any watch folders with un-handled exceptions.""" """Disables any watch folders with un-handled exceptions."""
self.disable_watchdir(watchdir_id) self.disable_watchdir(watchdir_id)
log.error("Disabling '%s', error during update: %s", log.error("Disabling '%s', error during update: %s",
self.watchdirs[watchdir_id]["path"], failure) self.watchdirs[watchdir_id]['path'], failure)
@export @export
def enable_watchdir(self, watchdir_id): def enable_watchdir(self, watchdir_id):
@ -337,10 +337,10 @@ class Core(CorePluginBase):
self.on_update_watchdir_error, w_id self.on_update_watchdir_error, w_id
) )
# Update the config # Update the config
if not self.watchdirs[w_id]["enabled"]: if not self.watchdirs[w_id]['enabled']:
self.watchdirs[w_id]["enabled"] = True self.watchdirs[w_id]['enabled'] = True
self.config.save() self.config.save()
component.get("EventManager").emit(AutoaddOptionsChangedEvent()) component.get('EventManager').emit(AutoaddOptionsChangedEvent())
@export @export
def disable_watchdir(self, watchdir_id): def disable_watchdir(self, watchdir_id):
@ -351,10 +351,10 @@ class Core(CorePluginBase):
self.update_timers[w_id].stop() self.update_timers[w_id].stop()
del self.update_timers[w_id] del self.update_timers[w_id]
# Update the config # Update the config
if self.watchdirs[w_id]["enabled"]: if self.watchdirs[w_id]['enabled']:
self.watchdirs[w_id]["enabled"] = False self.watchdirs[w_id]['enabled'] = False
self.config.save() self.config.save()
component.get("EventManager").emit(AutoaddOptionsChangedEvent()) component.get('EventManager').emit(AutoaddOptionsChangedEvent())
@export @export
def set_config(self, config): def set_config(self, config):
@ -363,7 +363,7 @@ class Core(CorePluginBase):
for key in config: for key in config:
self.config[key] = config[key] self.config[key] = config[key]
self.config.save() self.config.save()
component.get("EventManager").emit(AutoaddOptionsChangedEvent()) component.get('EventManager').emit(AutoaddOptionsChangedEvent())
@export @export
def get_config(self): def get_config(self):
@ -372,28 +372,28 @@ class Core(CorePluginBase):
@export @export
def get_watchdirs(self): def get_watchdirs(self):
rpcserver = component.get("RPCServer") rpcserver = component.get('RPCServer')
session_user = rpcserver.get_session_user() session_user = rpcserver.get_session_user()
session_auth_level = rpcserver.get_session_auth_level() session_auth_level = rpcserver.get_session_auth_level()
if session_auth_level == AUTH_LEVEL_ADMIN: if session_auth_level == AUTH_LEVEL_ADMIN:
log.debug("Current logged in user %s is an ADMIN, send all " log.debug('Current logged in user %s is an ADMIN, send all '
"watchdirs", session_user) 'watchdirs', session_user)
return self.watchdirs return self.watchdirs
watchdirs = {} watchdirs = {}
for watchdir_id, watchdir in self.watchdirs.iteritems(): for watchdir_id, watchdir in self.watchdirs.iteritems():
if watchdir.get("owner", "localclient") == session_user: if watchdir.get('owner', 'localclient') == session_user:
watchdirs[watchdir_id] = watchdir watchdirs[watchdir_id] = watchdir
log.debug("Current logged in user %s is not an ADMIN, send only " 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, watchdirs.keys())
return watchdirs return watchdirs
def _make_unicode(self, options): def _make_unicode(self, options):
opts = {} opts = {}
for key in options: for key in options:
if isinstance(options[key], str): if isinstance(options[key], str):
options[key] = unicode(options[key], "utf8") options[key] = unicode(options[key], 'utf8')
opts[key] = options[key] opts[key] = options[key]
return opts return opts
@ -403,58 +403,58 @@ class Core(CorePluginBase):
if options is None: if options is None:
options = {} options = {}
options = self._make_unicode(options) options = self._make_unicode(options)
abswatchdir = os.path.abspath(options["path"]) abswatchdir = os.path.abspath(options['path'])
check_input(os.path.isdir(abswatchdir), _("Path does not exist.")) check_input(os.path.isdir(abswatchdir), _('Path does not exist.'))
check_input( check_input(
os.access(abswatchdir, os.R_OK | os.W_OK), os.access(abswatchdir, os.R_OK | os.W_OK),
"You must have read and write access to watch folder." '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.itervalues()]:
raise Exception("Path is already being watched.") raise Exception('Path is already being watched.')
options.setdefault("enabled", False) options.setdefault('enabled', False)
options["abspath"] = abswatchdir options['abspath'] = abswatchdir
watchdir_id = self.config["next_id"] watchdir_id = self.config['next_id']
self.watchdirs[str(watchdir_id)] = options self.watchdirs[str(watchdir_id)] = options
if options.get("enabled"): if options.get('enabled'):
self.enable_watchdir(watchdir_id) self.enable_watchdir(watchdir_id)
self.config["next_id"] = watchdir_id + 1 self.config['next_id'] = watchdir_id + 1
self.config.save() self.config.save()
component.get("EventManager").emit(AutoaddOptionsChangedEvent()) component.get('EventManager').emit(AutoaddOptionsChangedEvent())
return watchdir_id return watchdir_id
@export @export
def remove(self, watchdir_id): def remove(self, watchdir_id):
"""Remove a watch folder.""" """Remove a watch folder."""
watchdir_id = str(watchdir_id) watchdir_id = str(watchdir_id)
check_input(watchdir_id in self.watchdirs, "Unknown Watchdir: %s" % self.watchdirs) check_input(watchdir_id in self.watchdirs, 'Unknown Watchdir: %s' % self.watchdirs)
if self.watchdirs[watchdir_id]["enabled"]: if self.watchdirs[watchdir_id]['enabled']:
self.disable_watchdir(watchdir_id) self.disable_watchdir(watchdir_id)
del self.watchdirs[watchdir_id] del self.watchdirs[watchdir_id]
self.config.save() self.config.save()
component.get("EventManager").emit(AutoaddOptionsChangedEvent()) component.get('EventManager').emit(AutoaddOptionsChangedEvent())
def __migrate_config_1_to_2(self, config): def __migrate_config_1_to_2(self, config):
for watchdir_id in config["watchdirs"].iterkeys(): for watchdir_id in config['watchdirs'].iterkeys():
config["watchdirs"][watchdir_id]["owner"] = "localclient" config['watchdirs'][watchdir_id]['owner'] = 'localclient'
return config return config
def __on_pre_torrent_removed(self, torrent_id): def __on_pre_torrent_removed(self, torrent_id):
try: try:
torrent = component.get("TorrentManager")[torrent_id] torrent = component.get('TorrentManager')[torrent_id]
except KeyError: except KeyError:
log.warning("Unable to remove torrent file for torrent id %s. It" log.warning('Unable to remove torrent file for torrent id %s. It'
"was already deleted from the TorrentManager", 'was already deleted from the TorrentManager',
torrent_id) torrent_id)
return return
torrent_fname = torrent.filename torrent_fname = torrent.filename
for watchdir in self.watchdirs.itervalues(): for watchdir in self.watchdirs.itervalues():
if not watchdir.get("copy_torrent_toggle", False): if not watchdir.get('copy_torrent_toggle', False):
# This watchlist does copy torrents # This watchlist does copy torrents
continue continue
elif not watchdir.get("delete_copy_torrent_toggle", False): elif not watchdir.get('delete_copy_torrent_toggle', False):
# This watchlist is not set to delete finished torrents # This watchlist is not set to delete finished torrents
continue continue
copy_torrent_path = watchdir["copy_torrent"] copy_torrent_path = watchdir['copy_torrent']
torrent_fname_path = os.path.join(copy_torrent_path, torrent_fname) torrent_fname_path = os.path.join(copy_torrent_path, torrent_fname)
if os.path.isfile(torrent_fname_path): if os.path.isfile(torrent_fname_path):
try: try:

View File

@ -34,10 +34,10 @@ class IncompatibleOption(Exception):
class OptionsDialog(object): class OptionsDialog(object):
spin_ids = ["max_download_speed", "max_upload_speed", "stop_ratio"] spin_ids = ['max_download_speed', 'max_upload_speed', 'stop_ratio']
spin_int_ids = ["max_upload_slots", "max_connections"] spin_int_ids = ['max_upload_slots', 'max_connections']
chk_ids = ["stop_at_ratio", "remove_at_ratio", "move_completed", chk_ids = ['stop_at_ratio', 'remove_at_ratio', 'move_completed',
"add_paused", "auto_managed", "queue_to_top"] 'add_paused', 'auto_managed', 'queue_to_top']
def __init__(self): def __init__(self):
self.accounts = gtk.ListStore(str) self.accounts = gtk.ListStore(str)
@ -47,16 +47,16 @@ class OptionsDialog(object):
def show(self, options=None, watchdir_id=None): def show(self, options=None, watchdir_id=None):
if options is None: if options is None:
options = {} options = {}
self.glade = gtk.glade.XML(get_resource("autoadd_options.glade")) self.glade = gtk.glade.XML(get_resource('autoadd_options.glade'))
self.glade.signal_autoconnect({ self.glade.signal_autoconnect({
"on_opts_add": self.on_add, 'on_opts_add': self.on_add,
"on_opts_apply": self.on_apply, 'on_opts_apply': self.on_apply,
"on_opts_cancel": self.on_cancel, 'on_opts_cancel': self.on_cancel,
"on_options_dialog_close": self.on_cancel, 'on_options_dialog_close': self.on_cancel,
"on_toggle_toggled": self.on_toggle_toggled 'on_toggle_toggled': self.on_toggle_toggled
}) })
self.dialog = self.glade.get_widget("options_dialog") self.dialog = self.glade.get_widget('options_dialog')
self.dialog.set_transient_for(component.get("Preferences").pref_dialog) self.dialog.set_transient_for(component.get('Preferences').pref_dialog)
if watchdir_id: if watchdir_id:
# We have an existing watchdir_id, we are editing # We have an existing watchdir_id, we are editing
@ -108,10 +108,10 @@ class OptionsDialog(object):
for spin_id in self.spin_ids + self.spin_int_ids: for spin_id in self.spin_ids + self.spin_int_ids:
self.glade.get_widget(spin_id).set_value(options.get(spin_id, 0)) self.glade.get_widget(spin_id).set_value(options.get(spin_id, 0))
self.glade.get_widget(spin_id + "_toggle").set_active(options.get(spin_id + "_toggle", False)) self.glade.get_widget(spin_id + '_toggle').set_active(options.get(spin_id + '_toggle', False))
for chk_id in self.chk_ids: for chk_id in self.chk_ids:
self.glade.get_widget(chk_id).set_active(bool(options.get(chk_id, True))) self.glade.get_widget(chk_id).set_active(bool(options.get(chk_id, True)))
self.glade.get_widget(chk_id + "_toggle").set_active(options.get(chk_id + "_toggle", False)) self.glade.get_widget(chk_id + '_toggle').set_active(options.get(chk_id + '_toggle', False))
if not options.get('add_paused', True): if not options.get('add_paused', True):
self.glade.get_widget('isnt_add_paused').set_active(True) self.glade.get_widget('isnt_add_paused').set_active(True)
if not options.get('queue_to_top', True): if not options.get('queue_to_top', True):
@ -121,59 +121,59 @@ class OptionsDialog(object):
for field in ['move_completed_path', 'path', 'download_location', for field in ['move_completed_path', 'path', 'download_location',
'copy_torrent']: 'copy_torrent']:
if client.is_localhost(): if client.is_localhost():
self.glade.get_widget(field + "_chooser").set_current_folder( self.glade.get_widget(field + '_chooser').set_current_folder(
options.get(field, os.path.expanduser("~")) options.get(field, os.path.expanduser('~'))
) )
self.glade.get_widget(field + "_chooser").show() self.glade.get_widget(field + '_chooser').show()
self.glade.get_widget(field + "_entry").hide() self.glade.get_widget(field + '_entry').hide()
else: else:
self.glade.get_widget(field + "_entry").set_text( self.glade.get_widget(field + '_entry').set_text(
options.get(field, "") options.get(field, '')
) )
self.glade.get_widget(field + "_entry").show() self.glade.get_widget(field + '_entry').show()
self.glade.get_widget(field + "_chooser").hide() self.glade.get_widget(field + '_chooser').hide()
self.set_sensitive() self.set_sensitive()
def on_core_config(config): def on_core_config(config):
if client.is_localhost(): if client.is_localhost():
self.glade.get_widget('download_location_chooser').set_current_folder( self.glade.get_widget('download_location_chooser').set_current_folder(
options.get('download_location', config["download_location"]) options.get('download_location', config['download_location'])
) )
if options.get('move_completed_toggle', config["move_completed"]): if options.get('move_completed_toggle', config['move_completed']):
self.glade.get_widget('move_completed_toggle').set_active(True) self.glade.get_widget('move_completed_toggle').set_active(True)
self.glade.get_widget('move_completed_path_chooser').set_current_folder( self.glade.get_widget('move_completed_path_chooser').set_current_folder(
options.get('move_completed_path', config["move_completed_path"]) options.get('move_completed_path', config['move_completed_path'])
) )
if options.get('copy_torrent_toggle', config["copy_torrent_file"]): if options.get('copy_torrent_toggle', config['copy_torrent_file']):
self.glade.get_widget('copy_torrent_toggle').set_active(True) self.glade.get_widget('copy_torrent_toggle').set_active(True)
self.glade.get_widget('copy_torrent_chooser').set_current_folder( self.glade.get_widget('copy_torrent_chooser').set_current_folder(
options.get('copy_torrent', config["torrentfiles_location"]) options.get('copy_torrent', config['torrentfiles_location'])
) )
else: else:
self.glade.get_widget('download_location_entry').set_text( self.glade.get_widget('download_location_entry').set_text(
options.get('download_location', config["download_location"]) options.get('download_location', config['download_location'])
) )
if options.get('move_completed_toggle', config["move_completed"]): if options.get('move_completed_toggle', config['move_completed']):
self.glade.get_widget('move_completed_toggle').set_active( self.glade.get_widget('move_completed_toggle').set_active(
options.get('move_completed_toggle', False) options.get('move_completed_toggle', False)
) )
self.glade.get_widget('move_completed_path_entry').set_text( self.glade.get_widget('move_completed_path_entry').set_text(
options.get('move_completed_path', config["move_completed_path"]) options.get('move_completed_path', config['move_completed_path'])
) )
if options.get('copy_torrent_toggle', config["copy_torrent_file"]): if options.get('copy_torrent_toggle', config['copy_torrent_file']):
self.glade.get_widget('copy_torrent_toggle').set_active(True) self.glade.get_widget('copy_torrent_toggle').set_active(True)
self.glade.get_widget('copy_torrent_entry').set_text( self.glade.get_widget('copy_torrent_entry').set_text(
options.get('copy_torrent', config["torrentfiles_location"]) options.get('copy_torrent', config['torrentfiles_location'])
) )
if options.get('delete_copy_torrent_toggle', config["del_copy_torrent_file"]): if options.get('delete_copy_torrent_toggle', config['del_copy_torrent_file']):
self.glade.get_widget('delete_copy_torrent_toggle').set_active(True) self.glade.get_widget('delete_copy_torrent_toggle').set_active(True)
if not options: if not options:
client.core.get_config().addCallback(on_core_config) client.core.get_config().addCallback(on_core_config)
def on_accounts(accounts, owner): def on_accounts(accounts, owner):
log.debug("Got Accounts") log.debug('Got Accounts')
selected_iter = None selected_iter = None
for account in accounts: for account in accounts:
acc_iter = self.accounts.append() acc_iter = self.accounts.append()
@ -185,14 +185,14 @@ class OptionsDialog(object):
self.glade.get_widget('OwnerCombobox').set_active_iter(selected_iter) self.glade.get_widget('OwnerCombobox').set_active_iter(selected_iter)
def on_accounts_failure(failure): def on_accounts_failure(failure):
log.debug("Failed to get accounts!!! %s", failure) log.debug('Failed to get accounts!!! %s', failure)
acc_iter = self.accounts.append() acc_iter = self.accounts.append()
self.accounts.set_value(acc_iter, 0, client.get_auth_user()) self.accounts.set_value(acc_iter, 0, client.get_auth_user())
self.glade.get_widget('OwnerCombobox').set_active(0) self.glade.get_widget('OwnerCombobox').set_active(0)
self.glade.get_widget('OwnerCombobox').set_sensitive(False) self.glade.get_widget('OwnerCombobox').set_sensitive(False)
def on_labels(labels): def on_labels(labels):
log.debug("Got Labels: %s", labels) log.debug('Got Labels: %s', labels)
for label in labels: for label in labels:
self.labels.set_value(self.labels.append(), 0, label) self.labels.set_value(self.labels.append(), 0, label)
label_widget = self.glade.get_widget('label') label_widget = self.glade.get_widget('label')
@ -228,10 +228,10 @@ class OptionsDialog(object):
'max_upload_slots', 'add_paused', 'auto_managed', 'max_upload_slots', 'add_paused', 'auto_managed',
'stop_at_ratio', 'queue_to_top', 'copy_torrent'] 'stop_at_ratio', 'queue_to_top', 'copy_torrent']
for maintoggle in maintoggles: for maintoggle in maintoggles:
self.on_toggle_toggled(self.glade.get_widget(maintoggle + "_toggle")) self.on_toggle_toggled(self.glade.get_widget(maintoggle + '_toggle'))
def on_toggle_toggled(self, tb): def on_toggle_toggled(self, tb):
toggle = str(tb.name).replace("_toggle", "") toggle = str(tb.name).replace('_toggle', '')
isactive = tb.get_active() isactive = tb.get_active()
if toggle == 'download_location': if toggle == 'download_location':
self.glade.get_widget('download_location_chooser').set_sensitive(isactive) self.glade.get_widget('download_location_chooser').set_sensitive(isactive)
@ -279,10 +279,10 @@ class OptionsDialog(object):
str(self.watchdir_id), options str(self.watchdir_id), options
).addCallbacks(self.on_added, self.on_error_show) ).addCallbacks(self.on_added, self.on_error_show)
except IncompatibleOption as ex: except IncompatibleOption as ex:
dialogs.ErrorDialog(_("Incompatible Option"), str(ex), self.dialog).run() dialogs.ErrorDialog(_('Incompatible Option'), str(ex), self.dialog).run()
def on_error_show(self, result): def on_error_show(self, result):
d = dialogs.ErrorDialog(_("Error"), result.value.exception_msg, self.dialog) d = dialogs.ErrorDialog(_('Error'), result.value.exception_msg, self.dialog)
result.cleanFailure() result.cleanFailure()
d.run() d.run()
@ -294,7 +294,7 @@ class OptionsDialog(object):
options = self.generate_opts() options = self.generate_opts()
client.autoadd.add(options).addCallbacks(self.on_added, self.on_error_show) client.autoadd.add(options).addCallbacks(self.on_added, self.on_error_show)
except IncompatibleOption as ex: except IncompatibleOption as ex:
dialogs.ErrorDialog(_("Incompatible Option"), str(ex), self.dialog).run() dialogs.ErrorDialog(_('Incompatible Option'), str(ex), self.dialog).run()
def on_cancel(self, event=None): def on_cancel(self, event=None):
self.dialog.destroy() self.dialog.destroy()
@ -332,13 +332,13 @@ class OptionsDialog(object):
for spin_id in self.spin_ids: for spin_id in self.spin_ids:
options[spin_id] = self.glade.get_widget(spin_id).get_value() options[spin_id] = self.glade.get_widget(spin_id).get_value()
options[spin_id + "_toggle"] = self.glade.get_widget(spin_id + "_toggle").get_active() options[spin_id + '_toggle'] = self.glade.get_widget(spin_id + '_toggle').get_active()
for spin_int_id in self.spin_int_ids: for spin_int_id in self.spin_int_ids:
options[spin_int_id] = self.glade.get_widget(spin_int_id).get_value_as_int() options[spin_int_id] = self.glade.get_widget(spin_int_id).get_value_as_int()
options[spin_int_id + "_toggle"] = self.glade.get_widget(spin_int_id + "_toggle").get_active() options[spin_int_id + '_toggle'] = self.glade.get_widget(spin_int_id + '_toggle').get_active()
for chk_id in self.chk_ids: for chk_id in self.chk_ids:
options[chk_id] = self.glade.get_widget(chk_id).get_active() options[chk_id] = self.glade.get_widget(chk_id).get_active()
options[chk_id + "_toggle"] = self.glade.get_widget(chk_id + "_toggle").get_active() options[chk_id + '_toggle'] = self.glade.get_widget(chk_id + '_toggle').get_active()
if options['copy_torrent_toggle'] and options['path'] == options['copy_torrent']: if options['copy_torrent_toggle'] and options['path'] == options['copy_torrent']:
raise IncompatibleOption(_("\"Watch Folder\" directory and \"Copy of .torrent" raise IncompatibleOption(_("\"Watch Folder\" directory and \"Copy of .torrent"
@ -349,27 +349,27 @@ class OptionsDialog(object):
class GtkUI(GtkPluginBase): class GtkUI(GtkPluginBase):
def enable(self): def enable(self):
self.glade = gtk.glade.XML(get_resource("config.glade")) self.glade = gtk.glade.XML(get_resource('config.glade'))
self.glade.signal_autoconnect({ self.glade.signal_autoconnect({
"on_add_button_clicked": self.on_add_button_clicked, 'on_add_button_clicked': self.on_add_button_clicked,
"on_edit_button_clicked": self.on_edit_button_clicked, 'on_edit_button_clicked': self.on_edit_button_clicked,
"on_remove_button_clicked": self.on_remove_button_clicked 'on_remove_button_clicked': self.on_remove_button_clicked
}) })
self.opts_dialog = OptionsDialog() self.opts_dialog = OptionsDialog()
component.get("PluginManager").register_hook( component.get('PluginManager').register_hook(
"on_apply_prefs", self.on_apply_prefs 'on_apply_prefs', self.on_apply_prefs
) )
component.get("PluginManager").register_hook( component.get('PluginManager').register_hook(
"on_show_prefs", self.on_show_prefs 'on_show_prefs', self.on_show_prefs
) )
client.register_event_handler( client.register_event_handler(
"AutoaddOptionsChangedEvent", self.on_options_changed_event 'AutoaddOptionsChangedEvent', self.on_options_changed_event
) )
self.watchdirs = {} self.watchdirs = {}
vbox = self.glade.get_widget("watchdirs_vbox") vbox = self.glade.get_widget('watchdirs_vbox')
sw = gtk.ScrolledWindow() sw = gtk.ScrolledWindow()
sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
@ -379,24 +379,24 @@ class GtkUI(GtkPluginBase):
self.store = self.create_model() self.store = self.create_model()
self.treeView = gtk.TreeView(self.store) self.treeView = gtk.TreeView(self.store)
self.treeView.connect("cursor-changed", self.on_listitem_activated) self.treeView.connect('cursor-changed', self.on_listitem_activated)
self.treeView.connect("row-activated", self.on_edit_button_clicked) self.treeView.connect('row-activated', self.on_edit_button_clicked)
self.treeView.set_rules_hint(True) self.treeView.set_rules_hint(True)
self.create_columns(self.treeView) self.create_columns(self.treeView)
sw.add(self.treeView) sw.add(self.treeView)
sw.show_all() sw.show_all()
component.get("Preferences").add_page( component.get('Preferences').add_page(
_("AutoAdd"), self.glade.get_widget("prefs_box") _('AutoAdd'), self.glade.get_widget('prefs_box')
) )
def disable(self): def disable(self):
component.get("Preferences").remove_page(_("AutoAdd")) component.get('Preferences').remove_page(_('AutoAdd'))
component.get("PluginManager").deregister_hook( component.get('PluginManager').deregister_hook(
"on_apply_prefs", self.on_apply_prefs 'on_apply_prefs', self.on_apply_prefs
) )
component.get("PluginManager").deregister_hook( component.get('PluginManager').deregister_hook(
"on_show_prefs", self.on_show_prefs 'on_show_prefs', self.on_show_prefs
) )
def create_model(self): def create_model(self):
@ -411,7 +411,7 @@ class GtkUI(GtkPluginBase):
def create_columns(self, treeview): def create_columns(self, treeview):
renderer_toggle = gtk.CellRendererToggle() renderer_toggle = gtk.CellRendererToggle()
column = gtk.TreeViewColumn( column = gtk.TreeViewColumn(
_("Active"), renderer_toggle, activatable=1, active=1 _('Active'), renderer_toggle, activatable=1, active=1
) )
column.set_sort_column_id(1) column.set_sort_column_id(1)
treeview.append_column(column) treeview.append_column(column)
@ -420,7 +420,7 @@ class GtkUI(GtkPluginBase):
treeview.set_tooltip_cell(tt, None, None, renderer_toggle) treeview.set_tooltip_cell(tt, None, None, renderer_toggle)
renderertext = gtk.CellRendererText() renderertext = gtk.CellRendererText()
column = gtk.TreeViewColumn(_("Owner"), renderertext, text=2) column = gtk.TreeViewColumn(_('Owner'), renderertext, text=2)
column.set_sort_column_id(2) column.set_sort_column_id(2)
treeview.append_column(column) treeview.append_column(column)
tt2 = gtk.Tooltip() tt2 = gtk.Tooltip()
@ -428,7 +428,7 @@ class GtkUI(GtkPluginBase):
treeview.set_has_tooltip(True) treeview.set_has_tooltip(True)
renderertext = gtk.CellRendererText() renderertext = gtk.CellRendererText()
column = gtk.TreeViewColumn(_("Path"), renderertext, text=3) column = gtk.TreeViewColumn(_('Path'), renderertext, text=3)
column.set_sort_column_id(3) column.set_sort_column_id(3)
treeview.append_column(column) treeview.append_column(column)
tt2 = gtk.Tooltip() tt2 = gtk.Tooltip()
@ -455,7 +455,7 @@ class GtkUI(GtkPluginBase):
tree, tree_id = self.treeView.get_selection().get_selected() tree, tree_id = self.treeView.get_selection().get_selected()
watchdir_id = str(self.store.get_value(tree_id, 0)) watchdir_id = str(self.store.get_value(tree_id, 0))
if watchdir_id: if watchdir_id:
if col and col.get_title() == _("Active"): if col and col.get_title() == _('Active'):
if self.watchdirs[watchdir_id]['enabled']: if self.watchdirs[watchdir_id]['enabled']:
client.autoadd.disable_watchdir(watchdir_id) client.autoadd.disable_watchdir(watchdir_id)
else: else:
@ -473,7 +473,7 @@ class GtkUI(GtkPluginBase):
self.glade.get_widget('remove_button').set_sensitive(False) self.glade.get_widget('remove_button').set_sensitive(False)
def on_apply_prefs(self): def on_apply_prefs(self):
log.debug("applying prefs for AutoAdd") log.debug('applying prefs for AutoAdd')
for watchdir_id, watchdir in self.watchdirs.iteritems(): for watchdir_id, watchdir in self.watchdirs.iteritems():
client.autoadd.set_options(watchdir_id, watchdir) client.autoadd.set_options(watchdir_id, watchdir)
@ -485,7 +485,7 @@ class GtkUI(GtkPluginBase):
def cb_get_config(self, watchdirs): def cb_get_config(self, watchdirs):
"""callback for on show_prefs""" """callback for on show_prefs"""
log.trace("Got whatchdirs from core: %s", watchdirs) log.trace('Got whatchdirs from core: %s', watchdirs)
self.watchdirs = watchdirs or {} self.watchdirs = watchdirs or {}
self.store.clear() self.store.clear()
for watchdir_id, watchdir in self.watchdirs.iteritems(): for watchdir_id, watchdir in self.watchdirs.iteritems():

View File

@ -23,7 +23,7 @@ log = logging.getLogger(__name__)
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("autoadd.js")] scripts = [get_resource('autoadd.js')]
def enable(self): def enable(self):
pass pass

View File

@ -15,15 +15,15 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "AutoAdd" __plugin_name__ = 'AutoAdd'
__author__ = "Chase Sterling, Pedro Algarvio" __author__ = 'Chase Sterling, Pedro Algarvio'
__author_email__ = "chase.sterling@gmail.com, pedro@algarvio.me" __author_email__ = 'chase.sterling@gmail.com, pedro@algarvio.me'
__version__ = "1.05" __version__ = '1.05'
__url__ = "http://dev.deluge-torrent.org/wiki/Plugins/AutoAdd" __url__ = 'http://dev.deluge-torrent.org/wiki/Plugins/AutoAdd'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Monitors folders for .torrent files." __description__ = 'Monitors folders for .torrent files.'
__long_description__ = """""" __long_description__ = """"""
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -35,7 +35,7 @@ setup(
license=__license__, license=__license__,
long_description=__long_description__ if __long_description__ else __description__, long_description=__long_description__ if __long_description__ else __description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -15,8 +15,8 @@ import pkg_resources
def get_resource(filename): def get_resource(filename):
return pkg_resources.resource_filename("deluge.plugins.blocklist", return pkg_resources.resource_filename('deluge.plugins.blocklist',
os.path.join("data", filename)) os.path.join('data', filename))
def raises_errors_as(error): def raises_errors_as(error):
@ -56,7 +56,7 @@ def remove_zeros(ip):
000.000.000.003 -> 0.0.0.3 000.000.000.003 -> 0.0.0.3
""" """
return ".".join([part.lstrip("0").zfill(1) for part in ip.split(".")]) return '.'.join([part.lstrip('0').zfill(1) for part in ip.split('.')])
class BadIP(Exception): class BadIP(Exception):

View File

@ -39,16 +39,16 @@ from .readers import ReaderParseError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DEFAULT_PREFS = { DEFAULT_PREFS = {
"url": "", 'url': '',
"load_on_start": False, 'load_on_start': False,
"check_after_days": 4, 'check_after_days': 4,
"list_compression": "", 'list_compression': '',
"list_type": "", 'list_type': '',
"last_update": 0.0, 'last_update': 0.0,
"list_size": 0, 'list_size': 0,
"timeout": 180, 'timeout': 180,
"try_times": 3, 'try_times': 3,
"whitelisted": [], 'whitelisted': [],
} }
# Constants # Constants
@ -70,26 +70,26 @@ class Core(CorePluginBase):
self.num_blocked = 0 self.num_blocked = 0
self.file_progress = 0.0 self.file_progress = 0.0
self.core = component.get("Core") self.core = component.get('Core')
self.config = deluge.configmanager.ConfigManager("blocklist.conf", DEFAULT_PREFS) self.config = deluge.configmanager.ConfigManager('blocklist.conf', DEFAULT_PREFS)
if "whitelisted" not in self.config: if 'whitelisted' not in self.config:
self.config["whitelisted"] = [] self.config['whitelisted'] = []
self.reader = create_reader(self.config["list_type"], self.config["list_compression"]) self.reader = create_reader(self.config['list_type'], self.config['list_compression'])
if not isinstance(self.config["last_update"], float): if not isinstance(self.config['last_update'], float):
self.config.config["last_update"] = 0.0 self.config.config['last_update'] = 0.0
update_now = False update_now = False
if self.config["load_on_start"]: if self.config['load_on_start']:
self.pause_session() self.pause_session()
if self.config["last_update"]: if self.config['last_update']:
last_update = datetime.fromtimestamp(self.config["last_update"]) last_update = datetime.fromtimestamp(self.config['last_update'])
check_period = timedelta(days=self.config["check_after_days"]) check_period = timedelta(days=self.config['check_after_days'])
if not self.config["last_update"] or last_update + check_period < datetime.now(): if not self.config['last_update'] or last_update + check_period < datetime.now():
update_now = True update_now = True
else: else:
d = self.import_list(deluge.configmanager.get_config_dir("blocklist.cache")) d = self.import_list(deluge.configmanager.get_config_dir('blocklist.cache'))
d.addCallbacks(self.on_import_complete, self.on_import_error) d.addCallbacks(self.on_import_complete, self.on_import_error)
if self.need_to_resume_session: if self.need_to_resume_session:
d.addBoth(self.resume_session) d.addBoth(self.resume_session)
@ -97,16 +97,16 @@ class Core(CorePluginBase):
# This function is called every 'check_after_days' days, to download # This function is called every 'check_after_days' days, to download
# and import a new list if needed. # and import a new list if needed.
self.update_timer = LoopingCall(self.check_import) self.update_timer = LoopingCall(self.check_import)
if self.config["check_after_days"] > 0: if self.config['check_after_days'] > 0:
self.update_timer.start( self.update_timer.start(
self.config["check_after_days"] * 24 * 60 * 60, update_now self.config['check_after_days'] * 24 * 60 * 60, update_now
) )
def disable(self): def disable(self):
self.config.save() self.config.save()
log.debug("Reset IP filter") log.debug('Reset IP filter')
self.core.session.get_ip_filter().add_rule( self.core.session.get_ip_filter().add_rule(
"0.0.0.0", "255.255.255.255", ALLOW_RANGE '0.0.0.0', '255.255.255.255', ALLOW_RANGE
) )
log.debug('Blocklist: Plugin disabled') log.debug('Blocklist: Plugin disabled')
@ -125,7 +125,7 @@ class Core(CorePluginBase):
Deferred: A Deferred which fires when the blocklist has been imported. Deferred: A Deferred which fires when the blocklist has been imported.
""" """
if not self.config["url"]: if not self.config['url']:
return return
# Reset variables # Reset variables
@ -136,7 +136,7 @@ class Core(CorePluginBase):
self.up_to_date = False self.up_to_date = False
if force: if force:
self.reader = None self.reader = None
self.is_url = is_url(self.config["url"]) self.is_url = is_url(self.config['url'])
# Start callback chain # Start callback chain
if self.is_url: if self.is_url:
@ -144,7 +144,7 @@ class Core(CorePluginBase):
d.addCallbacks(self.on_download_complete, self.on_download_error) d.addCallbacks(self.on_download_complete, self.on_download_error)
d.addCallback(self.import_list) d.addCallback(self.import_list)
else: else:
d = self.import_list(self.config["url"]) d = self.import_list(self.config['url'])
d.addCallbacks(self.on_import_complete, self.on_import_error) d.addCallbacks(self.on_import_complete, self.on_import_error)
if self.need_to_resume_session: if self.need_to_resume_session:
d.addBoth(self.resume_session) d.addBoth(self.resume_session)
@ -176,7 +176,7 @@ class Core(CorePluginBase):
update = set(config[key]) update = set(config[key])
diff = saved.symmetric_difference(update) diff = saved.symmetric_difference(update)
if diff: if diff:
log.debug("Whitelist changed. Updating...") log.debug('Whitelist changed. Updating...')
added = update.intersection(diff) added = update.intersection(diff)
removed = saved.intersection(diff) removed = saved.intersection(diff)
if added: if added:
@ -187,10 +187,10 @@ class Core(CorePluginBase):
ip.address, ip.address, ALLOW_RANGE ip.address, ip.address, ALLOW_RANGE
) )
saved.add(ip.address) saved.add(ip.address)
log.debug("Added %s to whitelisted", ip) log.debug('Added %s to whitelisted', ip)
self.num_whited += 1 self.num_whited += 1
except BadIP as ex: except BadIP as ex:
log.error("Bad IP: %s", ex) log.error('Bad IP: %s', ex)
continue continue
if removed: if removed:
needs_blocklist_import = True needs_blocklist_import = True
@ -198,37 +198,37 @@ class Core(CorePluginBase):
try: try:
ip = IP.parse(ip) ip = IP.parse(ip)
saved.remove(ip.address) saved.remove(ip.address)
log.debug("Removed %s from whitelisted", ip) log.debug('Removed %s from whitelisted', ip)
except BadIP as ex: except BadIP as ex:
log.error("Bad IP: %s", ex) log.error('Bad IP: %s', ex)
continue continue
self.config[key] = list(saved) self.config[key] = list(saved)
continue continue
elif key == "check_after_days": elif key == 'check_after_days':
if self.config[key] != config[key]: if self.config[key] != config[key]:
self.config[key] = config[key] self.config[key] = config[key]
update_now = False update_now = False
if self.config["last_update"]: if self.config['last_update']:
last_update = datetime.fromtimestamp(self.config["last_update"]) last_update = datetime.fromtimestamp(self.config['last_update'])
check_period = timedelta(days=self.config["check_after_days"]) check_period = timedelta(days=self.config['check_after_days'])
if not self.config["last_update"] or last_update + check_period < datetime.now(): if not self.config['last_update'] or last_update + check_period < datetime.now():
update_now = True update_now = True
if self.update_timer.running: if self.update_timer.running:
self.update_timer.stop() self.update_timer.stop()
if self.config["check_after_days"] > 0: if self.config['check_after_days'] > 0:
self.update_timer.start( self.update_timer.start(
self.config["check_after_days"] * 24 * 60 * 60, update_now self.config['check_after_days'] * 24 * 60 * 60, update_now
) )
continue continue
self.config[key] = config[key] self.config[key] = config[key]
if needs_blocklist_import: if needs_blocklist_import:
log.debug("IP addresses were removed from the whitelist. Since we " log.debug('IP addresses were removed from the whitelist. Since we '
"don't know if they were blocked before. Re-import " "don't know if they were blocked before. Re-import "
"current blocklist and re-add whitelisted.") 'current blocklist and re-add whitelisted.')
self.has_imported = False self.has_imported = False
d = self.import_list(deluge.configmanager.get_config_dir("blocklist.cache")) d = self.import_list(deluge.configmanager.get_config_dir('blocklist.cache'))
d.addCallbacks(self.on_import_complete, self.on_import_error) d.addCallbacks(self.on_import_complete, self.on_import_error)
@export @export
@ -241,23 +241,23 @@ class Core(CorePluginBase):
""" """
status = {} status = {}
if self.is_downloading: if self.is_downloading:
status["state"] = "Downloading" status['state'] = 'Downloading'
elif self.is_importing: elif self.is_importing:
status["state"] = "Importing" status['state'] = 'Importing'
else: else:
status["state"] = "Idle" status['state'] = 'Idle'
status["up_to_date"] = self.up_to_date status['up_to_date'] = self.up_to_date
status["num_whited"] = self.num_whited status['num_whited'] = self.num_whited
status["num_blocked"] = self.num_blocked status['num_blocked'] = self.num_blocked
status["file_progress"] = self.file_progress status['file_progress'] = self.file_progress
status["file_url"] = self.config["url"] status['file_url'] = self.config['url']
status["file_size"] = self.config["list_size"] status['file_size'] = self.config['list_size']
status["file_date"] = self.config["last_update"] status['file_date'] = self.config['last_update']
status["file_type"] = self.config["list_type"] status['file_type'] = self.config['list_type']
status["whitelisted"] = self.config["whitelisted"] status['whitelisted'] = self.config['whitelisted']
if self.config["list_compression"]: if self.config['list_compression']:
status["file_type"] += " (%s)" % self.config["list_compression"] status['file_type'] += ' (%s)' % self.config['list_compression']
return status return status
#### ####
@ -272,9 +272,9 @@ class Core(CorePluginBase):
str: Path of blocklist. str: Path of blocklist.
""" """
log.debug("Updating blocklist info: %s", blocklist) log.debug('Updating blocklist info: %s', blocklist)
self.config["last_update"] = time.time() self.config['last_update'] = time.time()
self.config["list_size"] = os.path.getsize(blocklist) self.config['list_size'] = os.path.getsize(blocklist)
self.filename = blocklist self.filename = blocklist
return blocklist return blocklist
@ -299,20 +299,20 @@ class Core(CorePluginBase):
self.file_progress = fp self.file_progress = fp
import socket import socket
socket.setdefaulttimeout(self.config["timeout"]) socket.setdefaulttimeout(self.config['timeout'])
if not url: if not url:
url = self.config["url"] url = self.config['url']
headers = {} headers = {}
if self.config["last_update"] and not self.force_download: if self.config['last_update'] and not self.force_download:
headers['If-Modified-Since'] = formatdate(self.config["last_update"], usegmt=True) headers['If-Modified-Since'] = formatdate(self.config['last_update'], usegmt=True)
log.debug("Attempting to download blocklist %s", url) log.debug('Attempting to download blocklist %s', url)
log.debug("Sending headers: %s", headers) log.debug('Sending headers: %s', headers)
self.is_downloading = True self.is_downloading = True
return download_file( return download_file(
url, deluge.configmanager.get_config_dir("blocklist.download"), url, deluge.configmanager.get_config_dir('blocklist.download'),
on_retrieve_data, headers on_retrieve_data, headers
) )
@ -326,7 +326,7 @@ class Core(CorePluginBase):
Deferred: a Deferred which fires when clean up is done. Deferred: a Deferred which fires when clean up is done.
""" """
log.debug("Blocklist download complete: %s", blocklist) log.debug('Blocklist download complete: %s', blocklist)
self.is_downloading = False self.is_downloading = False
return threads.deferToThread(self.update_info, blocklist) return threads.deferToThread(self.update_info, blocklist)
@ -345,21 +345,21 @@ class Core(CorePluginBase):
d = f d = f
if f.check(error.PageRedirect): if f.check(error.PageRedirect):
# Handle redirect errors # Handle redirect errors
location = urljoin(self.config["url"], error_msg.split(" to ")[1]) location = urljoin(self.config['url'], error_msg.split(' to ')[1])
if "Moved Permanently" in error_msg: if 'Moved Permanently' in error_msg:
log.debug("Setting blocklist url to %s", location) log.debug('Setting blocklist url to %s', location)
self.config["url"] = location self.config['url'] = location
d = self.download_list(location) d = self.download_list(location)
d.addCallbacks(self.on_download_complete, self.on_download_error) d.addCallbacks(self.on_download_complete, self.on_download_error)
else: else:
if "Not Modified" in error_msg: if 'Not Modified' in error_msg:
log.debug("Blocklist is up-to-date!") log.debug('Blocklist is up-to-date!')
self.up_to_date = True self.up_to_date = True
blocklist = deluge.configmanager.get_config_dir("blocklist.cache") blocklist = deluge.configmanager.get_config_dir('blocklist.cache')
d = threads.deferToThread(self.update_info, blocklist) d = threads.deferToThread(self.update_info, blocklist)
else: else:
log.warning("Blocklist download failed: %s", error_msg) log.warning('Blocklist download failed: %s', error_msg)
if self.failed_attempts < self.config["try_times"]: if self.failed_attempts < self.config['try_times']:
log.debug("Let's try again") log.debug("Let's try again")
self.failed_attempts += 1 self.failed_attempts += 1
d = self.download_list() d = self.download_list()
@ -376,7 +376,7 @@ class Core(CorePluginBase):
Deferred: A Deferred that fires when the blocklist has been imported. Deferred: A Deferred that fires when the blocklist has been imported.
""" """
log.trace("on import_list") log.trace('on import_list')
def on_read_ip_range(start, end): def on_read_ip_range(start, end):
"""Add ip range to blocklist""" """Add ip range to blocklist"""
@ -388,19 +388,19 @@ class Core(CorePluginBase):
"""Add any whitelisted IP's and add the blocklist to session""" """Add any whitelisted IP's and add the blocklist to session"""
# White listing happens last because the last rules added have # White listing happens last because the last rules added have
# priority # priority
log.info("Added %d ranges to ipfilter as blocked", self.num_blocked) log.info('Added %d ranges to ipfilter as blocked', self.num_blocked)
for ip in self.config["whitelisted"]: for ip in self.config['whitelisted']:
ip = IP.parse(ip) ip = IP.parse(ip)
self.blocklist.add_rule(ip.address, ip.address, ALLOW_RANGE) self.blocklist.add_rule(ip.address, ip.address, ALLOW_RANGE)
self.num_whited += 1 self.num_whited += 1
log.trace("Added %s to the ipfiler as white-listed", ip.address) log.trace('Added %s to the ipfiler as white-listed', ip.address)
log.info("Added %d ranges to ipfilter as white-listed", self.num_whited) log.info('Added %d ranges to ipfilter as white-listed', self.num_whited)
self.core.session.set_ip_filter(self.blocklist) self.core.session.set_ip_filter(self.blocklist)
return result return result
# TODO: double check logic # TODO: double check logic
if self.up_to_date and self.has_imported: if self.up_to_date and self.has_imported:
log.debug("Latest blocklist is already imported") log.debug('Latest blocklist is already imported')
return defer.succeed(blocklist) return defer.succeed(blocklist)
self.is_importing = True self.is_importing = True
@ -416,12 +416,12 @@ class Core(CorePluginBase):
self.auto_detected = True self.auto_detected = True
def on_reader_failure(failure): def on_reader_failure(failure):
log.error("Failed to read!!!!!!") log.error('Failed to read!!!!!!')
log.exception(failure) log.exception(failure)
log.debug("Importing using reader: %s", self.reader) log.debug('Importing using reader: %s', self.reader)
log.debug("Reader type: %s compression: %s", self.config["list_type"], self.config["list_compression"]) log.debug('Reader type: %s compression: %s', self.config['list_type'], self.config['list_compression'])
log.debug("Clearing current ip filtering") log.debug('Clearing current ip filtering')
# self.blocklist.add_rule("0.0.0.0", "255.255.255.255", ALLOW_RANGE) # self.blocklist.add_rule("0.0.0.0", "255.255.255.255", ALLOW_RANGE)
d = threads.deferToThread(self.reader(blocklist).read, on_read_ip_range) d = threads.deferToThread(self.reader(blocklist).read, on_read_ip_range)
d.addCallback(on_finish_read).addErrback(on_reader_failure) d.addCallback(on_finish_read).addErrback(on_reader_failure)
@ -438,18 +438,18 @@ class Core(CorePluginBase):
Deferred: A Deferred that fires when clean up is done. Deferred: A Deferred that fires when clean up is done.
""" """
log.trace("on_import_list_complete") log.trace('on_import_list_complete')
d = blocklist d = blocklist
self.is_importing = False self.is_importing = False
self.has_imported = True self.has_imported = True
log.debug("Blocklist import complete!") log.debug('Blocklist import complete!')
cache = deluge.configmanager.get_config_dir("blocklist.cache") cache = deluge.configmanager.get_config_dir('blocklist.cache')
if blocklist != cache: if blocklist != cache:
if self.is_url: if self.is_url:
log.debug("Moving %s to %s", blocklist, cache) log.debug('Moving %s to %s', blocklist, cache)
d = threads.deferToThread(shutil.move, blocklist, cache) d = threads.deferToThread(shutil.move, blocklist, cache)
else: else:
log.debug("Copying %s to %s", blocklist, cache) log.debug('Copying %s to %s', blocklist, cache)
d = threads.deferToThread(shutil.copy, blocklist, cache) d = threads.deferToThread(shutil.copy, blocklist, cache)
return d return d
@ -463,21 +463,21 @@ class Core(CorePluginBase):
Deferred or Failure: A Deferred if recovery was possible else original Failure. Deferred or Failure: A Deferred if recovery was possible else original Failure.
""" """
log.trace("on_import_error: %s", f) log.trace('on_import_error: %s', f)
d = f d = f
self.is_importing = False self.is_importing = False
try_again = False try_again = False
cache = deluge.configmanager.get_config_dir("blocklist.cache") cache = deluge.configmanager.get_config_dir('blocklist.cache')
if f.check(ReaderParseError) and not self.auto_detected: if f.check(ReaderParseError) and not self.auto_detected:
# Invalid / corrupt list, let's detect it # Invalid / corrupt list, let's detect it
log.warning("Invalid / corrupt blocklist") log.warning('Invalid / corrupt blocklist')
self.reader = None self.reader = None
blocklist = None blocklist = None
try_again = True try_again = True
elif self.filename != cache and os.path.exists(cache): elif self.filename != cache and os.path.exists(cache):
# If we have a backup and we haven't already used it # If we have a backup and we haven't already used it
log.warning("Error reading blocklist: %s", f.getErrorMessage()) log.warning('Error reading blocklist: %s', f.getErrorMessage())
blocklist = cache blocklist = cache
try_again = True try_again = True
@ -497,14 +497,14 @@ class Core(CorePluginBase):
UnknownFormatError: If the format cannot be detected. UnknownFormatError: If the format cannot be detected.
""" """
self.config["list_compression"] = detect_compression(blocklist) self.config['list_compression'] = detect_compression(blocklist)
self.config["list_type"] = detect_format(blocklist, self.config["list_compression"]) self.config['list_type'] = detect_format(blocklist, self.config['list_compression'])
log.debug("Auto-detected type: %s compression: %s", self.config["list_type"], self.config["list_compression"]) log.debug('Auto-detected type: %s compression: %s', self.config['list_type'], self.config['list_compression'])
if not self.config["list_type"]: if not self.config['list_type']:
self.config["list_compression"] = "" self.config['list_compression'] = ''
raise UnknownFormatError raise UnknownFormatError
else: else:
self.reader = create_reader(self.config["list_type"], self.config["list_compression"]) self.reader = create_reader(self.config['list_type'], self.config['list_compression'])
def pause_session(self): def pause_session(self):
self.need_to_resume_session = not self.core.session.is_paused() self.need_to_resume_session = not self.core.session.is_paused()

View File

@ -11,21 +11,21 @@ from .decompressers import BZipped2, GZipped, Zipped
from .readers import EmuleReader, PeerGuardianReader, SafePeerReader from .readers import EmuleReader, PeerGuardianReader, SafePeerReader
COMPRESSION_TYPES = { COMPRESSION_TYPES = {
"PK": "Zip", 'PK': 'Zip',
"\x1f\x8b": "GZip", '\x1f\x8b': 'GZip',
"BZ": "BZip2" 'BZ': 'BZip2'
} }
DECOMPRESSERS = { DECOMPRESSERS = {
"Zip": Zipped, 'Zip': Zipped,
"GZip": GZipped, 'GZip': GZipped,
"BZip2": BZipped2 'BZip2': BZipped2
} }
READERS = { READERS = {
"Emule": EmuleReader, 'Emule': EmuleReader,
"SafePeer": SafePeerReader, 'SafePeer': SafePeerReader,
"PeerGuardian": PeerGuardianReader 'PeerGuardian': PeerGuardianReader
} }
@ -34,13 +34,13 @@ class UnknownFormatError(Exception):
def detect_compression(filename): def detect_compression(filename):
with open(filename, "rb") as _file: with open(filename, 'rb') as _file:
magic_number = _file.read(2) magic_number = _file.read(2)
return COMPRESSION_TYPES.get(magic_number, "") return COMPRESSION_TYPES.get(magic_number, '')
def detect_format(filename, compression=""): def detect_format(filename, compression=''):
file_format = "" file_format = ''
for reader in READERS: for reader in READERS:
if create_reader(reader, compression)(filename).is_valid(): if create_reader(reader, compression)(filename).is_valid():
file_format = reader file_format = reader
@ -48,7 +48,7 @@ def detect_format(filename, compression=""):
return file_format return file_format
def create_reader(file_format, compression=""): def create_reader(file_format, compression=''):
reader = READERS.get(file_format) reader = READERS.get(file_format)
if reader and compression: if reader and compression:
decompressor = DECOMPRESSERS.get(compression) decompressor = DECOMPRESSERS.get(compression)

View File

@ -25,102 +25,102 @@ log = logging.getLogger(__name__)
class GtkUI(GtkPluginBase): class GtkUI(GtkPluginBase):
def enable(self): def enable(self):
log.debug("Blocklist GtkUI enable..") log.debug('Blocklist GtkUI enable..')
self.plugin = component.get("PluginManager") self.plugin = component.get('PluginManager')
self.load_preferences_page() self.load_preferences_page()
self.status_item = component.get("StatusBar").add_item( self.status_item = component.get('StatusBar').add_item(
image=common.get_resource("blocklist16.png"), image=common.get_resource('blocklist16.png'),
text="", text='',
callback=self._on_status_item_clicked, callback=self._on_status_item_clicked,
tooltip=_("Blocked IP Ranges /Whitelisted IP Ranges") tooltip=_('Blocked IP Ranges /Whitelisted IP Ranges')
) )
# Register some hooks # Register some hooks
self.plugin.register_hook("on_apply_prefs", self._on_apply_prefs) self.plugin.register_hook('on_apply_prefs', self._on_apply_prefs)
self.plugin.register_hook("on_show_prefs", self._on_show_prefs) self.plugin.register_hook('on_show_prefs', self._on_show_prefs)
def disable(self): def disable(self):
log.debug("Blocklist GtkUI disable..") log.debug('Blocklist GtkUI disable..')
# Remove the preferences page # Remove the preferences page
self.plugin.remove_preferences_page(_("Blocklist")) self.plugin.remove_preferences_page(_('Blocklist'))
# Remove status item # Remove status item
component.get("StatusBar").remove_item(self.status_item) component.get('StatusBar').remove_item(self.status_item)
del self.status_item del self.status_item
# Deregister the hooks # Deregister the hooks
self.plugin.deregister_hook("on_apply_prefs", self._on_apply_prefs) self.plugin.deregister_hook('on_apply_prefs', self._on_apply_prefs)
self.plugin.deregister_hook("on_show_prefs", self._on_show_prefs) self.plugin.deregister_hook('on_show_prefs', self._on_show_prefs)
del self.glade del self.glade
def update(self): def update(self):
def _on_get_status(status): def _on_get_status(status):
if status["state"] == "Downloading": if status['state'] == 'Downloading':
self.table_info.hide() self.table_info.hide()
self.glade.get_widget("button_check_download").set_sensitive(False) self.glade.get_widget('button_check_download').set_sensitive(False)
self.glade.get_widget("button_force_download").set_sensitive(False) self.glade.get_widget('button_force_download').set_sensitive(False)
self.glade.get_widget("image_up_to_date").hide() self.glade.get_widget('image_up_to_date').hide()
self.status_item.set_text( self.status_item.set_text(
"Downloading %.2f%%" % (status["file_progress"] * 100)) 'Downloading %.2f%%' % (status['file_progress'] * 100))
self.progress_bar.set_text("Downloading %.2f%%" % (status["file_progress"] * 100)) self.progress_bar.set_text('Downloading %.2f%%' % (status['file_progress'] * 100))
self.progress_bar.set_fraction(status["file_progress"]) self.progress_bar.set_fraction(status['file_progress'])
self.progress_bar.show() self.progress_bar.show()
elif status["state"] == "Importing": elif status['state'] == 'Importing':
self.table_info.hide() self.table_info.hide()
self.glade.get_widget("button_check_download").set_sensitive(False) self.glade.get_widget('button_check_download').set_sensitive(False)
self.glade.get_widget("button_force_download").set_sensitive(False) self.glade.get_widget('button_force_download').set_sensitive(False)
self.glade.get_widget("image_up_to_date").hide() self.glade.get_widget('image_up_to_date').hide()
self.status_item.set_text( self.status_item.set_text(
"Importing " + str(status["num_blocked"])) 'Importing ' + str(status['num_blocked']))
self.progress_bar.set_text("Importing %s" % (status["num_blocked"])) self.progress_bar.set_text('Importing %s' % (status['num_blocked']))
self.progress_bar.pulse() self.progress_bar.pulse()
self.progress_bar.show() self.progress_bar.show()
elif status["state"] == "Idle": elif status['state'] == 'Idle':
self.progress_bar.hide() self.progress_bar.hide()
self.glade.get_widget("button_check_download").set_sensitive(True) self.glade.get_widget('button_check_download').set_sensitive(True)
self.glade.get_widget("button_force_download").set_sensitive(True) self.glade.get_widget('button_force_download').set_sensitive(True)
if status["up_to_date"]: if status['up_to_date']:
self.glade.get_widget("image_up_to_date").show() self.glade.get_widget('image_up_to_date').show()
else: else:
self.glade.get_widget("image_up_to_date").hide() self.glade.get_widget('image_up_to_date').hide()
self.table_info.show() self.table_info.show()
self.status_item.set_text("%(num_blocked)s/%(num_whited)s" % status) self.status_item.set_text('%(num_blocked)s/%(num_whited)s' % status)
self.glade.get_widget("label_filesize").set_text( self.glade.get_widget('label_filesize').set_text(
deluge.common.fsize(status["file_size"])) deluge.common.fsize(status['file_size']))
self.glade.get_widget("label_modified").set_text( self.glade.get_widget('label_modified').set_text(
datetime.fromtimestamp(status["file_date"]).strftime("%c")) datetime.fromtimestamp(status['file_date']).strftime('%c'))
self.glade.get_widget("label_type").set_text(status["file_type"]) self.glade.get_widget('label_type').set_text(status['file_type'])
self.glade.get_widget("label_url").set_text( self.glade.get_widget('label_url').set_text(
status["file_url"]) status['file_url'])
client.blocklist.get_status().addCallback(_on_get_status) client.blocklist.get_status().addCallback(_on_get_status)
def _on_show_prefs(self): def _on_show_prefs(self):
def _on_get_config(config): def _on_get_config(config):
log.trace("Loaded config: %s", config) log.trace('Loaded config: %s', config)
self.glade.get_widget("entry_url").set_text(config["url"]) self.glade.get_widget('entry_url').set_text(config['url'])
self.glade.get_widget("spin_check_days").set_value(config["check_after_days"]) self.glade.get_widget('spin_check_days').set_value(config['check_after_days'])
self.glade.get_widget("chk_import_on_start").set_active(config["load_on_start"]) self.glade.get_widget('chk_import_on_start').set_active(config['load_on_start'])
self.populate_whitelist(config["whitelisted"]) self.populate_whitelist(config['whitelisted'])
client.blocklist.get_config().addCallback(_on_get_config) client.blocklist.get_config().addCallback(_on_get_config)
def _on_apply_prefs(self): def _on_apply_prefs(self):
config = {} config = {}
config["url"] = self.glade.get_widget("entry_url").get_text().strip() config['url'] = self.glade.get_widget('entry_url').get_text().strip()
config["check_after_days"] = self.glade.get_widget("spin_check_days").get_value_as_int() config['check_after_days'] = self.glade.get_widget('spin_check_days').get_value_as_int()
config["load_on_start"] = self.glade.get_widget("chk_import_on_start").get_active() config['load_on_start'] = self.glade.get_widget('chk_import_on_start').get_active()
config["whitelisted"] = [ip[0] for ip in self.whitelist_model if ip[0] != 'IP HERE'] config['whitelisted'] = [ip[0] for ip in self.whitelist_model if ip[0] != 'IP HERE']
client.blocklist.set_config(config) client.blocklist.set_config(config)
def _on_button_check_download_clicked(self, widget): def _on_button_check_download_clicked(self, widget):
@ -132,16 +132,16 @@ class GtkUI(GtkPluginBase):
client.blocklist.check_import(force=True) client.blocklist.check_import(force=True)
def _on_status_item_clicked(self, widget, event): def _on_status_item_clicked(self, widget, event):
component.get("Preferences").show(_("Blocklist")) component.get('Preferences').show(_('Blocklist'))
def load_preferences_page(self): def load_preferences_page(self):
"""Initializes the preferences page and adds it to the preferences dialog""" """Initializes the preferences page and adds it to the preferences dialog"""
# Load the preferences page # Load the preferences page
self.glade = gtk.glade.XML(common.get_resource("blocklist_pref.glade")) self.glade = gtk.glade.XML(common.get_resource('blocklist_pref.glade'))
self.whitelist_frame = self.glade.get_widget("whitelist_frame") self.whitelist_frame = self.glade.get_widget('whitelist_frame')
self.progress_bar = self.glade.get_widget("progressbar") self.progress_bar = self.glade.get_widget('progressbar')
self.table_info = self.glade.get_widget("table_info") self.table_info = self.glade.get_widget('table_info')
# Hide the progress bar initially # Hide the progress bar initially
self.progress_bar.hide() self.progress_bar.hide()
@ -151,8 +151,8 @@ class GtkUI(GtkPluginBase):
self.build_whitelist_model_treeview() self.build_whitelist_model_treeview()
self.glade.signal_autoconnect({ self.glade.signal_autoconnect({
"on_button_check_download_clicked": self._on_button_check_download_clicked, 'on_button_check_download_clicked': self._on_button_check_download_clicked,
"on_button_force_download_clicked": self._on_button_force_download_clicked, 'on_button_force_download_clicked': self._on_button_force_download_clicked,
'on_whitelist_add_clicked': (self.on_add_button_clicked, 'on_whitelist_add_clicked': (self.on_add_button_clicked,
self.whitelist_treeview), self.whitelist_treeview),
'on_whitelist_remove_clicked': (self.on_delete_button_clicked, 'on_whitelist_remove_clicked': (self.on_delete_button_clicked,
@ -160,32 +160,32 @@ class GtkUI(GtkPluginBase):
}) })
# Set button icons # Set button icons
self.glade.get_widget("image_download").set_from_file( self.glade.get_widget('image_download').set_from_file(
common.get_resource("blocklist_download24.png")) common.get_resource('blocklist_download24.png'))
self.glade.get_widget("image_import").set_from_file( self.glade.get_widget('image_import').set_from_file(
common.get_resource("blocklist_import24.png")) common.get_resource('blocklist_import24.png'))
# Update the preferences page with config values from the core # Update the preferences page with config values from the core
self._on_show_prefs() self._on_show_prefs()
# Add the page to the preferences dialog # Add the page to the preferences dialog
self.plugin.add_preferences_page( self.plugin.add_preferences_page(
_("Blocklist"), _('Blocklist'),
self.glade.get_widget("blocklist_prefs_box")) self.glade.get_widget('blocklist_prefs_box'))
def build_whitelist_model_treeview(self): def build_whitelist_model_treeview(self):
self.whitelist_treeview = self.glade.get_widget("whitelist_treeview") self.whitelist_treeview = self.glade.get_widget('whitelist_treeview')
treeview_selection = self.whitelist_treeview.get_selection() treeview_selection = self.whitelist_treeview.get_selection()
treeview_selection.connect( treeview_selection.connect(
"changed", self.on_whitelist_treeview_selection_changed 'changed', self.on_whitelist_treeview_selection_changed
) )
self.whitelist_model = gtk.ListStore(str, bool) self.whitelist_model = gtk.ListStore(str, bool)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
renderer.connect("edited", self.on_cell_edited, self.whitelist_model) renderer.connect('edited', self.on_cell_edited, self.whitelist_model)
renderer.set_data("ip", 0) renderer.set_data('ip', 0)
column = gtk.TreeViewColumn("IPs", renderer, text=0, editable=1) column = gtk.TreeViewColumn('IPs', renderer, text=0, editable=1)
column.set_expand(True) column.set_expand(True)
self.whitelist_treeview.append_column(column) self.whitelist_treeview.append_column(column)
self.whitelist_treeview.set_model(self.whitelist_model) self.whitelist_treeview.set_model(self.whitelist_model)
@ -199,21 +199,21 @@ class GtkUI(GtkPluginBase):
except common.BadIP as ex: except common.BadIP as ex:
model.remove(model.get_iter_from_string(path_string)) model.remove(model.get_iter_from_string(path_string))
from deluge.ui.gtkui import dialogs from deluge.ui.gtkui import dialogs
d = dialogs.ErrorDialog(_("Bad IP address"), ex.message) d = dialogs.ErrorDialog(_('Bad IP address'), ex.message)
d.run() d.run()
def on_whitelist_treeview_selection_changed(self, selection): def on_whitelist_treeview_selection_changed(self, selection):
model, selected_connection_iter = selection.get_selected() model, selected_connection_iter = selection.get_selected()
if selected_connection_iter: if selected_connection_iter:
self.glade.get_widget("whitelist_delete").set_property('sensitive', self.glade.get_widget('whitelist_delete').set_property('sensitive',
True) True)
else: else:
self.glade.get_widget("whitelist_delete").set_property('sensitive', self.glade.get_widget('whitelist_delete').set_property('sensitive',
False) False)
def on_add_button_clicked(self, widget, treeview): def on_add_button_clicked(self, widget, treeview):
model = treeview.get_model() model = treeview.get_model()
model.set(model.append(), 0, "IP HERE", 1, True) model.set(model.append(), 0, 'IP HERE', 1, True)
def on_delete_button_clicked(self, widget, treeview): def on_delete_button_clicked(self, widget, treeview):
selection = treeview.get_selection() selection = treeview.get_selection()

View File

@ -24,35 +24,35 @@ class PGException(Exception):
class PGReader(object): class PGReader(object):
def __init__(self, filename): def __init__(self, filename):
log.debug("PGReader loading: %s", filename) log.debug('PGReader loading: %s', filename)
try: try:
with gzip.open(filename, "rb") as _file: with gzip.open(filename, 'rb') as _file:
self.fd = _file self.fd = _file
except IOError: except IOError:
log.debug("Blocklist: PGReader: Incorrect file type or list is corrupt") log.debug('Blocklist: PGReader: Incorrect file type or list is corrupt')
# 4 bytes, should be 0xffffffff # 4 bytes, should be 0xffffffff
buf = self.fd.read(4) buf = self.fd.read(4)
hdr = unpack("l", buf)[0] hdr = unpack('l', buf)[0]
if hdr != -1: if hdr != -1:
raise PGException(_("Invalid leader") + " %d" % hdr) raise PGException(_('Invalid leader') + ' %d' % hdr)
magic = self.fd.read(3) magic = self.fd.read(3)
if magic != "P2B": if magic != 'P2B':
raise PGException(_("Invalid magic code")) raise PGException(_('Invalid magic code'))
buf = self.fd.read(1) buf = self.fd.read(1)
ver = ord(buf) ver = ord(buf)
if ver != 1 and ver != 2: if ver != 1 and ver != 2:
raise PGException(_("Invalid version") + " %d" % ver) raise PGException(_('Invalid version') + ' %d' % ver)
def __next__(self): def __next__(self):
# Skip over the string # Skip over the string
buf = -1 buf = -1
while buf != 0: while buf != 0:
buf = self.fd.read(1) buf = self.fd.read(1)
if buf == "": # EOF if buf == '': # EOF
return False return False
buf = ord(buf) buf = ord(buf)

View File

@ -39,7 +39,7 @@ class BaseReader(object):
try: try:
callback(IP.parse(start), IP.parse(end)) callback(IP.parse(start), IP.parse(end))
except BadIP as ex: except BadIP as ex:
log.error("Failed to parse IP: %s", ex) log.error('Failed to parse IP: %s', ex)
return self.file return self.file
def is_ignored(self, line): def is_ignored(self, line):
@ -55,8 +55,8 @@ class BaseReader(object):
if not self.is_ignored(line): if not self.is_ignored(line):
try: try:
(start, end) = self.parse(line) (start, end) = self.parse(line)
if not re.match(r"^(\d{1,3}\.){4}$", start + ".") or \ if not re.match(r'^(\d{1,3}\.){4}$', start + '.') or \
not re.match(r"^(\d{1,3}\.){4}$", end + "."): not re.match(r'^(\d{1,3}\.){4}$', end + '.'):
valid = False valid = False
except Exception: except Exception:
valid = False valid = False
@ -77,13 +77,13 @@ class BaseReader(object):
class EmuleReader(BaseReader): class EmuleReader(BaseReader):
"""Blocklist reader for emule style blocklists""" """Blocklist reader for emule style blocklists"""
def parse(self, line): def parse(self, line):
return line.strip().split(" , ")[0].split(" - ") return line.strip().split(' , ')[0].split(' - ')
class SafePeerReader(BaseReader): class SafePeerReader(BaseReader):
"""Blocklist reader for SafePeer style blocklists""" """Blocklist reader for SafePeer style blocklists"""
def parse(self, line): def parse(self, line):
return line.strip().split(":")[-1].split("-") return line.strip().split(':')[-1].split('-')
class PeerGuardianReader(SafePeerReader): class PeerGuardianReader(SafePeerReader):

View File

@ -16,14 +16,14 @@ from .common import get_resource
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
FORMAT_LIST = [ FORMAT_LIST = [
('gzmule', _("Emule IP list (GZip)")), ('gzmule', _('Emule IP list (GZip)')),
('spzip', _("SafePeer Text (Zipped)")), ('spzip', _('SafePeer Text (Zipped)')),
('pgtext', _("PeerGuardian Text (Uncompressed)")), ('pgtext', _('PeerGuardian Text (Uncompressed)')),
('p2bgz', _("PeerGuardian P2B (GZip)")) ('p2bgz', _('PeerGuardian P2B (GZip)'))
] ]
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("blocklist.js")] scripts = [get_resource('blocklist.js')]
debug_scripts = scripts debug_scripts = scripts

View File

@ -9,15 +9,15 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "Blocklist" __plugin_name__ = 'Blocklist'
__author__ = "John Garland" __author__ = 'John Garland'
__author_email__ = "johnnybg+deluge@gmail.com" __author_email__ = 'johnnybg+deluge@gmail.com'
__version__ = "1.3" __version__ = '1.3'
__url__ = "http://deluge-torrent.org" __url__ = 'http://deluge-torrent.org'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Download and import IP blocklists" __description__ = 'Download and import IP blocklists'
__long_description__ = __description__ __long_description__ = __description__
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ["data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -30,7 +30,7 @@ setup(
zip_safe=False, zip_safe=False,
long_description=__long_description__, long_description=__long_description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""
[deluge.plugin.core] [deluge.plugin.core]

View File

@ -13,5 +13,5 @@ import pkg_resources
def get_resource(filename): def get_resource(filename):
return pkg_resources.resource_filename("deluge.plugins.execute", return pkg_resources.resource_filename('deluge.plugins.execute',
os.path.join("data", filename)) os.path.join('data', filename))

View File

@ -24,7 +24,7 @@ from deluge.plugins.pluginbase import CorePluginBase
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
"commands": [] 'commands': []
} }
EXECUTE_ID = 0 EXECUTE_ID = 0
@ -32,9 +32,9 @@ EXECUTE_EVENT = 1
EXECUTE_COMMAND = 2 EXECUTE_COMMAND = 2
EVENT_MAP = { EVENT_MAP = {
"complete": "TorrentFinishedEvent", 'complete': 'TorrentFinishedEvent',
"added": "TorrentAddedEvent", 'added': 'TorrentAddedEvent',
"removed": "TorrentRemovedEvent" 'removed': 'TorrentRemovedEvent'
} }
@ -56,13 +56,13 @@ class ExecuteCommandRemovedEvent(DelugeEvent):
class Core(CorePluginBase): class Core(CorePluginBase):
def enable(self): def enable(self):
self.config = ConfigManager("execute.conf", DEFAULT_CONFIG) self.config = ConfigManager('execute.conf', DEFAULT_CONFIG)
event_manager = component.get("EventManager") event_manager = component.get('EventManager')
self.registered_events = {} self.registered_events = {}
self.preremoved_cache = {} self.preremoved_cache = {}
# Go through the commands list and register event handlers # Go through the commands list and register event handlers
for command in self.config["commands"]: for command in self.config['commands']:
event = command[EXECUTE_EVENT] event = command[EXECUTE_EVENT]
if event in self.registered_events: if event in self.registered_events:
continue continue
@ -73,47 +73,47 @@ class Core(CorePluginBase):
return event_handler return event_handler
event_handler = create_event_handler(event) event_handler = create_event_handler(event)
event_manager.register_event_handler(EVENT_MAP[event], event_handler) event_manager.register_event_handler(EVENT_MAP[event], event_handler)
if event == "removed": if event == 'removed':
event_manager.register_event_handler("PreTorrentRemovedEvent", self.on_preremoved) event_manager.register_event_handler('PreTorrentRemovedEvent', self.on_preremoved)
self.registered_events[event] = event_handler self.registered_events[event] = event_handler
log.debug("Execute core plugin enabled!") log.debug('Execute core plugin enabled!')
def on_preremoved(self, torrent_id): def on_preremoved(self, torrent_id):
# Get and store the torrent info before it is removed # Get and store the torrent info before it is removed
torrent = component.get("TorrentManager").torrents[torrent_id] torrent = component.get('TorrentManager').torrents[torrent_id]
info = torrent.get_status(["name", "download_location"]) info = torrent.get_status(['name', 'download_location'])
self.preremoved_cache[torrent_id] = [utf8_encoded(torrent_id), utf8_encoded(info["name"]), self.preremoved_cache[torrent_id] = [utf8_encoded(torrent_id), utf8_encoded(info['name']),
utf8_encoded(info["download_location"])] utf8_encoded(info['download_location'])]
def execute_commands(self, torrent_id, event, *arg): def execute_commands(self, torrent_id, event, *arg):
if event == "added" and arg[0]: if event == 'added' and arg[0]:
# No futher action as from_state (arg[0]) is True # No futher action as from_state (arg[0]) is True
return return
elif event == "removed": elif event == 'removed':
torrent_id, torrent_name, download_location = self.preremoved_cache.pop(torrent_id) torrent_id, torrent_name, download_location = self.preremoved_cache.pop(torrent_id)
else: else:
torrent = component.get("TorrentManager").torrents[torrent_id] torrent = component.get('TorrentManager').torrents[torrent_id]
info = torrent.get_status(["name", "download_location"]) info = torrent.get_status(['name', 'download_location'])
# Grab the torrent name and download location # Grab the torrent name and download location
# getProcessOutputAndValue requires args to be str # getProcessOutputAndValue requires args to be str
torrent_id = utf8_encoded(torrent_id) torrent_id = utf8_encoded(torrent_id)
torrent_name = utf8_encoded(info["name"]) torrent_name = utf8_encoded(info['name'])
download_location = utf8_encoded(info["download_location"]) download_location = utf8_encoded(info['download_location'])
log.debug("Running commands for %s", event) log.debug('Running commands for %s', event)
def log_error(result, command): def log_error(result, command):
(stdout, stderr, exit_code) = result (stdout, stderr, exit_code) = result
if exit_code: if exit_code:
log.warn("Command '%s' failed with exit code %d", command, exit_code) log.warn("Command '%s' failed with exit code %d", command, exit_code)
if stdout: if stdout:
log.warn("stdout: %s", stdout) log.warn('stdout: %s', stdout)
if stderr: if stderr:
log.warn("stderr: %s", stderr) log.warn('stderr: %s', stderr)
# Go through and execute all the commands # Go through and execute all the commands
for command in self.config["commands"]: for command in self.config['commands']:
if command[EXECUTE_EVENT] == event: if command[EXECUTE_EVENT] == event:
command = os.path.expandvars(command[EXECUTE_COMMAND]) command = os.path.expandvars(command[EXECUTE_COMMAND])
command = os.path.expanduser(command) command = os.path.expanduser(command)
@ -121,47 +121,47 @@ class Core(CorePluginBase):
cmd_args = [torrent_id, torrent_name, download_location] cmd_args = [torrent_id, torrent_name, download_location]
if windows_check(): if windows_check():
# Escape ampersand on windows (see #2784) # Escape ampersand on windows (see #2784)
cmd_args = [cmd_arg.replace("&", "^^^&") for cmd_arg in cmd_args] cmd_args = [cmd_arg.replace('&', '^^^&') for cmd_arg in cmd_args]
if os.path.isfile(command) and os.access(command, os.X_OK): if os.path.isfile(command) and os.access(command, os.X_OK):
log.debug("Running %s with args: %s", command, cmd_args) log.debug('Running %s with args: %s', command, cmd_args)
d = getProcessOutputAndValue(command, cmd_args, env=os.environ) d = getProcessOutputAndValue(command, cmd_args, env=os.environ)
d.addCallback(log_error, command) d.addCallback(log_error, command)
else: else:
log.error("Execute script not found or not executable") log.error('Execute script not found or not executable')
def disable(self): def disable(self):
self.config.save() self.config.save()
event_manager = component.get("EventManager") event_manager = component.get('EventManager')
for event, handler in self.registered_events.iteritems(): for event, handler in self.registered_events.iteritems():
event_manager.deregister_event_handler(event, handler) event_manager.deregister_event_handler(event, handler)
log.debug("Execute core plugin disabled!") log.debug('Execute core plugin disabled!')
# Exported RPC methods # # Exported RPC methods #
@export @export
def add_command(self, event, command): def add_command(self, event, command):
command_id = hashlib.sha1(str(time.time())).hexdigest() command_id = hashlib.sha1(str(time.time())).hexdigest()
self.config["commands"].append((command_id, event, command)) self.config['commands'].append((command_id, event, command))
self.config.save() self.config.save()
component.get("EventManager").emit(ExecuteCommandAddedEvent(command_id, event, command)) component.get('EventManager').emit(ExecuteCommandAddedEvent(command_id, event, command))
@export @export
def get_commands(self): def get_commands(self):
return self.config["commands"] return self.config['commands']
@export @export
def remove_command(self, command_id): def remove_command(self, command_id):
for command in self.config["commands"]: for command in self.config['commands']:
if command[EXECUTE_ID] == command_id: if command[EXECUTE_ID] == command_id:
self.config["commands"].remove(command) self.config['commands'].remove(command)
component.get("EventManager").emit(ExecuteCommandRemovedEvent(command_id)) component.get('EventManager').emit(ExecuteCommandRemovedEvent(command_id))
break break
self.config.save() self.config.save()
@export @export
def save_command(self, command_id, event, cmd): def save_command(self, command_id, event, cmd):
for i, command in enumerate(self.config["commands"]): for i, command in enumerate(self.config['commands']):
if command[EXECUTE_ID] == command_id: if command[EXECUTE_ID] == command_id:
self.config["commands"][i] = (command_id, event, cmd) self.config['commands'][i] = (command_id, event, cmd)
break break
self.config.save() self.config.save()

View File

@ -27,12 +27,12 @@ EXECUTE_EVENT = 1
EXECUTE_COMMAND = 2 EXECUTE_COMMAND = 2
EVENT_MAP = { EVENT_MAP = {
"complete": _("Torrent Complete"), 'complete': _('Torrent Complete'),
"added": _("Torrent Added"), 'added': _('Torrent Added'),
"removed": _("Torrent Removed") 'removed': _('Torrent Removed')
} }
EVENTS = ["complete", "added", "removed"] EVENTS = ['complete', 'added', 'removed']
class ExecutePreferences(object): class ExecutePreferences(object):
@ -40,13 +40,13 @@ class ExecutePreferences(object):
self.plugin = plugin self.plugin = plugin
def load(self): def load(self):
log.debug("Adding Execute Preferences page") log.debug('Adding Execute Preferences page')
self.glade = gtk.glade.XML(common.get_resource("execute_prefs.glade")) self.glade = gtk.glade.XML(common.get_resource('execute_prefs.glade'))
self.glade.signal_autoconnect({ self.glade.signal_autoconnect({
"on_add_button_clicked": self.on_add_button_clicked 'on_add_button_clicked': self.on_add_button_clicked
}) })
events = self.glade.get_widget("event_combobox") events = self.glade.get_widget('event_combobox')
store = gtk.ListStore(str, str) store = gtk.ListStore(str, str)
for event in EVENTS: for event in EVENTS:
@ -55,31 +55,31 @@ class ExecutePreferences(object):
events.set_model(store) events.set_model(store)
events.set_active(0) events.set_active(0)
self.plugin.add_preferences_page(_("Execute"), self.glade.get_widget("execute_box")) self.plugin.add_preferences_page(_('Execute'), self.glade.get_widget('execute_box'))
self.plugin.register_hook("on_show_prefs", self.load_commands) self.plugin.register_hook('on_show_prefs', self.load_commands)
self.plugin.register_hook("on_apply_prefs", self.on_apply_prefs) self.plugin.register_hook('on_apply_prefs', self.on_apply_prefs)
self.load_commands() self.load_commands()
client.register_event_handler("ExecuteCommandAddedEvent", self.on_command_added_event) client.register_event_handler('ExecuteCommandAddedEvent', self.on_command_added_event)
client.register_event_handler("ExecuteCommandRemovedEvent", self.on_command_removed_event) client.register_event_handler('ExecuteCommandRemovedEvent', self.on_command_removed_event)
def unload(self): def unload(self):
self.plugin.remove_preferences_page(_("Execute")) self.plugin.remove_preferences_page(_('Execute'))
self.plugin.deregister_hook("on_apply_prefs", self.on_apply_prefs) self.plugin.deregister_hook('on_apply_prefs', self.on_apply_prefs)
self.plugin.deregister_hook("on_show_prefs", self.load_commands) self.plugin.deregister_hook('on_show_prefs', self.load_commands)
def add_command(self, command_id, event, command): def add_command(self, command_id, event, command):
log.debug("Adding command `%s`", command_id) log.debug('Adding command `%s`', command_id)
vbox = self.glade.get_widget("commands_vbox") vbox = self.glade.get_widget('commands_vbox')
hbox = gtk.HBox(False, 5) hbox = gtk.HBox(False, 5)
hbox.set_name(command_id + "_" + event) hbox.set_name(command_id + '_' + event)
label = gtk.Label(EVENT_MAP[event]) label = gtk.Label(EVENT_MAP[event])
entry = gtk.Entry() entry = gtk.Entry()
entry.set_text(command) entry.set_text(command)
button = gtk.Button() button = gtk.Button()
button.set_name("remove_%s" % command_id) button.set_name('remove_%s' % command_id)
button.connect("clicked", self.on_remove_button_clicked) button.connect('clicked', self.on_remove_button_clicked)
img = gtk.Image() img = gtk.Image()
img.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON) img.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON)
@ -92,15 +92,15 @@ class ExecutePreferences(object):
vbox.pack_start(hbox) vbox.pack_start(hbox)
def remove_command(self, command_id): def remove_command(self, command_id):
vbox = self.glade.get_widget("commands_vbox") vbox = self.glade.get_widget('commands_vbox')
children = vbox.get_children() children = vbox.get_children()
for child in children: for child in children:
if child.get_name().split("_")[0] == command_id: if child.get_name().split('_')[0] == command_id:
vbox.remove(child) vbox.remove(child)
break break
def clear_commands(self): def clear_commands(self):
vbox = self.glade.get_widget("commands_vbox") vbox = self.glade.get_widget('commands_vbox')
children = vbox.get_children() children = vbox.get_children()
for child in children: for child in children:
vbox.remove(child) vbox.remove(child)
@ -108,7 +108,7 @@ class ExecutePreferences(object):
def load_commands(self): def load_commands(self):
def on_get_commands(commands): def on_get_commands(commands):
self.clear_commands() self.clear_commands()
log.debug("on_get_commands: %s", commands) log.debug('on_get_commands: %s', commands)
for command in commands: for command in commands:
command_id, event, command = command command_id, event, command = command
self.add_command(command_id, event, command) self.add_command(command_id, event, command)
@ -116,38 +116,38 @@ class ExecutePreferences(object):
client.execute.get_commands().addCallback(on_get_commands) client.execute.get_commands().addCallback(on_get_commands)
def on_add_button_clicked(self, *args): def on_add_button_clicked(self, *args):
command = self.glade.get_widget("command_entry").get_text() command = self.glade.get_widget('command_entry').get_text()
events = self.glade.get_widget("event_combobox") events = self.glade.get_widget('event_combobox')
event = events.get_model()[events.get_active()][1] event = events.get_model()[events.get_active()][1]
client.execute.add_command(event, command) client.execute.add_command(event, command)
def on_remove_button_clicked(self, widget, *args): def on_remove_button_clicked(self, widget, *args):
command_id = widget.get_name().replace("remove_", "") command_id = widget.get_name().replace('remove_', '')
client.execute.remove_command(command_id) client.execute.remove_command(command_id)
def on_apply_prefs(self): def on_apply_prefs(self):
vbox = self.glade.get_widget("commands_vbox") vbox = self.glade.get_widget('commands_vbox')
children = vbox.get_children() children = vbox.get_children()
for child in children: for child in children:
command_id, event = child.get_name().split("_") command_id, event = child.get_name().split('_')
for widget in child.get_children(): for widget in child.get_children():
if isinstance(widget, gtk.Entry): if isinstance(widget, gtk.Entry):
command = widget.get_text() command = widget.get_text()
client.execute.save_command(command_id, event, command) client.execute.save_command(command_id, event, command)
def on_command_added_event(self, command_id, event, command): def on_command_added_event(self, command_id, event, command):
log.debug("Adding command %s: %s", event, command) log.debug('Adding command %s: %s', event, command)
self.add_command(command_id, event, command) self.add_command(command_id, event, command)
def on_command_removed_event(self, command_id): def on_command_removed_event(self, command_id):
log.debug("Removing command %s", command_id) log.debug('Removing command %s', command_id)
self.remove_command(command_id) self.remove_command(command_id)
class GtkUI(GtkPluginBase): class GtkUI(GtkPluginBase):
def enable(self): def enable(self):
self.plugin = component.get("PluginManager") self.plugin = component.get('PluginManager')
self.preferences = ExecutePreferences(self.plugin) self.preferences = ExecutePreferences(self.plugin)
self.preferences.load() self.preferences.load()

View File

@ -18,5 +18,5 @@ log = logging.getLogger(__name__)
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("execute.js")] scripts = [get_resource('execute.js')]
debug_scripts = scripts debug_scripts = scripts

View File

@ -9,15 +9,15 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "Execute" __plugin_name__ = 'Execute'
__author__ = "Damien Churchill" __author__ = 'Damien Churchill'
__author_email__ = "damoxc@gmail.com" __author_email__ = 'damoxc@gmail.com'
__version__ = "1.2" __version__ = '1.2'
__url__ = "http://deluge-torrent.org" __url__ = 'http://deluge-torrent.org'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Plugin to execute a command upon an event" __description__ = 'Plugin to execute a command upon an event'
__long_description__ = __description__ __long_description__ = __description__
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -30,7 +30,7 @@ setup(
long_description=__long_description__, long_description=__long_description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -13,5 +13,5 @@ import pkg_resources
def get_resource(filename): def get_resource(filename):
return pkg_resources.resource_filename("deluge.plugins.extractor", return pkg_resources.resource_filename('deluge.plugins.extractor',
os.path.join("data", filename)) os.path.join('data', filename))

View File

@ -27,8 +27,8 @@ from deluge.plugins.pluginbase import CorePluginBase
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DEFAULT_PREFS = { DEFAULT_PREFS = {
"extract_path": "", 'extract_path': '',
"use_name_folder": True 'use_name_folder': True
} }
if windows_check(): if windows_check():
@ -40,15 +40,15 @@ if windows_check():
import _winreg import _winreg
try: try:
hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\7-Zip") hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\7-Zip')
except WindowsError: # pylint: disable=undefined-variable except WindowsError: # pylint: disable=undefined-variable
pass pass
else: else:
win_7z_path = os.path.join(_winreg.QueryValueEx(hkey, "Path")[0], "7z.exe") win_7z_path = os.path.join(_winreg.QueryValueEx(hkey, 'Path')[0], '7z.exe')
_winreg.CloseKey(hkey) _winreg.CloseKey(hkey)
win_7z_exes.insert(1, win_7z_path) win_7z_exes.insert(1, win_7z_path)
switch_7z = "x -y" switch_7z = 'x -y'
# Future suport: # Future suport:
# 7-zip cannot extract tar.* with single command. # 7-zip cannot extract tar.* with single command.
# ".tar.gz", ".tgz", # ".tar.gz", ".tgz",
@ -56,15 +56,15 @@ if windows_check():
# ".tar.lzma", ".tlz", # ".tar.lzma", ".tlz",
# ".tar.xz", ".txz", # ".tar.xz", ".txz",
exts_7z = [ exts_7z = [
".rar", ".zip", ".tar", '.rar', '.zip', '.tar',
".7z", ".xz", ".lzma", '.7z', '.xz', '.lzma',
] ]
for win_7z_exe in win_7z_exes: for win_7z_exe in win_7z_exes:
if which(win_7z_exe): if which(win_7z_exe):
EXTRACT_COMMANDS = dict.fromkeys(exts_7z, [win_7z_exe, switch_7z]) EXTRACT_COMMANDS = dict.fromkeys(exts_7z, [win_7z_exe, switch_7z])
break break
else: else:
required_cmds = ["unrar", "unzip", "tar", "unxz", "unlzma", "7zr", "bunzip2"] required_cmds = ['unrar', 'unzip', 'tar', 'unxz', 'unlzma', '7zr', 'bunzip2']
# Possible future suport: # Possible future suport:
# gunzip: gz (cmd will delete original archive) # gunzip: gz (cmd will delete original archive)
# the following do not extract to dest dir # the following do not extract to dest dir
@ -73,36 +73,36 @@ else:
# ".bz2": ["bzip2", "-d --keep"], # ".bz2": ["bzip2", "-d --keep"],
EXTRACT_COMMANDS = { EXTRACT_COMMANDS = {
".rar": ["unrar", "x -o+ -y"], '.rar': ['unrar', 'x -o+ -y'],
".tar": ["tar", "-xf"], '.tar': ['tar', '-xf'],
".zip": ["unzip", ""], '.zip': ['unzip', ''],
".tar.gz": ["tar", "-xzf"], ".tgz": ["tar", "-xzf"], '.tar.gz': ['tar', '-xzf'], '.tgz': ['tar', '-xzf'],
".tar.bz2": ["tar", "-xjf"], ".tbz": ["tar", "-xjf"], '.tar.bz2': ['tar', '-xjf'], '.tbz': ['tar', '-xjf'],
".tar.lzma": ["tar", "--lzma -xf"], ".tlz": ["tar", "--lzma -xf"], '.tar.lzma': ['tar', '--lzma -xf'], '.tlz': ['tar', '--lzma -xf'],
".tar.xz": ["tar", "--xz -xf"], ".txz": ["tar", "--xz -xf"], '.tar.xz': ['tar', '--xz -xf'], '.txz': ['tar', '--xz -xf'],
".7z": ["7zr", "x"], '.7z': ['7zr', 'x'],
} }
# Test command exists and if not, remove. # Test command exists and if not, remove.
for command in required_cmds: for command in required_cmds:
if not which(command): if not which(command):
for k, v in EXTRACT_COMMANDS.items(): for k, v in EXTRACT_COMMANDS.items():
if command in v[0]: if command in v[0]:
log.warning("%s not found, disabling support for %s", command, k) log.warning('%s not found, disabling support for %s', command, k)
del EXTRACT_COMMANDS[k] del EXTRACT_COMMANDS[k]
if not EXTRACT_COMMANDS: if not EXTRACT_COMMANDS:
raise Exception("No archive extracting programs found, plugin will be disabled") raise Exception('No archive extracting programs found, plugin will be disabled')
class Core(CorePluginBase): class Core(CorePluginBase):
def enable(self): def enable(self):
self.config = deluge.configmanager.ConfigManager("extractor.conf", DEFAULT_PREFS) self.config = deluge.configmanager.ConfigManager('extractor.conf', DEFAULT_PREFS)
if not self.config["extract_path"]: if not self.config['extract_path']:
self.config["extract_path"] = deluge.configmanager.ConfigManager("core.conf")["download_location"] self.config['extract_path'] = deluge.configmanager.ConfigManager('core.conf')['download_location']
component.get("EventManager").register_event_handler("TorrentFinishedEvent", self._on_torrent_finished) component.get('EventManager').register_event_handler('TorrentFinishedEvent', self._on_torrent_finished)
def disable(self): def disable(self):
component.get("EventManager").deregister_event_handler("TorrentFinishedEvent", self._on_torrent_finished) component.get('EventManager').deregister_event_handler('TorrentFinishedEvent', self._on_torrent_finished)
def update(self): def update(self):
pass pass
@ -111,57 +111,57 @@ class Core(CorePluginBase):
""" """
This is called when a torrent finishes and checks if any files to extract. This is called when a torrent finishes and checks if any files to extract.
""" """
tid = component.get("TorrentManager").torrents[torrent_id] tid = component.get('TorrentManager').torrents[torrent_id]
tid_status = tid.get_status(["download_location", "name"]) tid_status = tid.get_status(['download_location', 'name'])
files = tid.get_files() files = tid.get_files()
for f in files: for f in files:
file_root, file_ext = os.path.splitext(f["path"]) file_root, file_ext = os.path.splitext(f['path'])
file_ext_sec = os.path.splitext(file_root)[1] file_ext_sec = os.path.splitext(file_root)[1]
if file_ext_sec and file_ext_sec + file_ext in EXTRACT_COMMANDS: if file_ext_sec and file_ext_sec + file_ext in EXTRACT_COMMANDS:
file_ext = file_ext_sec + file_ext file_ext = file_ext_sec + file_ext
elif file_ext not in EXTRACT_COMMANDS or file_ext_sec == '.tar': elif file_ext not in EXTRACT_COMMANDS or file_ext_sec == '.tar':
log.debug("Can't extract file with unknown file type: %s", f["path"]) log.debug("Can't extract file with unknown file type: %s", f['path'])
continue continue
elif file_ext == ".rar" and "part" in file_ext_sec: elif file_ext == '.rar' and 'part' in file_ext_sec:
part_num = file_ext_sec.split("part")[1] part_num = file_ext_sec.split('part')[1]
if part_num.isdigit() and int(part_num) != 1: if part_num.isdigit() and int(part_num) != 1:
log.debug("Skipping remaining multi-part rar files: %s", f["path"]) log.debug('Skipping remaining multi-part rar files: %s', f['path'])
continue continue
cmd = EXTRACT_COMMANDS[file_ext] cmd = EXTRACT_COMMANDS[file_ext]
fpath = os.path.join(tid_status["download_location"], os.path.normpath(f["path"])) fpath = os.path.join(tid_status['download_location'], os.path.normpath(f['path']))
dest = os.path.normpath(self.config["extract_path"]) dest = os.path.normpath(self.config['extract_path'])
if self.config["use_name_folder"]: if self.config['use_name_folder']:
dest = os.path.join(dest, tid_status["name"]) dest = os.path.join(dest, tid_status['name'])
try: try:
os.makedirs(dest) os.makedirs(dest)
except OSError as ex: except OSError as ex:
if not (ex.errno == errno.EEXIST and os.path.isdir(dest)): if not (ex.errno == errno.EEXIST and os.path.isdir(dest)):
log.error("Error creating destination folder: %s", ex) log.error('Error creating destination folder: %s', ex)
break break
def on_extract(result, torrent_id, fpath): def on_extract(result, torrent_id, fpath):
# Check command exit code. # Check command exit code.
if not result[2]: if not result[2]:
log.info("Extract successful: %s (%s)", fpath, torrent_id) log.info('Extract successful: %s (%s)', fpath, torrent_id)
else: else:
log.error("Extract failed: %s (%s) %s", fpath, torrent_id, result[1]) log.error('Extract failed: %s (%s) %s', fpath, torrent_id, result[1])
# Run the command and add callback. # Run the command and add callback.
log.debug("Extracting %s from %s with %s %s to %s", fpath, torrent_id, cmd[0], cmd[1], dest) log.debug('Extracting %s from %s with %s %s to %s', fpath, torrent_id, cmd[0], cmd[1], dest)
d = getProcessOutputAndValue(cmd[0], cmd[1].split() + [str(fpath)], os.environ, str(dest)) d = getProcessOutputAndValue(cmd[0], cmd[1].split() + [str(fpath)], os.environ, str(dest))
d.addCallback(on_extract, torrent_id, fpath) d.addCallback(on_extract, torrent_id, fpath)
@export @export
def set_config(self, config): def set_config(self, config):
"sets the config dictionary" 'sets the config dictionary'
for key in config.keys(): for key in config.keys():
self.config[key] = config[key] self.config[key] = config[key]
self.config.save() self.config.save()
@export @export
def get_config(self): def get_config(self):
"returns the config dictionary" 'returns the config dictionary'
return self.config.config return self.config.config

View File

@ -27,47 +27,47 @@ log = logging.getLogger(__name__)
class GtkUI(GtkPluginBase): class GtkUI(GtkPluginBase):
def enable(self): def enable(self):
self.glade = gtk.glade.XML(get_resource("extractor_prefs.glade")) self.glade = gtk.glade.XML(get_resource('extractor_prefs.glade'))
component.get("Preferences").add_page(_("Extractor"), self.glade.get_widget("extractor_prefs_box")) component.get('Preferences').add_page(_('Extractor'), self.glade.get_widget('extractor_prefs_box'))
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').register_hook('on_apply_prefs', self.on_apply_prefs)
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs) component.get('PluginManager').register_hook('on_show_prefs', self.on_show_prefs)
self.on_show_prefs() self.on_show_prefs()
def disable(self): def disable(self):
component.get("Preferences").remove_page(_("Extractor")) component.get('Preferences').remove_page(_('Extractor'))
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').deregister_hook('on_apply_prefs', self.on_apply_prefs)
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs) component.get('PluginManager').deregister_hook('on_show_prefs', self.on_show_prefs)
del self.glade del self.glade
def on_apply_prefs(self): def on_apply_prefs(self):
log.debug("applying prefs for Extractor") log.debug('applying prefs for Extractor')
if client.is_localhost(): if client.is_localhost():
path = self.glade.get_widget("folderchooser_path").get_filename() path = self.glade.get_widget('folderchooser_path').get_filename()
else: else:
path = self.glade.get_widget("entry_path").get_text() path = self.glade.get_widget('entry_path').get_text()
config = { config = {
"extract_path": path, 'extract_path': path,
"use_name_folder": self.glade.get_widget("chk_use_name").get_active() 'use_name_folder': self.glade.get_widget('chk_use_name').get_active()
} }
client.extractor.set_config(config) client.extractor.set_config(config)
def on_show_prefs(self): def on_show_prefs(self):
if client.is_localhost(): if client.is_localhost():
self.glade.get_widget("folderchooser_path").show() self.glade.get_widget('folderchooser_path').show()
self.glade.get_widget("entry_path").hide() self.glade.get_widget('entry_path').hide()
else: else:
self.glade.get_widget("folderchooser_path").hide() self.glade.get_widget('folderchooser_path').hide()
self.glade.get_widget("entry_path").show() self.glade.get_widget('entry_path').show()
def on_get_config(config): def on_get_config(config):
if client.is_localhost(): if client.is_localhost():
self.glade.get_widget("folderchooser_path").set_current_folder(config["extract_path"]) self.glade.get_widget('folderchooser_path').set_current_folder(config['extract_path'])
else: else:
self.glade.get_widget("entry_path").set_text(config["extract_path"]) self.glade.get_widget('entry_path').set_text(config['extract_path'])
self.glade.get_widget("chk_use_name").set_active(config["use_name_folder"]) self.glade.get_widget('chk_use_name').set_active(config['use_name_folder'])
client.extractor.get_config().addCallback(on_get_config) client.extractor.get_config().addCallback(on_get_config)

View File

@ -22,5 +22,5 @@ log = logging.getLogger(__name__)
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("extractor.js")] scripts = [get_resource('extractor.js')]
debug_scripts = scripts debug_scripts = scripts

View File

@ -13,13 +13,13 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "Extractor" __plugin_name__ = 'Extractor'
__author__ = "Andrew Resch" __author__ = 'Andrew Resch'
__author_email__ = "andrewresch@gmail.com" __author_email__ = 'andrewresch@gmail.com'
__version__ = "0.6" __version__ = '0.6'
__url__ = "http://deluge-torrent.org" __url__ = 'http://deluge-torrent.org'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Extract files upon torrent completion" __description__ = 'Extract files upon torrent completion'
__long_description__ = """ __long_description__ = """
Extract files upon torrent completion Extract files upon torrent completion
@ -30,7 +30,7 @@ Windows support: .rar, .zip, .tar, .7z, .xz, .lzma
Note: Will not extract with 'Move Completed' enabled Note: Will not extract with 'Move Completed' enabled
""" """
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -43,7 +43,7 @@ setup(
long_description=__long_description__ if __long_description__ else __description__, long_description=__long_description__ if __long_description__ else __description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -26,40 +26,40 @@ from deluge.plugins.pluginbase import CorePluginBase
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
RE_VALID = re.compile(r"[a-z0-9_\-\.]*\Z") RE_VALID = re.compile(r'[a-z0-9_\-\.]*\Z')
KNOWN_STATES = ['Downloading', 'Seeding', 'Paused', 'Checking', 'Queued', 'Error'] KNOWN_STATES = ['Downloading', 'Seeding', 'Paused', 'Checking', 'Queued', 'Error']
STATE = "state" STATE = 'state'
TRACKER = "tracker" TRACKER = 'tracker'
KEYWORD = "keyword" KEYWORD = 'keyword'
LABEL = "label" LABEL = 'label'
CONFIG_DEFAULTS = { CONFIG_DEFAULTS = {
"torrent_labels": {}, # torrent_id:label_id 'torrent_labels': {}, # torrent_id:label_id
"labels": {}, # label_id:{name:value} 'labels': {}, # label_id:{name:value}
} }
CORE_OPTIONS = ["auto_add_trackers"] CORE_OPTIONS = ['auto_add_trackers']
OPTIONS_DEFAULTS = { OPTIONS_DEFAULTS = {
"apply_max": False, 'apply_max': False,
"max_download_speed": -1, 'max_download_speed': -1,
"max_upload_speed": -1, 'max_upload_speed': -1,
"max_connections": -1, 'max_connections': -1,
"max_upload_slots": -1, 'max_upload_slots': -1,
"prioritize_first_last": False, 'prioritize_first_last': False,
"apply_queue": False, 'apply_queue': False,
"is_auto_managed": False, 'is_auto_managed': False,
"stop_at_ratio": False, 'stop_at_ratio': False,
"stop_ratio": 2.0, 'stop_ratio': 2.0,
"remove_at_ratio": False, 'remove_at_ratio': False,
"apply_move_completed": False, 'apply_move_completed': False,
"move_completed": False, 'move_completed': False,
"move_completed_path": "", 'move_completed_path': '',
"auto_add": False, 'auto_add': False,
"auto_add_trackers": [] 'auto_add_trackers': []
} }
NO_LABEL = "No Label" NO_LABEL = 'No Label'
def check_input(cond, message): def check_input(cond, message):
@ -73,35 +73,35 @@ class Core(CorePluginBase):
self.torrent_labels = {torrent_id:label_id} self.torrent_labels = {torrent_id:label_id}
""" """
def enable(self): def enable(self):
log.info("*** Start Label plugin ***") log.info('*** Start Label plugin ***')
self.plugin = component.get("CorePluginManager") self.plugin = component.get('CorePluginManager')
self.plugin.register_status_field("label", self._status_get_label) self.plugin.register_status_field('label', self._status_get_label)
# __init__ # __init__
core = component.get("Core") core = component.get('Core')
self.config = ConfigManager("label.conf", defaults=CONFIG_DEFAULTS) self.config = ConfigManager('label.conf', defaults=CONFIG_DEFAULTS)
self.core_cfg = ConfigManager("core.conf") self.core_cfg = ConfigManager('core.conf')
# reduce typing, assigning some values to self... # reduce typing, assigning some values to self...
self.torrents = core.torrentmanager.torrents self.torrents = core.torrentmanager.torrents
self.labels = self.config["labels"] self.labels = self.config['labels']
self.torrent_labels = self.config["torrent_labels"] self.torrent_labels = self.config['torrent_labels']
self.clean_initial_config() self.clean_initial_config()
component.get("EventManager").register_event_handler("TorrentAddedEvent", self.post_torrent_add) component.get('EventManager').register_event_handler('TorrentAddedEvent', self.post_torrent_add)
component.get("EventManager").register_event_handler("TorrentRemovedEvent", self.post_torrent_remove) component.get('EventManager').register_event_handler('TorrentRemovedEvent', self.post_torrent_remove)
# register tree: # register tree:
component.get("FilterManager").register_tree_field("label", self.init_filter_dict) component.get('FilterManager').register_tree_field('label', self.init_filter_dict)
log.debug("Label plugin enabled..") log.debug('Label plugin enabled..')
def disable(self): def disable(self):
self.plugin.deregister_status_field("label") self.plugin.deregister_status_field('label')
component.get("FilterManager").deregister_tree_field("label") component.get('FilterManager').deregister_tree_field('label')
component.get("EventManager").deregister_event_handler("TorrentAddedEvent", self.post_torrent_add) component.get('EventManager').deregister_event_handler('TorrentAddedEvent', self.post_torrent_add)
component.get("EventManager").deregister_event_handler("TorrentRemovedEvent", self.post_torrent_remove) component.get('EventManager').deregister_event_handler('TorrentRemovedEvent', self.post_torrent_remove)
def update(self): def update(self):
pass pass
@ -115,17 +115,17 @@ class Core(CorePluginBase):
def post_torrent_add(self, torrent_id, from_state): def post_torrent_add(self, torrent_id, from_state):
if from_state: if from_state:
return return
log.debug("post_torrent_add") log.debug('post_torrent_add')
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
for label_id, options in self.labels.iteritems(): for label_id, options in self.labels.iteritems():
if options["auto_add"]: if options['auto_add']:
if self._has_auto_match(torrent, options): if self._has_auto_match(torrent, options):
self.set_torrent(torrent_id, label_id) self.set_torrent(torrent_id, label_id)
return return
def post_torrent_remove(self, torrent_id): def post_torrent_remove(self, torrent_id):
log.debug("post_torrent_remove") log.debug('post_torrent_remove')
if torrent_id in self.torrent_labels: if torrent_id in self.torrent_labels:
del self.torrent_labels[torrent_id] del self.torrent_labels[torrent_id]
@ -134,7 +134,7 @@ class Core(CorePluginBase):
"""remove invalid data from config-file""" """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.iteritems()):
if (label_id not in self.labels) or (torrent_id not in self.torrents): if (label_id not in self.labels) or (torrent_id not in self.torrents):
log.debug("label: rm %s:%s", torrent_id, label_id) log.debug('label: rm %s:%s', torrent_id, label_id)
del self.torrent_labels[torrent_id] del self.torrent_labels[torrent_id]
def clean_initial_config(self): def clean_initial_config(self):
@ -168,9 +168,9 @@ class Core(CorePluginBase):
see label_set_options for more options. see label_set_options for more options.
""" """
label_id = label_id.lower() label_id = label_id.lower()
check_input(RE_VALID.match(label_id), _("Invalid label, valid characters:[a-z0-9_-]")) check_input(RE_VALID.match(label_id), _('Invalid label, valid characters:[a-z0-9_-]'))
check_input(label_id, _("Empty Label")) check_input(label_id, _('Empty Label'))
check_input(not (label_id in self.labels), _("Label already exists")) check_input(not (label_id in self.labels), _('Label already exists'))
self.labels[label_id] = dict(OPTIONS_DEFAULTS) self.labels[label_id] = dict(OPTIONS_DEFAULTS)
self.config.save() self.config.save()
@ -178,7 +178,7 @@ class Core(CorePluginBase):
@export @export
def remove(self, label_id): def remove(self, label_id):
"""remove a label""" """remove a label"""
check_input(label_id in self.labels, _("Unknown Label")) check_input(label_id in self.labels, _('Unknown Label'))
del self.labels[label_id] del self.labels[label_id]
self.clean_config() self.clean_config()
self.config.save() self.config.save()
@ -187,27 +187,27 @@ class Core(CorePluginBase):
options = self.labels[label_id] options = self.labels[label_id]
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
if not options["move_completed_path"]: if not options['move_completed_path']:
options["move_completed_path"] = "" # no None. options['move_completed_path'] = '' # no None.
if options["apply_max"]: if options['apply_max']:
torrent.set_max_download_speed(options["max_download_speed"]) torrent.set_max_download_speed(options['max_download_speed'])
torrent.set_max_upload_speed(options["max_upload_speed"]) torrent.set_max_upload_speed(options['max_upload_speed'])
torrent.set_max_connections(options["max_connections"]) torrent.set_max_connections(options['max_connections'])
torrent.set_max_upload_slots(options["max_upload_slots"]) torrent.set_max_upload_slots(options['max_upload_slots'])
torrent.set_prioritize_first_last_pieces(options["prioritize_first_last"]) torrent.set_prioritize_first_last_pieces(options['prioritize_first_last'])
if options["apply_queue"]: if options['apply_queue']:
torrent.set_auto_managed(options['is_auto_managed']) torrent.set_auto_managed(options['is_auto_managed'])
torrent.set_stop_at_ratio(options['stop_at_ratio']) torrent.set_stop_at_ratio(options['stop_at_ratio'])
torrent.set_stop_ratio(options['stop_ratio']) torrent.set_stop_ratio(options['stop_ratio'])
torrent.set_remove_at_ratio(options['remove_at_ratio']) torrent.set_remove_at_ratio(options['remove_at_ratio'])
if options["apply_move_completed"]: if options['apply_move_completed']:
torrent.set_options( torrent.set_options(
{ {
"move_completed": options["move_completed"], 'move_completed': options['move_completed'],
"move_completed_path": options["move_completed_path"] 'move_completed_path': options['move_completed_path']
} }
) )
@ -215,32 +215,32 @@ class Core(CorePluginBase):
options = self.labels[label_id] options = self.labels[label_id]
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
if options["apply_max"]: if options['apply_max']:
torrent.set_max_download_speed(self.core_cfg.config["max_download_speed_per_torrent"]) torrent.set_max_download_speed(self.core_cfg.config['max_download_speed_per_torrent'])
torrent.set_max_upload_speed(self.core_cfg.config["max_upload_speed_per_torrent"]) torrent.set_max_upload_speed(self.core_cfg.config['max_upload_speed_per_torrent'])
torrent.set_max_connections(self.core_cfg.config["max_connections_per_torrent"]) torrent.set_max_connections(self.core_cfg.config['max_connections_per_torrent'])
torrent.set_max_upload_slots(self.core_cfg.config["max_upload_slots_per_torrent"]) torrent.set_max_upload_slots(self.core_cfg.config['max_upload_slots_per_torrent'])
torrent.set_prioritize_first_last_pieces(self.core_cfg.config["prioritize_first_last_pieces"]) torrent.set_prioritize_first_last_pieces(self.core_cfg.config['prioritize_first_last_pieces'])
if options["apply_queue"]: if options['apply_queue']:
torrent.set_auto_managed(self.core_cfg.config['auto_managed']) torrent.set_auto_managed(self.core_cfg.config['auto_managed'])
torrent.set_stop_at_ratio(self.core_cfg.config['stop_seed_at_ratio']) torrent.set_stop_at_ratio(self.core_cfg.config['stop_seed_at_ratio'])
torrent.set_stop_ratio(self.core_cfg.config['stop_seed_ratio']) torrent.set_stop_ratio(self.core_cfg.config['stop_seed_ratio'])
torrent.set_remove_at_ratio(self.core_cfg.config['remove_seed_at_ratio']) torrent.set_remove_at_ratio(self.core_cfg.config['remove_seed_at_ratio'])
if options["apply_move_completed"]: if options['apply_move_completed']:
torrent.set_options( torrent.set_options(
{ {
"move_completed": self.core_cfg.config["move_completed"], 'move_completed': self.core_cfg.config['move_completed'],
"move_completed_path": self.core_cfg.config["move_completed_path"] 'move_completed_path': self.core_cfg.config['move_completed_path']
} }
) )
def _has_auto_match(self, torrent, label_options): def _has_auto_match(self, torrent, label_options):
"""match for auto_add fields""" """match for auto_add fields"""
for tracker_match in label_options["auto_add_trackers"]: for tracker_match in label_options['auto_add_trackers']:
for tracker in torrent.trackers: for tracker in torrent.trackers:
if tracker_match in tracker["url"]: if tracker_match in tracker['url']:
return True return True
return False return False
@ -258,10 +258,10 @@ class Core(CorePluginBase):
"move_completed_to":string() or None "move_completed_to":string() or None
} }
""" """
check_input(label_id in self.labels, _("Unknown Label")) check_input(label_id in self.labels, _('Unknown Label'))
for key in options_dict.keys(): for key in options_dict.keys():
if key not in OPTIONS_DEFAULTS: if key not in OPTIONS_DEFAULTS:
raise Exception("label: Invalid options_dict key:%s" % key) raise Exception('label: Invalid options_dict key:%s' % key)
self.labels[label_id].update(options_dict) self.labels[label_id].update(options_dict)
@ -272,7 +272,7 @@ class Core(CorePluginBase):
# auto add # auto add
options = self.labels[label_id] options = self.labels[label_id]
if options["auto_add"]: if options['auto_add']:
for torrent_id, torrent in self.torrents.iteritems(): for torrent_id, torrent in self.torrents.iteritems():
if self._has_auto_match(torrent, options): if self._has_auto_match(torrent, options):
self.set_torrent(torrent_id, label_id) self.set_torrent(torrent_id, label_id)
@ -293,8 +293,8 @@ class Core(CorePluginBase):
if label_id == NO_LABEL: if label_id == NO_LABEL:
label_id = None label_id = None
check_input((not label_id) or (label_id in self.labels), _("Unknown Label")) check_input((not label_id) or (label_id in self.labels), _('Unknown Label'))
check_input(torrent_id in self.torrents, _("Unknown Torrent")) check_input(torrent_id in self.torrents, _('Unknown Torrent'))
if torrent_id in self.torrent_labels: if torrent_id in self.torrent_labels:
self._unset_torrent_options(torrent_id, self.torrent_labels[torrent_id]) self._unset_torrent_options(torrent_id, self.torrent_labels[torrent_id])
@ -322,4 +322,4 @@ class Core(CorePluginBase):
self.config.save() self.config.save()
def _status_get_label(self, torrent_id): def _status_get_label(self, torrent_id):
return self.torrent_labels.get(torrent_id) or "" return self.torrent_labels.get(torrent_id) or ''

View File

@ -16,7 +16,7 @@ from . import label_config, sidebar_menu, submenu
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
NO_LABEL = "No Label" NO_LABEL = 'No Label'
def cell_data_label(column, cell, model, row, data): def cell_data_label(column, cell, model, row, data):
@ -29,8 +29,8 @@ class GtkUI(GtkPluginBase):
self.label_menu.on_show() self.label_menu.on_show()
def enable(self): def enable(self):
self.plugin = component.get("PluginManager") self.plugin = component.get('PluginManager')
self.torrentmenu = component.get("MenuBar").torrentmenu self.torrentmenu = component.get('MenuBar').torrentmenu
self.label_menu = None self.label_menu = None
self.labelcfg = None self.labelcfg = None
self.sidebar_menu = None self.sidebar_menu = None
@ -44,7 +44,7 @@ class GtkUI(GtkPluginBase):
self.sidebar_menu.unload() self.sidebar_menu.unload()
del self.sidebar_menu del self.sidebar_menu
component.get("TorrentView").remove_column(_("Label")) component.get('TorrentView').remove_column(_('Label'))
def load_interface(self): def load_interface(self):
# sidebar # sidebar
@ -54,7 +54,7 @@ class GtkUI(GtkPluginBase):
# self.sidebar.load() # self.sidebar.load()
# menu: # menu:
log.debug("add items to torrentview-popup menu.") log.debug('add items to torrentview-popup menu.')
self.label_menu = submenu.LabelMenu() self.label_menu = submenu.LabelMenu()
self.torrentmenu.append(self.label_menu) self.torrentmenu.append(self.label_menu)
self.label_menu.show_all() self.label_menu.show_all()
@ -70,6 +70,6 @@ class GtkUI(GtkPluginBase):
log.debug('Finished loading Label plugin') log.debug('Finished loading Label plugin')
def load_columns(self): def load_columns(self):
log.debug("add columns") log.debug('add columns')
component.get("TorrentView").add_text_column(_("Label"), status_field=["label"]) component.get('TorrentView').add_text_column(_('Label'), status_field=['label'])

View File

@ -29,29 +29,29 @@ class LabelConfig(object):
def load(self): def load(self):
log.debug('Adding Label Preferences page') log.debug('Adding Label Preferences page')
self.glade = gtk.glade.XML(self.get_resource("label_pref.glade")) self.glade = gtk.glade.XML(self.get_resource('label_pref.glade'))
self.plugin.add_preferences_page(_("Label"), self.glade.get_widget("label_prefs_box")) self.plugin.add_preferences_page(_('Label'), self.glade.get_widget('label_prefs_box'))
self.plugin.register_hook("on_show_prefs", self.load_settings) self.plugin.register_hook('on_show_prefs', self.load_settings)
self.plugin.register_hook("on_apply_prefs", self.on_apply_prefs) self.plugin.register_hook('on_apply_prefs', self.on_apply_prefs)
self.load_settings() self.load_settings()
def unload(self): def unload(self):
self.plugin.remove_preferences_page(_("Label")) self.plugin.remove_preferences_page(_('Label'))
self.plugin.deregister_hook("on_apply_prefs", self.on_apply_prefs) self.plugin.deregister_hook('on_apply_prefs', self.on_apply_prefs)
self.plugin.deregister_hook("on_show_prefs", self.load_settings) self.plugin.deregister_hook('on_show_prefs', self.load_settings)
def get_resource(self, filename): def get_resource(self, filename):
return pkg_resources.resource_filename( return pkg_resources.resource_filename(
"deluge.plugins.label", os.path.join("data", filename) 'deluge.plugins.label', os.path.join('data', filename)
) )
def load_settings(self, widget=None, data=None): def load_settings(self, widget=None, data=None):
client.label.get_config().addCallback(self.cb_global_options) client.label.get_config().addCallback(self.cb_global_options)
def cb_global_options(self, options): def cb_global_options(self, options):
log.debug("options=%s", options) log.debug('options=%s', options)
# for id in self.chk_ids: # for id in self.chk_ids:
# self.glade.get_widget(id).set_active(bool(options[id])) # self.glade.get_widget(id).set_active(bool(options[id]))

View File

@ -18,7 +18,7 @@ from deluge.ui.client import client
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
NO_LABEL = "No Label" NO_LABEL = 'No Label'
# helpers: # helpers:
@ -26,7 +26,7 @@ def get_resource(filename):
import pkg_resources import pkg_resources
import os import os
return pkg_resources.resource_filename( return pkg_resources.resource_filename(
"deluge.plugins.label", os.path.join("data", filename) 'deluge.plugins.label', os.path.join('data', filename)
) )
@ -34,7 +34,7 @@ def get_resource(filename):
class LabelSidebarMenu(object): class LabelSidebarMenu(object):
def __init__(self): def __init__(self):
self.treeview = component.get("FilterTreeView") self.treeview = component.get('FilterTreeView')
self.menu = self.treeview.menu self.menu = self.treeview.menu
self.items = [] self.items = []
@ -42,27 +42,27 @@ class LabelSidebarMenu(object):
sep = gtk.SeparatorMenuItem() sep = gtk.SeparatorMenuItem()
self.items.append(sep) self.items.append(sep)
self.menu.prepend(sep) self.menu.prepend(sep)
self._add_item("options", _("Label _Options"), gtk.STOCK_PREFERENCES) self._add_item('options', _('Label _Options'), gtk.STOCK_PREFERENCES)
self._add_item("remove", _("_Remove Label"), gtk.STOCK_REMOVE) self._add_item('remove', _('_Remove Label'), gtk.STOCK_REMOVE)
self._add_item("add", _("_Add Label"), gtk.STOCK_ADD) self._add_item('add', _('_Add Label'), gtk.STOCK_ADD)
self.menu.show_all() self.menu.show_all()
# dialogs: # dialogs:
self.add_dialog = AddDialog() self.add_dialog = AddDialog()
self.options_dialog = OptionsDialog() self.options_dialog = OptionsDialog()
# hooks: # hooks:
self.menu.connect("show", self.on_show, None) self.menu.connect('show', self.on_show, None)
def _add_item(self, item_id, label, stock): def _add_item(self, item_id, label, stock):
"""I hate glade. """I hate glade.
id is automatically-added as self.item_<id> id is automatically-added as self.item_<id>
""" """
func = getattr(self, "on_%s" % item_id) func = getattr(self, 'on_%s' % item_id)
item = gtk.ImageMenuItem(stock) item = gtk.ImageMenuItem(stock)
item.get_children()[0].set_label(label) item.get_children()[0].set_label(label)
item.connect("activate", func) item.connect('activate', func)
self.menu.prepend(item) self.menu.prepend(item)
setattr(self, "item_%s" % item_id, item) setattr(self, 'item_%s' % item_id, item)
self.items.append(item) self.items.append(item)
return item return item
@ -76,17 +76,17 @@ class LabelSidebarMenu(object):
self.options_dialog.show(self.treeview.value) self.options_dialog.show(self.treeview.value)
def on_show(self, widget=None, data=None): def on_show(self, widget=None, data=None):
"No Label:disable options/del" 'No Label:disable options/del'
log.debug("label-sidebar-popup:on-show") log.debug('label-sidebar-popup:on-show')
cat = self.treeview.cat cat = self.treeview.cat
label = self.treeview.value label = self.treeview.value
if cat == "label" or (cat == "cat" and label == "label"): if cat == 'label' or (cat == 'cat' and label == 'label'):
# is a label : show menu-items # is a label : show menu-items
for item in self.items: for item in self.items:
item.show() item.show()
# default items # default items
sensitive = ((label not in (NO_LABEL, None, "", "All")) and (cat != "cat")) sensitive = ((label not in (NO_LABEL, None, '', 'All')) and (cat != 'cat'))
for item in self.items: for item in self.items:
item.set_sensitive(sensitive) item.set_sensitive(sensitive)
@ -98,11 +98,11 @@ class LabelSidebarMenu(object):
item.hide() item.hide()
def unload(self): def unload(self):
log.debug("disable01") log.debug('disable01')
for item in list(self.items): for item in list(self.items):
item.hide() item.hide()
item.destroy() item.destroy()
log.debug("disable02") log.debug('disable02')
self.items = [] self.items = []
@ -112,18 +112,18 @@ class AddDialog(object):
pass pass
def show(self): def show(self):
self.glade = gtk.glade.XML(get_resource("label_options.glade")) self.glade = gtk.glade.XML(get_resource('label_options.glade'))
self.dialog = self.glade.get_widget("dlg_label_add") self.dialog = self.glade.get_widget('dlg_label_add')
self.dialog.set_transient_for(component.get("MainWindow").window) self.dialog.set_transient_for(component.get('MainWindow').window)
self.glade.signal_autoconnect({ self.glade.signal_autoconnect({
"on_add_ok": self.on_ok, 'on_add_ok': self.on_ok,
"on_add_cancel": self.on_cancel, 'on_add_cancel': self.on_cancel,
}) })
self.dialog.run() self.dialog.run()
def on_ok(self, event=None): def on_ok(self, event=None):
value = self.glade.get_widget("txt_add").get_text() value = self.glade.get_widget('txt_add').get_text()
client.label.add(value) client.label.add(value)
self.dialog.destroy() self.dialog.destroy()
@ -132,19 +132,19 @@ class AddDialog(object):
class OptionsDialog(object): class OptionsDialog(object):
spin_ids = ["max_download_speed", "max_upload_speed", "stop_ratio"] spin_ids = ['max_download_speed', 'max_upload_speed', 'stop_ratio']
spin_int_ids = ["max_upload_slots", "max_connections"] spin_int_ids = ['max_upload_slots', 'max_connections']
chk_ids = ["apply_max", "apply_queue", "stop_at_ratio", "apply_queue", "remove_at_ratio", chk_ids = ['apply_max', 'apply_queue', 'stop_at_ratio', 'apply_queue', 'remove_at_ratio',
"apply_move_completed", "move_completed", "is_auto_managed", "auto_add"] 'apply_move_completed', 'move_completed', 'is_auto_managed', 'auto_add']
# list of tuples, because order matters when nesting. # list of tuples, because order matters when nesting.
sensitive_groups = [ sensitive_groups = [
("apply_max", ["max_download_speed", "max_upload_speed", "max_upload_slots", "max_connections"]), ('apply_max', ['max_download_speed', 'max_upload_speed', 'max_upload_slots', 'max_connections']),
("apply_queue", ["is_auto_managed", "stop_at_ratio"]), ('apply_queue', ['is_auto_managed', 'stop_at_ratio']),
("stop_at_ratio", ["remove_at_ratio", "stop_ratio"]), # nested ('stop_at_ratio', ['remove_at_ratio', 'stop_ratio']), # nested
("apply_move_completed", ["move_completed"]), ('apply_move_completed', ['move_completed']),
("move_completed", ["move_completed_path"]), # nested ('move_completed', ['move_completed_path']), # nested
("auto_add", ["auto_add_trackers"]) ('auto_add', ['auto_add_trackers'])
] ]
def __init__(self): def __init__(self):
@ -152,20 +152,20 @@ class OptionsDialog(object):
def show(self, label): def show(self, label):
self.label = label self.label = label
self.glade = gtk.glade.XML(get_resource("label_options.glade")) self.glade = gtk.glade.XML(get_resource('label_options.glade'))
self.dialog = self.glade.get_widget("dlg_label_options") self.dialog = self.glade.get_widget('dlg_label_options')
self.dialog.set_transient_for(component.get("MainWindow").window) self.dialog.set_transient_for(component.get('MainWindow').window)
self.glade.signal_autoconnect({ self.glade.signal_autoconnect({
"on_options_ok": self.on_ok, 'on_options_ok': self.on_ok,
"on_options_cancel": self.on_cancel, 'on_options_cancel': self.on_cancel,
}) })
# Show the label name in the header label # Show the label name in the header label
self.glade.get_widget("label_header").set_markup("<b>%s:</b> %s" % (_("Label Options"), self.label)) self.glade.get_widget('label_header').set_markup('<b>%s:</b> %s' % (_('Label Options'), self.label))
for chk_id, group in self.sensitive_groups: for chk_id, group in self.sensitive_groups:
chk = self.glade.get_widget(chk_id) chk = self.glade.get_widget(chk_id)
chk.connect("toggled", self.apply_sensitivity) chk.connect('toggled', self.apply_sensitivity)
client.label.get_options(self.label).addCallback(self.load_options) client.label.get_options(self.label).addCallback(self.load_options)
@ -180,20 +180,20 @@ class OptionsDialog(object):
self.glade.get_widget(chk_id).set_active(bool(options[chk_id])) self.glade.get_widget(chk_id).set_active(bool(options[chk_id]))
if client.is_localhost(): if client.is_localhost():
self.glade.get_widget("move_completed_path").set_filename(options["move_completed_path"]) self.glade.get_widget('move_completed_path').set_filename(options['move_completed_path'])
self.glade.get_widget("move_completed_path").show() self.glade.get_widget('move_completed_path').show()
self.glade.get_widget("move_completed_path_entry").hide() self.glade.get_widget('move_completed_path_entry').hide()
else: else:
self.glade.get_widget("move_completed_path_entry").set_text(options["move_completed_path"]) self.glade.get_widget('move_completed_path_entry').set_text(options['move_completed_path'])
self.glade.get_widget("move_completed_path_entry").show() self.glade.get_widget('move_completed_path_entry').show()
self.glade.get_widget("move_completed_path").hide() self.glade.get_widget('move_completed_path').hide()
self.glade.get_widget("auto_add_trackers").get_buffer().set_text("\n".join(options["auto_add_trackers"])) self.glade.get_widget('auto_add_trackers').get_buffer().set_text('\n'.join(options['auto_add_trackers']))
self.apply_sensitivity() self.apply_sensitivity()
def on_ok(self, event=None): def on_ok(self, event=None):
"save options.." 'save options..'
options = {} options = {}
for spin_id in self.spin_ids: for spin_id in self.spin_ids:
@ -204,13 +204,13 @@ class OptionsDialog(object):
options[chk_id] = self.glade.get_widget(chk_id).get_active() options[chk_id] = self.glade.get_widget(chk_id).get_active()
if client.is_localhost(): if client.is_localhost():
options["move_completed_path"] = self.glade.get_widget("move_completed_path").get_filename() options['move_completed_path'] = self.glade.get_widget('move_completed_path').get_filename()
else: else:
options["move_completed_path"] = self.glade.get_widget("move_completed_path_entry").get_text() options['move_completed_path'] = self.glade.get_widget('move_completed_path_entry').get_text()
buff = self.glade.get_widget("auto_add_trackers").get_buffer() # sometimes I hate gtk... buff = self.glade.get_widget('auto_add_trackers').get_buffer() # sometimes I hate gtk...
tracker_lst = buff.get_text(buff.get_start_iter(), buff.get_end_iter()).strip().split("\n") tracker_lst = buff.get_text(buff.get_start_iter(), buff.get_end_iter()).strip().split('\n')
options["auto_add_trackers"] = [x for x in tracker_lst if x] # filter out empty lines. options['auto_add_trackers'] = [x for x in tracker_lst if x] # filter out empty lines.
log.debug(options) log.debug(options)
client.label.set_options(self.label, options) client.label.set_options(self.label, options)
@ -219,7 +219,7 @@ class OptionsDialog(object):
def apply_sensitivity(self, event=None): def apply_sensitivity(self, event=None):
for chk_id, sensitive_list in self.sensitive_groups: for chk_id, sensitive_list in self.sensitive_groups:
chk = self.glade.get_widget(chk_id) chk = self.glade.get_widget(chk_id)
sens = chk.get_active() and chk.get_property("sensitive") sens = chk.get_active() and chk.get_property('sensitive')
for widget_id in sensitive_list: for widget_id in sensitive_list:
self.glade.get_widget(widget_id).set_sensitive(sens) self.glade.get_widget(widget_id).set_sensitive(sens)

View File

@ -21,26 +21,26 @@ log = logging.getLogger(__name__)
# Deferred Translation # Deferred Translation
def _(message): def _(message):
return message return message
NO_LABEL = _("No Label") NO_LABEL = _('No Label')
del _ del _
class LabelMenu(gtk.MenuItem): class LabelMenu(gtk.MenuItem):
def __init__(self): def __init__(self):
gtk.MenuItem.__init__(self, _("Label")) gtk.MenuItem.__init__(self, _('Label'))
self.sub_menu = gtk.Menu() self.sub_menu = gtk.Menu()
self.set_submenu(self.sub_menu) self.set_submenu(self.sub_menu)
self.items = [] self.items = []
# attach.. # attach..
self.sub_menu.connect("show", self.on_show, None) self.sub_menu.connect('show', self.on_show, None)
def get_torrent_ids(self): def get_torrent_ids(self):
return component.get("TorrentView").get_selected_torrents() return component.get('TorrentView').get_selected_torrents()
def on_show(self, widget=None, data=None): def on_show(self, widget=None, data=None):
log.debug("label-on-show") log.debug('label-on-show')
client.label.get_labels().addCallback(self.cb_labels) client.label.get_labels().addCallback(self.cb_labels)
def cb_labels(self, labels): def cb_labels(self, labels):
@ -50,12 +50,12 @@ class LabelMenu(gtk.MenuItem):
if label == NO_LABEL: if label == NO_LABEL:
item = gtk.MenuItem(_(NO_LABEL)) item = gtk.MenuItem(_(NO_LABEL))
else: else:
item = gtk.MenuItem(label.replace("_", "__")) item = gtk.MenuItem(label.replace('_', '__'))
item.connect("activate", self.on_select_label, label) item.connect('activate', self.on_select_label, label)
self.sub_menu.append(item) self.sub_menu.append(item)
self.show_all() self.show_all()
def on_select_label(self, widget=None, label_id=None): def on_select_label(self, widget=None, label_id=None):
log.debug("select label:%s,%s", label_id, self.get_torrent_ids()) log.debug('select label:%s,%s', label_id, self.get_torrent_ids())
for torrent_id in self.get_torrent_ids(): for torrent_id in self.get_torrent_ids():
client.label.set_torrent(torrent_id, label_id) client.label.set_torrent(torrent_id, label_id)

View File

@ -19,32 +19,32 @@ sclient.set_core_uri()
print(sclient.get_enabled_plugins()) print(sclient.get_enabled_plugins())
# enable plugin. # enable plugin.
if "label" not in sclient.get_enabled_plugins(): if 'label' not in sclient.get_enabled_plugins():
sclient.enable_plugin("label") sclient.enable_plugin('label')
# test labels. # test labels.
print("#init labels") print('#init labels')
try: try:
sclient.label_remove("test") sclient.label_remove('test')
except Exception: except Exception:
pass pass
sess_id = sclient.get_session_state()[0] sess_id = sclient.get_session_state()[0]
print("#add") print('#add')
sclient.label_add("test") sclient.label_add('test')
print("#set") print('#set')
sclient.label_set_torrent(id, "test") sclient.label_set_torrent(id, 'test')
print(sclient.get_torrents_status({"label": "test"}, "name")) print(sclient.get_torrents_status({'label': 'test'}, 'name'))
print("#set options") print('#set options')
sclient.label_set_options("test", {"max_download_speed": 999}, True) sclient.label_set_options('test', {'max_download_speed': 999}, True)
print(sclient.get_torrent_status(sess_id, ["max_download_speed"]), "999") print(sclient.get_torrent_status(sess_id, ['max_download_speed']), '999')
sclient.label_set_options("test", {"max_download_speed": 9}, True) sclient.label_set_options('test', {'max_download_speed': 9}, True)
print(sclient.get_torrent_status(sess_id, ["max_download_speed"]), "9") print(sclient.get_torrent_status(sess_id, ['max_download_speed']), '9')
sclient.label_set_options("test", {"max_download_speed": 888}, False) sclient.label_set_options('test', {'max_download_speed': 888}, False)
print(sclient.get_torrent_status(sess_id, ["max_download_speed"]), "9 (888)") print(sclient.get_torrent_status(sess_id, ['max_download_speed']), '9 (888)')
print(sclient.get_torrent_status(sess_id, ['name', 'tracker_host', 'label'])) print(sclient.get_torrent_status(sess_id, ['name', 'tracker_host', 'label']))

View File

@ -22,11 +22,11 @@ log = logging.getLogger(__name__)
def get_resource(filename): def get_resource(filename):
return pkg_resources.resource_filename("deluge.plugins.label", return pkg_resources.resource_filename('deluge.plugins.label',
os.path.join("data", filename)) os.path.join('data', filename))
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("label.js")] scripts = [get_resource('label.js')]
debug_scripts = scripts debug_scripts = scripts

View File

@ -9,19 +9,19 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "Label" __plugin_name__ = 'Label'
__author__ = "Martijn Voncken" __author__ = 'Martijn Voncken'
__author_email__ = "mvoncken@gmail.com" __author_email__ = 'mvoncken@gmail.com'
__version__ = "0.2" __version__ = '0.2'
__url__ = "http://deluge-torrent.org" __url__ = 'http://deluge-torrent.org'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Allows labels to be assigned to torrents" __description__ = 'Allows labels to be assigned to torrents'
__long_description__ = """ __long_description__ = """
Allows labels to be assigned to torrents Allows labels to be assigned to torrents
Also offers filters on state, tracker and keywords Also offers filters on state, tracker and keywords
""" """
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -34,7 +34,7 @@ setup(
long_description=__long_description__, long_description=__long_description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -30,17 +30,17 @@ except ImportError:
def get_resource(filename): def get_resource(filename):
import os import os
import pkg_resources import pkg_resources
return pkg_resources.resource_filename("deluge.plugins.notifications", os.path.join("data", filename)) return pkg_resources.resource_filename('deluge.plugins.notifications', os.path.join('data', filename))
class CustomNotifications(object): class CustomNotifications(object):
def __init__(self, plugin_name=None): def __init__(self, plugin_name=None):
self.custom_notifications = { self.custom_notifications = {
"email": {}, 'email': {},
"popup": {}, 'popup': {},
"blink": {}, 'blink': {},
"sound": {} 'sound': {}
} }
def enable(self): def enable(self):
@ -55,9 +55,9 @@ class CustomNotifications(object):
def _handle_custom_providers(self, kind, eventtype, *args, **kwargs): def _handle_custom_providers(self, kind, eventtype, *args, **kwargs):
log.debug("Calling CORE's custom %s providers for %s: %s %s", log.debug("Calling CORE's custom %s providers for %s: %s %s",
kind, eventtype, args, kwargs) kind, eventtype, args, kwargs)
if eventtype in self.config["subscriptions"][kind]: if eventtype in self.config['subscriptions'][kind]:
wrapper, handler = self.custom_notifications[kind][eventtype] wrapper, handler = self.custom_notifications[kind][eventtype]
log.debug("Found handler for kind %s: %s", kind, handler) log.debug('Found handler for kind %s: %s', kind, handler)
custom_notif_func = getattr(self, custom_notif_func = getattr(self,
'handle_custom_%s_notification' % kind) 'handle_custom_%s_notification' % kind)
d = defer.maybeDeferred(handler, *args, **kwargs) d = defer.maybeDeferred(handler, *args, **kwargs)
@ -68,7 +68,7 @@ class CustomNotifications(object):
def _register_custom_provider(self, kind, eventtype, handler): def _register_custom_provider(self, kind, eventtype, handler):
if not self._handled_eventtype(eventtype, handler): if not self._handled_eventtype(eventtype, handler):
return defer.succeed("Event not handled") return defer.succeed('Event not handled')
if eventtype not in self.custom_notifications: if eventtype not in self.custom_notifications:
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
return self._handle_custom_providers(kind, eventtype, *args, **kwargs) return self._handle_custom_providers(kind, eventtype, *args, **kwargs)
@ -76,7 +76,7 @@ class CustomNotifications(object):
else: else:
wrapper, handler = self.custom_notifications[kind][eventtype] wrapper, handler = self.custom_notifications[kind][eventtype]
try: try:
component.get("EventManager").register_event_handler( component.get('EventManager').register_event_handler(
eventtype, wrapper eventtype, wrapper
) )
except KeyError: except KeyError:
@ -87,7 +87,7 @@ class CustomNotifications(object):
try: try:
wrapper, handler = self.custom_notifications[kind][eventtype] wrapper, handler = self.custom_notifications[kind][eventtype]
try: try:
component.get("EventManager").deregister_event_handler( component.get('EventManager').deregister_event_handler(
eventtype, wrapper eventtype, wrapper
) )
except KeyError: except KeyError:
@ -104,15 +104,15 @@ class CustomNotifications(object):
if known_events[eventtype].__module__.startswith('deluge.event'): if known_events[eventtype].__module__.startswith('deluge.event'):
if handler.__self__ is self: if handler.__self__ is self:
return True return True
log.error("You cannot register custom notification providers " log.error('You cannot register custom notification providers '
"for built-in event types.") 'for built-in event types.')
return False return False
return True return True
def _on_notify_sucess(self, result, kind): def _on_notify_sucess(self, result, kind):
log.debug("Notification success using %s: %s", kind, result) log.debug('Notification success using %s: %s', kind, result)
return result return result
def _on_notify_failure(self, failure, kind): def _on_notify_failure(self, failure, kind):
log.debug("Notification failure using %s: %s", kind, failure) log.debug('Notification failure using %s: %s', kind, failure)
return failure return failure

View File

@ -29,17 +29,17 @@ from .common import CustomNotifications
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DEFAULT_PREFS = { DEFAULT_PREFS = {
"smtp_enabled": False, 'smtp_enabled': False,
"smtp_host": "", 'smtp_host': '',
"smtp_port": 25, 'smtp_port': 25,
"smtp_user": "", 'smtp_user': '',
"smtp_pass": "", 'smtp_pass': '',
"smtp_from": "", 'smtp_from': '',
"smtp_tls": False, # SSL or TLS 'smtp_tls': False, # SSL or TLS
"smtp_recipients": [], 'smtp_recipients': [],
# Subscriptions # Subscriptions
"subscriptions": { 'subscriptions': {
"email": [] 'email': []
} }
} }
@ -73,9 +73,9 @@ class CoreNotifications(CustomNotifications):
def handle_custom_email_notification(self, result, eventtype): def handle_custom_email_notification(self, result, eventtype):
if not self.config['smtp_enabled']: if not self.config['smtp_enabled']:
return defer.succeed("SMTP notification not enabled.") return defer.succeed('SMTP notification not enabled.')
subject, message = result subject, message = result
log.debug("Spawning new thread to send email with subject: %s: %s", log.debug('Spawning new thread to send email with subject: %s: %s',
subject, message) subject, message)
# Spawn thread because we don't want Deluge to lock up while we send the # Spawn thread because we don't want Deluge to lock up while we send the
# email. # email.
@ -90,11 +90,11 @@ class CoreNotifications(CustomNotifications):
continue continue
classdoc = known_events[evt].__doc__.strip() classdoc = known_events[evt].__doc__.strip()
handled_events.append((evt, classdoc)) handled_events.append((evt, classdoc))
log.debug("Handled Notification Events: %s", handled_events) log.debug('Handled Notification Events: %s', handled_events)
return handled_events return handled_events
def _notify_email(self, subject='', message=''): def _notify_email(self, subject='', message=''):
log.debug("Email prepared") log.debug('Email prepared')
to_addrs = self.config['smtp_recipients'] to_addrs = self.config['smtp_recipients']
to_addrs_str = ', '.join(self.config['smtp_recipients']) to_addrs_str = ', '.join(self.config['smtp_recipients'])
headers_dict = { headers_dict = {
@ -115,9 +115,9 @@ Date: %(date)s
try: try:
# Python 2.6 # Python 2.6
server = smtplib.SMTP(self.config["smtp_host"], self.config["smtp_port"], timeout=60) server = smtplib.SMTP(self.config['smtp_host'], self.config['smtp_port'], timeout=60)
except Exception as ex: except Exception as ex:
err_msg = _("There was an error sending the notification email: %s") % ex err_msg = _('There was an error sending the notification email: %s') % ex
log.error(err_msg) log.error(err_msg)
return ex return ex
@ -126,7 +126,7 @@ Date: %(date)s
if security_enabled: if security_enabled:
server.ehlo() server.ehlo()
if 'starttls' not in server.esmtp_features: if 'starttls' not in server.esmtp_features:
log.warning("TLS/SSL enabled but server does not support it") log.warning('TLS/SSL enabled but server does not support it')
else: else:
server.starttls() server.starttls()
server.ehlo() server.ehlo()
@ -136,12 +136,12 @@ Date: %(date)s
server.login(self.config['smtp_user'], self.config['smtp_pass']) server.login(self.config['smtp_user'], self.config['smtp_pass'])
except smtplib.SMTPHeloError as ex: except smtplib.SMTPHeloError as ex:
err_msg = _("The server didn't reply properly to the helo " err_msg = _("The server didn't reply properly to the helo "
"greeting: %s") % ex 'greeting: %s') % ex
log.error(err_msg) log.error(err_msg)
return ex return ex
except smtplib.SMTPAuthenticationError as ex: except smtplib.SMTPAuthenticationError as ex:
err_msg = _("The server didn't accept the username/password " err_msg = _("The server didn't accept the username/password "
"combination: %s") % ex 'combination: %s') % ex
log.error(err_msg) log.error(err_msg)
return ex return ex
@ -149,8 +149,8 @@ Date: %(date)s
try: try:
server.sendmail(self.config['smtp_from'], to_addrs, message) server.sendmail(self.config['smtp_from'], to_addrs, message)
except smtplib.SMTPException as ex: except smtplib.SMTPException as ex:
err_msg = _("There was an error sending the notification email:" err_msg = _('There was an error sending the notification email:'
" %s") % ex ' %s') % ex
log.error(err_msg) log.error(err_msg)
return ex return ex
finally: finally:
@ -164,20 +164,20 @@ Date: %(date)s
pass pass
else: else:
server.quit() server.quit()
return _("Notification email sent.") return _('Notification email sent.')
def _on_torrent_finished_event(self, torrent_id): def _on_torrent_finished_event(self, torrent_id):
log.debug("Handler for TorrentFinishedEvent called for CORE") log.debug('Handler for TorrentFinishedEvent called for CORE')
torrent = component.get("TorrentManager")[torrent_id] torrent = component.get('TorrentManager')[torrent_id]
torrent_status = torrent.get_status({}) torrent_status = torrent.get_status({})
# Email # Email
subject = _("Finished Torrent \"%(name)s\"") % torrent_status subject = _("Finished Torrent \"%(name)s\"") % torrent_status
message = _( message = _(
"This email is to inform you that Deluge has finished " 'This email is to inform you that Deluge has finished '
"downloading \"%(name)s\", which includes %(num_files)i files." "downloading \"%(name)s\", which includes %(num_files)i files."
"\nTo stop receiving these alerts, simply turn off email " '\nTo stop receiving these alerts, simply turn off email '
"notification in Deluge's preferences.\n\n" "notification in Deluge's preferences.\n\n"
"Thank you,\nDeluge." 'Thank you,\nDeluge.'
) % torrent_status ) % torrent_status
return subject, message return subject, message
@ -197,23 +197,23 @@ class Core(CorePluginBase, CoreNotifications):
def enable(self): def enable(self):
CoreNotifications.enable(self) CoreNotifications.enable(self)
self.config = deluge.configmanager.ConfigManager( self.config = deluge.configmanager.ConfigManager(
"notifications-core.conf", DEFAULT_PREFS) 'notifications-core.conf', DEFAULT_PREFS)
log.debug("ENABLING CORE NOTIFICATIONS") log.debug('ENABLING CORE NOTIFICATIONS')
def disable(self): def disable(self):
log.debug("DISABLING CORE NOTIFICATIONS") log.debug('DISABLING CORE NOTIFICATIONS')
CoreNotifications.disable(self) CoreNotifications.disable(self)
@export @export
def set_config(self, config): def set_config(self, config):
"sets the config dictionary" 'sets the config dictionary'
for key in config.keys(): for key in config.keys():
self.config[key] = config[key] self.config[key] = config[key]
self.config.save() self.config.save()
@export @export
def get_config(self): def get_config(self):
"returns the config dictionary" 'returns the config dictionary'
return self.config.config return self.config.config
@export @export

View File

@ -48,20 +48,20 @@ except ImportError:
DEFAULT_PREFS = { DEFAULT_PREFS = {
# BLINK # BLINK
"blink_enabled": False, 'blink_enabled': False,
# FLASH # FLASH
"flash_enabled": False, 'flash_enabled': False,
# POPUP # POPUP
"popup_enabled": False, 'popup_enabled': False,
# SOUND # SOUND
"sound_enabled": False, 'sound_enabled': False,
"sound_path": "", 'sound_path': '',
"custom_sounds": {}, 'custom_sounds': {},
# Subscriptions # Subscriptions
"subscriptions": { 'subscriptions': {
"popup": [], 'popup': [],
"blink": [], 'blink': [],
"sound": [], 'sound': [],
}, },
} }
@ -79,19 +79,19 @@ class GtkUiNotifications(CustomNotifications):
def enable(self): def enable(self):
CustomNotifications.enable(self) CustomNotifications.enable(self)
self.register_custom_blink_notification( self.register_custom_blink_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_blink 'TorrentFinishedEvent', self._on_torrent_finished_event_blink
) )
self.register_custom_sound_notification( self.register_custom_sound_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_sound 'TorrentFinishedEvent', self._on_torrent_finished_event_sound
) )
self.register_custom_popup_notification( self.register_custom_popup_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_popup 'TorrentFinishedEvent', self._on_torrent_finished_event_popup
) )
def disable(self): def disable(self):
self.deregister_custom_blink_notification("TorrentFinishedEvent") self.deregister_custom_blink_notification('TorrentFinishedEvent')
self.deregister_custom_sound_notification("TorrentFinishedEvent") self.deregister_custom_sound_notification('TorrentFinishedEvent')
self.deregister_custom_popup_notification("TorrentFinishedEvent") self.deregister_custom_popup_notification('TorrentFinishedEvent')
CustomNotifications.disable(self) CustomNotifications.disable(self)
def register_custom_popup_notification(self, eventtype, handler): def register_custom_popup_notification(self, eventtype, handler):
@ -146,7 +146,7 @@ class GtkUiNotifications(CustomNotifications):
if result: if result:
return defer.maybeDeferred(self.__blink) return defer.maybeDeferred(self.__blink)
return defer.succeed("Won't blink. The returned value from the custom " return defer.succeed("Won't blink. The returned value from the custom "
"handler was: %s" % result) 'handler was: %s' % result)
def handle_custom_sound_notification(self, result, eventtype): def handle_custom_sound_notification(self, result, eventtype):
if isinstance(result, basestring): if isinstance(result, basestring):
@ -155,33 +155,33 @@ class GtkUiNotifications(CustomNotifications):
self.__play_sound, self.config['custom_sounds'][eventtype]) self.__play_sound, self.config['custom_sounds'][eventtype])
return defer.maybeDeferred(self.__play_sound, result) return defer.maybeDeferred(self.__play_sound, result)
return defer.succeed("Won't play sound. The returned value from the " return defer.succeed("Won't play sound. The returned value from the "
"custom handler was: %s" % result) 'custom handler was: %s' % result)
def __blink(self): def __blink(self):
self.systray.blink(True) self.systray.blink(True)
return defer.succeed(_("Notification Blink shown")) return defer.succeed(_('Notification Blink shown'))
def __popup(self, title='', message=''): def __popup(self, title='', message=''):
if not self.config['popup_enabled']: if not self.config['popup_enabled']:
return defer.succeed(_("Popup notification is not enabled.")) return defer.succeed(_('Popup notification is not enabled.'))
if not POPUP_AVAILABLE: if not POPUP_AVAILABLE:
return defer.fail(_("pynotify is not installed")) return defer.fail(_('pynotify is not installed'))
if pynotify.init("Deluge"): if pynotify.init('Deluge'):
icon = gtk.gdk.pixbuf_new_from_file_at_size(deluge.common.get_pixmap("deluge.svg"), 48, 48) icon = gtk.gdk.pixbuf_new_from_file_at_size(deluge.common.get_pixmap('deluge.svg'), 48, 48)
self.note = pynotify.Notification(title, message) self.note = pynotify.Notification(title, message)
self.note.set_icon_from_pixbuf(icon) self.note.set_icon_from_pixbuf(icon)
if not self.note.show(): if not self.note.show():
err_msg = _("pynotify failed to show notification") err_msg = _('pynotify failed to show notification')
log.warning(err_msg) log.warning(err_msg)
return defer.fail(err_msg) return defer.fail(err_msg)
return defer.succeed(_("Notification popup shown")) return defer.succeed(_('Notification popup shown'))
def __play_sound(self, sound_path=''): def __play_sound(self, sound_path=''):
if not self.config['sound_enabled']: if not self.config['sound_enabled']:
return defer.succeed(_("Sound notification not enabled")) return defer.succeed(_('Sound notification not enabled'))
if not SOUND_AVAILABLE: if not SOUND_AVAILABLE:
err_msg = _("pygame is not installed") err_msg = _('pygame is not installed')
log.warning(err_msg) log.warning(err_msg)
return defer.fail(err_msg) return defer.fail(err_msg)
@ -193,11 +193,11 @@ class GtkUiNotifications(CustomNotifications):
alert_sound.load(sound_path) alert_sound.load(sound_path)
alert_sound.play() alert_sound.play()
except pygame.error as ex: except pygame.error as ex:
err_msg = _("Sound notification failed %s") % ex err_msg = _('Sound notification failed %s') % ex
log.warning(err_msg) log.warning(err_msg)
return defer.fail(err_msg) return defer.fail(err_msg)
else: else:
msg = _("Sound notification Success") msg = _('Sound notification Success')
log.info(msg) log.info(msg)
return defer.succeed(msg) return defer.succeed(msg)
@ -209,21 +209,21 @@ class GtkUiNotifications(CustomNotifications):
return '' return ''
def _on_torrent_finished_event_popup(self, torrent_id): def _on_torrent_finished_event_popup(self, torrent_id):
d = client.core.get_torrent_status(torrent_id, ["name", "file_progress"]) d = client.core.get_torrent_status(torrent_id, ['name', 'file_progress'])
d.addCallback(self._on_torrent_finished_event_got_torrent_status) d.addCallback(self._on_torrent_finished_event_got_torrent_status)
d.addErrback(self._on_torrent_finished_event_torrent_status_failure) d.addErrback(self._on_torrent_finished_event_torrent_status_failure)
return d return d
def _on_torrent_finished_event_torrent_status_failure(self, failure): def _on_torrent_finished_event_torrent_status_failure(self, failure):
log.debug("Failed to get torrent status to be able to show the popup") log.debug('Failed to get torrent status to be able to show the popup')
def _on_torrent_finished_event_got_torrent_status(self, torrent_status): def _on_torrent_finished_event_got_torrent_status(self, torrent_status):
log.debug("Handler for TorrentFinishedEvent GTKUI called. " log.debug('Handler for TorrentFinishedEvent GTKUI called. '
"Got Torrent Status") 'Got Torrent Status')
title = _("Finished Torrent") title = _('Finished Torrent')
torrent_status["num_files"] = torrent_status["file_progress"].count(1.0) torrent_status['num_files'] = torrent_status['file_progress'].count(1.0)
message = _("The torrent \"%(name)s\" including %(num_files)i file(s) " message = _("The torrent \"%(name)s\" including %(num_files)i file(s) "
"has finished downloading.") % torrent_status 'has finished downloading.') % torrent_status
return title, message return title, message
@ -234,11 +234,11 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
def enable(self): def enable(self):
self.config = deluge.configmanager.ConfigManager( self.config = deluge.configmanager.ConfigManager(
"notifications-gtk.conf", DEFAULT_PREFS 'notifications-gtk.conf', DEFAULT_PREFS
) )
self.glade = gtk.glade.XML(get_resource("config.glade")) self.glade = gtk.glade.XML(get_resource('config.glade'))
self.glade.get_widget("smtp_port").set_value(25) self.glade.get_widget('smtp_port').set_value(25)
self.prefs = self.glade.get_widget("prefs_box") self.prefs = self.glade.get_widget('prefs_box')
self.prefs.show_all() self.prefs.show_all()
self.build_recipients_model_populate_treeview() self.build_recipients_model_populate_treeview()
@ -261,25 +261,25 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
'on_sound_path_update_preview': self.on_sound_path_update_preview 'on_sound_path_update_preview': self.on_sound_path_update_preview
}) })
prefs = component.get("Preferences") prefs = component.get('Preferences')
parent = self.prefs.get_parent() parent = self.prefs.get_parent()
if parent: if parent:
parent.remove(self.prefs) parent.remove(self.prefs)
index = prefs.notebook.append_page(self.prefs) index = prefs.notebook.append_page(self.prefs)
prefs.liststore.append([index, _("Notifications")]) prefs.liststore.append([index, _('Notifications')])
component.get("PluginManager").register_hook("on_apply_prefs", component.get('PluginManager').register_hook('on_apply_prefs',
self.on_apply_prefs) self.on_apply_prefs)
component.get("PluginManager").register_hook("on_show_prefs", component.get('PluginManager').register_hook('on_show_prefs',
self.on_show_prefs) self.on_show_prefs)
if not POPUP_AVAILABLE: if not POPUP_AVAILABLE:
self.glade.get_widget("popup_enabled").set_property('sensitive', self.glade.get_widget('popup_enabled').set_property('sensitive',
False) False)
if not SOUND_AVAILABLE: if not SOUND_AVAILABLE:
# for widget_name in ('sound_enabled', 'sound_path', 'sounds_page', 'sounds_page_label'): # for widget_name in ('sound_enabled', 'sound_path', 'sounds_page', 'sounds_page_label'):
# self.glade.get_widget(widget_name).set_property('sensitive', False) # self.glade.get_widget(widget_name).set_property('sensitive', False)
self.glade.get_widget("sound_enabled").set_property('sensitive', self.glade.get_widget('sound_enabled').set_property('sensitive',
False) False)
self.glade.get_widget('sound_path').set_property('sensitive', False) self.glade.get_widget('sound_path').set_property('sensitive', False)
self.glade.get_widget('sounds_page').set_property('sensitive', self.glade.get_widget('sounds_page').set_property('sensitive',
@ -287,7 +287,7 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
self.glade.get_widget('sounds_page_label').set_property('sensitive', self.glade.get_widget('sounds_page_label').set_property('sensitive',
False) False)
self.systray = component.get("SystemTray") self.systray = component.get('SystemTray')
if not hasattr(self.systray, 'tray'): if not hasattr(self.systray, 'tray'):
# Tray is not beeing used # Tray is not beeing used
self.glade.get_widget('blink_enabled').set_property('sensitive', self.glade.get_widget('blink_enabled').set_property('sensitive',
@ -297,25 +297,25 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
def disable(self): def disable(self):
GtkUiNotifications.disable(self) GtkUiNotifications.disable(self)
component.get("Preferences").remove_page(_("Notifications")) component.get('Preferences').remove_page(_('Notifications'))
component.get("PluginManager").deregister_hook("on_apply_prefs", component.get('PluginManager').deregister_hook('on_apply_prefs',
self.on_apply_prefs) self.on_apply_prefs)
component.get("PluginManager").deregister_hook("on_show_prefs", component.get('PluginManager').deregister_hook('on_show_prefs',
self.on_show_prefs) self.on_show_prefs)
def build_recipients_model_populate_treeview(self): def build_recipients_model_populate_treeview(self):
# SMTP Recipients treeview/model # SMTP Recipients treeview/model
self.recipients_treeview = self.glade.get_widget("smtp_recipients") self.recipients_treeview = self.glade.get_widget('smtp_recipients')
treeview_selection = self.recipients_treeview.get_selection() treeview_selection = self.recipients_treeview.get_selection()
treeview_selection.connect( treeview_selection.connect(
"changed", self.on_recipients_treeview_selection_changed 'changed', self.on_recipients_treeview_selection_changed
) )
self.recipients_model = gtk.ListStore(str, bool) self.recipients_model = gtk.ListStore(str, bool)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
renderer.connect("edited", self.on_cell_edited, self.recipients_model) renderer.connect('edited', self.on_cell_edited, self.recipients_model)
renderer.set_data("recipient", RECIPIENT_FIELD) renderer.set_data('recipient', RECIPIENT_FIELD)
column = gtk.TreeViewColumn("Recipients", renderer, column = gtk.TreeViewColumn('Recipients', renderer,
text=RECIPIENT_FIELD, text=RECIPIENT_FIELD,
editable=RECIPIENT_EDIT) editable=RECIPIENT_EDIT)
column.set_expand(True) column.set_expand(True)
@ -327,32 +327,32 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
self.sounds_treeview = self.glade.get_widget('sounds_treeview') self.sounds_treeview = self.glade.get_widget('sounds_treeview')
sounds_selection = self.sounds_treeview.get_selection() sounds_selection = self.sounds_treeview.get_selection()
sounds_selection.connect( sounds_selection.connect(
"changed", self.on_sounds_treeview_selection_changed 'changed', self.on_sounds_treeview_selection_changed
) )
self.sounds_treeview.set_tooltip_column(SND_EVENT_DOC) self.sounds_treeview.set_tooltip_column(SND_EVENT_DOC)
self.sounds_model = gtk.ListStore(str, str, str, str) self.sounds_model = gtk.ListStore(str, str, str, str)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
renderer.set_data("event", SND_EVENT) renderer.set_data('event', SND_EVENT)
column = gtk.TreeViewColumn("Event", renderer, text=SND_EVENT) column = gtk.TreeViewColumn('Event', renderer, text=SND_EVENT)
column.set_expand(True) column.set_expand(True)
self.sounds_treeview.append_column(column) self.sounds_treeview.append_column(column)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
renderer.set_data("event_doc", SND_EVENT_DOC) renderer.set_data('event_doc', SND_EVENT_DOC)
column = gtk.TreeViewColumn("Doc", renderer, text=SND_EVENT_DOC) column = gtk.TreeViewColumn('Doc', renderer, text=SND_EVENT_DOC)
column.set_property('visible', False) column.set_property('visible', False)
self.sounds_treeview.append_column(column) self.sounds_treeview.append_column(column)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
renderer.set_data("sound_name", SND_NAME) renderer.set_data('sound_name', SND_NAME)
column = gtk.TreeViewColumn("Name", renderer, text=SND_NAME) column = gtk.TreeViewColumn('Name', renderer, text=SND_NAME)
self.sounds_treeview.append_column(column) self.sounds_treeview.append_column(column)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
renderer.set_data("sound_path", SND_PATH) renderer.set_data('sound_path', SND_PATH)
column = gtk.TreeViewColumn("Path", renderer, text=SND_PATH) column = gtk.TreeViewColumn('Path', renderer, text=SND_PATH)
column.set_property('visible', False) column.set_property('visible', False)
self.sounds_treeview.append_column(column) self.sounds_treeview.append_column(column)
@ -360,51 +360,51 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
def build_notifications_model_populate_treeview(self): def build_notifications_model_populate_treeview(self):
# Notification Subscriptions treeview/model # Notification Subscriptions treeview/model
self.subscriptions_treeview = self.glade.get_widget("subscriptions_treeview") self.subscriptions_treeview = self.glade.get_widget('subscriptions_treeview')
subscriptions_selection = self.subscriptions_treeview.get_selection() subscriptions_selection = self.subscriptions_treeview.get_selection()
subscriptions_selection.connect( subscriptions_selection.connect(
"changed", self.on_subscriptions_treeview_selection_changed 'changed', self.on_subscriptions_treeview_selection_changed
) )
self.subscriptions_treeview.set_tooltip_column(SUB_EVENT_DOC) self.subscriptions_treeview.set_tooltip_column(SUB_EVENT_DOC)
self.subscriptions_model = gtk.ListStore(str, str, bool, bool, bool, bool) self.subscriptions_model = gtk.ListStore(str, str, bool, bool, bool, bool)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
renderer.set_data("event", SUB_EVENT) renderer.set_data('event', SUB_EVENT)
column = gtk.TreeViewColumn("Event", renderer, text=SUB_EVENT) column = gtk.TreeViewColumn('Event', renderer, text=SUB_EVENT)
column.set_expand(True) column.set_expand(True)
self.subscriptions_treeview.append_column(column) self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
renderer.set_data("event_doc", SUB_EVENT) renderer.set_data('event_doc', SUB_EVENT)
column = gtk.TreeViewColumn("Doc", renderer, text=SUB_EVENT_DOC) column = gtk.TreeViewColumn('Doc', renderer, text=SUB_EVENT_DOC)
column.set_property('visible', False) column.set_property('visible', False)
self.subscriptions_treeview.append_column(column) self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererToggle() renderer = gtk.CellRendererToggle()
renderer.set_property('activatable', True) renderer.set_property('activatable', True)
renderer.connect('toggled', self._on_email_col_toggled) renderer.connect('toggled', self._on_email_col_toggled)
column = gtk.TreeViewColumn("Email", renderer, active=SUB_NOT_EMAIL) column = gtk.TreeViewColumn('Email', renderer, active=SUB_NOT_EMAIL)
column.set_clickable(True) column.set_clickable(True)
self.subscriptions_treeview.append_column(column) self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererToggle() renderer = gtk.CellRendererToggle()
renderer.set_property("activatable", True) renderer.set_property('activatable', True)
renderer.connect("toggled", self._on_popup_col_toggled) renderer.connect('toggled', self._on_popup_col_toggled)
column = gtk.TreeViewColumn("Popup", renderer, active=SUB_NOT_POPUP) column = gtk.TreeViewColumn('Popup', renderer, active=SUB_NOT_POPUP)
column.set_clickable(True) column.set_clickable(True)
self.subscriptions_treeview.append_column(column) self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererToggle() renderer = gtk.CellRendererToggle()
renderer.set_property("activatable", True) renderer.set_property('activatable', True)
renderer.connect("toggled", self._on_blink_col_toggled) renderer.connect('toggled', self._on_blink_col_toggled)
column = gtk.TreeViewColumn("Blink", renderer, active=SUB_NOT_BLINK) column = gtk.TreeViewColumn('Blink', renderer, active=SUB_NOT_BLINK)
column.set_clickable(True) column.set_clickable(True)
self.subscriptions_treeview.append_column(column) self.subscriptions_treeview.append_column(column)
renderer = gtk.CellRendererToggle() renderer = gtk.CellRendererToggle()
renderer.set_property('activatable', True) renderer.set_property('activatable', True)
renderer.connect('toggled', self._on_sound_col_toggled) renderer.connect('toggled', self._on_sound_col_toggled)
column = gtk.TreeViewColumn("Sound", renderer, active=SUB_NOT_SOUND) column = gtk.TreeViewColumn('Sound', renderer, active=SUB_NOT_SOUND)
column.set_clickable(True) column.set_clickable(True)
self.subscriptions_treeview.append_column(column) self.subscriptions_treeview.append_column(column)
self.subscriptions_treeview.set_model(self.subscriptions_model) self.subscriptions_treeview.set_model(self.subscriptions_model)
@ -444,13 +444,13 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
SUB_EVENT, event_name, SUB_EVENT, event_name,
SUB_EVENT_DOC, event_doc, SUB_EVENT_DOC, event_doc,
SUB_NOT_EMAIL, event_name in email_subscriptions, SUB_NOT_EMAIL, event_name in email_subscriptions,
SUB_NOT_POPUP, event_name in subscriptions_dict["popup"], SUB_NOT_POPUP, event_name in subscriptions_dict['popup'],
SUB_NOT_BLINK, event_name in subscriptions_dict['blink'], SUB_NOT_BLINK, event_name in subscriptions_dict['blink'],
SUB_NOT_SOUND, event_name in subscriptions_dict['sound'] SUB_NOT_SOUND, event_name in subscriptions_dict['sound']
) )
def on_apply_prefs(self): def on_apply_prefs(self):
log.debug("applying prefs for Notifications") log.debug('applying prefs for Notifications')
current_popup_subscriptions = [] current_popup_subscriptions = []
current_blink_subscriptions = [] current_blink_subscriptions = []
@ -467,8 +467,8 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
current_sound_subscriptions.append(event) current_sound_subscriptions.append(event)
old_sound_file = self.config['sound_path'] old_sound_file = self.config['sound_path']
new_sound_file = self.glade.get_widget("sound_path").get_filename() new_sound_file = self.glade.get_widget('sound_path').get_filename()
log.debug("Old Default sound file: %s New one: %s", log.debug('Old Default sound file: %s New one: %s',
old_sound_file, new_sound_file) old_sound_file, new_sound_file)
custom_sounds = {} custom_sounds = {}
for event_name, event_doc, filename, filepath in self.sounds_model: for event_name, event_doc, filename, filepath in self.sounds_model:
@ -478,30 +478,30 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
custom_sounds[event_name] = filepath custom_sounds[event_name] = filepath
self.config.config.update({ self.config.config.update({
"popup_enabled": self.glade.get_widget("popup_enabled").get_active(), 'popup_enabled': self.glade.get_widget('popup_enabled').get_active(),
"blink_enabled": self.glade.get_widget("blink_enabled").get_active(), 'blink_enabled': self.glade.get_widget('blink_enabled').get_active(),
"sound_enabled": self.glade.get_widget("sound_enabled").get_active(), 'sound_enabled': self.glade.get_widget('sound_enabled').get_active(),
"sound_path": new_sound_file, 'sound_path': new_sound_file,
"subscriptions": { 'subscriptions': {
"popup": current_popup_subscriptions, 'popup': current_popup_subscriptions,
"blink": current_blink_subscriptions, 'blink': current_blink_subscriptions,
"sound": current_sound_subscriptions 'sound': current_sound_subscriptions
}, },
"custom_sounds": custom_sounds 'custom_sounds': custom_sounds
}) })
self.config.save() self.config.save()
core_config = { core_config = {
"smtp_enabled": self.glade.get_widget("smtp_enabled").get_active(), 'smtp_enabled': self.glade.get_widget('smtp_enabled').get_active(),
"smtp_host": self.glade.get_widget("smtp_host").get_text(), 'smtp_host': self.glade.get_widget('smtp_host').get_text(),
"smtp_port": self.glade.get_widget("smtp_port").get_value(), 'smtp_port': self.glade.get_widget('smtp_port').get_value(),
"smtp_user": self.glade.get_widget("smtp_user").get_text(), 'smtp_user': self.glade.get_widget('smtp_user').get_text(),
"smtp_pass": self.glade.get_widget("smtp_pass").get_text(), 'smtp_pass': self.glade.get_widget('smtp_pass').get_text(),
"smtp_from": self.glade.get_widget("smtp_from").get_text(), 'smtp_from': self.glade.get_widget('smtp_from').get_text(),
"smtp_tls": self.glade.get_widget("smtp_tls").get_active(), 'smtp_tls': self.glade.get_widget('smtp_tls').get_active(),
"smtp_recipients": [dest[0] for dest in self.recipients_model if 'smtp_recipients': [dest[0] for dest in self.recipients_model if
dest[0] != "USER@HOST"], dest[0] != 'USER@HOST'],
"subscriptions": {"email": current_email_subscriptions} 'subscriptions': {'email': current_email_subscriptions}
} }
client.notifications.set_config(core_config) client.notifications.set_config(core_config)
@ -511,37 +511,37 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
client.notifications.get_config().addCallback(self.cb_get_config) client.notifications.get_config().addCallback(self.cb_get_config)
def cb_get_config(self, core_config): def cb_get_config(self, core_config):
"callback for on show_prefs" 'callback for on show_prefs'
self.glade.get_widget("smtp_host").set_text(core_config["smtp_host"]) self.glade.get_widget('smtp_host').set_text(core_config['smtp_host'])
self.glade.get_widget("smtp_port").set_value(core_config["smtp_port"]) self.glade.get_widget('smtp_port').set_value(core_config['smtp_port'])
self.glade.get_widget("smtp_user").set_text(core_config["smtp_user"]) self.glade.get_widget('smtp_user').set_text(core_config['smtp_user'])
self.glade.get_widget("smtp_pass").set_text(core_config["smtp_pass"]) self.glade.get_widget('smtp_pass').set_text(core_config['smtp_pass'])
self.glade.get_widget("smtp_from").set_text(core_config["smtp_from"]) self.glade.get_widget('smtp_from').set_text(core_config['smtp_from'])
self.glade.get_widget("smtp_tls").set_active(core_config["smtp_tls"]) self.glade.get_widget('smtp_tls').set_active(core_config['smtp_tls'])
self.recipients_model.clear() self.recipients_model.clear()
for recipient in core_config['smtp_recipients']: for recipient in core_config['smtp_recipients']:
self.recipients_model.set(self.recipients_model.append(), self.recipients_model.set(self.recipients_model.append(),
RECIPIENT_FIELD, recipient, RECIPIENT_FIELD, recipient,
RECIPIENT_EDIT, False) RECIPIENT_EDIT, False)
self.glade.get_widget("smtp_enabled").set_active( self.glade.get_widget('smtp_enabled').set_active(
core_config['smtp_enabled'] core_config['smtp_enabled']
) )
self.glade.get_widget("sound_enabled").set_active( self.glade.get_widget('sound_enabled').set_active(
self.config['sound_enabled'] self.config['sound_enabled']
) )
self.glade.get_widget("popup_enabled").set_active( self.glade.get_widget('popup_enabled').set_active(
self.config['popup_enabled'] self.config['popup_enabled']
) )
self.glade.get_widget("blink_enabled").set_active( self.glade.get_widget('blink_enabled').set_active(
self.config['blink_enabled'] self.config['blink_enabled']
) )
if self.config['sound_path']: if self.config['sound_path']:
sound_path = self.config['sound_path'] sound_path = self.config['sound_path']
else: else:
sound_path = deluge.common.get_default_download_dir() sound_path = deluge.common.get_default_download_dir()
self.glade.get_widget("sound_path").set_filename(sound_path) self.glade.get_widget('sound_path').set_filename(sound_path)
# Force toggle # Force toggle
self.on_enabled_toggled(self.glade.get_widget("smtp_enabled")) self.on_enabled_toggled(self.glade.get_widget('smtp_enabled'))
self.on_sound_enabled_toggled(self.glade.get_widget('sound_enabled')) self.on_sound_enabled_toggled(self.glade.get_widget('sound_enabled'))
client.notifications.get_handled_events().addCallback( client.notifications.get_handled_events().addCallback(
@ -557,7 +557,7 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
def on_add_button_clicked(self, widget, treeview): def on_add_button_clicked(self, widget, treeview):
model = treeview.get_model() model = treeview.get_model()
model.set(model.append(), model.set(model.append(),
RECIPIENT_FIELD, "USER@HOST", RECIPIENT_FIELD, 'USER@HOST',
RECIPIENT_EDIT, True) RECIPIENT_EDIT, True)
def on_delete_button_clicked(self, widget, treeview): def on_delete_button_clicked(self, widget, treeview):
@ -573,53 +573,53 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
def on_recipients_treeview_selection_changed(self, selection): def on_recipients_treeview_selection_changed(self, selection):
model, selected_connection_iter = selection.get_selected() model, selected_connection_iter = selection.get_selected()
if selected_connection_iter: if selected_connection_iter:
self.glade.get_widget("delete_button").set_property('sensitive', self.glade.get_widget('delete_button').set_property('sensitive',
True) True)
else: else:
self.glade.get_widget("delete_button").set_property('sensitive', self.glade.get_widget('delete_button').set_property('sensitive',
False) False)
def on_subscriptions_treeview_selection_changed(self, selection): def on_subscriptions_treeview_selection_changed(self, selection):
model, selected_connection_iter = selection.get_selected() model, selected_connection_iter = selection.get_selected()
if selected_connection_iter: if selected_connection_iter:
self.glade.get_widget("delete_button").set_property('sensitive', self.glade.get_widget('delete_button').set_property('sensitive',
True) True)
else: else:
self.glade.get_widget("delete_button").set_property('sensitive', self.glade.get_widget('delete_button').set_property('sensitive',
False) False)
def on_sounds_treeview_selection_changed(self, selection): def on_sounds_treeview_selection_changed(self, selection):
model, selected_iter = selection.get_selected() model, selected_iter = selection.get_selected()
if selected_iter: if selected_iter:
self.glade.get_widget("sounds_edit_button").set_property("sensitive", True) self.glade.get_widget('sounds_edit_button').set_property('sensitive', True)
path = model.get(selected_iter, SND_PATH)[0] path = model.get(selected_iter, SND_PATH)[0]
log.debug("Sound selection changed: %s", path) log.debug('Sound selection changed: %s', path)
if path != self.config['sound_path']: if path != self.config['sound_path']:
self.glade.get_widget("sounds_revert_button").set_property("sensitive", True) self.glade.get_widget('sounds_revert_button').set_property('sensitive', True)
else: else:
self.glade.get_widget("sounds_revert_button").set_property("sensitive", False) self.glade.get_widget('sounds_revert_button').set_property('sensitive', False)
else: else:
self.glade.get_widget("sounds_edit_button").set_property("sensitive", False) self.glade.get_widget('sounds_edit_button').set_property('sensitive', False)
self.glade.get_widget("sounds_revert_button").set_property("sensitive", False) self.glade.get_widget('sounds_revert_button').set_property('sensitive', False)
def on_sounds_revert_button_clicked(self, widget): def on_sounds_revert_button_clicked(self, widget):
log.debug("on_sounds_revert_button_clicked") log.debug('on_sounds_revert_button_clicked')
selection = self.sounds_treeview.get_selection() selection = self.sounds_treeview.get_selection()
model, selected_iter = selection.get_selected() model, selected_iter = selection.get_selected()
if selected_iter: if selected_iter:
log.debug("on_sounds_revert_button_clicked: got iter") log.debug('on_sounds_revert_button_clicked: got iter')
model.set(selected_iter, model.set(selected_iter,
SND_PATH, self.config['sound_path'], SND_PATH, self.config['sound_path'],
SND_NAME, basename(self.config['sound_path'])) SND_NAME, basename(self.config['sound_path']))
def on_sounds_edit_button_clicked(self, widget): def on_sounds_edit_button_clicked(self, widget):
log.debug("on_sounds_edit_button_clicked") log.debug('on_sounds_edit_button_clicked')
selection = self.sounds_treeview.get_selection() selection = self.sounds_treeview.get_selection()
model, selected_iter = selection.get_selected() model, selected_iter = selection.get_selected()
if selected_iter: if selected_iter:
path = model.get(selected_iter, SND_PATH)[0] path = model.get(selected_iter, SND_PATH)[0]
dialog = gtk.FileChooserDialog( dialog = gtk.FileChooserDialog(
title=_("Choose Sound File"), title=_('Choose Sound File'),
buttons=(gtk.STOCK_CANCEL, buttons=(gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OPEN, gtk.STOCK_OPEN,
@ -638,7 +638,7 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
d = defer.maybeDeferred(dialog.run) d = defer.maybeDeferred(dialog.run)
d.addCallback(update_model) d.addCallback(update_model)
log.debug("dialog should have been shown") log.debug('dialog should have been shown')
def on_enabled_toggled(self, widget): def on_enabled_toggled(self, widget):
for widget_name in ('smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass', for widget_name in ('smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass',

View File

@ -37,16 +37,16 @@ class TestEmailNotifications(component.Component):
self.events_classes = [] self.events_classes = []
def enable(self): def enable(self):
log.debug("\n\nEnabling %s", self.__class__.__name__) log.debug('\n\nEnabling %s', self.__class__.__name__)
for event in self.events: for event in self.events:
if self.__imp == 'core': if self.__imp == 'core':
# component.get("CorePlugin.Notifications").register_custom_email_notification( # component.get("CorePlugin.Notifications").register_custom_email_notification(
component.get("Notifications").register_custom_email_notification( component.get('Notifications').register_custom_email_notification(
event.__class__.__name__, event.__class__.__name__,
self.custom_email_message_provider self.custom_email_message_provider
) )
elif self.__imp == 'gtk': elif self.__imp == 'gtk':
notifications_component = component.get("Notifications") notifications_component = component.get('Notifications')
notifications_component.register_custom_popup_notification( notifications_component.register_custom_popup_notification(
event.__class__.__name__, event.__class__.__name__,
self.custom_popup_message_provider self.custom_popup_message_provider
@ -63,32 +63,32 @@ class TestEmailNotifications(component.Component):
self.lc.start(60, False) self.lc.start(60, False)
def disable(self): def disable(self):
log.debug("\n\nDisabling %s", self.__class__.__name__) log.debug('\n\nDisabling %s', self.__class__.__name__)
self.lc.stop() self.lc.stop()
def update(self): def update(self):
if self.__imp == 'core': if self.__imp == 'core':
log.debug("\n\nUpdating %s", self.__class__.__name__) log.debug('\n\nUpdating %s', self.__class__.__name__)
self.events.append(self.events.pop(0)) # Re-Queue self.events.append(self.events.pop(0)) # Re-Queue
self.n += 1 self.n += 1
component.get("EventManager").emit(self.events[0]) component.get('EventManager').emit(self.events[0])
def custom_email_message_provider(self, *evt_args, **evt_kwargs): def custom_email_message_provider(self, *evt_args, **evt_kwargs):
log.debug("Running custom email message provider: %s %s", evt_args, evt_kwargs) log.debug('Running custom email message provider: %s %s', evt_args, evt_kwargs)
subject = "%s Email Subject: %s" % (self.events[0].__class__.__name__, self.n) subject = '%s Email Subject: %s' % (self.events[0].__class__.__name__, self.n)
message = "%s Email Message: %s" % (self.events[0].__class__.__name__, self.n) message = '%s Email Message: %s' % (self.events[0].__class__.__name__, self.n)
return subject, message return subject, message
def custom_popup_message_provider(self, *evt_args, **evt_kwargs): def custom_popup_message_provider(self, *evt_args, **evt_kwargs):
log.debug("Running custom popup message provider: %s %s", evt_args, evt_kwargs) log.debug('Running custom popup message provider: %s %s', evt_args, evt_kwargs)
title = "%s Popup Title: %s" % (self.events[0].__class__.__name__, self.n) title = '%s Popup Title: %s' % (self.events[0].__class__.__name__, self.n)
message = "%s Popup Message: %s" % (self.events[0].__class__.__name__, self.n) message = '%s Popup Message: %s' % (self.events[0].__class__.__name__, self.n)
return title, message return title, message
def custom_blink_message_provider(self, *evt_args, **evt_kwargs): def custom_blink_message_provider(self, *evt_args, **evt_kwargs):
log.debug("Running custom blink message provider: %s %s", evt_args, evt_kwargs) log.debug('Running custom blink message provider: %s %s', evt_args, evt_kwargs)
return True return True
def custom_sound_message_provider(self, *evt_args, **evt_kwargs): def custom_sound_message_provider(self, *evt_args, **evt_kwargs):
log.debug("Running custom sound message provider: %s %s", evt_args, evt_kwargs) log.debug('Running custom sound message provider: %s %s', evt_args, evt_kwargs)
return '' return ''

View File

@ -23,11 +23,11 @@ log = logging.getLogger(__name__)
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("notifications.js")] scripts = [get_resource('notifications.js')]
debug_scripts = scripts debug_scripts = scripts
def enable(self): def enable(self):
log.debug("Enabling Web UI notifications") log.debug('Enabling Web UI notifications')
def disable(self): def disable(self):
log.debug("Disabling Web UI notifications") log.debug('Disabling Web UI notifications')

View File

@ -14,13 +14,13 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "Notifications" __plugin_name__ = 'Notifications'
__author__ = "Pedro Algarvio" __author__ = 'Pedro Algarvio'
__author_email__ = "pedro@algarvio.me" __author_email__ = 'pedro@algarvio.me'
__version__ = "0.2" __version__ = '0.2'
__url__ = "http://dev.deluge-torrent.org/" __url__ = 'http://dev.deluge-torrent.org/'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Plugin which provides notifications to Deluge." __description__ = 'Plugin which provides notifications to Deluge.'
__long_description__ = """ __long_description__ = """
Plugin which provides notifications to Deluge Plugin which provides notifications to Deluge
@ -29,7 +29,7 @@ Email, Popup, Blink and Sound notifications
The plugin also allows other plugins to make The plugin also allows other plugins to make
use of itself for their own custom notifications use of itself for their own custom notifications
""" """
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -42,7 +42,7 @@ setup(
long_description=__long_description__ if __long_description__ else __description__, long_description=__long_description__ if __long_description__ else __description__,
packages=find_packages(exclude=['**/test.py']), packages=find_packages(exclude=['**/test.py']),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -15,4 +15,4 @@
def get_resource(filename): def get_resource(filename):
import os import os
import pkg_resources import pkg_resources
return pkg_resources.resource_filename("deluge.plugins.scheduler", os.path.join("data", filename)) return pkg_resources.resource_filename('deluge.plugins.scheduler', os.path.join('data', filename))

View File

@ -25,26 +25,26 @@ from deluge.plugins.pluginbase import CorePluginBase
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DEFAULT_PREFS = { DEFAULT_PREFS = {
"low_down": -1.0, 'low_down': -1.0,
"low_up": -1.0, 'low_up': -1.0,
"low_active": -1, 'low_active': -1,
"low_active_down": -1, 'low_active_down': -1,
"low_active_up": -1, 'low_active_up': -1,
"button_state": [[0] * 7 for dummy in xrange(24)] 'button_state': [[0] * 7 for dummy in xrange(24)]
} }
STATES = { STATES = {
0: "Green", 0: 'Green',
1: "Yellow", 1: 'Yellow',
2: "Red" 2: 'Red'
} }
CONTROLLED_SETTINGS = [ CONTROLLED_SETTINGS = [
"max_download_speed", 'max_download_speed',
"max_upload_speed", 'max_upload_speed',
"max_active_limit", 'max_active_limit',
"max_active_downloading", 'max_active_downloading',
"max_active_seeding" 'max_active_seeding'
] ]
@ -62,14 +62,14 @@ class SchedulerEvent(DelugeEvent):
class Core(CorePluginBase): class Core(CorePluginBase):
def enable(self): def enable(self):
# Create the defaults with the core config # Create the defaults with the core config
core_config = component.get("Core").config core_config = component.get('Core').config
DEFAULT_PREFS["low_down"] = core_config["max_download_speed"] DEFAULT_PREFS['low_down'] = core_config['max_download_speed']
DEFAULT_PREFS["low_up"] = core_config["max_upload_speed"] DEFAULT_PREFS['low_up'] = core_config['max_upload_speed']
DEFAULT_PREFS["low_active"] = core_config["max_active_limit"] DEFAULT_PREFS['low_active'] = core_config['max_active_limit']
DEFAULT_PREFS["low_active_down"] = core_config["max_active_downloading"] DEFAULT_PREFS['low_active_down'] = core_config['max_active_downloading']
DEFAULT_PREFS["low_active_up"] = core_config["max_active_seeding"] DEFAULT_PREFS['low_active_up'] = core_config['max_active_seeding']
self.config = deluge.configmanager.ConfigManager("scheduler.conf", DEFAULT_PREFS) self.config = deluge.configmanager.ConfigManager('scheduler.conf', DEFAULT_PREFS)
self.state = self.get_state() self.state = self.get_state()
@ -82,12 +82,12 @@ class Core(CorePluginBase):
self.timer = reactor.callLater(secs_to_next_hour, self.do_schedule) self.timer = reactor.callLater(secs_to_next_hour, self.do_schedule)
# Register for config changes so state isn't overridden # Register for config changes so state isn't overridden
component.get("EventManager").register_event_handler("ConfigValueChangedEvent", self.on_config_value_changed) component.get('EventManager').register_event_handler('ConfigValueChangedEvent', self.on_config_value_changed)
def disable(self): def disable(self):
if self.timer.active(): if self.timer.active():
self.timer.cancel() self.timer.cancel()
component.get("EventManager").deregister_event_handler("ConfigValueChangedEvent", self.on_config_value_changed) component.get('EventManager').deregister_event_handler('ConfigValueChangedEvent', self.on_config_value_changed)
self.__apply_set_functions() self.__apply_set_functions()
def update(self): def update(self):
@ -101,11 +101,11 @@ class Core(CorePluginBase):
""" """
Have the core apply it's bandwidth settings as specified in core.conf. Have the core apply it's bandwidth settings as specified in core.conf.
""" """
core_config = deluge.configmanager.ConfigManager("core.conf") core_config = deluge.configmanager.ConfigManager('core.conf')
for setting in CONTROLLED_SETTINGS: for setting in CONTROLLED_SETTINGS:
component.get("PreferencesManager").do_config_set_func(setting, core_config[setting]) component.get('PreferencesManager').do_config_set_func(setting, core_config[setting])
# Resume the session if necessary # Resume the session if necessary
component.get("Core").resume_session() component.get('Core').resume_session()
def do_schedule(self, timer=True): def do_schedule(self, timer=True):
""" """
@ -114,30 +114,30 @@ class Core(CorePluginBase):
state = self.get_state() state = self.get_state()
if state == "Green": if state == 'Green':
# This is Green (Normal) so we just make sure we've applied the # This is Green (Normal) so we just make sure we've applied the
# global defaults # global defaults
self.__apply_set_functions() self.__apply_set_functions()
elif state == "Yellow": elif state == 'Yellow':
# This is Yellow (Slow), so use the settings provided from the user # This is Yellow (Slow), so use the settings provided from the user
settings = { settings = {
"active_limit": self.config["low_active"], 'active_limit': self.config['low_active'],
"active_downloads": self.config["low_active_down"], 'active_downloads': self.config['low_active_down'],
"active_seeds": self.config["low_active_up"], 'active_seeds': self.config['low_active_up'],
"download_rate_limit": int(self.config["low_down"] * 1024), 'download_rate_limit': int(self.config['low_down'] * 1024),
"upload_rate_limit": int(self.config["low_up"] * 1024) 'upload_rate_limit': int(self.config['low_up'] * 1024)
} }
component.get("Core").apply_session_settings(settings) component.get('Core').apply_session_settings(settings)
# Resume the session if necessary # Resume the session if necessary
component.get("Core").resume_session() component.get('Core').resume_session()
elif state == "Red": elif state == 'Red':
# This is Red (Stop), so pause the libtorrent session # This is Red (Stop), so pause the libtorrent session
component.get("Core").pause_session() component.get('Core').pause_session()
if state != self.state: if state != self.state:
# The state has changed since last update so we need to emit an event # The state has changed since last update so we need to emit an event
self.state = state self.state = state
component.get("EventManager").emit(SchedulerEvent(self.state)) component.get('EventManager').emit(SchedulerEvent(self.state))
if timer: if timer:
# Call this again in 1 hour # Call this again in 1 hour
@ -145,7 +145,7 @@ class Core(CorePluginBase):
@export() @export()
def set_config(self, config): def set_config(self, config):
"sets the config dictionary" 'sets the config dictionary'
for key in config.keys(): for key in config.keys():
self.config[key] = config[key] self.config[key] = config[key]
self.config.save() self.config.save()
@ -153,11 +153,11 @@ class Core(CorePluginBase):
@export() @export()
def get_config(self): def get_config(self):
"returns the config dictionary" 'returns the config dictionary'
return self.config.config return self.config.config
@export() @export()
def get_state(self): def get_state(self):
now = time.localtime(time.time()) now = time.localtime(time.time())
level = self.config["button_state"][now[3]][now[6]] level = self.config['button_state'][now[3]][now[6]]
return STATES[level] return STATES[level]

View File

@ -25,7 +25,7 @@ from .common import get_resource
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
class SchedulerSelectWidget(gtk.DrawingArea): class SchedulerSelectWidget(gtk.DrawingArea):
@ -34,11 +34,11 @@ class SchedulerSelectWidget(gtk.DrawingArea):
self.set_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | self.set_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK |
gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.LEAVE_NOTIFY_MASK) gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.LEAVE_NOTIFY_MASK)
self.connect("expose_event", self.expose) self.connect('expose_event', self.expose)
self.connect("button_press_event", self.mouse_down) self.connect('button_press_event', self.mouse_down)
self.connect("button_release_event", self.mouse_up) self.connect('button_release_event', self.mouse_up)
self.connect("motion_notify_event", self.mouse_hover) self.connect('motion_notify_event', self.mouse_hover)
self.connect("leave_notify_event", self.mouse_leave) self.connect('leave_notify_event', self.mouse_leave)
self.colors = [[115 / 255, 210 / 255, 22 / 255], self.colors = [[115 / 255, 210 / 255, 22 / 255],
[237 / 255, 212 / 255, 0 / 255], [237 / 255, 212 / 255, 0 / 255],
@ -124,8 +124,8 @@ class SchedulerSelectWidget(gtk.DrawingArea):
self.hover_point = self.get_point(event) self.hover_point = self.get_point(event)
self.hover_label.set_text(self.hover_days[self.hover_point[1]] + self.hover_label.set_text(self.hover_days[self.hover_point[1]] +
" " + str(self.hover_point[0]) + ' ' + str(self.hover_point[0]) +
":00 - " + str(self.hover_point[0]) + ":59") ':00 - ' + str(self.hover_point[0]) + ':59')
if self.mouse_press: if self.mouse_press:
points = [[self.hover_point[0], self.start_point[0]], [self.hover_point[1], self.start_point[1]]] points = [[self.hover_point[0], self.start_point[0]], [self.hover_point[1], self.start_point[1]]]
@ -138,7 +138,7 @@ class SchedulerSelectWidget(gtk.DrawingArea):
# clear hover text on mouse leave # clear hover text on mouse leave
def mouse_leave(self, widget, event): def mouse_leave(self, widget, event):
self.hover_label.set_text("") self.hover_label.set_text('')
self.hover_point = [-1, -1] self.hover_point = [-1, -1]
@ -146,63 +146,63 @@ class GtkUI(GtkPluginBase):
def enable(self): def enable(self):
self.create_prefs_page() self.create_prefs_page()
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').register_hook('on_apply_prefs', self.on_apply_prefs)
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs) component.get('PluginManager').register_hook('on_show_prefs', self.on_show_prefs)
self.statusbar = component.get("StatusBar") self.statusbar = component.get('StatusBar')
self.status_item = self.statusbar.add_item( self.status_item = self.statusbar.add_item(
image=get_resource("green.png"), image=get_resource('green.png'),
text="", text='',
callback=self.on_status_item_clicked, callback=self.on_status_item_clicked,
tooltip="Scheduler") tooltip='Scheduler')
def on_state_deferred(state): def on_state_deferred(state):
self.state = state self.state = state
self.on_scheduler_event(state) self.on_scheduler_event(state)
client.scheduler.get_state().addCallback(on_state_deferred) client.scheduler.get_state().addCallback(on_state_deferred)
client.register_event_handler("SchedulerEvent", self.on_scheduler_event) client.register_event_handler('SchedulerEvent', self.on_scheduler_event)
def disable(self): def disable(self):
component.get("Preferences").remove_page(_("Scheduler")) component.get('Preferences').remove_page(_('Scheduler'))
# Reset statusbar dict. # Reset statusbar dict.
self.statusbar.config_value_changed_dict["max_download_speed"] = self.statusbar._on_max_download_speed self.statusbar.config_value_changed_dict['max_download_speed'] = self.statusbar._on_max_download_speed
self.statusbar.config_value_changed_dict["max_upload_speed"] = self.statusbar._on_max_upload_speed self.statusbar.config_value_changed_dict['max_upload_speed'] = self.statusbar._on_max_upload_speed
# Remove statusbar item. # Remove statusbar item.
self.statusbar.remove_item(self.status_item) self.statusbar.remove_item(self.status_item)
del self.status_item del self.status_item
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').deregister_hook('on_apply_prefs', self.on_apply_prefs)
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs) component.get('PluginManager').deregister_hook('on_show_prefs', self.on_show_prefs)
def on_apply_prefs(self): def on_apply_prefs(self):
log.debug("applying prefs for Scheduler") log.debug('applying prefs for Scheduler')
config = {} config = {}
config["low_down"] = self.spin_download.get_value() config['low_down'] = self.spin_download.get_value()
config["low_up"] = self.spin_upload.get_value() config['low_up'] = self.spin_upload.get_value()
config["low_active"] = self.spin_active.get_value_as_int() config['low_active'] = self.spin_active.get_value_as_int()
config["low_active_down"] = self.spin_active_down.get_value_as_int() config['low_active_down'] = self.spin_active_down.get_value_as_int()
config["low_active_up"] = self.spin_active_up.get_value_as_int() config['low_active_up'] = self.spin_active_up.get_value_as_int()
config["button_state"] = self.scheduler_select.button_state config['button_state'] = self.scheduler_select.button_state
client.scheduler.set_config(config) client.scheduler.set_config(config)
def on_show_prefs(self): def on_show_prefs(self):
def on_get_config(config): def on_get_config(config):
log.debug("config: %s", config) log.debug('config: %s', config)
self.scheduler_select.set_button_state(config["button_state"]) self.scheduler_select.set_button_state(config['button_state'])
self.spin_download.set_value(config["low_down"]) self.spin_download.set_value(config['low_down'])
self.spin_upload.set_value(config["low_up"]) self.spin_upload.set_value(config['low_up'])
self.spin_active.set_value(config["low_active"]) self.spin_active.set_value(config['low_active'])
self.spin_active_down.set_value(config["low_active_down"]) self.spin_active_down.set_value(config['low_active_down'])
self.spin_active_up.set_value(config["low_active_up"]) self.spin_active_up.set_value(config['low_active_up'])
client.scheduler.get_config().addCallback(on_get_config) client.scheduler.get_config().addCallback(on_get_config)
def on_scheduler_event(self, state): def on_scheduler_event(self, state):
self.state = state self.state = state
self.status_item.set_image_from_file(get_resource(self.state.lower() + ".png")) self.status_item.set_image_from_file(get_resource(self.state.lower() + '.png'))
if self.state == "Yellow": if self.state == 'Yellow':
# Prevent func calls in Statusbar if the config changes. # Prevent func calls in Statusbar if the config changes.
self.statusbar.config_value_changed_dict.pop("max_download_speed", None) self.statusbar.config_value_changed_dict.pop('max_download_speed', None)
self.statusbar.config_value_changed_dict.pop("max_upload_speed", None) self.statusbar.config_value_changed_dict.pop('max_upload_speed', None)
try: try:
self.statusbar._on_max_download_speed(self.spin_download.get_value()) self.statusbar._on_max_download_speed(self.spin_download.get_value())
self.statusbar._on_max_upload_speed(self.spin_upload.get_value()) self.statusbar._on_max_upload_speed(self.spin_upload.get_value())
@ -210,20 +210,20 @@ class GtkUI(GtkPluginBase):
# Skip error due to Plugin being enabled before statusbar items created on startup. # Skip error due to Plugin being enabled before statusbar items created on startup.
pass pass
else: else:
self.statusbar.config_value_changed_dict["max_download_speed"] = self.statusbar._on_max_download_speed self.statusbar.config_value_changed_dict['max_download_speed'] = self.statusbar._on_max_download_speed
self.statusbar.config_value_changed_dict["max_upload_speed"] = self.statusbar._on_max_upload_speed self.statusbar.config_value_changed_dict['max_upload_speed'] = self.statusbar._on_max_upload_speed
def update_config_values(config): def update_config_values(config):
try: try:
self.statusbar._on_max_download_speed(config["max_download_speed"]) self.statusbar._on_max_download_speed(config['max_download_speed'])
self.statusbar._on_max_upload_speed(config["max_upload_speed"]) self.statusbar._on_max_upload_speed(config['max_upload_speed'])
except AttributeError: except AttributeError:
# Skip error due to Plugin being enabled before statusbar items created on startup. # Skip error due to Plugin being enabled before statusbar items created on startup.
pass pass
client.core.get_config_values(["max_download_speed", "max_upload_speed"]).addCallback(update_config_values) client.core.get_config_values(['max_download_speed', 'max_upload_speed']).addCallback(update_config_values)
def on_status_item_clicked(self, widget, event): def on_status_item_clicked(self, widget, event):
component.get("Preferences").show("Scheduler") component.get('Preferences').show('Scheduler')
# Configuration dialog # Configuration dialog
def create_prefs_page(self): def create_prefs_page(self):
@ -240,7 +240,7 @@ class GtkUI(GtkPluginBase):
hbox.pack_start(self.scheduler_select, True, True) hbox.pack_start(self.scheduler_select, True, True)
frame = gtk.Frame() frame = gtk.Frame()
label = gtk.Label() label = gtk.Label()
label.set_markup("<b>Schedule</b>") label.set_markup('<b>Schedule</b>')
frame.set_label_widget(label) frame.set_label_widget(label)
frame.set_shadow_type(gtk.SHADOW_NONE) frame.set_shadow_type(gtk.SHADOW_NONE)
frame.add(hbox) frame.add(hbox)
@ -250,7 +250,7 @@ class GtkUI(GtkPluginBase):
table = gtk.Table(3, 4) table = gtk.Table(3, 4)
label = gtk.Label(_("Download Limit:")) label = gtk.Label(_('Download Limit:'))
label.set_alignment(0.0, 0.6) label.set_alignment(0.0, 0.6)
table.attach(label, 0, 1, 0, 1, gtk.FILL) table.attach(label, 0, 1, 0, 1, gtk.FILL)
self.spin_download = gtk.SpinButton() self.spin_download = gtk.SpinButton()
@ -259,7 +259,7 @@ class GtkUI(GtkPluginBase):
self.spin_download.set_increments(1, 10) self.spin_download.set_increments(1, 10)
table.attach(self.spin_download, 1, 2, 0, 1, gtk.FILL) table.attach(self.spin_download, 1, 2, 0, 1, gtk.FILL)
label = gtk.Label(_("Upload Limit:")) label = gtk.Label(_('Upload Limit:'))
label.set_alignment(0.0, 0.6) label.set_alignment(0.0, 0.6)
table.attach(label, 0, 1, 1, 2, gtk.FILL) table.attach(label, 0, 1, 1, 2, gtk.FILL)
self.spin_upload = gtk.SpinButton() self.spin_upload = gtk.SpinButton()
@ -268,7 +268,7 @@ class GtkUI(GtkPluginBase):
self.spin_upload.set_increments(1, 10) self.spin_upload.set_increments(1, 10)
table.attach(self.spin_upload, 1, 2, 1, 2, gtk.FILL) table.attach(self.spin_upload, 1, 2, 1, 2, gtk.FILL)
label = gtk.Label(_("Active Torrents:")) label = gtk.Label(_('Active Torrents:'))
label.set_alignment(0.0, 0.6) label.set_alignment(0.0, 0.6)
table.attach(label, 2, 3, 0, 1, gtk.FILL) table.attach(label, 2, 3, 0, 1, gtk.FILL)
self.spin_active = gtk.SpinButton() self.spin_active = gtk.SpinButton()
@ -277,7 +277,7 @@ class GtkUI(GtkPluginBase):
self.spin_active.set_increments(1, 10) self.spin_active.set_increments(1, 10)
table.attach(self.spin_active, 3, 4, 0, 1, gtk.FILL) table.attach(self.spin_active, 3, 4, 0, 1, gtk.FILL)
label = gtk.Label(_("Active Downloading:")) label = gtk.Label(_('Active Downloading:'))
label.set_alignment(0.0, 0.6) label.set_alignment(0.0, 0.6)
table.attach(label, 2, 3, 1, 2, gtk.FILL) table.attach(label, 2, 3, 1, 2, gtk.FILL)
self.spin_active_down = gtk.SpinButton() self.spin_active_down = gtk.SpinButton()
@ -286,7 +286,7 @@ class GtkUI(GtkPluginBase):
self.spin_active_down.set_increments(1, 10) self.spin_active_down.set_increments(1, 10)
table.attach(self.spin_active_down, 3, 4, 1, 2, gtk.FILL) table.attach(self.spin_active_down, 3, 4, 1, 2, gtk.FILL)
label = gtk.Label(_("Active Seeding:")) label = gtk.Label(_('Active Seeding:'))
label.set_alignment(0.0, 0.6) label.set_alignment(0.0, 0.6)
table.attach(label, 2, 3, 2, 3, gtk.FILL) table.attach(label, 2, 3, 2, 3, gtk.FILL)
self.spin_active_up = gtk.SpinButton() self.spin_active_up = gtk.SpinButton()
@ -296,16 +296,16 @@ class GtkUI(GtkPluginBase):
table.attach(self.spin_active_up, 3, 4, 2, 3, gtk.FILL) table.attach(self.spin_active_up, 3, 4, 2, 3, gtk.FILL)
eventbox = gtk.EventBox() eventbox = gtk.EventBox()
eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#EDD400")) eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#EDD400'))
eventbox.add(table) eventbox.add(table)
frame = gtk.Frame() frame = gtk.Frame()
label = gtk.Label() label = gtk.Label()
label.set_markup(_("<b>Slow Settings</b>")) label.set_markup(_('<b>Slow Settings</b>'))
frame.set_label_widget(label) frame.set_label_widget(label)
frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#CDB400")) frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#CDB400'))
frame.set_border_width(2) frame.set_border_width(2)
frame.add(eventbox) frame.add(eventbox)
vbox.pack_start(frame, False, False) vbox.pack_start(frame, False, False)
vbox.show_all() vbox.show_all()
component.get("Preferences").add_page(_("Scheduler"), vbox) component.get('Preferences').add_page(_('Scheduler'), vbox)

View File

@ -23,5 +23,5 @@ log = logging.getLogger(__name__)
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("scheduler.js")] scripts = [get_resource('scheduler.js')]
debug_scripts = scripts debug_scripts = scripts

View File

@ -13,15 +13,15 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "Scheduler" __plugin_name__ = 'Scheduler'
__author__ = "Andrew Resch" __author__ = 'Andrew Resch'
__author_email__ = "andrewresch@gmail.com" __author_email__ = 'andrewresch@gmail.com'
__version__ = "0.2" __version__ = '0.2'
__url__ = "http://deluge-torrent.org" __url__ = 'http://deluge-torrent.org'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Schedule limits on a per-hour per-day basis." __description__ = 'Schedule limits on a per-hour per-day basis.'
__long_description__ = """""" __long_description__ = """"""
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -34,7 +34,7 @@ setup(
long_description=__long_description__ if __long_description__ else __description__, long_description=__long_description__ if __long_description__ else __description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -13,4 +13,4 @@ import pkg_resources
def get_resource(filename): def get_resource(filename):
return pkg_resources.resource_filename("deluge.plugins.stats", os.path.join("data", filename)) return pkg_resources.resource_filename('deluge.plugins.stats', os.path.join('data', filename))

View File

@ -23,17 +23,17 @@ from deluge.core.rpcserver import export
from deluge.plugins.pluginbase import CorePluginBase from deluge.plugins.pluginbase import CorePluginBase
DEFAULT_PREFS = { DEFAULT_PREFS = {
"test": "NiNiNi", 'test': 'NiNiNi',
"update_interval": 1, # 2 seconds. 'update_interval': 1, # 2 seconds.
"length": 150, # 2 seconds * 150 --> 5 minutes. 'length': 150, # 2 seconds * 150 --> 5 minutes.
} }
DEFAULT_TOTALS = { DEFAULT_TOTALS = {
"total_upload": 0, 'total_upload': 0,
"total_download": 0, 'total_download': 0,
"total_payload_upload": 0, 'total_payload_upload': 0,
"total_payload_download": 0, 'total_payload_download': 0,
"stats": {} 'stats': {}
} }
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -57,8 +57,8 @@ class Core(CorePluginBase):
totals = {} # class var to catch only updating this once per session in enable. totals = {} # class var to catch only updating this once per session in enable.
def enable(self): def enable(self):
log.debug("Stats plugin enabled") log.debug('Stats plugin enabled')
self.core = component.get("Core") self.core = component.get('Core')
self.stats = {} self.stats = {}
self.count = {} self.count = {}
self.intervals = [1, 5, 30, 300] self.intervals = [1, 5, 30, 300]
@ -70,12 +70,12 @@ class Core(CorePluginBase):
self.last_update[i] = t self.last_update[i] = t
self.count[i] = 0 self.count[i] = 0
self.config = configmanager.ConfigManager("stats.conf", DEFAULT_PREFS) self.config = configmanager.ConfigManager('stats.conf', DEFAULT_PREFS)
self.saved_stats = configmanager.ConfigManager("stats.totals", DEFAULT_TOTALS) self.saved_stats = configmanager.ConfigManager('stats.totals', DEFAULT_TOTALS)
if self.totals == {}: if self.totals == {}:
self.totals.update(self.saved_stats.config) self.totals.update(self.saved_stats.config)
self.length = self.config["length"] self.length = self.config['length']
# self.stats = get_key(self.saved_stats, "stats") or {} # self.stats = get_key(self.saved_stats, "stats") or {}
self.stats_keys = [] self.stats_keys = []
@ -92,7 +92,7 @@ class Core(CorePluginBase):
self.update_stats() self.update_stats()
self.update_timer = LoopingCall(self.update_stats) self.update_timer = LoopingCall(self.update_stats)
self.update_timer.start(self.config["update_interval"]) self.update_timer.start(self.config['update_interval'])
self.save_timer = LoopingCall(self.save_stats) self.save_timer = LoopingCall(self.save_stats)
self.save_timer.start(60) self.save_timer.start(60)
@ -124,10 +124,10 @@ class Core(CorePluginBase):
stats.update(self.core.get_session_status([key])) stats.update(self.core.get_session_status([key]))
except AttributeError: except AttributeError:
pass pass
stats["num_connections"] = stats["num_peers"] stats['num_connections'] = stats['num_peers']
stats.update(self.core.get_config_values(["max_download", stats.update(self.core.get_config_values(['max_download',
"max_upload", 'max_upload',
"max_num_connections"])) 'max_num_connections']))
# status = self.core.session.status() # status = self.core.session.status()
# for stat in dir(status): # for stat in dir(status):
# if not stat.startswith('_') and stat not in stats: # if not stat.startswith('_') and stat not in stats:
@ -166,16 +166,16 @@ class Core(CorePluginBase):
update_interval(300, 30, 10) update_interval(300, 30, 10)
except Exception as ex: except Exception as ex:
log.error("Stats update error %s", ex) log.error('Stats update error %s', ex)
return True return True
def save_stats(self): def save_stats(self):
try: try:
self.saved_stats["stats"] = self.stats self.saved_stats['stats'] = self.stats
self.saved_stats.config.update(self.get_totals()) self.saved_stats.config.update(self.get_totals())
self.saved_stats.save() self.saved_stats.save()
except Exception as ex: except Exception as ex:
log.error("Stats save error %s", ex) log.error('Stats save error %s', ex)
return True return True
# export: # export:
@ -189,9 +189,9 @@ class Core(CorePluginBase):
if key in self.stats[interval]: if key in self.stats[interval]:
stats_dict[key] = self.stats[interval][key] stats_dict[key] = self.stats[interval][key]
stats_dict["_last_update"] = self.last_update[interval] stats_dict['_last_update'] = self.last_update[interval]
stats_dict["_length"] = self.config["length"] stats_dict['_length'] = self.config['length']
stats_dict["_update_interval"] = interval stats_dict['_update_interval'] = interval
return stats_dict return stats_dict
@export @export
@ -206,25 +206,25 @@ class Core(CorePluginBase):
def get_session_totals(self): def get_session_totals(self):
status = self.core.session.status() status = self.core.session.status()
return { return {
"total_upload": status.total_upload, 'total_upload': status.total_upload,
"total_download": status.total_download, 'total_download': status.total_download,
"total_payload_upload": status.total_payload_upload, 'total_payload_upload': status.total_payload_upload,
"total_payload_download": status.total_payload_download 'total_payload_download': status.total_payload_download
} }
@export @export
def set_config(self, config): def set_config(self, config):
"sets the config dictionary" 'sets the config dictionary'
for key in config.keys(): for key in config.keys():
self.config[key] = config[key] self.config[key] = config[key]
self.config.save() self.config.save()
@export @export
def get_config(self): def get_config(self):
"returns the config dictionary" 'returns the config dictionary'
return self.config.config return self.config.config
@export @export
def get_intervals(self): def get_intervals(self):
"Returns the available resolutions" 'Returns the available resolutions'
return self.intervals return self.intervals

View File

@ -88,12 +88,12 @@ class Graph(object):
} }
def set_stats(self, stats): def set_stats(self, stats):
self.last_update = stats["_last_update"] self.last_update = stats['_last_update']
del stats["_last_update"] del stats['_last_update']
self.length = stats["_length"] self.length = stats['_length']
del stats["_length"] del stats['_length']
self.interval = stats["_update_interval"] self.interval = stats['_update_interval']
del stats["_update_interval"] del stats['_update_interval']
self.stats = stats self.stats = stats
return return

View File

@ -36,17 +36,17 @@ DEFAULT_CONF = {
'version': 1, 'version': 1,
'colors': { 'colors': {
'bandwidth_graph': { 'bandwidth_graph': {
'upload_rate': str(gtk.gdk.Color("blue")), 'upload_rate': str(gtk.gdk.Color('blue')),
'download_rate': str(gtk.gdk.Color("green")), 'download_rate': str(gtk.gdk.Color('green')),
}, },
'connections_graph': { 'connections_graph': {
'dht_nodes': str(gtk.gdk.Color("orange")), 'dht_nodes': str(gtk.gdk.Color('orange')),
'dht_cache_nodes': str(gtk.gdk.Color("blue")), 'dht_cache_nodes': str(gtk.gdk.Color('blue')),
'dht_torrents': str(gtk.gdk.Color("green")), 'dht_torrents': str(gtk.gdk.Color('green')),
'num_connections': str(gtk.gdk.Color("darkred")), 'num_connections': str(gtk.gdk.Color('darkred')),
}, },
'seeds_graph': { 'seeds_graph': {
'num_peers': str(gtk.gdk.Color("blue")), 'num_peers': str(gtk.gdk.Color('blue')),
}}} }}}
@ -54,13 +54,13 @@ def neat_time(column, cell, model, data):
"""Render seconds as seconds or minutes with label""" """Render seconds as seconds or minutes with label"""
seconds = model.get_value(data, 0) seconds = model.get_value(data, 0)
if seconds > 60: if seconds > 60:
text = "%d %s" % (seconds // 60, _("minutes")) text = '%d %s' % (seconds // 60, _('minutes'))
elif seconds == 60: elif seconds == 60:
text = _("1 minute") text = _('1 minute')
elif seconds == 1: elif seconds == 1:
text = _("1 second") text = _('1 second')
else: else:
text = "%d %s" % (seconds, _("seconds")) text = '%d %s' % (seconds, _('seconds'))
cell.set_property('text', text) cell.set_property('text', text)
return return
@ -114,7 +114,7 @@ class GraphsTab(Tab):
cell = gtk.CellRendererText() cell = gtk.CellRendererText()
self.intervals_combo.pack_start(cell, True) self.intervals_combo.pack_start(cell, True)
self.intervals_combo.set_cell_data_func(cell, neat_time) self.intervals_combo.set_cell_data_func(cell, neat_time)
self.intervals_combo.connect("changed", self._on_selected_interval_changed) self.intervals_combo.connect('changed', self._on_selected_interval_changed)
self.update_intervals() self.update_intervals()
def graph_expose(self, widget, event): def graph_expose(self, widget, event):
@ -145,7 +145,7 @@ class GraphsTab(Tab):
client.stats.get_intervals().addCallback(self._on_intervals_changed) client.stats.get_intervals().addCallback(self._on_intervals_changed)
def select_bandwidth_graph(self): def select_bandwidth_graph(self):
log.debug("Selecting bandwidth graph") log.debug('Selecting bandwidth graph')
self.graph_widget = self.bandwidth_graph self.graph_widget = self.bandwidth_graph
self.graph = Graph() self.graph = Graph()
colors = self.colors['bandwidth_graph'] colors = self.colors['bandwidth_graph']
@ -157,7 +157,7 @@ class GraphsTab(Tab):
formatter_scale=size_formatter_scale) formatter_scale=size_formatter_scale)
def select_connections_graph(self): def select_connections_graph(self):
log.debug("Selecting connections graph") log.debug('Selecting connections graph')
self.graph_widget = self.connections_graph self.graph_widget = self.connections_graph
g = Graph() g = Graph()
self.graph = g self.graph = g
@ -169,7 +169,7 @@ class GraphsTab(Tab):
g.set_left_axis(formatter=int_str, min=10) g.set_left_axis(formatter=int_str, min=10)
def select_seeds_graph(self): def select_seeds_graph(self):
log.debug("Selecting connections graph") log.debug('Selecting connections graph')
self.graph_widget = self.seeds_graph self.graph_widget = self.seeds_graph
self.graph = Graph() self.graph = Graph()
colors = self.colors['seeds_graph'] colors = self.colors['seeds_graph']
@ -219,32 +219,32 @@ class GraphsTab(Tab):
class GtkUI(GtkPluginBase): class GtkUI(GtkPluginBase):
def enable(self): def enable(self):
log.debug("Stats plugin enable called") log.debug('Stats plugin enable called')
self.config = deluge.configmanager.ConfigManager("stats.gtkui.conf", DEFAULT_CONF) self.config = deluge.configmanager.ConfigManager('stats.gtkui.conf', DEFAULT_CONF)
self.glade = XML(common.get_resource("config.glade")) self.glade = XML(common.get_resource('config.glade'))
component.get("Preferences").add_page("Stats", self.glade.get_widget("prefs_box")) component.get('Preferences').add_page('Stats', self.glade.get_widget('prefs_box'))
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').register_hook('on_apply_prefs', self.on_apply_prefs)
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs) component.get('PluginManager').register_hook('on_show_prefs', self.on_show_prefs)
self.on_show_prefs() self.on_show_prefs()
self.graphs_tab = GraphsTab(XML(common.get_resource("tabs.glade")), self.config['colors']) self.graphs_tab = GraphsTab(XML(common.get_resource('tabs.glade')), self.config['colors'])
self.torrent_details = component.get('TorrentDetails') self.torrent_details = component.get('TorrentDetails')
self.torrent_details.add_tab(self.graphs_tab) self.torrent_details.add_tab(self.graphs_tab)
def disable(self): def disable(self):
component.get("Preferences").remove_page("Stats") component.get('Preferences').remove_page('Stats')
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').deregister_hook('on_apply_prefs', self.on_apply_prefs)
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs) component.get('PluginManager').deregister_hook('on_show_prefs', self.on_show_prefs)
self.torrent_details.remove_tab(self.graphs_tab.get_name()) self.torrent_details.remove_tab(self.graphs_tab.get_name())
def on_apply_prefs(self): def on_apply_prefs(self):
log.debug("applying prefs for Stats") log.debug('applying prefs for Stats')
gtkconf = {} gtkconf = {}
for graph, colors in self.config['colors'].items(): for graph, colors in self.config['colors'].items():
gtkconf[graph] = {} gtkconf[graph] = {}
for value, color in colors.items(): for value, color in colors.items():
try: try:
color_btn = self.glade.get_widget("%s_%s_color" % (graph, value)) color_btn = self.glade.get_widget('%s_%s_color' % (graph, value))
gtkconf[graph][value] = str(color_btn.get_color()) gtkconf[graph][value] = str(color_btn.get_color())
except Exception: except Exception:
gtkconf[graph][value] = DEFAULT_CONF['colors'][graph][value] gtkconf[graph][value] = DEFAULT_CONF['colors'][graph][value]
@ -258,12 +258,12 @@ class GtkUI(GtkPluginBase):
for graph, colors in self.config['colors'].items(): for graph, colors in self.config['colors'].items():
for value, color in colors.items(): for value, color in colors.items():
try: try:
color_btn = self.glade.get_widget("%s_%s_color" % (graph, value)) color_btn = self.glade.get_widget('%s_%s_color' % (graph, value))
color_btn.set_color(gtk.gdk.Color(color)) color_btn.set_color(gtk.gdk.Color(color))
except Exception: except Exception:
log.debug("Unable to set %s %s %s", graph, value, color) log.debug('Unable to set %s %s %s', graph, value, color)
client.stats.get_config().addCallback(self.cb_get_config) client.stats.get_config().addCallback(self.cb_get_config)
def cb_get_config(self, config): def cb_get_config(self, config):
"callback for on show_prefs" 'callback for on show_prefs'
pass pass

View File

@ -21,9 +21,9 @@ def print_totals(totals):
for name, value in totals.iteritems(): for name, value in totals.iteritems():
print(name, fsize(value)) print(name, fsize(value))
print("overhead:") print('overhead:')
print("up:", fsize(totals["total_upload"] - totals["total_payload_upload"])) print('up:', fsize(totals['total_upload'] - totals['total_payload_upload']))
print("down:", fsize(totals["total_download"] - totals["total_payload_download"])) print('down:', fsize(totals['total_download'] - totals['total_payload_download']))
class StatsTestCase(BaseTestCase): class StatsTestCase(BaseTestCase):
@ -32,7 +32,7 @@ class StatsTestCase(BaseTestCase):
defer.setDebugging(True) defer.setDebugging(True)
tests_common.set_tmp_config_dir() tests_common.set_tmp_config_dir()
client.start_standalone() client.start_standalone()
client.core.enable_plugin("Stats") client.core.enable_plugin('Stats')
return component.start() return component.start()
def tear_down(self): def tear_down(self):
@ -42,8 +42,8 @@ class StatsTestCase(BaseTestCase):
@defer.inlineCallbacks @defer.inlineCallbacks
def test_client_totals(self): def test_client_totals(self):
plugins = yield client.core.get_available_plugins() plugins = yield client.core.get_available_plugins()
if "Stats" not in plugins: if 'Stats' not in plugins:
raise unittest.SkipTest("WebUi plugin not available for testing") raise unittest.SkipTest('WebUi plugin not available for testing')
totals = yield client.stats.get_totals() totals = yield client.stats.get_totals()
self.assertEquals(totals['total_upload'], 0) self.assertEquals(totals['total_upload'], 0)
@ -55,8 +55,8 @@ class StatsTestCase(BaseTestCase):
@defer.inlineCallbacks @defer.inlineCallbacks
def test_session_totals(self): def test_session_totals(self):
plugins = yield client.core.get_available_plugins() plugins = yield client.core.get_available_plugins()
if "Stats" not in plugins: if 'Stats' not in plugins:
raise unittest.SkipTest("WebUi plugin not available for testing") raise unittest.SkipTest('WebUi plugin not available for testing')
totals = yield client.stats.get_session_totals() totals = yield client.stats.get_session_totals()
self.assertEquals(totals['total_upload'], 0) self.assertEquals(totals['total_upload'], 0)
@ -82,7 +82,7 @@ class StatsTestCase(BaseTestCase):
from deluge.ui.gtkui.torrentview import TorrentView from deluge.ui.gtkui.torrentview import TorrentView
from deluge.plugins.Stats.deluge.plugins.stats import graph, gtkui from deluge.plugins.Stats.deluge.plugins.stats import graph, gtkui
ConfigManager("gtkui.conf", defaults=DEFAULT_PREFS) ConfigManager('gtkui.conf', defaults=DEFAULT_PREFS)
self.plugins = PluginManager() self.plugins = PluginManager()
MainWindow() MainWindow()
@ -97,7 +97,7 @@ class StatsTestCase(BaseTestCase):
def write(self, data): def write(self, data):
self.data.append(data) self.data.append(data)
stats_gtkui = gtkui.GtkUI("test_stats") stats_gtkui = gtkui.GtkUI('test_stats')
stats_gtkui.enable() stats_gtkui.enable()
yield stats_gtkui.graphs_tab.update() yield stats_gtkui.graphs_tab.update()
@ -109,6 +109,6 @@ class StatsTestCase(BaseTestCase):
surface = g.draw(900, 150) surface = g.draw(900, 150)
file_like = FakeFile() file_like = FakeFile()
surface.write_to_png(file_like) surface.write_to_png(file_like)
data = "".join(file_like.data) data = ''.join(file_like.data)
with open("file_like.png", "wb") as _file: with open('file_like.png', 'wb') as _file:
_file.write(data) _file.write(data)

View File

@ -22,13 +22,13 @@ log = logging.getLogger(__name__)
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("stats.js")] scripts = [get_resource('stats.js')]
# The enable and disable methods are not scrictly required on the WebUI # The enable and disable methods are not scrictly required on the WebUI
# plugins. They are only here if you need to register images/stylesheets # plugins. They are only here if you need to register images/stylesheets
# with the webserver. # with the webserver.
def enable(self): def enable(self):
log.debug("Stats Web plugin enabled!") log.debug('Stats Web plugin enabled!')
def disable(self): def disable(self):
log.debug("Stats Web plugin disabled!") log.debug('Stats Web plugin disabled!')

View File

@ -14,18 +14,18 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "Stats" __plugin_name__ = 'Stats'
__author__ = "Ian Martin" __author__ = 'Ian Martin'
__author_email__ = "ianmartin@cantab.net" __author_email__ = 'ianmartin@cantab.net'
__version__ = "0.3.2" __version__ = '0.3.2'
__url__ = "http://deluge-torrent.org" __url__ = 'http://deluge-torrent.org'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Display stats graphs" __description__ = 'Display stats graphs'
__long_description__ = """ __long_description__ = """
Records lots of extra stats Records lots of extra stats
and produces time series and produces time series
graphs""" graphs"""
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -38,7 +38,7 @@ setup(
long_description=__long_description__, long_description=__long_description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -16,5 +16,5 @@
def get_resource(filename): def get_resource(filename):
import os.path import os.path
import pkg_resources import pkg_resources
return pkg_resources.resource_filename("deluge.plugins.toggle", return pkg_resources.resource_filename('deluge.plugins.toggle',
os.path.join("data", filename)) os.path.join('data', filename))

View File

@ -26,7 +26,7 @@ DEFAULT_PREFS = {
class Core(CorePluginBase): class Core(CorePluginBase):
def enable(self): def enable(self):
self.core = component.get("Core") self.core = component.get('Core')
def disable(self): def disable(self):
pass pass

View File

@ -24,25 +24,25 @@ log = logging.getLogger(__name__)
class GtkUI(GtkPluginBase): class GtkUI(GtkPluginBase):
def enable(self): def enable(self):
self.core = client.toggle self.core = client.toggle
self.plugin = component.get("PluginManager") self.plugin = component.get('PluginManager')
self.separator = self.plugin.add_toolbar_separator() self.separator = self.plugin.add_toolbar_separator()
self.button = self.plugin.add_toolbar_button(self._on_button_clicked, label="Pause Session", self.button = self.plugin.add_toolbar_button(self._on_button_clicked, label='Pause Session',
stock="gtk-media-pause", tooltip="Pause the session") stock='gtk-media-pause', tooltip='Pause the session')
def disable(self): def disable(self):
component.get("PluginManager").remove_toolbar_button(self.button) component.get('PluginManager').remove_toolbar_button(self.button)
component.get("PluginManager").remove_toolbar_button(self.separator) component.get('PluginManager').remove_toolbar_button(self.separator)
def update(self): def update(self):
def _on_get_status(paused): def _on_get_status(paused):
if paused: if paused:
self.button.set_label("Resume Session") self.button.set_label('Resume Session')
self.button.set_tooltip_text("Resume the session") self.button.set_tooltip_text('Resume the session')
self.button.set_stock_id("gtk-media-play") self.button.set_stock_id('gtk-media-play')
else: else:
self.button.set_label("Pause Session") self.button.set_label('Pause Session')
self.button.set_tooltip_text("Pause the session") self.button.set_tooltip_text('Pause the session')
self.button.set_stock_id("gtk-media-pause") self.button.set_stock_id('gtk-media-pause')
self.core.get_status().addCallback(_on_get_status) self.core.get_status().addCallback(_on_get_status)
def _on_button_clicked(self, widget): def _on_button_clicked(self, widget):

View File

@ -23,7 +23,7 @@ log = logging.getLogger(__name__)
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
scripts = [get_resource("toggle.js")] scripts = [get_resource('toggle.js')]
def enable(self): def enable(self):
pass pass

View File

@ -14,15 +14,15 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "Toggle" __plugin_name__ = 'Toggle'
__author__ = "John Garland" __author__ = 'John Garland'
__author_email__ = "johnnybg+deluge@gmail.com" __author_email__ = 'johnnybg+deluge@gmail.com'
__version__ = "0.3" __version__ = '0.3'
__url__ = "http://deluge-torrent.org" __url__ = 'http://deluge-torrent.org'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Toggles the session" __description__ = 'Toggles the session'
__long_description__ = """""" __long_description__ = """"""
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -35,7 +35,7 @@ setup(
long_description=__long_description__ if __long_description__ else __description__, long_description=__long_description__ if __long_description__ else __description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -15,5 +15,5 @@
def get_resource(filename): def get_resource(filename):
import os.path import os.path
import pkg_resources import pkg_resources
return pkg_resources.resource_filename("deluge.plugins.webui", return pkg_resources.resource_filename('deluge.plugins.webui',
os.path.join("data", filename)) os.path.join('data', filename))

View File

@ -24,9 +24,9 @@ from deluge.plugins.pluginbase import CorePluginBase
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DEFAULT_PREFS = { DEFAULT_PREFS = {
"enabled": False, 'enabled': False,
"ssl": False, 'ssl': False,
"port": 8112 'port': 8112
} }
@ -34,7 +34,7 @@ class Core(CorePluginBase):
server = None server = None
def enable(self): def enable(self):
self.config = configmanager.ConfigManager("web_plugin.conf", DEFAULT_PREFS) self.config = configmanager.ConfigManager('web_plugin.conf', DEFAULT_PREFS)
if self.config['enabled']: if self.config['enabled']:
self.start_server() self.start_server()
@ -63,16 +63,16 @@ class Core(CorePluginBase):
return False return False
try: try:
self.server = component.get("DelugeWeb") self.server = component.get('DelugeWeb')
except KeyError: except KeyError:
self.server = server.DelugeWeb(daemon=False) self.server = server.DelugeWeb(daemon=False)
self.server.port = self.config["port"] self.server.port = self.config['port']
self.server.https = self.config["ssl"] self.server.https = self.config['ssl']
try: try:
self.server.start() self.server.start()
except CannotListenError as ex: except CannotListenError as ex:
log.warn("Failed to start WebUI server: %s", ex) log.warn('Failed to start WebUI server: %s', ex)
raise raise
return True return True
@ -86,14 +86,14 @@ class Core(CorePluginBase):
@export @export
def set_config(self, config): def set_config(self, config):
"sets the config dictionary" 'sets the config dictionary'
action = None action = None
if "enabled" in config: if 'enabled' in config:
if config["enabled"] != self.config["enabled"]: if config['enabled'] != self.config['enabled']:
action = config["enabled"] and 'start' or 'stop' action = config['enabled'] and 'start' or 'stop'
if "ssl" in config: if 'ssl' in config:
if not action: if not action:
action = 'restart' action = 'restart'
@ -110,5 +110,5 @@ class Core(CorePluginBase):
@export @export
def get_config(self): def get_config(self):
"returns the config dictionary" 'returns the config dictionary'
return self.config.config return self.config.config

View File

@ -27,27 +27,27 @@ log = logging.getLogger(__name__)
class GtkUI(GtkPluginBase): class GtkUI(GtkPluginBase):
def enable(self): def enable(self):
self.glade = gtk.glade.XML(get_resource("config.glade")) self.glade = gtk.glade.XML(get_resource('config.glade'))
component.get("Preferences").add_page(_("WebUi"), self.glade.get_widget("prefs_box")) component.get('Preferences').add_page(_('WebUi'), self.glade.get_widget('prefs_box'))
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').register_hook('on_apply_prefs', self.on_apply_prefs)
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs) component.get('PluginManager').register_hook('on_show_prefs', self.on_show_prefs)
client.webui.get_config().addCallback(self.cb_get_config) client.webui.get_config().addCallback(self.cb_get_config)
client.webui.got_deluge_web().addCallback(self.cb_chk_deluge_web) client.webui.got_deluge_web().addCallback(self.cb_chk_deluge_web)
def disable(self): def disable(self):
component.get("Preferences").remove_page(_("WebUi")) component.get('Preferences').remove_page(_('WebUi'))
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').deregister_hook('on_apply_prefs', self.on_apply_prefs)
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs) component.get('PluginManager').deregister_hook('on_show_prefs', self.on_show_prefs)
def on_apply_prefs(self): def on_apply_prefs(self):
if not self.have_web: if not self.have_web:
return return
log.debug("applying prefs for WebUi") log.debug('applying prefs for WebUi')
config = { config = {
"enabled": self.glade.get_widget("enabled_checkbutton").get_active(), 'enabled': self.glade.get_widget('enabled_checkbutton').get_active(),
"ssl": self.glade.get_widget("ssl_checkbutton").get_active(), 'ssl': self.glade.get_widget('ssl_checkbutton').get_active(),
"port": self.glade.get_widget("port_spinbutton").get_value_as_int() 'port': self.glade.get_widget('port_spinbutton').get_value_as_int()
} }
client.webui.set_config(config) client.webui.set_config(config)
@ -55,26 +55,26 @@ class GtkUI(GtkPluginBase):
client.webui.get_config().addCallback(self.cb_get_config) client.webui.get_config().addCallback(self.cb_get_config)
def cb_get_config(self, config): def cb_get_config(self, config):
"callback for on show_prefs" 'callback for on show_prefs'
self.glade.get_widget("enabled_checkbutton").set_active(config["enabled"]) self.glade.get_widget('enabled_checkbutton').set_active(config['enabled'])
self.glade.get_widget("ssl_checkbutton").set_active(config["ssl"]) self.glade.get_widget('ssl_checkbutton').set_active(config['ssl'])
self.glade.get_widget("port_spinbutton").set_value(config["port"]) self.glade.get_widget('port_spinbutton').set_value(config['port'])
def cb_chk_deluge_web(self, have_web): def cb_chk_deluge_web(self, have_web):
self.have_web = have_web self.have_web = have_web
if have_web: if have_web:
return return
self.glade.get_widget("settings_vbox").set_sensitive(False) self.glade.get_widget('settings_vbox').set_sensitive(False)
vbox = self.glade.get_widget("prefs_box") vbox = self.glade.get_widget('prefs_box')
hbox = gtk.HBox() hbox = gtk.HBox()
icon = gtk.image_new_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_SMALL_TOOLBAR) icon = gtk.image_new_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_SMALL_TOOLBAR)
icon.set_padding(5, 5) icon.set_padding(5, 5)
hbox.pack_start(icon, False, False) hbox.pack_start(icon, False, False)
label = gtk.Label(_("The Deluge web interface is not installed, " label = gtk.Label(_('The Deluge web interface is not installed, '
"please install the\ninterface and try again")) 'please install the\ninterface and try again'))
label.set_alignment(0, 0.5) label.set_alignment(0, 0.5)
label.set_padding(5, 5) label.set_padding(5, 5)
hbox.pack_start(label) hbox.pack_start(label)

View File

@ -34,14 +34,14 @@ class WebUIPluginTestCase(BaseTestCase):
return component.shutdown().addCallback(on_shutdown) return component.shutdown().addCallback(on_shutdown)
def test_enable_webui(self): def test_enable_webui(self):
if "WebUi" not in self.core.get_available_plugins(): if 'WebUi' not in self.core.get_available_plugins():
raise unittest.SkipTest("WebUi plugin not available for testing") raise unittest.SkipTest('WebUi plugin not available for testing')
d = self.core.enable_plugin("WebUi") d = self.core.enable_plugin('WebUi')
def result_cb(result): def result_cb(result):
if "WebUi" not in self.core.get_enabled_plugins(): if 'WebUi' not in self.core.get_enabled_plugins():
self.fail("Failed to enable WebUi plugin") self.fail('Failed to enable WebUi plugin')
self.assertTrue(result) self.assertTrue(result)
d.addBoth(result_cb) d.addBoth(result_cb)

View File

@ -13,15 +13,15 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
__plugin_name__ = "WebUi" __plugin_name__ = 'WebUi'
__author__ = "Damien Churchill" __author__ = 'Damien Churchill'
__author_email__ = "damoxc@gmail.com" __author_email__ = 'damoxc@gmail.com'
__version__ = "0.1" __version__ = '0.1'
__url__ = "http://deluge-torrent.org" __url__ = 'http://deluge-torrent.org'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Allows starting the web interface within the daemon." __description__ = 'Allows starting the web interface within the daemon.'
__long_description__ = """""" __long_description__ = """"""
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@ -34,7 +34,7 @@ setup(
long_description=__long_description__ if __long_description__ else __description__, long_description=__long_description__ if __long_description__ else __description__,
packages=find_packages(), packages=find_packages(),
namespace_packages=["deluge", "deluge.plugins"], namespace_packages=['deluge', 'deluge.plugins'],
package_data=__pkg_data__, package_data=__pkg_data__,
entry_points=""" entry_points="""

View File

@ -22,22 +22,22 @@ class PluginBase(component.Component):
super(PluginBase, self).__init__(name, self.update_interval) super(PluginBase, self).__init__(name, self.update_interval)
def enable(self): def enable(self):
raise NotImplementedError("Need to define an enable method!") raise NotImplementedError('Need to define an enable method!')
def disable(self): def disable(self):
raise NotImplementedError("Need to define a disable method!") raise NotImplementedError('Need to define a disable method!')
class CorePluginBase(PluginBase): class CorePluginBase(PluginBase):
def __init__(self, plugin_name): def __init__(self, plugin_name):
super(CorePluginBase, self).__init__("CorePlugin." + plugin_name) super(CorePluginBase, self).__init__('CorePlugin.' + plugin_name)
# Register RPC methods # Register RPC methods
component.get("RPCServer").register_object(self, plugin_name.lower()) component.get('RPCServer').register_object(self, plugin_name.lower())
log.debug("CorePlugin initialized..") log.debug('CorePlugin initialized..')
def __del__(self): def __del__(self):
component.get("RPCServer").deregister_object(self) component.get('RPCServer').deregister_object(self)
def enable(self): def enable(self):
super(CorePluginBase, self).enable() super(CorePluginBase, self).enable()
@ -49,8 +49,8 @@ class CorePluginBase(PluginBase):
class GtkPluginBase(PluginBase): class GtkPluginBase(PluginBase):
def __init__(self, plugin_name): def __init__(self, plugin_name):
super(GtkPluginBase, self).__init__("GtkPlugin." + plugin_name) super(GtkPluginBase, self).__init__('GtkPlugin.' + plugin_name)
log.debug("GtkPlugin initialized..") log.debug('GtkPlugin initialized..')
def enable(self): def enable(self):
super(GtkPluginBase, self).enable() super(GtkPluginBase, self).enable()
@ -68,11 +68,11 @@ class WebPluginBase(PluginBase):
debug_stylesheets = [] debug_stylesheets = []
def __init__(self, plugin_name): def __init__(self, plugin_name):
super(WebPluginBase, self).__init__("WebPlugin." + plugin_name) super(WebPluginBase, self).__init__('WebPlugin.' + plugin_name)
# Register JSON rpc methods # Register JSON rpc methods
component.get("JSON").register_object(self, plugin_name.lower()) component.get('JSON').register_object(self, plugin_name.lower())
log.debug("WebPlugin initialized..") log.debug('WebPlugin initialized..')
def enable(self): def enable(self):
pass pass

View File

@ -62,7 +62,7 @@ import struct
import sys import sys
from threading import Lock from threading import Lock
__version__ = ("Python", 1, 0, 4) __version__ = ('Python', 1, 0, 4)
__all__ = ['dumps', 'loads'] __all__ = ['dumps', 'loads']
py3 = sys.version_info[0] >= 3 py3 = sys.version_info[0] >= 3
@ -244,7 +244,7 @@ def make_fixed_length_string_decoders():
def f(x, f): def f(x, f):
s = x[f + 1:f + 1 + slen] s = x[f + 1:f + 1 + slen]
if _decode_utf8: if _decode_utf8:
s = s.decode("utf8") s = s.decode('utf8')
return (s, f + 1 + slen) return (s, f + 1 + slen)
return f return f
for i in range(STR_FIXED_COUNT): for i in range(STR_FIXED_COUNT):
@ -324,7 +324,7 @@ def encode_int(x, r):
else: else:
s = str(x) s = str(x)
if py3: if py3:
s = bytes(s, "ascii") s = bytes(s, 'ascii')
if len(s) >= MAX_INT_LENGTH: if len(s) >= MAX_INT_LENGTH:
raise ValueError('overflow') raise ValueError('overflow')
@ -353,12 +353,12 @@ def encode_string(x, r):
else: else:
s = str(len(x)) s = str(len(x))
if py3: if py3:
s = bytes(s, "ascii") s = bytes(s, 'ascii')
r.extend((s, b':', x)) r.extend((s, b':', x))
def encode_unicode(x, r): def encode_unicode(x, r):
encode_string(x.encode("utf8"), r) encode_string(x.encode('utf8'), r)
def encode_list(x, r): def encode_list(x, r):
@ -447,7 +447,7 @@ def test():
assert 1e-10 < abs(loads(dumps(1.1)) - 1.1) < 1e-6 assert 1e-10 < abs(loads(dumps(1.1)) - 1.1) < 1e-6
assert 1e-10 < abs(loads(dumps(1.1, 32)) - 1.1) < 1e-6 assert 1e-10 < abs(loads(dumps(1.1, 32)) - 1.1) < 1e-6
assert abs(loads(dumps(1.1, 64)) - 1.1) < 1e-12 assert abs(loads(dumps(1.1, 64)) - 1.1) < 1e-12
assert loads(dumps("Hello World!!"), decode_utf8=True) assert loads(dumps('Hello World!!'), decode_utf8=True)
try: try:
import psyco import psyco
psyco.bind(dumps) psyco.bind(dumps)

View File

@ -16,15 +16,15 @@ from datetime import datetime
import deluge.common import deluge.common
parser = ArgumentParser() parser = ArgumentParser()
parser.add_argument("-n", "--name", metavar="<plugin name>", required=True, help="Plugin name") parser.add_argument('-n', '--name', metavar='<plugin name>', required=True, help='Plugin name')
parser.add_argument("-m", "--module-name", metavar="<module name>", help="Module name") parser.add_argument('-m', '--module-name', metavar='<module name>', help='Module name')
parser.add_argument("-p", "--basepath", metavar="<path>", required=True, help="Base path") parser.add_argument('-p', '--basepath', metavar='<path>', required=True, help='Base path')
parser.add_argument("-a", "--author-name", metavar="<author name>", required=True, parser.add_argument('-a', '--author-name', metavar='<author name>', required=True,
help="Author name,for the GPL header") help='Author name,for the GPL header')
parser.add_argument("-e", "--author-email", metavar="<author email>", required=True, parser.add_argument('-e', '--author-email', metavar='<author email>', required=True,
help="Author email,for the GPL header") help='Author email,for the GPL header')
parser.add_argument("-u", "--url", metavar="<URL>", help="Homepage URL") parser.add_argument('-u', '--url', metavar='<URL>', help='Homepage URL')
parser.add_argument("-c", "--config", metavar="<Config dir>", dest="configdir", help="Location of deluge configuration") parser.add_argument('-c', '--config', metavar='<Config dir>', dest='configdir', help='Location of deluge configuration')
options = parser.parse_args() options = parser.parse_args()
@ -32,10 +32,10 @@ options = parser.parse_args()
def create_plugin(): def create_plugin():
if not options.url: if not options.url:
options.url = "" options.url = ''
if not os.path.exists(options.basepath): if not os.path.exists(options.basepath):
print("basepath does not exist") print('basepath does not exist')
return return
if not options.configdir: if not options.configdir:
@ -44,65 +44,65 @@ def create_plugin():
options.configdir = os.path.realpath(options.configdir) options.configdir = os.path.realpath(options.configdir)
real_name = options.name real_name = options.name
name = real_name.replace(" ", "_") name = real_name.replace(' ', '_')
safe_name = name.lower() safe_name = name.lower()
if options.module_name: if options.module_name:
safe_name = options.module_name.lower() safe_name = options.module_name.lower()
plugin_base = os.path.realpath(os.path.join(options.basepath, name)) plugin_base = os.path.realpath(os.path.join(options.basepath, name))
deluge_namespace = os.path.join(plugin_base, "deluge") deluge_namespace = os.path.join(plugin_base, 'deluge')
plugins_namespace = os.path.join(deluge_namespace, "plugins") plugins_namespace = os.path.join(deluge_namespace, 'plugins')
src = os.path.join(plugins_namespace, safe_name) src = os.path.join(plugins_namespace, safe_name)
data_dir = os.path.join(src, "data") data_dir = os.path.join(src, 'data')
python_path = sys.executable python_path = sys.executable
if os.path.exists(plugin_base): if os.path.exists(plugin_base):
print("the directory %s already exists, delete it first" % plugin_base) print('the directory %s already exists, delete it first' % plugin_base)
return return
def write_file(path, filename, template, include_gpl=True): def write_file(path, filename, template, include_gpl=True):
plugin_args = { plugin_args = {
"author_name": options.author_name, 'author_name': options.author_name,
"author_email": options.author_email, 'author_email': options.author_email,
"name": name, 'name': name,
"safe_name": safe_name, 'safe_name': safe_name,
"filename": filename, 'filename': filename,
"plugin_base": plugin_base, 'plugin_base': plugin_base,
"python_path": python_path, 'python_path': python_path,
"url": options.url, 'url': options.url,
"configdir": options.configdir, 'configdir': options.configdir,
"current_year": datetime.utcnow().year 'current_year': datetime.utcnow().year
} }
filename = os.path.join(path, filename) filename = os.path.join(path, filename)
with open(filename, "w") as _file: with open(filename, 'w') as _file:
if filename.endswith(".py") and include_gpl: if filename.endswith('.py') and include_gpl:
_file.write(GPL % plugin_args) _file.write(GPL % plugin_args)
_file.write(template % plugin_args) _file.write(template % plugin_args)
print("creating folders..") print('creating folders..')
os.mkdir(plugin_base) os.mkdir(plugin_base)
os.mkdir(deluge_namespace) os.mkdir(deluge_namespace)
os.mkdir(plugins_namespace) os.mkdir(plugins_namespace)
os.mkdir(src) os.mkdir(src)
os.mkdir(data_dir) os.mkdir(data_dir)
print("creating files..") print('creating files..')
write_file(plugin_base, "setup.py", SETUP) write_file(plugin_base, 'setup.py', SETUP)
write_file(deluge_namespace, "__init__.py", NAMESPACE_INIT, False) write_file(deluge_namespace, '__init__.py', NAMESPACE_INIT, False)
write_file(plugins_namespace, "__init__.py", NAMESPACE_INIT, False) write_file(plugins_namespace, '__init__.py', NAMESPACE_INIT, False)
write_file(src, "__init__.py", INIT) write_file(src, '__init__.py', INIT)
write_file(src, "gtkui.py", GTKUI) write_file(src, 'gtkui.py', GTKUI)
write_file(src, "webui.py", WEBUI) write_file(src, 'webui.py', WEBUI)
write_file(src, "core.py", CORE) write_file(src, 'core.py', CORE)
write_file(src, "common.py", COMMON) write_file(src, 'common.py', COMMON)
write_file(data_dir, "config.glade", GLADE) write_file(data_dir, 'config.glade', GLADE)
write_file(data_dir, "%s.js" % safe_name, DEFAULT_JS) write_file(data_dir, '%s.js' % safe_name, DEFAULT_JS)
# add an input parameter for this? # add an input parameter for this?
print("building dev-link..") print('building dev-link..')
write_file(plugin_base, "create_dev_link.sh", CREATE_DEV_LINK) write_file(plugin_base, 'create_dev_link.sh', CREATE_DEV_LINK)
dev_link_path = os.path.join(plugin_base, "create_dev_link.sh") dev_link_path = os.path.join(plugin_base, 'create_dev_link.sh')
os.system("chmod +x %s" % dev_link_path) # lazy.. os.system('chmod +x %s' % dev_link_path) # lazy..
os.system(dev_link_path) os.system(dev_link_path)

View File

@ -28,21 +28,21 @@ def is_float_digit(string):
# set up command-line options # set up command-line options
parser = OptionParser() parser = OptionParser()
parser.add_option("--port", help="port for deluge backend host (default: 58846)", default="58846", dest="port") parser.add_option('--port', help='port for deluge backend host (default: 58846)', default='58846', dest='port')
parser.add_option("--host", help="hostname of deluge backend to connect to (default: localhost)", parser.add_option('--host', help='hostname of deluge backend to connect to (default: localhost)',
default="localhost", dest="host") default='localhost', dest='host')
parser.add_option("--max_active_limit", dest="max_active_limit", parser.add_option('--max_active_limit', dest='max_active_limit',
help="sets the absolute maximum number of active torrents on the deluge backend") help='sets the absolute maximum number of active torrents on the deluge backend')
parser.add_option("--max_active_downloading", dest="max_active_downloading", parser.add_option('--max_active_downloading', dest='max_active_downloading',
help="sets the maximum number of active downloading torrents on the deluge backend") help='sets the maximum number of active downloading torrents on the deluge backend')
parser.add_option("--max_active_seeding", dest="max_active_seeding", parser.add_option('--max_active_seeding', dest='max_active_seeding',
help="sets the maximum number of active seeding torrents on the deluge backend") help='sets the maximum number of active seeding torrents on the deluge backend')
parser.add_option("--max_download_speed", help="sets the maximum global download speed on the deluge backend", parser.add_option('--max_download_speed', help='sets the maximum global download speed on the deluge backend',
dest="max_download_speed") dest='max_download_speed')
parser.add_option("--max_upload_speed", help="sets the maximum global upload speed on the deluge backend", parser.add_option('--max_upload_speed', help='sets the maximum global upload speed on the deluge backend',
dest="max_upload_speed") dest='max_upload_speed')
parser.add_option("--debug", help="outputs debug information to the console", default=False, action="store_true", parser.add_option('--debug', help='outputs debug information to the console', default=False, action='store_true',
dest="debug") dest='debug')
# grab command-line options # grab command-line options
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
@ -57,21 +57,21 @@ if options.max_active_limit:
if options.max_active_limit.isdigit() and int(options.max_active_limit) >= 0: if options.max_active_limit.isdigit() and int(options.max_active_limit) >= 0:
settings['max_active_limit'] = int(options.max_active_limit) settings['max_active_limit'] = int(options.max_active_limit)
else: else:
sys.stderr.write("ERROR: Invalid max_active_limit parameter!\n") sys.stderr.write('ERROR: Invalid max_active_limit parameter!\n')
sys.exit(-1) sys.exit(-1)
if options.max_active_downloading: if options.max_active_downloading:
if options.max_active_downloading.isdigit() and int(options.max_active_downloading) >= 0: if options.max_active_downloading.isdigit() and int(options.max_active_downloading) >= 0:
settings['max_active_downloading'] = int(options.max_active_downloading) settings['max_active_downloading'] = int(options.max_active_downloading)
else: else:
sys.stderr.write("ERROR: Invalid max_active_downloading parameter!\n") sys.stderr.write('ERROR: Invalid max_active_downloading parameter!\n')
sys.exit(-1) sys.exit(-1)
if options.max_active_seeding: if options.max_active_seeding:
if options.max_active_seeding.isdigit() and int(options.max_active_seeding) >= 0: if options.max_active_seeding.isdigit() and int(options.max_active_seeding) >= 0:
settings['max_active_seeding'] = int(options.max_active_seeding) settings['max_active_seeding'] = int(options.max_active_seeding)
else: else:
sys.stderr.write("ERROR: Invalid max_active_seeding parameter!\n") sys.stderr.write('ERROR: Invalid max_active_seeding parameter!\n')
sys.exit(-1) sys.exit(-1)
if options.max_download_speed: if options.max_download_speed:
@ -79,7 +79,7 @@ if options.max_download_speed:
float(options.max_download_speed) >= 0.0 or float(options.max_download_speed) == -1.0): float(options.max_download_speed) >= 0.0 or float(options.max_download_speed) == -1.0):
settings['max_download_speed'] = float(options.max_download_speed) settings['max_download_speed'] = float(options.max_download_speed)
else: else:
sys.stderr.write("ERROR: Invalid max_download_speed parameter!\n") sys.stderr.write('ERROR: Invalid max_download_speed parameter!\n')
sys.exit(-1) sys.exit(-1)
if options.max_upload_speed: if options.max_upload_speed:
@ -87,14 +87,14 @@ if options.max_upload_speed:
float(options.max_upload_speed) >= 0.0 or float(options.max_upload_speed) == -1.0): float(options.max_upload_speed) >= 0.0 or float(options.max_upload_speed) == -1.0):
settings['max_upload_speed'] = float(options.max_upload_speed) settings['max_upload_speed'] = float(options.max_upload_speed)
else: else:
sys.stderr.write("ERROR: Invalid max_upload_speed parameter!\n") sys.stderr.write('ERROR: Invalid max_upload_speed parameter!\n')
sys.exit(-1) sys.exit(-1)
# If there is something to do ... # If there is something to do ...
if settings: if settings:
# create connection to daemon # create connection to daemon
from deluge.ui.client import sclient as client from deluge.ui.client import sclient as client
client.set_core_uri("http://" + options.host + ":" + options.port) client.set_core_uri('http://' + options.host + ':' + options.port)
# commit configurations changes # commit configurations changes
client.set_config(settings) client.set_config(settings)

View File

@ -10,4 +10,4 @@ else:
try: try:
resource.setrlimit(resource.RLIMIT_NOFILE, (65536, 65536)) resource.setrlimit(resource.RLIMIT_NOFILE, (65536, 65536))
except (ValueError, resource.error) as ex: except (ValueError, resource.error) as ex:
print("Failed to raise file descriptor limit:", ex) print('Failed to raise file descriptor limit:', ex)

View File

@ -16,13 +16,13 @@ class BaseTestCase(unittest.TestCase):
def setUp(self): # NOQA def setUp(self): # NOQA
if len(component._ComponentRegistry.components) != 0: if len(component._ComponentRegistry.components) != 0:
warnings.warn("The component._ComponentRegistry.components is not empty on test setup.\n" warnings.warn('The component._ComponentRegistry.components is not empty on test setup.\n'
"This is probably caused by another test that didn't clean up after finishing!: %s" % "This is probably caused by another test that didn't clean up after finishing!: %s" %
component._ComponentRegistry.components) component._ComponentRegistry.components)
d = maybeDeferred(self.set_up) d = maybeDeferred(self.set_up)
def on_setup_error(error): def on_setup_error(error):
warnings.warn("Error caught in test setup!\n%s" % error.getTraceback()) warnings.warn('Error caught in test setup!\n%s' % error.getTraceback())
self.fail() self.fail()
return d.addErrback(on_setup_error) return d.addErrback(on_setup_error)
@ -31,7 +31,7 @@ class BaseTestCase(unittest.TestCase):
d = maybeDeferred(self.tear_down) d = maybeDeferred(self.tear_down)
def on_teardown_failed(error): def on_teardown_failed(error):
warnings.warn("Error caught in test teardown!\n%s" % error.getTraceback()) warnings.warn('Error caught in test teardown!\n%s' % error.getTraceback())
self.fail() self.fail()
def on_teardown_complete(result): def on_teardown_complete(result):

View File

@ -26,11 +26,11 @@ from deluge.error import DelugeError
from deluge.ui.util import lang from deluge.ui.util import lang
# This sets log level to critical, so use log.critical() to debug while running unit tests # This sets log level to critical, so use log.critical() to debug while running unit tests
deluge.log.setup_logger("none") deluge.log.setup_logger('none')
def disable_new_release_check(): def disable_new_release_check():
deluge.core.preferencesmanager.DEFAULT_PREFS["new_release_check"] = False deluge.core.preferencesmanager.DEFAULT_PREFS['new_release_check'] = False
def set_tmp_config_dir(): def set_tmp_config_dir():
@ -39,24 +39,24 @@ def set_tmp_config_dir():
return config_directory return config_directory
def setup_test_logger(level="info", prefix="deluge"): def setup_test_logger(level='info', prefix='deluge'):
deluge.log.setup_logger(level, filename="%s.log" % prefix, twisted_observer=False) deluge.log.setup_logger(level, filename='%s.log' % prefix, twisted_observer=False)
def get_test_data_file(filename): def get_test_data_file(filename):
return os.path.join(os.path.join(os.path.dirname(__file__), "data"), filename) return os.path.join(os.path.join(os.path.dirname(__file__), 'data'), filename)
def todo_test(caller): def todo_test(caller):
# If we are using the delugereporter we can set todo mark on the test # If we are using the delugereporter we can set todo mark on the test
# Without the delugereporter the todo would print a stack trace, so in # Without the delugereporter the todo would print a stack trace, so in
# that case we rely only on skipTest # that case we rely only on skipTest
if os.environ.get("DELUGE_REPORTER", None): if os.environ.get('DELUGE_REPORTER', None):
getattr(caller, caller._testMethodName).__func__.todo = "To be fixed" getattr(caller, caller._testMethodName).__func__.todo = 'To be fixed'
filename = os.path.basename(traceback.extract_stack(None, 2)[0][0]) filename = os.path.basename(traceback.extract_stack(None, 2)[0][0])
funcname = traceback.extract_stack(None, 2)[0][2] funcname = traceback.extract_stack(None, 2)[0][2]
raise unittest.SkipTest("TODO: %s:%s" % (filename, funcname)) raise unittest.SkipTest('TODO: %s:%s' % (filename, funcname))
def add_watchdog(deferred, timeout=0.05, message=None): def add_watchdog(deferred, timeout=0.05, message=None):
@ -85,9 +85,9 @@ class ReactorOverride(object):
""" """
def __getattr__(self, attr): def __getattr__(self, attr):
if attr == "run": if attr == 'run':
return self._run return self._run
if attr == "stop": if attr == 'stop':
return self._stop return self._stop
return getattr(reactor, attr) return getattr(reactor, attr)
@ -115,8 +115,8 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
""" """
self.callbacks = callbacks self.callbacks = callbacks
self.script = script self.script = script
self.log_output = "" self.log_output = ''
self.stderr_out = "" self.stderr_out = ''
self.logfile = logfile self.logfile = logfile
self.print_stderr = print_stderr self.print_stderr = print_stderr
self.quit_d = None self.quit_d = None
@ -163,24 +163,24 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
else: else:
self.quit_d.errback(status) self.quit_d.errback(status)
def check_callbacks(self, data, cb_type="stdout"): def check_callbacks(self, data, cb_type='stdout'):
ret = False ret = False
for c in self.callbacks: for c in self.callbacks:
if cb_type not in c["types"] or c["deferred"].called: if cb_type not in c['types'] or c['deferred'].called:
continue continue
for trigger in c["triggers"]: for trigger in c['triggers']:
if trigger["expr"] in data: if trigger['expr'] in data:
ret = True ret = True
if "cb" in trigger: if 'cb' in trigger:
trigger["cb"](self, c["deferred"], data, self.log_output) trigger['cb'](self, c['deferred'], data, self.log_output)
elif "value" not in trigger: elif 'value' not in trigger:
raise Exception("Trigger must specify either 'cb' or 'value'") raise Exception("Trigger must specify either 'cb' or 'value'")
else: else:
val = trigger["value"](self, data, self.log_output) val = trigger['value'](self, data, self.log_output)
if trigger.get("type", "callback") == "errback": if trigger.get('type', 'callback') == 'errback':
c["deferred"].errback(val) c['deferred'].errback(val)
else: else:
c["deferred"].callback(val) c['deferred'].callback(val)
return ret return ret
def outReceived(self, data): # NOQA def outReceived(self, data): # NOQA
@ -195,16 +195,16 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
"""Process output from stderr""" """Process output from stderr"""
self.log_output += data self.log_output += data
self.stderr_out += data self.stderr_out += data
self.check_callbacks(data, cb_type="stderr") self.check_callbacks(data, cb_type='stderr')
if not self.print_stderr: if not self.print_stderr:
return return
data = "\n%s" % data.strip() data = '\n%s' % data.strip()
prefixed = data.replace("\n", "\nSTDERR: ") prefixed = data.replace('\n', '\nSTDERR: ')
print("\n%s" % prefixed) print('\n%s' % prefixed)
def start_core(listen_port=58846, logfile=None, timeout=10, timeout_msg=None, def start_core(listen_port=58846, logfile=None, timeout=10, timeout_msg=None,
custom_script="", print_stderr=True, extra_callbacks=None): custom_script='', print_stderr=True, extra_callbacks=None):
"""Start the deluge core as a daemon. """Start the deluge core as a daemon.
Args: Args:
@ -240,18 +240,18 @@ except:
sys.stderr.write("Exception raised:\\n %%s" %% traceback.format_exc()) sys.stderr.write("Exception raised:\\n %%s" %% traceback.format_exc())
""" % (config_directory, listen_port, custom_script) """ % (config_directory, listen_port, custom_script)
callbacks = [] callbacks = []
default_core_cb = {"deferred": Deferred(), "types": "stdout"} default_core_cb = {'deferred': Deferred(), 'types': 'stdout'}
if timeout: if timeout:
default_core_cb["timeout"] = timeout default_core_cb['timeout'] = timeout
# Specify the triggers for daemon log output # Specify the triggers for daemon log output
default_core_cb["triggers"] = [ default_core_cb['triggers'] = [
{"expr": "Finished loading ", "value": lambda reader, data, data_all: reader}, {'expr': 'Finished loading ', 'value': lambda reader, data, data_all: reader},
{"expr": "Couldn't listen on localhost:%d" % (listen_port), "type": "errback", # Error from libtorrent {'expr': "Couldn't listen on localhost:%d" % (listen_port), 'type': 'errback', # Error from libtorrent
"value": lambda reader, data, data_all: CannotListenError("localhost", listen_port, 'value': lambda reader, data, data_all: CannotListenError('localhost', listen_port,
"Could not start deluge test client!\n%s" % data)}, 'Could not start deluge test client!\n%s' % data)},
{"expr": "Traceback", "type": "errback", {'expr': 'Traceback', 'type': 'errback',
"value": lambda reader, data, data_all: DelugeError("Traceback found when starting daemon:\n%s" % data)} 'value': lambda reader, data, data_all: DelugeError('Traceback found when starting daemon:\n%s' % data)}
] ]
callbacks.append(default_core_cb) callbacks.append(default_core_cb)
@ -259,7 +259,7 @@ except:
callbacks.extend(extra_callbacks) callbacks.extend(extra_callbacks)
process_protocol = start_process(daemon_script, callbacks, logfile, print_stderr) process_protocol = start_process(daemon_script, callbacks, logfile, print_stderr)
return default_core_cb["deferred"], process_protocol return default_core_cb['deferred'], process_protocol
def start_process(script, callbacks, logfile=None, print_stderr=True): def start_process(script, callbacks, logfile=None, print_stderr=True):
@ -291,8 +291,8 @@ def start_process(script, callbacks, logfile=None, print_stderr=True):
# Add timeouts to deferreds # Add timeouts to deferreds
for c in callbacks: for c in callbacks:
if "timeout" in c: if 'timeout' in c:
w = add_watchdog(c["deferred"], timeout=c["timeout"], message=c.get("timeout_msg", None)) w = add_watchdog(c['deferred'], timeout=c['timeout'], message=c.get('timeout_msg', None))
process_protocol.watchdogs.append(w) process_protocol.watchdogs.append(w)
reactor.spawnProcess(process_protocol, sys.executable, args=[sys.executable], path=cwd) reactor.spawnProcess(process_protocol, sys.executable, args=[sys.executable], path=cwd)

View File

@ -29,9 +29,9 @@ class ReactorOverride(object):
""" """
def __getattr__(self, attr): def __getattr__(self, attr):
if attr == "run": if attr == 'run':
return self._run return self._run
if attr == "stop": if attr == 'stop':
return self._stop return self._stop
return getattr(reactor, attr) return getattr(reactor, attr)
@ -59,14 +59,14 @@ class WebServerTestBase(BaseTestCase, DaemonBase):
self.webserver_listen_port = 8999 self.webserver_listen_port = 8999
config_defaults = deluge.ui.web.server.CONFIG_DEFAULTS.copy() config_defaults = deluge.ui.web.server.CONFIG_DEFAULTS.copy()
config_defaults["port"] = self.webserver_listen_port config_defaults['port'] = self.webserver_listen_port
self.config = configmanager.ConfigManager("web.conf", config_defaults) self.config = configmanager.ConfigManager('web.conf', config_defaults)
self.deluge_web = DelugeWeb(daemon=False) self.deluge_web = DelugeWeb(daemon=False)
host = list(self.deluge_web.web_api.host_list["hosts"][0]) host = list(self.deluge_web.web_api.host_list['hosts'][0])
host[2] = self.listen_port host[2] = self.listen_port
self.deluge_web.web_api.host_list["hosts"][0] = tuple(host) self.deluge_web.web_api.host_list['hosts'][0] = tuple(host)
self.host_id = host[0] self.host_id = host[0]
self.deluge_web.start() self.deluge_web.start()
@ -86,11 +86,11 @@ class WebServerMockBase(object):
def check_request(request, method=None, level=None): def check_request(request, method=None, level=None):
pass pass
self.patch(auth, "check_request", check_request) self.patch(auth, 'check_request', check_request)
def mock_compress_body(self): def mock_compress_body(self):
def compress(contents, request): def compress(contents, request):
return contents return contents
# Patch compress to avoid having to decompress output with zlib # Patch compress to avoid having to decompress output with zlib
self.patch(deluge.ui.web.json_api, "compress", compress) self.patch(deluge.ui.web.json_api, 'compress', compress)

View File

@ -21,21 +21,21 @@ class DaemonBase(object):
def terminate_core(self, *args): def terminate_core(self, *args):
if args[0] is not None: if args[0] is not None:
if hasattr(args[0], "getTraceback"): if hasattr(args[0], 'getTraceback'):
print("terminate_core: Errback Exception: %s" % args[0].getTraceback()) print('terminate_core: Errback Exception: %s' % args[0].getTraceback())
if not self.core.killed: if not self.core.killed:
d = self.core.kill() d = self.core.kill()
return d return d
@defer.inlineCallbacks @defer.inlineCallbacks
def start_core(self, arg, custom_script="", logfile="", print_stderr=True, timeout=5, def start_core(self, arg, custom_script='', logfile='', print_stderr=True, timeout=5,
port_range=10, extra_callbacks=None): port_range=10, extra_callbacks=None):
if logfile == "": if logfile == '':
logfile = "daemon_%s.log" % self.id() logfile = 'daemon_%s.log' % self.id()
# We are running py.test # We are running py.test
if hasattr(pytest, "config"): if hasattr(pytest, 'config'):
# Put log file in the py.test --basetemp argument # Put log file in the py.test --basetemp argument
basetemp = pytest.config.option.basetemp basetemp = pytest.config.option.basetemp
if basetemp: if basetemp:
@ -46,7 +46,7 @@ class DaemonBase(object):
for dummy in range(port_range): for dummy in range(port_range):
try: try:
d, self.core = common.start_core(listen_port=self.listen_port, logfile=logfile, d, self.core = common.start_core(listen_port=self.listen_port, logfile=logfile,
timeout=timeout, timeout_msg="Timeout!", timeout=timeout, timeout_msg='Timeout!',
custom_script=custom_script, custom_script=custom_script,
print_stderr=print_stderr, print_stderr=print_stderr,
extra_callbacks=extra_callbacks) extra_callbacks=extra_callbacks)

View File

@ -15,8 +15,8 @@ class AlertManagerTestCase(BaseTestCase):
def set_up(self): def set_up(self):
self.core = Core() self.core = Core()
self.am = component.get("AlertManager") self.am = component.get('AlertManager')
return component.start(["AlertManager"]) return component.start(['AlertManager'])
def tear_down(self): def tear_down(self):
return component.shutdown() return component.shutdown()
@ -25,13 +25,13 @@ class AlertManagerTestCase(BaseTestCase):
def handler(alert): def handler(alert):
return return
self.am.register_handler("dummy_alert", handler) self.am.register_handler('dummy_alert', handler)
self.assertEquals(self.am.handlers["dummy_alert"], [handler]) self.assertEquals(self.am.handlers['dummy_alert'], [handler])
def test_deregister_handler(self): def test_deregister_handler(self):
def handler(alert): def handler(alert):
return return
self.am.register_handler("dummy_alert", handler) self.am.register_handler('dummy_alert', handler)
self.am.deregister_handler(handler) self.am.deregister_handler(handler)
self.assertEquals(self.am.handlers["dummy_alert"], []) self.assertEquals(self.am.handlers['dummy_alert'], [])

View File

@ -20,7 +20,7 @@ from .daemon_base import DaemonBase
class NoVersionSendingDaemonSSLProxy(DaemonSSLProxy): class NoVersionSendingDaemonSSLProxy(DaemonSSLProxy):
def authenticate(self, username, password): def authenticate(self, username, password):
self.login_deferred = defer.Deferred() self.login_deferred = defer.Deferred()
d = self.call("daemon.login", username, password) d = self.call('daemon.login', username, password)
d.addCallback(self.__on_login, username) d.addCallback(self.__on_login, username)
d.addErrback(self.__on_login_fail) d.addErrback(self.__on_login_fail)
return self.login_deferred return self.login_deferred
@ -34,7 +34,7 @@ class NoVersionSendingDaemonSSLProxy(DaemonSSLProxy):
class NoVersionSendingClient(Client): class NoVersionSendingClient(Client):
def connect(self, host="127.0.0.1", port=58846, username="", password="", def connect(self, host='127.0.0.1', port=58846, username='', password='',
skip_authentication=False): skip_authentication=False):
self._daemon_proxy = NoVersionSendingDaemonSSLProxy() self._daemon_proxy = NoVersionSendingDaemonSSLProxy()
self._daemon_proxy.set_disconnect_callback(self.__on_disconnect) self._daemon_proxy.set_disconnect_callback(self.__on_disconnect)
@ -85,7 +85,7 @@ class ClientTestCase(BaseTestCase, DaemonBase):
return d return d
def test_connect_no_credentials(self): def test_connect_no_credentials(self):
d = client.connect("localhost", self.listen_port, username="", password="") d = client.connect('localhost', self.listen_port, username='', password='')
def on_connect(result): def on_connect(result):
self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN) self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN)
@ -97,7 +97,7 @@ class ClientTestCase(BaseTestCase, DaemonBase):
def test_connect_localclient(self): def test_connect_localclient(self):
username, password = deluge.ui.common.get_localhost_auth() username, password = deluge.ui.common.get_localhost_auth()
d = client.connect("localhost", self.listen_port, username=username, password=password) d = client.connect('localhost', self.listen_port, username=username, password=password)
def on_connect(result): def on_connect(result):
self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN) self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN)
@ -109,14 +109,14 @@ class ClientTestCase(BaseTestCase, DaemonBase):
def test_connect_bad_password(self): def test_connect_bad_password(self):
username, password = deluge.ui.common.get_localhost_auth() username, password = deluge.ui.common.get_localhost_auth()
d = client.connect("localhost", self.listen_port, username=username, password=password + "1") d = client.connect('localhost', self.listen_port, username=username, password=password + '1')
def on_failure(failure): def on_failure(failure):
self.assertEqual( self.assertEqual(
failure.trap(error.BadLoginError), failure.trap(error.BadLoginError),
error.BadLoginError error.BadLoginError
) )
self.assertEquals(failure.value.message, "Password does not match") self.assertEquals(failure.value.message, 'Password does not match')
self.addCleanup(client.disconnect) self.addCleanup(client.disconnect)
d.addCallbacks(self.fail, on_failure) d.addCallbacks(self.fail, on_failure)
@ -124,14 +124,14 @@ class ClientTestCase(BaseTestCase, DaemonBase):
def test_connect_invalid_user(self): def test_connect_invalid_user(self):
username, password = deluge.ui.common.get_localhost_auth() username, password = deluge.ui.common.get_localhost_auth()
d = client.connect("localhost", self.listen_port, username="invalid-user") d = client.connect('localhost', self.listen_port, username='invalid-user')
def on_failure(failure): def on_failure(failure):
self.assertEqual( self.assertEqual(
failure.trap(error.BadLoginError), failure.trap(error.BadLoginError),
error.BadLoginError error.BadLoginError
) )
self.assertEquals(failure.value.message, "Username does not exist") self.assertEquals(failure.value.message, 'Username does not exist')
self.addCleanup(client.disconnect) self.addCleanup(client.disconnect)
d.addCallbacks(self.fail, on_failure) d.addCallbacks(self.fail, on_failure)
@ -139,7 +139,7 @@ class ClientTestCase(BaseTestCase, DaemonBase):
def test_connect_without_password(self): def test_connect_without_password(self):
username, password = deluge.ui.common.get_localhost_auth() username, password = deluge.ui.common.get_localhost_auth()
d = client.connect("localhost", self.listen_port, username=username) d = client.connect('localhost', self.listen_port, username=username)
def on_failure(failure): def on_failure(failure):
self.assertEqual( self.assertEqual(
@ -155,16 +155,16 @@ class ClientTestCase(BaseTestCase, DaemonBase):
@defer.inlineCallbacks @defer.inlineCallbacks
def test_connect_with_password(self): def test_connect_with_password(self):
username, password = deluge.ui.common.get_localhost_auth() username, password = deluge.ui.common.get_localhost_auth()
yield client.connect("localhost", self.listen_port, username=username, password=password) yield client.connect('localhost', self.listen_port, username=username, password=password)
yield client.core.create_account("testuser", "testpw", "DEFAULT") yield client.core.create_account('testuser', 'testpw', 'DEFAULT')
yield client.disconnect() yield client.disconnect()
ret = yield client.connect("localhost", self.listen_port, username="testuser", password="testpw") ret = yield client.connect('localhost', self.listen_port, username='testuser', password='testpw')
self.assertEquals(ret, deluge.common.AUTH_LEVEL_NORMAL) self.assertEquals(ret, deluge.common.AUTH_LEVEL_NORMAL)
yield yield
@defer.inlineCallbacks @defer.inlineCallbacks
def test_invalid_rpc_method_call(self): def test_invalid_rpc_method_call(self):
yield client.connect("localhost", self.listen_port, username="", password="") yield client.connect('localhost', self.listen_port, username='', password='')
d = client.core.invalid_method() d = client.core.invalid_method()
def on_failure(failure): def on_failure(failure):
@ -177,7 +177,7 @@ class ClientTestCase(BaseTestCase, DaemonBase):
username, password = deluge.ui.common.get_localhost_auth() username, password = deluge.ui.common.get_localhost_auth()
no_version_sending_client = NoVersionSendingClient() no_version_sending_client = NoVersionSendingClient()
d = no_version_sending_client.connect( d = no_version_sending_client.connect(
"localhost", self.listen_port, username=username, password=password 'localhost', self.listen_port, username=username, password=password
) )
def on_failure(failure): def on_failure(failure):

View File

@ -15,95 +15,95 @@ class CommonTestCase(unittest.TestCase):
pass pass
def test_fsize(self): def test_fsize(self):
self.assertEquals(fsize(0), "0 B") self.assertEquals(fsize(0), '0 B')
self.assertEquals(fsize(100), "100 B") self.assertEquals(fsize(100), '100 B')
self.assertEquals(fsize(1023), "1023 B") self.assertEquals(fsize(1023), '1023 B')
self.assertEquals(fsize(1024), "1.0 KiB") self.assertEquals(fsize(1024), '1.0 KiB')
self.assertEquals(fsize(1048575), "1024.0 KiB") self.assertEquals(fsize(1048575), '1024.0 KiB')
self.assertEquals(fsize(1048576), "1.0 MiB") self.assertEquals(fsize(1048576), '1.0 MiB')
self.assertEquals(fsize(1073741823), "1024.0 MiB") self.assertEquals(fsize(1073741823), '1024.0 MiB')
self.assertEquals(fsize(1073741824), "1.0 GiB") self.assertEquals(fsize(1073741824), '1.0 GiB')
self.assertEquals(fsize(112245), "109.6 KiB") self.assertEquals(fsize(112245), '109.6 KiB')
self.assertEquals(fsize(110723441824), "103.1 GiB") self.assertEquals(fsize(110723441824), '103.1 GiB')
self.assertEquals(fsize(1099511627775), "1024.0 GiB") self.assertEquals(fsize(1099511627775), '1024.0 GiB')
self.assertEquals(fsize(1099511627777), "1.0 TiB") self.assertEquals(fsize(1099511627777), '1.0 TiB')
self.assertEquals(fsize(766148267453245), "696.8 TiB") self.assertEquals(fsize(766148267453245), '696.8 TiB')
def test_fpcnt(self): def test_fpcnt(self):
self.failUnless(fpcnt(0.9311) == "93.11%") self.failUnless(fpcnt(0.9311) == '93.11%')
def test_fspeed(self): def test_fspeed(self):
self.failUnless(fspeed(43134) == "42.1 KiB/s") self.failUnless(fspeed(43134) == '42.1 KiB/s')
def test_fpeer(self): def test_fpeer(self):
self.failUnless(fpeer(10, 20) == "10 (20)") self.failUnless(fpeer(10, 20) == '10 (20)')
self.failUnless(fpeer(10, -1) == "10") self.failUnless(fpeer(10, -1) == '10')
def test_ftime(self): def test_ftime(self):
self.failUnless(ftime(0) == "") self.failUnless(ftime(0) == '')
self.failUnless(ftime(5) == "5s") self.failUnless(ftime(5) == '5s')
self.failUnless(ftime(100) == "1m 40s") self.failUnless(ftime(100) == '1m 40s')
self.failUnless(ftime(3789) == "1h 3m") self.failUnless(ftime(3789) == '1h 3m')
self.failUnless(ftime(23011) == "6h 23m") self.failUnless(ftime(23011) == '6h 23m')
self.failUnless(ftime(391187) == "4d 12h") self.failUnless(ftime(391187) == '4d 12h')
self.failUnless(ftime(604800) == "1w 0d") self.failUnless(ftime(604800) == '1w 0d')
self.failUnless(ftime(13893086) == "22w 6d") self.failUnless(ftime(13893086) == '22w 6d')
self.failUnless(ftime(59740269) == "1y 46w") self.failUnless(ftime(59740269) == '1y 46w')
def test_fdate(self): def test_fdate(self):
self.failUnless(fdate(-1) == "") self.failUnless(fdate(-1) == '')
def test_is_url(self): def test_is_url(self):
self.failUnless(is_url("http://deluge-torrent.org")) self.failUnless(is_url('http://deluge-torrent.org'))
self.failIf(is_url("file://test.torrent")) self.failIf(is_url('file://test.torrent'))
def test_is_magnet(self): def test_is_magnet(self):
self.failUnless(is_magnet("magnet:?xt=urn:btih:SU5225URMTUEQLDXQWRB2EQWN6KLTYKN")) self.failUnless(is_magnet('magnet:?xt=urn:btih:SU5225URMTUEQLDXQWRB2EQWN6KLTYKN'))
def test_is_infohash(self): def test_is_infohash(self):
self.failUnless(is_infohash("2dc5d0e71a66fe69649a640d39cb00a259704973")) self.failUnless(is_infohash('2dc5d0e71a66fe69649a640d39cb00a259704973'))
def test_get_path_size(self): def test_get_path_size(self):
self.failUnless(get_path_size(os.devnull) == 0) self.failUnless(get_path_size(os.devnull) == 0)
self.failUnless(get_path_size("non-existant.file") == -1) self.failUnless(get_path_size('non-existant.file') == -1)
def test_is_ip(self): def test_is_ip(self):
self.failUnless(is_ip("127.0.0.1")) self.failUnless(is_ip('127.0.0.1'))
self.failIf(is_ip("127..0.0")) self.failIf(is_ip('127..0.0'))
def test_version_split(self): def test_version_split(self):
self.failUnless(VersionSplit("1.2.2") == VersionSplit("1.2.2")) self.failUnless(VersionSplit('1.2.2') == VersionSplit('1.2.2'))
self.failUnless(VersionSplit("1.2.1") < VersionSplit("1.2.2")) self.failUnless(VersionSplit('1.2.1') < VersionSplit('1.2.2'))
self.failUnless(VersionSplit("1.1.9") < VersionSplit("1.2.2")) self.failUnless(VersionSplit('1.1.9') < VersionSplit('1.2.2'))
self.failUnless(VersionSplit("1.2.2") > VersionSplit("1.2.1")) self.failUnless(VersionSplit('1.2.2') > VersionSplit('1.2.1'))
self.failUnless(VersionSplit("1.2.2") < VersionSplit("1.2.2-dev")) self.failUnless(VersionSplit('1.2.2') < VersionSplit('1.2.2-dev'))
self.failUnless(VersionSplit("1.2.2-dev") < VersionSplit("1.3.0-rc2")) self.failUnless(VersionSplit('1.2.2-dev') < VersionSplit('1.3.0-rc2'))
self.failUnless(VersionSplit("1.2.2") > VersionSplit("1.2.2-rc2")) self.failUnless(VersionSplit('1.2.2') > VersionSplit('1.2.2-rc2'))
self.failUnless(VersionSplit("1.2.2-rc2-dev") > VersionSplit("1.2.2-rc2")) self.failUnless(VersionSplit('1.2.2-rc2-dev') > VersionSplit('1.2.2-rc2'))
self.failUnless(VersionSplit("1.2.2-rc3") > VersionSplit("1.2.2-rc2")) self.failUnless(VersionSplit('1.2.2-rc3') > VersionSplit('1.2.2-rc2'))
self.failUnless(VersionSplit("0.14.9") == VersionSplit("0.14.9")) self.failUnless(VersionSplit('0.14.9') == VersionSplit('0.14.9'))
self.failUnless(VersionSplit("0.14.9") > VersionSplit("0.14.5")) self.failUnless(VersionSplit('0.14.9') > VersionSplit('0.14.5'))
self.failUnless(VersionSplit("0.14.10") >= VersionSplit("0.14.9")) self.failUnless(VersionSplit('0.14.10') >= VersionSplit('0.14.9'))
self.failUnless(VersionSplit("1.4.0") > VersionSplit("1.3.900.dev123")) self.failUnless(VersionSplit('1.4.0') > VersionSplit('1.3.900.dev123'))
self.failUnless(VersionSplit("1.3.2rc2.dev1") < VersionSplit("1.3.2-rc2")) self.failUnless(VersionSplit('1.3.2rc2.dev1') < VersionSplit('1.3.2-rc2'))
self.failUnless(VersionSplit("1.3.900.dev888") > VersionSplit("1.3.900.dev123")) self.failUnless(VersionSplit('1.3.900.dev888') > VersionSplit('1.3.900.dev123'))
self.failUnless(VersionSplit("1.4.0") > VersionSplit("1.4.0.dev123")) self.failUnless(VersionSplit('1.4.0') > VersionSplit('1.4.0.dev123'))
self.failUnless(VersionSplit("1.4.0.dev1") < VersionSplit("1.4.0")) self.failUnless(VersionSplit('1.4.0.dev1') < VersionSplit('1.4.0'))
self.failUnless(VersionSplit("1.4.0a1") < VersionSplit("1.4.0")) self.failUnless(VersionSplit('1.4.0a1') < VersionSplit('1.4.0'))
def test_parse_human_size(self): def test_parse_human_size(self):
from deluge.common import parse_human_size from deluge.common import parse_human_size
sizes = [("1", 1), sizes = [('1', 1),
("10 bytes", 10), ('10 bytes', 10),
("2048 bytes", 2048), ('2048 bytes', 2048),
("1MiB", 2**(10 * 2)), ('1MiB', 2**(10 * 2)),
("1 MiB", 2**(10 * 2)), ('1 MiB', 2**(10 * 2)),
("1 GiB", 2**(10 * 3)), ('1 GiB', 2**(10 * 3)),
("1 GiB", 2**(10 * 3)), ('1 GiB', 2**(10 * 3)),
("1M", 10**6), ('1M', 10**6),
("1MB", 10**6), ('1MB', 10**6),
("1 GB", 10**9), ('1 GB', 10**9),
("1 TB", 10**12)] ('1 TB', 10**12)]
for human_size, byte_size in sizes: for human_size, byte_size in sizes:
parsed = parse_human_size(human_size) parsed = parse_human_size(human_size)

View File

@ -69,41 +69,41 @@ class ComponentTestClass(BaseTestCase):
def test_start_component(self): def test_start_component(self):
def on_start(result, c): def on_start(result, c):
self.assertEquals(c._component_state, "Started") self.assertEquals(c._component_state, 'Started')
self.assertEquals(c.start_count, 1) self.assertEquals(c.start_count, 1)
c = ComponentTester("test_start_c1") c = ComponentTester('test_start_c1')
d = component.start(["test_start_c1"]) d = component.start(['test_start_c1'])
d.addCallback(on_start, c) d.addCallback(on_start, c)
return d return d
def test_start_stop_depends(self): def test_start_stop_depends(self):
def on_stop(result, c1, c2): def on_stop(result, c1, c2):
self.assertEquals(c1._component_state, "Stopped") self.assertEquals(c1._component_state, 'Stopped')
self.assertEquals(c2._component_state, "Stopped") self.assertEquals(c2._component_state, 'Stopped')
self.assertEquals(c1.stop_count, 1) self.assertEquals(c1.stop_count, 1)
self.assertEquals(c2.stop_count, 1) self.assertEquals(c2.stop_count, 1)
def on_start(result, c1, c2): def on_start(result, c1, c2):
self.assertEquals(c1._component_state, "Started") self.assertEquals(c1._component_state, 'Started')
self.assertEquals(c2._component_state, "Started") self.assertEquals(c2._component_state, 'Started')
self.assertEquals(c1.start_count, 1) self.assertEquals(c1.start_count, 1)
self.assertEquals(c2.start_count, 1) self.assertEquals(c2.start_count, 1)
return component.stop(["test_start_depends_c1"]).addCallback(on_stop, c1, c2) return component.stop(['test_start_depends_c1']).addCallback(on_stop, c1, c2)
c1 = ComponentTester("test_start_depends_c1") c1 = ComponentTester('test_start_depends_c1')
c2 = ComponentTester("test_start_depends_c2", depend=["test_start_depends_c1"]) c2 = ComponentTester('test_start_depends_c2', depend=['test_start_depends_c1'])
d = component.start(["test_start_depends_c2"]) d = component.start(['test_start_depends_c2'])
d.addCallback(on_start, c1, c2) d.addCallback(on_start, c1, c2)
return d return d
def start_with_depends(self): def start_with_depends(self):
c1 = ComponentTesterDelayStart("test_start_all_c1") c1 = ComponentTesterDelayStart('test_start_all_c1')
c2 = ComponentTester("test_start_all_c2", depend=["test_start_all_c4"]) c2 = ComponentTester('test_start_all_c2', depend=['test_start_all_c4'])
c3 = ComponentTesterDelayStart("test_start_all_c3", depend=["test_start_all_c5", "test_start_all_c1"]) c3 = ComponentTesterDelayStart('test_start_all_c3', depend=['test_start_all_c5', 'test_start_all_c1'])
c4 = ComponentTester("test_start_all_c4", depend=["test_start_all_c3"]) c4 = ComponentTester('test_start_all_c4', depend=['test_start_all_c3'])
c5 = ComponentTester("test_start_all_c5") c5 = ComponentTester('test_start_all_c5')
d = component.start() d = component.start()
return (d, c1, c2, c3, c4, c5) return (d, c1, c2, c3, c4, c5)
@ -115,7 +115,7 @@ class ComponentTestClass(BaseTestCase):
def test_start_all(self): def test_start_all(self):
def on_start(*args): def on_start(*args):
for c in args[1:]: for c in args[1:]:
self.assertEquals(c._component_state, "Started") self.assertEquals(c._component_state, 'Started')
self.assertEquals(c.start_count, 1) self.assertEquals(c.start_count, 1)
ret = self.start_with_depends() ret = self.start_with_depends()
@ -124,36 +124,36 @@ class ComponentTestClass(BaseTestCase):
return ret[0] return ret[0]
def test_register_exception(self): def test_register_exception(self):
ComponentTester("test_register_exception_c1") ComponentTester('test_register_exception_c1')
self.assertRaises( self.assertRaises(
component.ComponentAlreadyRegistered, component.ComponentAlreadyRegistered,
ComponentTester, ComponentTester,
"test_register_exception_c1") 'test_register_exception_c1')
def test_stop_component(self): def test_stop_component(self):
def on_stop(result, c): def on_stop(result, c):
self.assertEquals(c._component_state, "Stopped") self.assertEquals(c._component_state, 'Stopped')
self.assertFalse(c._component_timer.running) self.assertFalse(c._component_timer.running)
self.assertEquals(c.stop_count, 1) self.assertEquals(c.stop_count, 1)
def on_start(result, c): def on_start(result, c):
self.assertEquals(c._component_state, "Started") self.assertEquals(c._component_state, 'Started')
return component.stop(["test_stop_component_c1"]).addCallback(on_stop, c) return component.stop(['test_stop_component_c1']).addCallback(on_stop, c)
c = ComponentTesterUpdate("test_stop_component_c1") c = ComponentTesterUpdate('test_stop_component_c1')
d = component.start(["test_stop_component_c1"]) d = component.start(['test_stop_component_c1'])
d.addCallback(on_start, c) d.addCallback(on_start, c)
return d return d
def test_stop_all(self): def test_stop_all(self):
def on_stop(result, *args): def on_stop(result, *args):
for c in args: for c in args:
self.assertEquals(c._component_state, "Stopped") self.assertEquals(c._component_state, 'Stopped')
self.assertEquals(c.stop_count, 1) self.assertEquals(c.stop_count, 1)
def on_start(result, *args): def on_start(result, *args):
for c in args: for c in args:
self.assertEquals(c._component_state, "Started") self.assertEquals(c._component_state, 'Started')
return component.stop().addCallback(on_stop, *args) return component.stop().addCallback(on_stop, *args)
ret = self.start_with_depends() ret = self.start_with_depends()
@ -168,50 +168,50 @@ class ComponentTestClass(BaseTestCase):
self.assertNotEqual(c1.counter, counter) self.assertNotEqual(c1.counter, counter)
return component.stop() return component.stop()
c1 = ComponentTesterUpdate("test_update_c1") c1 = ComponentTesterUpdate('test_update_c1')
cnt = int(c1.counter) cnt = int(c1.counter)
d = component.start(["test_update_c1"]) d = component.start(['test_update_c1'])
d.addCallback(on_start, c1, cnt) d.addCallback(on_start, c1, cnt)
return d return d
def test_pause(self): def test_pause(self):
def on_pause(result, c1, counter): def on_pause(result, c1, counter):
self.assertEqual(c1._component_state, "Paused") self.assertEqual(c1._component_state, 'Paused')
self.assertNotEqual(c1.counter, counter) self.assertNotEqual(c1.counter, counter)
self.assertFalse(c1._component_timer.running) self.assertFalse(c1._component_timer.running)
def on_start(result, c1, counter): def on_start(result, c1, counter):
self.assertTrue(c1._component_timer) self.assertTrue(c1._component_timer)
self.assertNotEqual(c1.counter, counter) self.assertNotEqual(c1.counter, counter)
d = component.pause(["test_pause_c1"]) d = component.pause(['test_pause_c1'])
d.addCallback(on_pause, c1, counter) d.addCallback(on_pause, c1, counter)
return d return d
c1 = ComponentTesterUpdate("test_pause_c1") c1 = ComponentTesterUpdate('test_pause_c1')
cnt = int(c1.counter) cnt = int(c1.counter)
d = component.start(["test_pause_c1"]) d = component.start(['test_pause_c1'])
d.addCallback(on_start, c1, cnt) d.addCallback(on_start, c1, cnt)
return d return d
@defer.inlineCallbacks @defer.inlineCallbacks
def test_component_start_error(self): def test_component_start_error(self):
ComponentTesterUpdate("test_pause_c1") ComponentTesterUpdate('test_pause_c1')
yield component.start(["test_pause_c1"]) yield component.start(['test_pause_c1'])
yield component.pause(["test_pause_c1"]) yield component.pause(['test_pause_c1'])
test_comp = component.get("test_pause_c1") test_comp = component.get('test_pause_c1')
try: try:
result = self.failureResultOf(test_comp._component_start()) result = self.failureResultOf(test_comp._component_start())
except AttributeError: except AttributeError:
raise SkipTest("This test requires trial failureResultOf() in Twisted version >= 13") raise SkipTest('This test requires trial failureResultOf() in Twisted version >= 13')
self.assertEqual(result.check(component.ComponentException), component.ComponentException) self.assertEqual(result.check(component.ComponentException), component.ComponentException)
@defer.inlineCallbacks @defer.inlineCallbacks
def test_start_paused_error(self): def test_start_paused_error(self):
ComponentTesterUpdate("test_pause_c1") ComponentTesterUpdate('test_pause_c1')
yield component.start(["test_pause_c1"]) yield component.start(['test_pause_c1'])
yield component.pause(["test_pause_c1"]) yield component.pause(['test_pause_c1'])
# Deferreds that fail in component have to error handler which results in # Deferreds that fail in component have to error handler which results in
# twisted doing a log.err call which causes the test to fail. # twisted doing a log.err call which causes the test to fail.
@ -223,12 +223,12 @@ class ComponentTestClass(BaseTestCase):
[(defer.FAILURE, [(defer.FAILURE,
component.ComponentException("Trying to start a component ('%s') not in " component.ComponentException("Trying to start a component ('%s') not in "
"stopped state. Current state: '%s'" % "stopped state. Current state: '%s'" %
("test_pause_c1", "Paused"), ""))]) ('test_pause_c1', 'Paused'), ''))])
def test_shutdown(self): def test_shutdown(self):
def on_shutdown(result, c1): def on_shutdown(result, c1):
self.assertTrue(c1.shutdowned) self.assertTrue(c1.shutdowned)
self.assertEquals(c1._component_state, "Stopped") self.assertEquals(c1._component_state, 'Stopped')
self.assertEquals(c1.stop_count, 1) self.assertEquals(c1.stop_count, 1)
def on_start(result, c1): def on_start(result, c1):
@ -236,7 +236,7 @@ class ComponentTestClass(BaseTestCase):
d.addCallback(on_shutdown, c1) d.addCallback(on_shutdown, c1)
return d return d
c1 = ComponentTesterShutdown("test_shutdown_c1") c1 = ComponentTesterShutdown('test_shutdown_c1')
d = component.start(["test_shutdown_c1"]) d = component.start(['test_shutdown_c1'])
d.addCallback(on_start, c1) d.addCallback(on_start, c1)
return d return d

View File

@ -10,7 +10,7 @@ from deluge.config import Config
from .common import set_tmp_config_dir from .common import set_tmp_config_dir
DEFAULTS = {"string": "foobar", "int": 1, "float": 0.435, "bool": True, "unicode": u"foobar"} DEFAULTS = {'string': 'foobar', 'int': 1, 'float': 0.435, 'bool': True, 'unicode': u'foobar'}
class ConfigTestCase(unittest.TestCase): class ConfigTestCase(unittest.TestCase):
@ -18,102 +18,102 @@ class ConfigTestCase(unittest.TestCase):
self.config_dir = set_tmp_config_dir() self.config_dir = set_tmp_config_dir()
def test_init(self): def test_init(self):
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir) config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
self.assertEquals(DEFAULTS, config.config) self.assertEquals(DEFAULTS, config.config)
config = Config("test.conf", config_dir=self.config_dir) config = Config('test.conf', config_dir=self.config_dir)
self.assertEquals({}, config.config) self.assertEquals({}, config.config)
def test_set_get_item(self): def test_set_get_item(self):
config = Config("test.conf", config_dir=self.config_dir) config = Config('test.conf', config_dir=self.config_dir)
config["foo"] = 1 config['foo'] = 1
self.assertEquals(config["foo"], 1) self.assertEquals(config['foo'], 1)
self.assertRaises(ValueError, config.set_item, "foo", "bar") self.assertRaises(ValueError, config.set_item, 'foo', 'bar')
config["foo"] = 2 config['foo'] = 2
self.assertEquals(config.get_item("foo"), 2) self.assertEquals(config.get_item('foo'), 2)
config["foo"] = "3" config['foo'] = '3'
self.assertEquals(config.get_item("foo"), 3) self.assertEquals(config.get_item('foo'), 3)
config["unicode"] = u"ВИДЕОФИЛЬМЫ" config['unicode'] = u'ВИДЕОФИЛЬМЫ'
self.assertEquals(config["unicode"], u"ВИДЕОФИЛЬМЫ") self.assertEquals(config['unicode'], u'ВИДЕОФИЛЬМЫ')
config["unicode"] = "foostring" config['unicode'] = 'foostring'
self.assertTrue(isinstance(config.get_item("unicode"), unicode)) self.assertTrue(isinstance(config.get_item('unicode'), unicode))
config._save_timer.cancel() config._save_timer.cancel()
def test_set_get_item_none(self): def test_set_get_item_none(self):
config = Config("test.conf", config_dir=self.config_dir) config = Config('test.conf', config_dir=self.config_dir)
config["foo"] = None config['foo'] = None
self.assertIsNone(config["foo"]) self.assertIsNone(config['foo'])
self.assertIsInstance(config["foo"], type(None)) self.assertIsInstance(config['foo'], type(None))
config["foo"] = 1 config['foo'] = 1
self.assertEquals(config.get("foo"), 1) self.assertEquals(config.get('foo'), 1)
config["foo"] = None config['foo'] = None
self.assertIsNone(config["foo"]) self.assertIsNone(config['foo'])
config["bar"] = None config['bar'] = None
self.assertIsNone(config["bar"]) self.assertIsNone(config['bar'])
config["bar"] = None config['bar'] = None
self.assertIsNone(config["bar"]) self.assertIsNone(config['bar'])
config._save_timer.cancel() config._save_timer.cancel()
def test_get(self): def test_get(self):
config = Config("test.conf", config_dir=self.config_dir) config = Config('test.conf', config_dir=self.config_dir)
config["foo"] = 1 config['foo'] = 1
self.assertEquals(config.get("foo"), 1) self.assertEquals(config.get('foo'), 1)
self.assertEquals(config.get("foobar"), None) self.assertEquals(config.get('foobar'), None)
self.assertEquals(config.get("foobar", 2), 2) self.assertEquals(config.get('foobar', 2), 2)
config["foobar"] = 5 config['foobar'] = 5
self.assertEquals(config.get("foobar", 2), 5) self.assertEquals(config.get('foobar', 2), 5)
def test_load(self): def test_load(self):
def check_config(): def check_config():
config = Config("test.conf", config_dir=self.config_dir) config = Config('test.conf', config_dir=self.config_dir)
self.assertEquals(config["string"], "foobar") self.assertEquals(config['string'], 'foobar')
self.assertEquals(config["float"], 0.435) self.assertEquals(config['float'], 0.435)
# Test loading an old config from 1.1.x # Test loading an old config from 1.1.x
import pickle import pickle
with open(os.path.join(self.config_dir, "test.conf"), "wb") as _file: with open(os.path.join(self.config_dir, 'test.conf'), 'wb') as _file:
pickle.dump(DEFAULTS, _file) pickle.dump(DEFAULTS, _file)
check_config() check_config()
# Test opening a previous 1.2 config file of just a json object # Test opening a previous 1.2 config file of just a json object
import json import json
with open(os.path.join(self.config_dir, "test.conf"), "wb") as _file: with open(os.path.join(self.config_dir, 'test.conf'), 'wb') as _file:
json.dump(DEFAULTS, _file, indent=2) json.dump(DEFAULTS, _file, indent=2)
check_config() check_config()
# Test opening a previous 1.2 config file of having the format versions # Test opening a previous 1.2 config file of having the format versions
# as ints # as ints
with open(os.path.join(self.config_dir, "test.conf"), "wb") as _file: with open(os.path.join(self.config_dir, 'test.conf'), 'wb') as _file:
_file.write(str(1) + "\n") _file.write(str(1) + '\n')
_file.write(str(1) + "\n") _file.write(str(1) + '\n')
json.dump(DEFAULTS, _file, indent=2) json.dump(DEFAULTS, _file, indent=2)
check_config() check_config()
# Test the 1.2 config format # Test the 1.2 config format
version = {"format": 1, "file": 1} version = {'format': 1, 'file': 1}
with open(os.path.join(self.config_dir, "test.conf"), "wb") as _file: with open(os.path.join(self.config_dir, 'test.conf'), 'wb') as _file:
json.dump(version, _file, indent=2) json.dump(version, _file, indent=2)
json.dump(DEFAULTS, _file, indent=2) json.dump(DEFAULTS, _file, indent=2)
check_config() check_config()
def test_save(self): def test_save(self):
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir) config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
# We do this twice because the first time we need to save the file to disk # We do this twice because the first time we need to save the file to disk
# and the second time we do a compare and we should not write # and the second time we do a compare and we should not write
ret = config.save() ret = config.save()
@ -121,23 +121,23 @@ class ConfigTestCase(unittest.TestCase):
ret = config.save() ret = config.save()
self.assertTrue(ret) self.assertTrue(ret)
config["string"] = "baz" config['string'] = 'baz'
config["int"] = 2 config['int'] = 2
ret = config.save() ret = config.save()
self.assertTrue(ret) self.assertTrue(ret)
del config del config
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir) config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
self.assertEquals(config["string"], "baz") self.assertEquals(config['string'], 'baz')
self.assertEquals(config["int"], 2) self.assertEquals(config['int'], 2)
def test_save_timer(self): def test_save_timer(self):
self.clock = task.Clock() self.clock = task.Clock()
deluge.config.callLater = self.clock.callLater deluge.config.callLater = self.clock.callLater
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir) config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
config["string"] = "baz" config['string'] = 'baz'
config["int"] = 2 config['int'] = 2
self.assertTrue(config._save_timer.active()) self.assertTrue(config._save_timer.active())
# Timeout set for 5 seconds in config, so lets move clock by 5 seconds # Timeout set for 5 seconds in config, so lets move clock by 5 seconds
@ -146,9 +146,9 @@ class ConfigTestCase(unittest.TestCase):
def check_config(config): def check_config(config):
self.assertTrue(not config._save_timer.active()) self.assertTrue(not config._save_timer.active())
del config del config
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir) config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
self.assertEquals(config["string"], "baz") self.assertEquals(config['string'], 'baz')
self.assertEquals(config["int"], 2) self.assertEquals(config['int'], 2)
check_config(config) check_config(config)

Some files were not shown because too many files have changed in this diff Show More