summaryrefslogtreecommitdiffstats
path: root/deluge/ui
diff options
context:
space:
mode:
authorCalum Lind <calumlind+deluge@gmail.com>2014-09-03 22:28:28 +0100
committerCalum Lind <calumlind+deluge@gmail.com>2014-09-03 23:48:34 +0100
commit5167e93d12cb9f3c43ab2cecdac3961dac6b0fb2 (patch)
tree92c4504c3943999836edeeaee2b52af3f04dd6c4 /deluge/ui
parent5d88504c34bab3d00c338ad7f5da7048beba9223 (diff)
downloaddeluge-5167e93d12cb9f3c43ab2cecdac3961dac6b0fb2.tar.gz
deluge-5167e93d12cb9f3c43ab2cecdac3961dac6b0fb2.tar.bz2
deluge-5167e93d12cb9f3c43ab2cecdac3961dac6b0fb2.zip
Flake8 core and common files
* Added N802 to flake8 ignore as certain inherited funcs cannot be changed to lowercase and this unresolved warning hides other errors/warnings. * Include new header
Diffstat (limited to 'deluge/ui')
-rw-r--r--deluge/ui/Win32IconImagePlugin.py385
-rw-r--r--deluge/ui/client.py60
-rw-r--r--deluge/ui/common.py58
-rw-r--r--deluge/ui/coreconfig.py37
-rw-r--r--deluge/ui/sessionproxy.py42
-rw-r--r--deluge/ui/tracker_icons.py69
-rw-r--r--deluge/ui/ui.py57
-rw-r--r--deluge/ui/web/__init__.py1
-rw-r--r--deluge/ui/web/auth.py6
-rw-r--r--deluge/ui/web/json_api.py2
-rw-r--r--deluge/ui/web/server.py2
11 files changed, 282 insertions, 437 deletions
diff --git a/deluge/ui/Win32IconImagePlugin.py b/deluge/ui/Win32IconImagePlugin.py
index ae6c6c3e7..d46d057ca 100644
--- a/deluge/ui/Win32IconImagePlugin.py
+++ b/deluge/ui/Win32IconImagePlugin.py
@@ -57,220 +57,199 @@ _MAGIC = '\0\0\1\0'
log = logging.getLogger(__name__)
-class Win32IcoFile (object):
- """
- Decoder for Microsoft .ico files.
- """
-
- def __init__ (self, buf):
- """
- Args:
- buf: file-like object containing ico file data
- """
- self.buf = buf
- self.entry = []
-
- header = struct.unpack('<3H', buf.read(6))
- if (0, 1) != header[:2]:
- raise SyntaxError('not an ico file')
-
- self.nb_items = header[2]
-
- dir_fields = ('width', 'height', 'nb_color', 'reserved', 'planes', 'bpp',
- 'size', 'offset')
- for i in xrange(self.nb_items):
- directory = list(struct.unpack('<4B2H2I', buf.read(16)))
- for j in xrange(3):
- if not directory[j]:
- directory[j] = 256
- icon_header = dict(zip(dir_fields, directory))
- icon_header['color_depth'] = (
- icon_header['bpp'] or
- (icon_header['nb_color'] == 16 and 4))
- icon_header['dim'] = (icon_header['width'], icon_header['height'])
- self.entry.append(icon_header)
- #end for (read headers)
-
- # order by size and color depth
- self.entry.sort(lambda x, y: \
- cmp(x['width'], y['width']) or cmp(x['color_depth'], y['color_depth']))
- self.entry.reverse()
- #end __init__
-
-
- def sizes (self):
- """
- Get a list of all available icon sizes and color depths.
- """
- return set((h['width'], h['height']) for h in self.entry)
- #end sizes
-
+class Win32IcoFile(object):
+ """Decoder for Microsoft .ico files."""
+
+ def __init__(self, buf):
+ """
+ Args:
+ buf: file-like object containing ico file data
+ """
+ self.buf = buf
+ self.entry = []
+
+ header = struct.unpack('<3H', buf.read(6))
+ if (0, 1) != header[:2]:
+ raise SyntaxError('not an ico file')
+
+ self.nb_items = header[2]
+
+ dir_fields = ('width', 'height', 'nb_color', 'reserved', 'planes', 'bpp', 'size', 'offset')
+ for i in xrange(self.nb_items):
+ directory = list(struct.unpack('<4B2H2I', buf.read(16)))
+ for j in xrange(3):
+ if not directory[j]:
+ directory[j] = 256
+ icon_header = dict(zip(dir_fields, directory))
+ icon_header['color_depth'] = (icon_header['bpp'] or (icon_header['nb_color'] == 16 and 4))
+ icon_header['dim'] = (icon_header['width'], icon_header['height'])
+ self.entry.append(icon_header)
+ #end for (read headers)
+
+ # order by size and color depth
+ self.entry.sort(lambda x, y: cmp(x['width'], y['width'])
+ or cmp(x['color_depth'], y['color_depth']))
+ self.entry.reverse()
+
+ def sizes(self):
+ """Get a list of all available icon sizes and color depths."""
+ return set((h['width'], h['height']) for h in self.entry)
+
+ def get_image(self, size, bpp=False):
+ """Get an image from the icon
+
+ Args:
+ size: tuple of (width, height)
+ bpp: color depth
+ """
+ for i in range(self.nb_items):
+ h = self.entry[i]
+ if size == h['dim'] and (bpp is False or bpp == h['color_depth']):
+ return self.frame(i)
+
+ return self.frame(0)
+
+ def frame(self, idx):
+ """
+ Get the icon from frame idx
+
+ Args:
+ idx: Frame index
+
+ Returns:
+ PIL.Image
+ """
+ header = self.entry[idx]
+ self.buf.seek(header['offset'])
+ data = self.buf.read(8)
+ self.buf.seek(header['offset'])
+ if data[:8] == PIL.PngImagePlugin._MAGIC:
+ # png frame
+ im = PIL.PngImagePlugin.PngImageFile(self.buf)
+
+ else:
+ # XOR + AND mask bmp frame
+ im = PIL.BmpImagePlugin.DibImageFile(self.buf)
+ log.debug("Loaded image: %s %s %s %s", im.format, im.mode, im.size, im.info)
+
+ # change tile dimension to only encompass XOR image
+ im.size = im.size[0], im.size[1] / 2
+ d, e, o, a = im.tile[0]
+ im.tile[0] = d, (0, 0) + im.size, o, a
+
+ # figure out where AND mask image starts
+ mode = a[0]
+ bpp = 8
+ for k in PIL.BmpImagePlugin.BIT2MODE.keys():
+ if mode == PIL.BmpImagePlugin.BIT2MODE[k][1]:
+ bpp = k
+ break
+ #end for
+ log.debug("o:%s, w:%s, h:%s, bpp:%s", o, im.size[0], im.size[1], bpp)
+ and_mask_offset = o + (im.size[0] * im.size[1] * (bpp / 8.0))
+
+ if 32 == bpp:
+ # 32-bit color depth icon image allows semitransparent areas
+ # PIL's DIB format ignores transparency bits, recover them
+ # The DIB is packed in BGRX byte order where X is the alpha channel
+
+ # Back up to start of bmp data
+ self.buf.seek(o)
+ # extract every 4th byte (eg. 3,7,11,15,...)
+ alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4]
+
+ # convert to an 8bpp grayscale image
+ mask = PIL.Image.frombuffer(
+ 'L', # 8bpp
+ im.size, # (w, h)
+ alpha_bytes, # source chars
+ 'raw', # raw decoder
+ ('L', 0, -1) # 8bpp inverted, unpadded, reversed
+ )
+
+ # apply mask image as alpha channel
+ im = im.convert('RGBA')
+ im.putalpha(mask)
+ log.debug("image mode: %s", im.mode)
+
+ else:
+ # get AND image from end of bitmap
+ w = im.size[0]
+ if (w % 32) > 0:
+ # bitmap row data is aligned to word boundaries
+ w += 32 - (im.size[0] % 32)
+ # the total mask data is padded row size * height / bits per char
+ total_bytes = long((w * im.size[1]) / 8)
+ log.debug("tot=%d, off=%d, w=%d, size=%d", len(data), and_mask_offset, w, total_bytes)
+
+ self.buf.seek(and_mask_offset)
+ mask_data = self.buf.read(total_bytes)
+
+ # convert raw data to image
+ mask = PIL.Image.frombuffer(
+ '1', # 1 bpp
+ im.size, # (w, h)
+ mask_data, # source chars
+ 'raw', # raw decoder
+ ('1;I', int(w / 8), -1) # 1bpp inverted, padded, reversed
+ )
+
+ # now we have two images, im is XOR image and mask is AND image
+ # set mask as alpha channel
+ im = im.convert('RGBA')
+ im.putalpha(mask)
+ log.debug("image mode: %s", im.mode)
+ #end if !'RGBA'
+ #end if (png)/else(bmp)
+
+ return im
+ #end frame
+
+ def __repr__(self):
+ s = 'Microsoft Icon: %d images (max %dx%d %dbpp)' % (
+ len(self.entry), self.entry[0]['width'], self.entry[0]['height'],
+ self.entry[0]['bpp'])
+ return s
+#end Win32IcoFile
- def get_image (self, size, bpp=False):
- """
- Get an image from the icon
- Args:
- size: tuple of (width, height)
- bpp: color depth
+class Win32IconImageFile (PIL.ImageFile.ImageFile):
"""
- idx = 0
- for i in range(self.nb_items):
- h = self.entry[i]
- if size == h['dim'] and (bpp == False or bpp == h['color_depth']):
- return self.frame(i)
+ PIL read-only image support for Microsoft .ico files.
- return self.frame(0)
- #end get_image
+ By default the largest resolution image in the file will be loaded. This can
+ be changed by altering the 'size' attribute before calling 'load'.
+ The info dictionary has a key 'sizes' that is a list of the sizes available
+ in the icon file.
- def frame (self, idx):
+ Handles classic, XP and Vista icon formats.
"""
- Get the icon from frame idx
- Args:
- idx: Frame index
-
- Returns:
- PIL.Image
- """
- header = self.entry[idx]
- self.buf.seek(header['offset'])
- data = self.buf.read(8)
- self.buf.seek(header['offset'])
- if data[:8] == PIL.PngImagePlugin._MAGIC:
- # png frame
- im = PIL.PngImagePlugin.PngImageFile(self.buf)
-
- else:
- # XOR + AND mask bmp frame
- im = PIL.BmpImagePlugin.DibImageFile(self.buf)
- log.debug("Loaded image: %s %s %s %s", im.format, im.mode, im.size,
- im.info)
-
- # change tile dimension to only encompass XOR image
- im.size = im.size[0], im.size[1] / 2
- d, e, o, a = im.tile[0]
- im.tile[0] = d, (0, 0) + im.size, o, a
-
- # figure out where AND mask image starts
- mode = a[0]
- bpp = 8
- for k in PIL.BmpImagePlugin.BIT2MODE.keys():
- if mode == PIL.BmpImagePlugin.BIT2MODE[k][1]:
- bpp = k
- break
- #end for
- log.debug("o:%s, w:%s, h:%s, bpp:%s", o, im.size[0], im.size[1], bpp)
- and_mask_offset = o + (im.size[0] * im.size[1] * (bpp / 8.0))
-
- if 32 == bpp:
- # 32-bit color depth icon image allows semitransparent areas
- # PIL's DIB format ignores transparency bits, recover them
- # The DIB is packed in BGRX byte order where X is the alpha channel
-
- # Back up to start of bmp data
- self.buf.seek(o)
- # extract every 4th byte (eg. 3,7,11,15,...)
- alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4]
-
- # convert to an 8bpp grayscale image
- mask = PIL.Image.frombuffer(
- 'L', # 8bpp
- im.size, # (w, h)
- alpha_bytes, # source chars
- 'raw', # raw decoder
- ('L', 0, -1) # 8bpp inverted, unpadded, reversed
- )
-
- # apply mask image as alpha channel
- im = im.convert('RGBA')
- im.putalpha(mask)
- log.debug("image mode: %s", im.mode)
-
- else:
- # get AND image from end of bitmap
- w = im.size[0]
- if (w % 32) > 0:
- # bitmap row data is aligned to word boundaries
- w += 32 - (im.size[0] % 32)
- # the total mask data is padded row size * height / bits per char
- total_bytes = long((w * im.size[1]) / 8)
- log.debug("tot=%d, off=%d, w=%d, size=%d",
- len(data), and_mask_offset, w, total_bytes)
-
- self.buf.seek(and_mask_offset)
- maskData = self.buf.read(total_bytes)
-
- # convert raw data to image
- mask = PIL.Image.frombuffer(
- '1', # 1 bpp
- im.size, # (w, h)
- maskData, # source chars
- 'raw', # raw decoder
- ('1;I', int(w/8), -1) # 1bpp inverted, padded, reversed
- )
-
- # now we have two images, im is XOR image and mask is AND image
- # set mask as alpha channel
- im = im.convert('RGBA')
- im.putalpha(mask)
- log.debug("image mode: %s", im.mode)
- #end if !'RGBA'
- #end if (png)/else(bmp)
-
- return im
- #end frame
-
-
- def __repr__ (self):
- s = 'Microsoft Icon: %d images (max %dx%d %dbpp)' % (
- len(self.entry), self.entry[0]['width'], self.entry[0]['height'],
- self.entry[0]['bpp'])
- return s
- #end __repr__
-#end Win32IcoFile
-
-
-class Win32IconImageFile (PIL.ImageFile.ImageFile):
- """
- PIL read-only image support for Microsoft .ico files.
-
- By default the largest resolution image in the file will be loaded. This can
- be changed by altering the 'size' attribute before calling 'load'.
-
- The info dictionary has a key 'sizes' that is a list of the sizes available
- in the icon file.
-
- Handles classic, XP and Vista icon formats.
- """
-
- format = 'ICO'
- format_description = 'Microsoft icon'
-
- def _open (self):
- self.ico = Win32IcoFile(self.fp)
- self.info['sizes'] = self.ico.sizes()
- self.size = self.ico.entry[0]['dim']
- self.load()
- #end _open
-
- def load (self):
- im = self.ico.get_image(self.size)
- # if tile is PNG, it won't really be loaded yet
- im.load()
- self.im = im.im
- self.mode = im.mode
- self.size = im.size
- #end load
+ format = 'ICO'
+ format_description = 'Microsoft icon'
+
+ def _open(self):
+ self.ico = Win32IcoFile(self.fp)
+ self.info['sizes'] = self.ico.sizes()
+ self.size = self.ico.entry[0]['dim']
+ self.load()
+
+ def load(self):
+ im = self.ico.get_image(self.size)
+ # if tile is PNG, it won't really be loaded yet
+ im.load()
+ self.im = im.im
+ self.mode = im.mode
+ self.size = im.size
#end class Win32IconImageFile
-def _accept (prefix):
- """
- Quick file test helper for Image.open()
- """
- return prefix[:4] == _MAGIC
+def _accept(prefix):
+ """
+ Quick file test helper for Image.open()
+ """
+ return prefix[:4] == _MAGIC
#end _accept
diff --git a/deluge/ui/client.py b/deluge/ui/client.py
index 9472e0349..f0598ac16 100644
--- a/deluge/ui/client.py
+++ b/deluge/ui/client.py
@@ -1,37 +1,11 @@
-#
-# client.py
+# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me>
#
-# Deluge is free software.
-#
-# You may redistribute it and/or modify it under the terms of the
-# GNU General Public License, as published by the Free Software
-# Foundation; either version 3 of the License, or (at your option)
-# any later version.
-#
-# deluge is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with deluge. If not, write to:
-# The Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor
-# Boston, MA 02110-1301, USA.
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
-#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
#
import logging
@@ -43,7 +17,6 @@ from twisted.internet.protocol import ClientFactory
import deluge.common
from deluge import error
-from deluge.event import known_events
from deluge.transfer import DelugeTransferProtocol
from deluge.ui.common import get_localhost_auth
@@ -53,6 +26,7 @@ RPC_EVENT = 3
log = logging.getLogger(__name__)
+
def format_kwargs(kwargs):
return ", ".join([key + "=" + str(value) for key, value in kwargs.items()])
@@ -91,10 +65,8 @@ class DelugeRPCRequest(object):
:returns: a properly formated RPCRequest
"""
- if self.request_id is None or self.method is None or self.args is None \
- or self.kwargs is None:
- raise TypeError("You must set the properties of this object "
- "before calling format_message!")
+ if self.request_id is None or self.method is None or self.args is None or self.kwargs is None:
+ raise TypeError("You must set the properties of this object before calling format_message!")
return (self.request_id, self.method, self.args, self.kwargs)
@@ -156,7 +128,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
try:
exception_cls = getattr(error, request[2])
exception = exception_cls(*request[3], **request[4])
- except TypeError as err:
+ except TypeError:
log.warn("Received invalid RPC_ERROR (Old daemon?): %s", request[2])
return
@@ -189,7 +161,8 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
log.debug(msg)
except:
import traceback
- log.error("Failed to handle RPC_ERROR (Old daemon?): %s\nLocal error: %s", request[2], traceback.format_exc())
+ log.error("Failed to handle RPC_ERROR (Old daemon?): %s\nLocal error: %s",
+ request[2], traceback.format_exc())
d.errback(exception)
del self.__rpc_requests[request_id]
@@ -211,6 +184,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
except Exception as ex:
log.warn("Error occurred when sending message: %s", ex)
+
class DelugeRPCClientFactory(ClientFactory):
protocol = DelugeRPCProtocol
@@ -240,9 +214,11 @@ class DelugeRPCClientFactory(ClientFactory):
if self.daemon.disconnect_callback:
self.daemon.disconnect_callback()
+
class DaemonProxy(object):
pass
+
class DaemonSSLProxy(DaemonProxy):
def __init__(self, event_handlers=None):
if event_handlers is None:
@@ -445,6 +421,7 @@ class DaemonSSLProxy(DaemonProxy):
def get_bytes_sent(self):
return self.protocol.get_bytes_sent()
+
class DaemonClassicProxy(DaemonProxy):
def __init__(self, event_handlers=None):
if event_handlers is None:
@@ -513,6 +490,7 @@ class DaemonClassicProxy(DaemonProxy):
"""
self.__daemon.core.eventmanager.deregister_event_handler(event, handler)
+
class DottedObject(object):
"""
This is used for dotted name calls to client
@@ -527,6 +505,7 @@ class DottedObject(object):
def __getattr__(self, name):
return RemoteMethod(self.daemon, self.base + "." + name)
+
class RemoteMethod(DottedObject):
"""
This is used when something like 'client.core.get_something()' is attempted.
@@ -534,6 +513,7 @@ class RemoteMethod(DottedObject):
def __call__(self, *args, **kwargs):
return self.daemon.call(self.base, *args, **kwargs)
+
class Client(object):
"""
This class is used to connect to a daemon process and issue RPC requests.
@@ -650,7 +630,7 @@ class Client(object):
that you forgot to install the deluged package or it's not in your PATH."))
else:
log.exception(ex)
- raise e
+ raise ex
except Exception as ex:
log.error("Unable to start daemon!")
log.exception(ex)
@@ -665,8 +645,8 @@ that you forgot to install the deluged package or it's not in your PATH."))
:returns: bool, True if connected to a localhost
"""
- if self._daemon_proxy and self._daemon_proxy.host in ("127.0.0.1", "localhost") or\
- isinstance(self._daemon_proxy, DaemonClassicProxy):
+ if (self._daemon_proxy and self._daemon_proxy.host in ("127.0.0.1", "localhost") or
+ isinstance(self._daemon_proxy, DaemonClassicProxy)):
return True
return False
diff --git a/deluge/ui/common.py b/deluge/ui/common.py
index 97755837d..f0bc6c05a 100644
--- a/deluge/ui/common.py
+++ b/deluge/ui/common.py
@@ -1,41 +1,15 @@
# -*- coding: utf-8 -*-
#
-# deluge/ui/common.py
-#
# Copyright (C) Damien Churchill 2008-2009 <damoxc@gmail.com>
# Copyright (C) Andrew Resch 2009 <andrewresch@gmail.com>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, write to:
-# The Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor
-# Boston, MA 02110-1301, USA.
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
-#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
#
"""
-The ui common module contains methods and classes that are deemed useful for
-all the interfaces.
+The ui common module contains methods and classes that are deemed useful for all the interfaces.
"""
import logging
@@ -125,7 +99,8 @@ class TorrentInfo(object):
path = os.path.join(prefix, *f["path.utf-8"])
del f["path.utf-8"]
else:
- path = utf8_encoded(os.path.join(prefix, utf8_encoded(os.path.join(*f["path"]), self.encoding)), self.encoding)
+ path = utf8_encoded(os.path.join(prefix, utf8_encoded(os.path.join(*f["path"]),
+ self.encoding)), self.encoding)
f["path"] = path
f["index"] = index
if "sha1" in f and len(f["sha1"]) == 20:
@@ -192,7 +167,7 @@ class TorrentInfo(object):
"path": self.__m_name,
"size": self.__m_metadata["info"]["length"],
"download": True
- })
+ })
def as_dict(self, *keys):
"""
@@ -267,6 +242,7 @@ class TorrentInfo(object):
"""
return self.__m_filedata
+
class FileTree2(object):
"""
Converts a list of paths in to a file tree.
@@ -328,16 +304,17 @@ class FileTree2(object):
for path in directory["contents"].keys():
full_path = path_join(parent_path, path)
if directory["contents"][path]["type"] == "dir":
- directory["contents"][path] = callback(full_path, directory["contents"][path]) or \
- directory["contents"][path]
+ directory["contents"][path] = callback(full_path, directory["contents"][path]
+ ) or directory["contents"][path]
walk(directory["contents"][path], full_path)
else:
- directory["contents"][path] = callback(full_path, directory["contents"][path]) or \
- directory["contents"][path]
+ directory["contents"][path] = callback(full_path, directory["contents"][path]
+ ) or directory["contents"][path]
walk(self.tree, "")
def __str__(self):
lines = []
+
def write(path, item):
depth = path.count("/")
path = os.path.basename(path)
@@ -346,6 +323,7 @@ class FileTree2(object):
self.walk(write)
return "\n".join(lines)
+
class FileTree(object):
"""
Convert a list of paths in a file tree.
@@ -404,16 +382,15 @@ class FileTree(object):
for path in directory.keys():
full_path = os.path.join(parent_path, path)
if type(directory[path]) is dict:
- directory[path] = callback(full_path, directory[path]) or \
- directory[path]
+ directory[path] = callback(full_path, directory[path]) or directory[path]
walk(directory[path], full_path)
else:
- directory[path] = callback(full_path, directory[path]) or \
- directory[path]
+ directory[path] = callback(full_path, directory[path]) or directory[path]
walk(self.tree, "")
def __str__(self):
lines = []
+
def write(path, item):
depth = path.count("/")
path = os.path.basename(path)
@@ -422,6 +399,7 @@ class FileTree(object):
self.walk(write)
return "\n".join(lines)
+
def get_localhost_auth():
"""
Grabs the localclient auth line from the 'auth' file and creates a localhost uri
diff --git a/deluge/ui/coreconfig.py b/deluge/ui/coreconfig.py
index 6f90739ec..766466bb9 100644
--- a/deluge/ui/coreconfig.py
+++ b/deluge/ui/coreconfig.py
@@ -1,38 +1,11 @@
-#
-# coreconfig.py
+# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
-# Deluge is free software.
-#
-# You may redistribute it and/or modify it under the terms of the
-# GNU General Public License, as published by the Free Software
-# Foundation; either version 3 of the License, or (at your option)
-# any later version.
-#
-# deluge is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with deluge. If not, write to:
-# The Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor
-# Boston, MA 02110-1301, USA.
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
#
-#
-
import logging
@@ -41,11 +14,13 @@ from deluge.ui.client import client
log = logging.getLogger(__name__)
+
class CoreConfig(component.Component):
def __init__(self):
log.debug("CoreConfig init..")
component.Component.__init__(self, "CoreConfig")
self.config = {}
+
def on_configvaluechanged_event(key, value):
self.config[key] = value
client.register_event_handler("ConfigValueChangedEvent", on_configvaluechanged_event)
diff --git a/deluge/ui/sessionproxy.py b/deluge/ui/sessionproxy.py
index 926193e77..ce3d0b627 100644
--- a/deluge/ui/sessionproxy.py
+++ b/deluge/ui/sessionproxy.py
@@ -1,38 +1,13 @@
-#
-# sessionproxy.py
+# -*- coding: utf-8 -*-
#
# Copyright (C) 2010 Andrew Resch <andrewresch@gmail.com>
#
-# Deluge is free software.
-#
-# You may redistribute it and/or modify it under the terms of the
-# GNU General Public License, as published by the Free Software
-# Foundation; either version 3 of the License, or (at your option)
-# any later version.
-#
-# deluge is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with deluge. If not, write to:
-# The Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor
-# Boston, MA 02110-1301, USA.
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
-#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
#
+
import logging
import time
@@ -43,6 +18,7 @@ from deluge.ui.client import client
log = logging.getLogger(__name__)
+
class SessionProxy(component.Component):
"""
The SessionProxy component is used to cache session information client-side
@@ -101,7 +77,7 @@ class SessionProxy(component.Component):
"""
sd = {}
keys = set(keys)
- keys_len = -1 # The number of keys for the current cache (not the len of keys_diff_cached)
+ keys_len = -1 # The number of keys for the current cache (not the len of keys_diff_cached)
keys_diff_cached = []
for torrent_id in torrent_ids:
@@ -161,6 +137,7 @@ class SessionProxy(component.Component):
)
else:
d = client.core.get_torrent_status(torrent_id, keys_to_get, True)
+
def on_status(result, torrent_id):
t = time.time()
self.torrents[torrent_id][0] = t
@@ -171,6 +148,7 @@ class SessionProxy(component.Component):
return d.addCallback(on_status, torrent_id)
else:
d = client.core.get_torrent_status(torrent_id, keys, True)
+
def on_status(result):
if result:
t = time.time()
@@ -247,7 +225,6 @@ class SessionProxy(component.Component):
# Don't need to fetch anything
return maybeDeferred(self.create_status_dict, self.torrents.keys(), keys)
-
if len(filter_dict) == 1 and "id" in filter_dict:
# At this point we should have a filter with just "id" in it
to_fetch = find_torrents_to_fetch(filter_dict["id"])
@@ -271,6 +248,7 @@ class SessionProxy(component.Component):
def on_torrent_added(self, torrent_id, from_state):
self.torrents[torrent_id] = [time.time() - self.cache_time - 1, {}]
self.cache_times[torrent_id] = {}
+
def on_status(status):
self.torrents[torrent_id][1].update(status)
t = time.time()
diff --git a/deluge/ui/tracker_icons.py b/deluge/ui/tracker_icons.py
index 204954483..61db43427 100644
--- a/deluge/ui/tracker_icons.py
+++ b/deluge/ui/tracker_icons.py
@@ -1,36 +1,10 @@
-#
-# tracker_icons.py
+# -*- coding: utf-8 -*-
#
# Copyright (C) 2010 John Garland <johnnybg+deluge@gmail.com>
#
-# Deluge is free software.
-#
-# You may redistribute it and/or modify it under the terms of the
-# GNU General Public License, as published by the Free Software
-# Foundation; either version 3 of the License, or (at your option)
-# any later version.
-#
-# deluge is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with deluge. If not, write to:
-# The Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor
-# Boston, MA 02110-1301, USA.
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
-#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
#
import logging
@@ -53,11 +27,10 @@ except ImportError:
# twisted 8
from twisted.web.error import NoResource, ForbiddenResource
-
-
try:
import PIL.Image as Image
import deluge.ui.Win32IconImagePlugin
+ assert deluge.ui.Win32IconImagePlugin # silence pyflakes
except ImportError:
PIL_INSTALLED = False
else:
@@ -65,6 +38,7 @@ else:
log = logging.getLogger(__name__)
+
class TrackerIcon(object):
"""
Represents a tracker's icon
@@ -77,7 +51,7 @@ class TrackerIcon(object):
:type filename: string
"""
self.filename = os.path.abspath(filename)
- self.mimetype = extension_to_mimetype(self.filename.rpartition('.')[2])
+ self.mimetype = extension_to_mimetype(self.filename.rpartition(".")[2])
self.data = None
self.icon_cache = None
@@ -90,9 +64,9 @@ class TrackerIcon(object):
:returns: whether or not they're equal
:rtype: boolean
"""
- return os.path.samefile(self.filename, other.filename) or \
- self.get_mimetype() == other.get_mimetype() and \
- self.get_data() == other.get_data()
+ return (os.path.samefile(self.filename, other.filename) or
+ self.get_mimetype() == other.get_mimetype() and
+ self.get_data() == other.get_data())
def get_mimetype(self):
"""
@@ -142,6 +116,7 @@ class TrackerIcon(object):
"""
return self.icon_cache
+
class TrackerIcons(Component):
"""
A TrackerIcon factory class
@@ -175,7 +150,7 @@ class TrackerIcons(Component):
self.icons[None] = TrackerIcon(no_icon)
else:
self.icons[None] = None
- self.icons[''] = self.icons[None]
+ self.icons[""] = self.icons[None]
self.pending = {}
self.redirects = {}
@@ -433,7 +408,7 @@ class TrackerIcons(Component):
if f.check(PageRedirect):
# Handle redirect errors
location = urljoin(self.host_to_url(host), error_msg.split(" to ")[1])
- d = self.download_icon([(location, extension_to_mimetype(location.rpartition('.')[2]))] + icons, host)
+ d = self.download_icon([(location, extension_to_mimetype(location.rpartition(".")[2]))] + icons, host)
if not icons:
d.addCallbacks(self.on_download_icon_complete, self.on_download_icon_fail,
callbackArgs=(host,), errbackArgs=(host,))
@@ -441,7 +416,8 @@ class TrackerIcons(Component):
d = self.download_icon(icons, host)
elif f.check(NoIconsError, HTMLParseError):
# No icons, try favicon.ico as an act of desperation
- d = self.download_icon([(urljoin(self.host_to_url(host), "favicon.ico"), extension_to_mimetype("ico"))], host)
+ d = self.download_icon([(urljoin(self.host_to_url(host), "favicon.ico"),
+ extension_to_mimetype("ico"))], host)
d.addCallbacks(self.on_download_icon_complete, self.on_download_icon_fail,
callbackArgs=(host,), errbackArgs=(host,))
else:
@@ -465,7 +441,7 @@ class TrackerIcons(Component):
filename = icon.get_filename()
img = Image.open(filename)
if img.size > (16, 16):
- new_filename = filename.rpartition('.')[0]+".png"
+ new_filename = filename.rpartition(".")[0] + ".png"
img = img.resize((16, 16), Image.ANTIALIAS)
img.save(new_filename)
if new_filename != filename:
@@ -506,6 +482,7 @@ class TrackerIcons(Component):
################################ HELPER CLASSES ###############################
+
class FaviconParser(HTMLParser):
"""
A HTMLParser which extracts favicons from a HTML page
@@ -526,7 +503,7 @@ class FaviconParser(HTMLParser):
type = value
if href:
try:
- mimetype = extension_to_mimetype(href.rpartition('.')[2])
+ mimetype = extension_to_mimetype(href.rpartition(".")[2])
except KeyError:
pass
else:
@@ -561,6 +538,7 @@ def url_to_host(url):
"""
return urlparse(url).hostname
+
def host_to_icon_name(host, mimetype):
"""
Given a host, returns the appropriate icon name
@@ -573,7 +551,8 @@ def host_to_icon_name(host, mimetype):
:rtype: string
"""
- return host+'.'+mimetype_to_extension(mimetype)
+ return host + "." + mimetype_to_extension(mimetype)
+
def icon_name_to_host(icon):
"""
@@ -584,7 +563,7 @@ def icon_name_to_host(icon):
:returns: the host name
:rtype: string
"""
- return icon.rpartition('.')[0]
+ return icon.rpartition(".")[0]
MIME_MAP = {
"image/gif": "gif",
@@ -599,6 +578,7 @@ MIME_MAP = {
"ico": "image/vnd.microsoft.icon",
}
+
def mimetype_to_extension(mimetype):
"""
Given a mimetype, returns the appropriate filename extension
@@ -611,6 +591,7 @@ def mimetype_to_extension(mimetype):
"""
return MIME_MAP[mimetype.lower()]
+
def extension_to_mimetype(extension):
"""
Given a filename extension, returns the appropriate mimetype
@@ -625,8 +606,10 @@ def extension_to_mimetype(extension):
################################## EXCEPTIONS #################################
+
class NoIconsError(Exception):
pass
+
class InvalidIconError(Exception):
pass
diff --git a/deluge/ui/ui.py b/deluge/ui/ui.py
index 83cb01b3e..62fff5e76 100644
--- a/deluge/ui/ui.py
+++ b/deluge/ui/ui.py
@@ -1,36 +1,10 @@
-#
-# ui.py
+# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
#
-# Deluge is free software.
-#
-# You may redistribute it and/or modify it under the terms of the
-# GNU General Public License, as published by the Free Software
-# Foundation; either version 3 of the License, or (at your option)
-# any later version.
-#
-# deluge is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with deluge. If not, write to:
-# The Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor
-# Boston, MA 02110-1301, USA.
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
-#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
#
from __future__ import print_function
@@ -75,18 +49,15 @@ class _UI(object):
self.__parser = OptionParser(usage="%prog [options] [actions]")
self.__parser.add_option("-v", "--version", action="callback", callback=version_callback,
- help="Show program's version number and exit")
+ help="Show program's version number and exit")
group = OptionGroup(self.__parser, "Common Options")
- group.add_option("-c", "--config", dest="config",
- help="Set the config folder location", action="store", type="str")
- group.add_option("-l", "--logfile", dest="logfile",
- help="Output to designated logfile instead of stdout", action="store", type="str")
+ group.add_option("-c", "--config", dest="config", help="Set the config folder location")
+ group.add_option("-l", "--logfile", dest="logfile", help="Output to designated logfile instead of stdout")
group.add_option("-L", "--loglevel", dest="loglevel",
- help="Set the log level: none, info, warning, error, critical, debug", action="store", type="str")
- group.add_option("-q", "--quiet", dest="quiet",
- help="Sets the log level to 'none', this is the same as `-L none`", action="store_true", default=False)
- group.add_option("-r", "--rotate-logs",
- help="Rotate logfiles.", action="store_true", default=False)
+ help="Set the log level: none, info, warning, error, critical, debug")
+ group.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False,
+ help="Sets the log level to 'none', this is the same as `-L none`")
+ group.add_option("-r", "--rotate-logs", help="Rotate logfiles.", action="store_true", default=False)
self.__parser.add_option_group(group)
@property
@@ -171,15 +142,15 @@ class UI:
if selected_ui == "gtk":
log.info("Starting GtkUI..")
from deluge.ui.gtkui.gtkui import GtkUI
- ui = GtkUI(args)
+ GtkUI(args)
elif selected_ui == "web":
log.info("Starting WebUI..")
from deluge.ui.web.web import WebUI
- ui = WebUI(args)
+ WebUI(args)
elif selected_ui == "console":
log.info("Starting ConsoleUI..")
from deluge.ui.console.main import ConsoleUI
- ui = ConsoleUI(ui_args)
+ ConsoleUI(ui_args)
except ImportError as ex:
import sys
import traceback
diff --git a/deluge/ui/web/__init__.py b/deluge/ui/web/__init__.py
index f70f6a9c8..763684964 100644
--- a/deluge/ui/web/__init__.py
+++ b/deluge/ui/web/__init__.py
@@ -1 +1,2 @@
from web import start
+assert start # silence pyflakes
diff --git a/deluge/ui/web/auth.py b/deluge/ui/web/auth.py
index 3bf4e2b92..22dffd11a 100644
--- a/deluge/ui/web/auth.py
+++ b/deluge/ui/web/auth.py
@@ -42,7 +42,7 @@ class AuthError(Exception):
def make_checksum(session_id):
- return reduce(lambda x, y: x+y, map(ord, session_id))
+ return reduce(lambda x, y: x + y, map(ord, session_id))
def get_session_id(session_id):
@@ -118,7 +118,7 @@ class Auth(JSONComponent):
checksum = str(make_checksum(session_id))
request.addCookie('_session_id', session_id + checksum,
- path=request.base+"json", expires=expires_str)
+ path=request.base + "json", expires=expires_str)
log.debug("Creating session for %s", login)
config = component.get("DelugeWeb").config
@@ -215,7 +215,7 @@ class Auth(JSONComponent):
_session_id = request.getCookie("_session_id")
request.addCookie('_session_id', _session_id,
- path=request.base+"json", expires=expires_str)
+ path=request.base + "json", expires=expires_str)
if method:
if not hasattr(method, "_json_export"):
diff --git a/deluge/ui/web/json_api.py b/deluge/ui/web/json_api.py
index 9b435819b..c315a0691 100644
--- a/deluge/ui/web/json_api.py
+++ b/deluge/ui/web/json_api.py
@@ -757,7 +757,7 @@ class WebApi(JSONComponent):
Return the hosts in the hostlist.
"""
log.debug("get_hosts called")
- return [(tuple(host[HOSTS_ID:HOSTS_PORT+1]) + (_("Offline"),)) for host in self.host_list["hosts"]]
+ return [(tuple(host[HOSTS_ID:HOSTS_PORT + 1]) + (_("Offline"),)) for host in self.host_list["hosts"]]
@export
def get_host_status(self, host_id):
diff --git a/deluge/ui/web/server.py b/deluge/ui/web/server.py
index 6fd61630d..aa5fc2d08 100644
--- a/deluge/ui/web/server.py
+++ b/deluge/ui/web/server.py
@@ -354,7 +354,7 @@ class ScriptResource(resource.Resource, component.Component):
except:
pass
- dirpath = dirpath[len(filepath)+1:]
+ dirpath = dirpath[len(filepath) + 1:]
if dirpath:
scripts.extend(['js/' + path + '/' + dirpath + '/' + f for f in files])
else: