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
This commit is contained in:
Calum Lind 2014-09-03 22:28:28 +01:00
parent 5d88504c34
commit 5167e93d12
44 changed files with 636 additions and 1277 deletions

View File

@ -1,3 +1,12 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
# 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 new import classobj
from deluge.core.core import Core
@ -7,6 +16,7 @@ from deluge.core.daemon import Daemon
class RpcApi:
pass
def scan_for_methods(obj):
methods = {
'__doc__': 'Methods available in %s' % obj.__name__.lower()

View File

@ -1,36 +1,10 @@
#
# _libtorrent.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 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.
#
"""
@ -47,6 +21,7 @@ supports.
REQUIRED_VERSION = "0.16.7.0"
def check_version(lt):
from deluge.common import VersionSplit
if VersionSplit(lt.version) < VersionSplit(REQUIRED_VERSION):

View File

@ -20,22 +20,22 @@ def decode_int(x, f):
if x[f] == '-':
if x[f + 1] == '0':
raise ValueError
elif x[f] == '0' and newf != f+1:
elif x[f] == '0' and newf != f + 1:
raise ValueError
return (n, newf+1)
return (n, newf + 1)
def decode_string(x, f):
colon = x.index(':', f)
n = int(x[f:colon])
if x[f] == '0' and colon != f+1:
if x[f] == '0' and colon != f + 1:
raise ValueError
colon += 1
return (x[colon:colon+n], colon+n)
return (x[colon:colon + n], colon + n)
def decode_list(x, f):
r, f = [], f+1
r, f = [], f + 1
while x[f] != 'e':
v, f = decode_func[x[f]](x, f)
r.append(v)
@ -43,7 +43,7 @@ def decode_list(x, f):
def decode_dict(x, f):
r, f = {}, f+1
r, f = {}, f + 1
while x[f] != 'e':
k, f = decode_string(x, f)
r[k], f = decode_func[x[f]](x, f)

View File

@ -183,7 +183,7 @@ def resource_filename(module, path):
# enough.
# This is a work-around that.
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]))
)

View File

@ -1,36 +1,10 @@
#
# component.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-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
@ -41,9 +15,11 @@ from twisted.internet.task import LoopingCall
log = logging.getLogger(__name__)
class ComponentAlreadyRegistered(Exception):
pass
class Component(object):
"""
Component objects are singletons managed by the :class:`ComponentRegistry`.
@ -219,6 +195,7 @@ class Component(object):
def shutdown(self):
pass
class ComponentRegistry(object):
"""
The ComponentRegistry holds a list of currently registered
@ -264,6 +241,7 @@ class ComponentRegistry(object):
if obj in self.components.values():
log.debug("Deregistering Component: %s", obj._component_name)
d = self.stop([obj._component_name])
def on_stop(result, name):
del self.components[name]
return d.addCallback(on_stop, obj._component_name)
@ -430,6 +408,7 @@ resume = _ComponentRegistry.resume
update = _ComponentRegistry.update
shutdown = _ComponentRegistry.shutdown
def get(name):
"""
Return a reference to a component.

View File

@ -1,38 +1,11 @@
#
# config.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
# Deluge is free software.
# 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.
#
# 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.
#
#
"""
Deluge Config Module
@ -121,7 +94,7 @@ def find_json_objects(s):
elif c == "}":
opens -= 1
if opens == 0:
objects.append((start, index+offset+1))
objects.append((start, index + offset + 1))
start = index + offset + 1
return objects
@ -208,7 +181,7 @@ what is currently in the config and it could not convert the value
# Do not allow the type to change unless it is None
oldtype, newtype = type(self.__config[key]), type(value)
if value is not None and oldtype != type(None) and oldtype != newtype:
if value is not None and not isinstance(oldtype, type(None)) and not isinstance(oldtype, newtype):
try:
if oldtype == unicode:
value = oldtype(value, "utf8")
@ -542,7 +515,7 @@ what is currently in the config and it could not convert the value
log.exception(ex)
log.error("There was an exception try to convert config file %s %s to %s",
self.__config_file, self.__version["file"], output_version)
raise e
raise ex
else:
self.__version["file"] = output_version
self.save()

View File

@ -1,36 +1,10 @@
#
# configmanager.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.
#
import logging
@ -42,6 +16,7 @@ from deluge.config import Config
log = logging.getLogger(__name__)
class _ConfigManager:
def __init__(self):
log.debug("ConfigManager started..")
@ -121,18 +96,22 @@ class _ConfigManager:
# Singleton functions
_configmanager = _ConfigManager()
def ConfigManager(config, defaults=None):
return _configmanager.get_config(config, defaults)
def set_config_dir(directory):
"""Sets the config directory, else just uses default"""
return _configmanager.set_config_dir(directory)
def get_config_dir(filename=None):
if filename != None:
if filename is not None:
return os.path.join(_configmanager.get_config_dir(), filename)
else:
return _configmanager.get_config_dir()
def close(config):
return _configmanager.close(config)

View File

@ -205,7 +205,7 @@ class PreferencesManager(component.Component):
listen_ports = []
randrange = lambda: random.randrange(49152, 65525)
listen_ports.append(randrange())
listen_ports.append(listen_ports[0]+10)
listen_ports.append(listen_ports[0] + 10)
else:
listen_ports = self.config["listen_ports"]

View File

@ -573,7 +573,7 @@ def generate_ssl_keys():
cert = crypto.X509()
cert.set_serial_number(0)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(60*60*24*365*5) # Five Years
cert.gmtime_adj_notAfter(60 * 60 * 24 * 365 * 5) # Five Years
cert.set_issuer(req.get_subject())
cert.set_subject(req.get_subject())
cert.set_pubkey(req.get_pubkey())

View File

@ -1,36 +1,10 @@
#
# decorators.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.
#
from functools import wraps

View File

@ -1,37 +1,11 @@
#
# error.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 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.
#

View File

@ -1,36 +1,10 @@
#
# event.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 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.
#
"""
@ -48,10 +22,10 @@ class DelugeEventMetaClass(type):
"""
This metaclass simply keeps a list of all events classes created.
"""
def __init__(cls, name, bases, dct):
super(DelugeEventMetaClass, cls).__init__(name, bases, dct)
def __init__(self, name, bases, dct):
super(DelugeEventMetaClass, self).__init__(name, bases, dct)
if name != "DelugeEvent":
known_events[name] = cls
known_events[name] = self
class DelugeEvent(object):

View File

@ -1,35 +1,10 @@
#
# httpdownloader.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 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
@ -45,6 +20,7 @@ from common import get_version
log = logging.getLogger(__name__)
class HTTPDownloader(client.HTTPDownloader):
"""
Factory class for downloading files and keeping track of progress.
@ -132,6 +108,7 @@ class HTTPDownloader(client.HTTPDownloader):
return client.HTTPDownloader.pageEnd(self)
def sanitise_filename(filename):
"""
Sanitises a filename to use as a download destination file.
@ -159,8 +136,8 @@ def sanitise_filename(filename):
return filename
def download_file(url, filename, callback=None, headers=None,
force_filename=False, allow_compression=True):
def download_file(url, filename, callback=None, headers=None, force_filename=False, allow_compression=True):
"""
Downloads a file from a specific URL and returns a Deferred. You can also
specify a callback function to be called as parts are received.
@ -198,7 +175,7 @@ def download_file(url, filename, callback=None, headers=None,
headers = {}
headers["accept-encoding"] = "deflate, gzip, x-gzip"
# In twisted 13.1.0 the _parse() function was replaced by the _URI class
# In twisted 13.1.0 the _parse() function was replaced by the _URI class
if hasattr(client, '_parse'):
scheme, host, port, path = client._parse(url)
else:
@ -207,7 +184,6 @@ def download_file(url, filename, callback=None, headers=None,
scheme = uri.scheme
host = uri.host
port = uri.port
path = uri.path
factory = HTTPDownloader(url, filename, callback, headers, force_filename, allow_compression)
if scheme == "https":

View File

@ -1,37 +1,11 @@
#
# log.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2010 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.
#
"""Logging functions"""
@ -49,12 +23,13 @@ __all__ = ["setupLogger", "setLoggerLevel", "getPluginLogger", "LOG"]
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"
else:
DEFAULT_LOGGING_FORMAT = "%%(asctime)s [%%(levelname)-8s][%%(name)-%ds] %%(message)s"
MAX_LOGGER_NAME_LENGTH = 10
class Logging(LoggingLoggerClass):
def __init__(self, logger_name):
LoggingLoggerClass.__init__(self, logger_name)
@ -110,8 +85,8 @@ class Logging(LoggingLoggerClass):
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename in (__file__.replace('.pyc', '.py'),
defer.__file__.replace('.pyc', '.py')):
if filename in (__file__.replace(".pyc", ".py"),
defer.__file__.replace(".pyc", ".py")):
f = f.f_back
continue
rv = (filename, f.f_lineno, co.co_name)
@ -143,27 +118,27 @@ def setupLogger(level="error", filename=None, filemode="w"):
if logging.getLoggerClass() is not Logging:
logging.setLoggerClass(Logging)
logging.addLevelName(5, 'TRACE')
logging.addLevelName(1, 'GARBAGE')
logging.addLevelName(5, "TRACE")
logging.addLevelName(1, "GARBAGE")
level = levels.get(level, logging.ERROR)
rootLogger = logging.getLogger()
root_logger = logging.getLogger()
if filename and filemode=='a':
if filename and filemode == "a":
import logging.handlers
handler = logging.handlers.RotatingFileHandler(
filename, filemode,
maxBytes=50*1024*1024, # 50 Mb
maxBytes=50 * 1024 * 1024, # 50 Mb
backupCount=3,
encoding='utf-8',
encoding="utf-8",
delay=0
)
elif filename and filemode=='w':
elif filename and filemode == "w":
import logging.handlers
handler = getattr(
logging.handlers, 'WatchedFileHandler', logging.FileHandler)(
filename, filemode, 'utf-8', delay=0
logging.handlers, "WatchedFileHandler", logging.FileHandler)(
filename, filemode, "utf-8", delay=0
)
else:
handler = logging.StreamHandler()
@ -176,13 +151,14 @@ def setupLogger(level="error", filename=None, filemode="w"):
)
handler.setFormatter(formatter)
rootLogger.addHandler(handler)
rootLogger.setLevel(level)
root_logger.addHandler(handler)
root_logger.setLevel(level)
twisted_logging = PythonLoggingObserver('twisted')
twisted_logging = PythonLoggingObserver("twisted")
twisted_logging.start()
logging.getLogger("twisted").setLevel(level)
def tweak_logging_levels():
"""This function allows tweaking the logging levels for all or some loggers.
This is mostly usefull for developing purposes hence the contents of the
@ -202,17 +178,16 @@ def tweak_logging_levels():
the command line.
"""
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):
return
log = logging.getLogger(__name__)
log.warn("logging.conf found! tweaking logging levels from %s",
logging_config_file)
for line in open(logging_config_file, 'r').readlines():
for line in open(logging_config_file, "r").readlines():
if line.strip().startswith("#"):
continue
name, level = line.strip().split(':')
name, level = line.strip().split(":")
if level not in levels:
continue
@ -237,15 +212,15 @@ def getPluginLogger(logger_name):
import warnings
stack = inspect.stack()
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])
# 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,
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("deluge.plugin.%s" % logger_name)
@ -272,16 +247,17 @@ The above will result in, regarding the "Label" plugin for example a log message
Triggering code:"""
class __BackwardsCompatibleLOG(object):
class _BackwardsCompatibleLOG(object):
def __getattribute__(self, name):
import warnings
logger_name = 'deluge'
logger_name = "deluge"
stack = inspect.stack()
stack.pop(0) # The logging call from this module
module_stack = stack.pop(0) # The module that called the log function
stack.pop(0) # The logging call from this module
module_stack = stack.pop(0) # The module that called the log function
caller_module = inspect.getmodule(module_stack[0])
# 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,
module_stack[1], module_stack[2],
caller_module_name)
@ -290,9 +266,9 @@ class __BackwardsCompatibleLOG(object):
module = inspect.getmodule(member[0])
if not module:
continue
if module.__name__ in ('deluge.plugins.pluginbase',
'deluge.plugins.init'):
logger_name += '.plugin.%s' % caller_module_name
if module.__name__ in ("deluge.plugins.pluginbase",
"deluge.plugins.init"):
logger_name += ".plugin.%s" % caller_module_name
# Monkey Patch The Plugin Module
caller_module.log = logging.getLogger(logger_name)
break
@ -303,4 +279,4 @@ class __BackwardsCompatibleLOG(object):
)
return getattr(logging.getLogger(logger_name), name)
LOG = __BackwardsCompatibleLOG()
LOG = _BackwardsCompatibleLOG()

View File

@ -1,37 +1,11 @@
#
# main.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2010 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.
#
@ -68,26 +42,26 @@ def start_ui():
# Setup the argument parser
parser = OptionParser(usage="%prog [options] [actions]")
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")
parser.add_option("-u", "--ui", dest="ui",
help="""The UI that you wish to launch. The UI choices are:\n
\t gtk -- A GTK-based graphical user interface (default)\n
\t web -- A web-based interface (http://localhost:8112)\n
\t console -- A console or command-line interface""", action="store", type="str")
help="""The UI that you wish to launch. The UI choices are:\n
\t gtk -- A GTK-based graphical user interface (default)\n
\t web -- A web-based interface (http://localhost:8112)\n
\t console -- A console or command-line interface""")
parser.add_option("-s", "--set-default-ui", dest="default_ui",
help="Sets the default UI to be run when no UI is specified", action="store", type="str")
help="Sets the default UI to be run when no UI is specified")
parser.add_option("-a", "--args", dest="args",
help="Arguments to pass to UI, -a '--option args'", action="store", type="str")
help="Arguments to pass to UI, -a '--option args'")
parser.add_option("-c", "--config", dest="config",
help="Set the config folder location", action="store", type="str")
help="Set the config folder location")
parser.add_option("-l", "--logfile", dest="logfile",
help="Output to designated logfile instead of stdout", action="store", type="str")
help="Output to designated logfile instead of stdout")
parser.add_option("-L", "--loglevel", dest="loglevel",
help="Set the log level: none, info, warning, error, critical, debug", action="store", type="str")
parser.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)
help="Set the log level: none, info, warning, error, critical, debug")
parser.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`")
parser.add_option("-r", "--rotate-logs",
help="Rotate logfiles.", action="store_true", default=False)
help="Rotate logfiles.", action="store_true", default=False)
# Get the options and args from the OptionParser
(options, args) = parser.parse_args(deluge.common.unicode_argv()[1:])
@ -150,38 +124,29 @@ def start_daemon():
# Setup the argument parser
parser = OptionParser(usage="%prog [options] [actions]")
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")
parser.add_option("-p", "--port", dest="port",
help="Port daemon will listen on", action="store", type="int")
help="Port daemon will listen on", type="int")
parser.add_option("-i", "--interface", dest="listen_interface",
help="Interface daemon will listen for bittorrent connections on, \
this should be an IP address", metavar="IFACE",
action="store", type="str")
parser.add_option("-u", "--ui-interface", dest="ui_interface",
help="Interface daemon will listen for UI connections on, this should be\
an IP address", metavar="IFACE", action="store", type="str")
help="Interface daemon will listen for bittorrent connections on,"
"this should be an IP address", metavar="IFACE")
parser.add_option("-u", "--ui-interface", dest="ui_interface", metavar="IFACE",
help="Interface daemon will listen for UI connections on, this should be an IP address")
if not (deluge.common.windows_check() or deluge.common.osx_check()):
parser.add_option("-d", "--do-not-daemonize", dest="donot",
help="Do not daemonize", action="store_true", default=False)
parser.add_option("-c", "--config", dest="config",
help="Set the config location", action="store", type="str")
parser.add_option("-P", "--pidfile", dest="pidfile",
help="Use pidfile to store process id", action="store", type="str")
help="Do not daemonize", action="store_true", default=False)
parser.add_option("-c", "--config", dest="config", help="Set the config location")
parser.add_option("-P", "--pidfile", dest="pidfile", help="Use pidfile to store process id")
if not deluge.common.windows_check():
parser.add_option("-U", "--user", dest="user",
help="User to switch to. Only use it when starting as root", action="store", type="str")
parser.add_option("-g", "--group", dest="group",
help="Group to switch to. Only use it when starting as root", action="store", type="str")
parser.add_option("-l", "--logfile", dest="logfile",
help="Set the logfile location", action="store", type="str")
parser.add_option("-U", "--user", dest="user", help="User to switch to. Only use it when starting as root")
parser.add_option("-g", "--group", dest="group", help="Group to switch to. Only use it when starting as root")
parser.add_option("-l", "--logfile", dest="logfile", help="Set the logfile location")
parser.add_option("-L", "--loglevel", dest="loglevel",
help="Set the log level: none, info, warning, error, critical, debug", action="store", type="str")
parser.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)
parser.add_option("-r", "--rotate-logs",
help="Rotate logfiles.", action="store_true", default=False)
parser.add_option("--profile", dest="profile", action="store_true", default=False,
help="Profiles the daemon")
help="Set the log level: none, info, warning, error, critical, debug")
parser.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`")
parser.add_option("-r", "--rotate-logs", help="Rotate logfiles.", action="store_true", default=False)
parser.add_option("--profile", dest="profile", action="store_true", default=False, help="Profiles the daemon")
# Get the options and args from the OptionParser
(options, args) = parser.parse_args()

View File

@ -1,36 +1,10 @@
#
# maketorrent.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 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 os
@ -47,6 +21,7 @@ class InvalidPath(Exception):
"""
pass
class InvalidPieceSize(Exception):
"""
Raised when an invalid piece size is set. Piece sizes must be multiples of
@ -54,6 +29,7 @@ class InvalidPieceSize(Exception):
"""
pass
class TorrentMetadata(object):
"""
This class is used to create .torrent files.
@ -94,7 +70,7 @@ class TorrentMetadata(object):
torrent = {
"info": {}
}
}
if self.comment:
torrent["comment"] = self.comment.encode("UTF-8")
@ -125,7 +101,7 @@ class TorrentMetadata(object):
datasize = get_path_size(self.data_path)
if self.piece_size:
piece_size = piece_size * 1024
piece_size = self.piece_size * 1024
else:
# We need to calculate a piece size
piece_size = 16384

View File

@ -38,15 +38,18 @@ for i in xrange(0xFDD0, 0xFDF0):
for i in (0xFFFE, 0xFFFF):
noncharacter_translate[i] = ord('-')
def gmtime():
return time.mktime(time.gmtime())
def get_filesystem_encoding():
return sys.getfilesystemencoding()
def decode_from_filesystem(path):
encoding = get_filesystem_encoding()
if encoding == None:
if encoding is None:
assert isinstance(path, unicode), "Path should be unicode not %s" % type(path)
decoded_path = path
else:
@ -55,9 +58,11 @@ def decode_from_filesystem(path):
return decoded_path
def dummy(*v):
pass
class RemoteFileProgress(object):
def __init__(self, session_id):
self.session_id = session_id
@ -67,6 +72,7 @@ class RemoteFileProgress(object):
self.session_id, CreateTorrentProgressEvent(piece_count, num_pieces)
)
def make_meta_file(path, url, piece_length, progress=None, title=None, comment=None,
safe=None, content_type=None, target=None, webseeds=None, name=None,
private=False, created_by=None, trackers=None):
@ -127,15 +133,16 @@ def make_meta_file(path, url, piece_length, progress=None, title=None, comment=N
h.write(bencode(data))
h.close()
def calcsize(path):
total = 0
for s in subfiles(os.path.abspath(path)):
total += os.path.getsize(s[1])
return total
def makeinfo(path, piece_length, progress, name = None,
content_type = None, private=False): # HEREDAVE. If path is directory,
# how do we assign content type?
def makeinfo(path, piece_length, progress, name=None, content_type=None, private=False):
# HEREDAVE. If path is directory, how do we assign content type?
def to_utf8(name):
if isinstance(name, unicode):
u = name
@ -150,8 +157,8 @@ def makeinfo(path, piece_length, progress, name = None,
if u.translate(noncharacter_translate) != u:
raise Exception('File/directory name "%s" contains reserved '
'unicode values that do not correspond to '
'characters.' % name)
'unicode values that do not correspond to '
'characters.' % name)
return u.encode('utf-8')
path = os.path.abspath(path)
piece_count = 0
@ -178,7 +185,7 @@ def makeinfo(path, piece_length, progress, name = None,
p2 = [to_utf8(n) for n in p]
if content_type:
fs.append({'length': size, 'path': p2,
'content_type' : content_type}) # HEREDAVE. bad for batch!
'content_type': content_type}) # HEREDAVE. bad for batch!
else:
fs.append({'length': size, 'path': p2})
h = file(f, 'rb')
@ -208,9 +215,10 @@ def makeinfo(path, piece_length, progress, name = None,
name = to_utf8(os.path.split(path)[1])
return {'pieces': ''.join(pieces),
'piece length': piece_length, 'files': fs,
'name': name,
'private': private}
'piece length': piece_length,
'files': fs,
'name': name,
'private': private}
else:
size = os.path.getsize(path)
if size >= piece_length:
@ -232,14 +240,15 @@ def makeinfo(path, piece_length, progress, name = None,
h.close()
if content_type is not None:
return {'pieces': ''.join(pieces),
'piece length': piece_length, 'length': size,
'name': to_utf8(os.path.split(path)[1]),
'content_type': content_type,
'private': private}
return {'pieces': ''.join(pieces),
'piece length': piece_length, 'length': size,
'name': to_utf8(os.path.split(path)[1]),
'content_type' : content_type,
'private': private }
return {'pieces': ''.join(pieces),
'piece length': piece_length, 'length': size,
'name': to_utf8(os.path.split(path)[1]),
'private': private}
'private': private}
def subfiles(d):
r = []

View File

@ -1,37 +1,11 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# path_chooser_common.py
#
# Copyright (C) 2013 Bro <bro.development@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 os
@ -41,9 +15,11 @@ def get_resource(filename):
import deluge
return deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", filename))
def is_hidden(filepath):
def has_hidden_attribute(filepath):
import win32api, win32con
import win32api
import win32con
try:
attribute = win32api.GetFileAttributes(filepath)
return attribute & (win32con.FILE_ATTRIBUTE_HIDDEN | win32con.FILE_ATTRIBUTE_SYSTEM)
@ -52,10 +28,11 @@ def is_hidden(filepath):
name = os.path.basename(os.path.abspath(filepath))
# Windows
if os.name== 'nt':
if os.name == 'nt':
return has_hidden_attribute(filepath)
return name.startswith('.')
def get_completion_paths(args):
"""
Takes a path value and returns the available completions.

View File

@ -1,36 +1,10 @@
#
# pluginmanagerbase.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.
#
@ -69,6 +43,7 @@ If you're the developer, please take a look at the plugins hosted on deluge's
git repository to have an idea of what needs to be changed.
"""
class PluginManagerBase:
"""PluginManagerBase is a base class for PluginManagers to inherit"""
@ -130,9 +105,9 @@ class PluginManagerBase:
self.available_plugins = []
for name in self.pkg_env:
log.debug("Found plugin: %s %s at %s",
self.pkg_env[name][0].project_name,
self.pkg_env[name][0].version,
self.pkg_env[name][0].location)
self.pkg_env[name][0].project_name,
self.pkg_env[name][0].version,
self.pkg_env[name][0].location)
self.available_plugins.append(self.pkg_env[name][0].project_name)
def enable_plugin(self, plugin_name):
@ -170,8 +145,7 @@ class PluginManagerBase:
plugin_name = plugin_name.replace("-", " ")
self.plugins[plugin_name] = instance
if plugin_name not in self.config["enabled_plugins"]:
log.debug("Adding %s to enabled_plugins list in config",
plugin_name)
log.debug("Adding %s to enabled_plugins list in config", plugin_name)
self.config["enabled_plugins"].append(plugin_name)
log.info("Plugin %s enabled..", plugin_name)

View File

@ -1,36 +1,10 @@
#
# init.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.
#
"""
@ -40,8 +14,10 @@ import logging
log = logging.getLogger(__name__)
class PluginInitBase(object):
_plugin_cls = None
def __init__(self, plugin_name):
self.plugin = self._plugin_cls(plugin_name)

View File

@ -1,36 +1,10 @@
#
# pluginbase.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-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
@ -39,6 +13,7 @@ import deluge.component as component
log = logging.getLogger(__name__)
class PluginBase(component.Component):
update_interval = 1
@ -52,6 +27,7 @@ class PluginBase(component.Component):
def disable(self):
raise NotImplementedError("Need to define a disable method!")
class CorePluginBase(PluginBase):
def __init__(self, plugin_name):
super(CorePluginBase, self).__init__("CorePlugin." + plugin_name)
@ -62,11 +38,13 @@ class CorePluginBase(PluginBase):
def __del__(self):
component.get("RPCServer").deregister_object(self)
class GtkPluginBase(PluginBase):
def __init__(self, plugin_name):
super(GtkPluginBase, self).__init__("GtkPlugin." + plugin_name)
log.debug("GtkPlugin initialized..")
class WebPluginBase(PluginBase):
scripts = []

View File

@ -106,7 +106,7 @@ STR_FIXED_START = 128
STR_FIXED_COUNT = 64
# Lists with length embedded in typecode.
LIST_FIXED_START = STR_FIXED_START+STR_FIXED_COUNT
LIST_FIXED_START = STR_FIXED_START + STR_FIXED_COUNT
LIST_FIXED_COUNT = 64
# Whether strings should be decoded when loading
@ -125,41 +125,41 @@ def decode_int(x, f):
if x[f] == '-':
if x[f + 1] == '0':
raise ValueError
elif x[f] == '0' and newf != f+1:
elif x[f] == '0' and newf != f + 1:
raise ValueError
return (n, newf+1)
return (n, newf + 1)
def decode_intb(x, f):
f += 1
return (struct.unpack('!b', x[f:f+1])[0], f+1)
return (struct.unpack('!b', x[f:f + 1])[0], f + 1)
def decode_inth(x, f):
f += 1
return (struct.unpack('!h', x[f:f+2])[0], f+2)
return (struct.unpack('!h', x[f:f + 2])[0], f + 2)
def decode_intl(x, f):
f += 1
return (struct.unpack('!l', x[f:f+4])[0], f+4)
return (struct.unpack('!l', x[f:f + 4])[0], f + 4)
def decode_intq(x, f):
f += 1
return (struct.unpack('!q', x[f:f+8])[0], f+8)
return (struct.unpack('!q', x[f:f + 8])[0], f + 8)
def decode_float32(x, f):
f += 1
n = struct.unpack('!f', x[f:f+4])[0]
return (n, f+4)
n = struct.unpack('!f', x[f:f + 4])[0]
return (n, f + 4)
def decode_float64(x, f):
f += 1
n = struct.unpack('!d', x[f:f+8])[0]
return (n, f+8)
n = struct.unpack('!d', x[f:f + 8])[0]
return (n, f + 8)
def decode_string(x, f):
@ -168,17 +168,17 @@ def decode_string(x, f):
n = int(x[f:colon])
except (OverflowError, ValueError):
n = long(x[f:colon])
if x[f] == '0' and colon != f+1:
if x[f] == '0' and colon != f + 1:
raise ValueError
colon += 1
s = x[colon:colon+n]
s = x[colon:colon + n]
if _decode_utf8:
s = s.decode('utf8')
return (s, colon+n)
return (s, colon + n)
def decode_list(x, f):
r, f = [], f+1
r, f = [], f + 1
while x[f] != CHR_TERM:
v, f = decode_func[x[f]](x, f)
r.append(v)
@ -186,7 +186,7 @@ def decode_list(x, f):
def decode_dict(x, f):
r, f = {}, f+1
r, f = {}, f + 1
while x[f] != CHR_TERM:
k, f = decode_func[x[f]](x, f)
r[k], f = decode_func[x[f]](x, f)
@ -194,15 +194,15 @@ def decode_dict(x, f):
def decode_true(x, f):
return (True, f+1)
return (True, f + 1)
def decode_false(x, f):
return (False, f+1)
return (False, f + 1)
def decode_none(x, f):
return (None, f+1)
return (None, f + 1)
decode_func = {}
decode_func['0'] = decode_string
@ -232,13 +232,13 @@ decode_func[CHR_NONE] = decode_none
def make_fixed_length_string_decoders():
def make_decoder(slen):
def f(x, f):
s = x[f+1:f+1+slen]
s = x[f + 1:f + 1 + slen]
if _decode_utf8:
s = s.decode("utf8")
return (s, f+1+slen)
return (s, f + 1 + slen)
return f
for i in range(STR_FIXED_COUNT):
decode_func[chr(STR_FIXED_START+i)] = make_decoder(i)
decode_func[chr(STR_FIXED_START + i)] = make_decoder(i)
make_fixed_length_string_decoders()
@ -246,14 +246,14 @@ make_fixed_length_string_decoders()
def make_fixed_length_list_decoders():
def make_decoder(slen):
def f(x, f):
r, f = [], f+1
r, f = [], f + 1
for i in range(slen):
v, f = decode_func[x[f]](x, f)
r.append(v)
return (tuple(r), f)
return f
for i in range(LIST_FIXED_COUNT):
decode_func[chr(LIST_FIXED_START+i)] = make_decoder(i)
decode_func[chr(LIST_FIXED_START + i)] = make_decoder(i)
make_fixed_length_list_decoders()
@ -261,12 +261,12 @@ make_fixed_length_list_decoders()
def make_fixed_length_int_decoders():
def make_decoder(j):
def f(x, f):
return (j, f+1)
return (j, f + 1)
return f
for i in range(INT_POS_FIXED_COUNT):
decode_func[chr(INT_POS_FIXED_START+i)] = make_decoder(i)
decode_func[chr(INT_POS_FIXED_START + i)] = make_decoder(i)
for i in range(INT_NEG_FIXED_COUNT):
decode_func[chr(INT_NEG_FIXED_START+i)] = make_decoder(-1-i)
decode_func[chr(INT_NEG_FIXED_START + i)] = make_decoder(-1 - i)
make_fixed_length_int_decoders()
@ -274,14 +274,14 @@ make_fixed_length_int_decoders()
def make_fixed_length_dict_decoders():
def make_decoder(slen):
def f(x, f):
r, f = {}, f+1
r, f = {}, f + 1
for j in range(slen):
k, f = decode_func[x[f]](x, f)
r[k], f = decode_func[x[f]](x, f)
return (r, f)
return f
for i in range(DICT_FIXED_COUNT):
decode_func[chr(DICT_FIXED_START+i)] = make_decoder(i)
decode_func[chr(DICT_FIXED_START + i)] = make_decoder(i)
make_fixed_length_dict_decoders()
@ -298,12 +298,11 @@ def loads(x, decode_utf8=False):
return r
def encode_int(x, r):
if 0 <= x < INT_POS_FIXED_COUNT:
r.append(chr(INT_POS_FIXED_START+x))
r.append(chr(INT_POS_FIXED_START + x))
elif -INT_NEG_FIXED_COUNT <= x < 0:
r.append(chr(INT_NEG_FIXED_START-1-x))
r.append(chr(INT_NEG_FIXED_START - 1 - x))
elif -128 <= x < 128:
r.extend((CHR_INT1, struct.pack('!b', x)))
elif -32768 <= x < 32768:
@ -415,15 +414,15 @@ def test():
f1 = struct.unpack('!f', struct.pack('!f', 25.5))[0]
f2 = struct.unpack('!f', struct.pack('!f', 29.3))[0]
f3 = struct.unpack('!f', struct.pack('!f', -0.6))[0]
ld = (({'a': 15, 'bb': f1, 'ccc': f2, '': (f3, (), False, True, '')}, ('a', 10**20),
tuple(range(-100000, 100000)), 'b'*31, 'b'*62, 'b'*64, 2**30, 2**33, 2**62, 2**64,
2**30, 2**33, 2**62, 2**64, False, False, True, -1, 2, 0),)
ld = (({'a': 15, 'bb': f1, 'ccc': f2, '': (f3, (), False, True, '')}, ('a', 10 ** 20),
tuple(range(-100000, 100000)), 'b' * 31, 'b' * 62, 'b' * 64, 2 ** 30, 2 ** 33, 2 ** 62, 2 ** 64,
2 ** 30, 2 ** 33, 2 ** 62, 2 ** 64, False, False, True, -1, 2, 0),)
assert loads(dumps(ld)) == ld
d = dict(zip(range(-100000, 100000), range(-100000, 100000)))
d.update({'a': 20, 20: 40, 40: 41, f1: f2, f2: f3, f3: False, False: True, True: False})
ld = (d, {}, {5: 6}, {7: 7, True: 8}, {9: 10, 22: 39, 49: 50, 44: ''})
assert loads(dumps(ld)) == ld
ld = ('', 'a'*10, 'a'*100, 'a'*1000, 'a'*10000, 'a'*100000, 'a'*1000000, 'a'*10000000)
ld = ('', 'a' * 10, 'a' * 100, 'a' * 1000, 'a' * 10000, 'a' * 100000, 'a' * 1000000, 'a' * 10000000)
assert loads(dumps(ld)) == ld
ld = tuple([dict(zip(range(n), range(n))) for n in range(100)]) + ('b',)
assert loads(dumps(ld)) == ld
@ -431,15 +430,15 @@ def test():
assert loads(dumps(ld)) == ld
ld = tuple([tuple(range(n)) for n in range(100)]) + ('b',)
assert loads(dumps(ld)) == ld
ld = tuple(['a'*n for n in range(1000)]) + ('b',)
ld = tuple(['a' * n for n in range(1000)]) + ('b',)
assert loads(dumps(ld)) == ld
ld = tuple(['a'*n for n in range(1000)]) + (None, True, None)
ld = tuple(['a' * n for n in range(1000)]) + (None, True, None)
assert loads(dumps(ld)) == ld
assert loads(dumps(None)) is None
assert loads(dumps({None: None})) == {None: None}
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 abs(loads(dumps(1.1, 64))-1.1) < 1e-12
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 abs(loads(dumps(1.1, 64)) - 1.1) < 1e-12
assert loads(dumps(u"Hello World!!"))
try:
import psyco

View File

@ -114,7 +114,7 @@ def create_plugin():
print("building 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")
os.system("chmod +x %s" % dev_link_path) #lazy..
os.system("chmod +x %s" % dev_link_path) # lazy..
os.system(dev_link_path)
@ -367,8 +367,8 @@ new %(name)sPlugin();
"""
GPL = """#
# %(filename)s
#
# -*- coding: utf-8 -*-#
# Copyright (C) %(current_year)d %(author_name)s <%(author_email)s>
#
# Basic plugin template created by:
@ -377,37 +377,13 @@ GPL = """#
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
# Copyright (C) 2010 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.
#
"""
NAMESPACE_INIT="""# this is a namespace package
NAMESPACE_INIT = """# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)
"""
@ -415,7 +391,8 @@ pkg_resources.declare_namespace(__name__)
CREATE_DEV_LINK = """#!/bin/bash
BASEDIR=$(cd `dirname $0` && pwd)
CONFIG_DIR=$( test -z $1 && echo "%(configdir)s" || echo "$1")
[ -d "$CONFIG_DIR/plugins" ] || echo "Config dir \"$CONFIG_DIR\" is either not a directory or is not a proper deluge config directory. Exiting"
[ -d "$CONFIG_DIR/plugins" ] || echo "Config dir \"$CONFIG_DIR\" is either not a directory \
or is not a proper deluge config directory. Exiting"
[ -d "$CONFIG_DIR/plugins" ] || exit 1
cd $BASEDIR
test -d $BASEDIR/temp || mkdir $BASEDIR/temp

View File

@ -3,32 +3,9 @@
#
# Copyright (C) Martijn Voncken 2008 <mvoncken@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.
#
#
@ -49,10 +26,10 @@ sclient.set_core_uri()
print("\n\n")
if 0: #aclient non-core
methods = sorted([m for m in dir(aclient) if not m.startswith('_')
if not m in ['add_torrent_file', 'has_callback', 'get_method',
'methodHelp', 'methodSignature', 'list_methods', 'add_torrent_file_binary']])
if 0: # aclient non-core
methods = sorted([m for m in dir(aclient) if not m.startswith('_')
if not m in ['add_torrent_file', 'has_callback', 'get_method', 'methodHelp',
'methodSignature', 'list_methods', 'add_torrent_file_binary']])
for m in methods:
func = getattr(aclient, m)
@ -64,14 +41,12 @@ if 0: #aclient non-core
except:
continue
print("\n'''%s(%s): '''\n" %(method_name, ", ".join(params)))
print("\n'''%s(%s): '''\n" % (method_name, ", ".join(params)))
print("%s" % pydoc.getdoc(func))
if 1: #baseclient/core
if 1: # baseclient/core
methods = sorted([m for m in dir(Core) if m.startswith("export")]
+ ['export_add_torrent_file_binary'] #HACK
)
+ ['export_add_torrent_file_binary']) # HACK
for m in methods:
@ -86,27 +61,26 @@ if 1: #baseclient/core
and not method_name in ['add_torrent_file_binary']):
params = ["[callback]"] + params
print("\n'''%s(%s): '''\n" %(method_name, ", ".join(params)))
print("\n'''%s(%s): '''\n" % (method_name, ", ".join(params)))
print("{{{\n%s\n}}}" % pydoc.getdoc(func))
if 0: #plugin-manager
import WebUi
if 0: # plugin-manager
from WebUi.pluginmanager import PluginManager
for m in methods:
func = getattr(PluginManager, m)
method_name = m
params = inspect.getargspec(func)[0][1:]
print("\n'''%s(%s): '''\n" %(method_name, ", ".join(params)))
print("\n'''%s(%s): '''\n" % (method_name, ", ".join(params)))
print("%s" % pydoc.getdoc(func))
if 0: #possible config-values
if 0: # possible config-values
print("=== config-values ===")
cfg = sclient.get_sconfig()
for key in sorted(cfg.keys()):
print("%s:%s()" % (key, type(cfg[key]).__name__))
if 0: #keys
if 0: # keys
print("""== Notes ==
* The available keys for get_torrent_status(id, keys)
{{{
@ -115,7 +89,4 @@ if 0: #keys
print("\n".join(textwrap.wrap(str(sorted(sclient.get_status_keys())), 100)))
print("""}}}""")
print("\n\n")

View File

@ -88,6 +88,7 @@ class ClientTestCase(unittest.TestCase):
d = client.connect(
"localhost", self.listen_port, username="", password=""
)
def on_connect(result):
self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN)
self.addCleanup(client.disconnect)

View File

@ -65,6 +65,7 @@ class TopLevelResource(Resource):
self.putChild("ubuntu-9.04-desktop-i386.iso.torrent",
File(common.rpath("ubuntu-9.04-desktop-i386.iso.torrent")))
class CoreTestCase(unittest.TestCase):
def setUp(self):
common.set_tmp_config_dir()

View File

@ -1,41 +1,12 @@
#
# test_rpcserver.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2013 Bro <bro.development@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 os
from twisted.python import log
from twisted.trial import unittest
import deluge.component as component
@ -48,14 +19,15 @@ from deluge.ui.common import get_localhost_auth
setupLogger("none")
class DelugeRPCProtocolTester(DelugeRPCProtocol):
messages = []
def transfer_message(self, data):
import traceback
self.messages.append(data)
class RPCServerTestCase(unittest.TestCase):
def setUp(self):
@ -91,13 +63,7 @@ class RPCServerTestCase(unittest.TestCase):
self.assertEquals(msg[2], data, str(msg))
def test_invalid_client_login(self):
ret = self.protocol.dispatch(self.request_id, "daemon.login", [1], {})
msg = self.protocol.messages.pop()
self.assertEquals(msg[0], rpcserver.RPC_ERROR)
self.assertEquals(msg[1], self.request_id)
def test_invalid_client_login(self):
ret = self.protocol.dispatch(self.request_id, "daemon.login", [1], {})
self.protocol.dispatch(self.request_id, "daemon.login", [1], {})
msg = self.protocol.messages.pop()
self.assertEquals(msg[0], rpcserver.RPC_ERROR)
self.assertEquals(msg[1], self.request_id)
@ -105,7 +71,7 @@ class RPCServerTestCase(unittest.TestCase):
def test_valid_client_login(self):
self.authmanager = AuthManager()
auth = get_localhost_auth()
ret = self.protocol.dispatch(self.request_id, "daemon.login", auth, {"client_version": "Test"})
self.protocol.dispatch(self.request_id, "daemon.login", auth, {"client_version": "Test"})
msg = self.protocol.messages.pop()
self.assertEquals(msg[0], rpcserver.RPC_RESPONSE, str(msg))
self.assertEquals(msg[1], self.request_id, str(msg))
@ -124,7 +90,7 @@ class RPCServerTestCase(unittest.TestCase):
self.assertEquals(msg[3][1], "AttributeError")
def test_daemon_info(self):
ret = self.protocol.dispatch(self.request_id, "daemon.info", [], {})
self.protocol.dispatch(self.request_id, "daemon.info", [], {})
msg = self.protocol.messages.pop()
self.assertEquals(msg[0], rpcserver.RPC_RESPONSE, str(msg))
self.assertEquals(msg[1], self.request_id, str(msg))

View File

@ -1,36 +1,10 @@
# -*- coding: utf-8 -*-
#
# test_transfer.py
#
# Copyright (C) 2012 Bro <bro.development@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
@ -113,8 +87,8 @@ class TransferTestClass(DelugeTransferProtocol):
try:
request = rencode.loads(dobj.decompress(data))
print("Successfully loaded message", end=' ')
print(" - Buffer length: %d, data length: %d, unused length: %d" % \
(len(data), len(data) - len(dobj.unused_data), len(dobj.unused_data)))
print(" - Buffer length: %d, data length: %d, unused length: %d" %
(len(data), len(data) - len(dobj.unused_data), len(dobj.unused_data)))
print("Packet count:", self.packet_count)
except Exception as ex:
#log.debug("Received possible invalid message (%r): %s", data, e)
@ -286,8 +260,8 @@ class DelugeTransferProtocolTestCase(unittest.TestCase):
expected_msgs_received_count = 0
# Verify that the expected number of complete messages has arrived
if expected_msgs_received_count != len(self.transfer.get_messages_in()):
print("Expected number of messages received is %d, but %d have been received." % \
(expected_msgs_received_count, len(self.transfer.get_messages_in())))
print("Expected number of messages received is %d, but %d have been received." %
(expected_msgs_received_count, len(self.transfer.get_messages_in())))
# Get the data as received by DelugeTransferProtocol
message1 = self.transfer.get_messages_in().pop(0)

View File

@ -1,37 +1,10 @@
# -*- coding: utf-8 -*-
#
# transfer.py
#
# Copyright (C) 2012 Bro <bro.development@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.
#
try:
@ -49,6 +22,7 @@ log = logging.getLogger(__name__)
MESSAGE_HEADER_SIZE = 5
class DelugeTransferProtocol(Protocol):
"""
Data messages are transfered using very a simple protocol.

View File

@ -57,220 +57,199 @@ _MAGIC = '\0\0\1\0'
log = logging.getLogger(__name__)
class Win32IcoFile (object):
"""
Decoder for Microsoft .ico files.
"""
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 = []
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')
header = struct.unpack('<3H', buf.read(6))
if (0, 1) != header[:2]:
raise SyntaxError('not an ico file')
self.nb_items = header[2]
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)
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__
# 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 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
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)
def get_image (self, size, bpp=False):
"""
Get an image from the icon
return self.frame(0)
Args:
size: tuple of (width, height)
bpp: color depth
"""
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)
def frame(self, idx):
"""
Get the icon from frame idx
return self.frame(0)
#end get_image
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)
def frame (self, idx):
"""
Get the icon from frame idx
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)
Args:
idx: Frame index
# 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
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)
# 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))
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)
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
# 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
# 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]
# 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))
# 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
)
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
# apply mask image as alpha channel
im = im.convert('RGBA')
im.putalpha(mask)
log.debug("image mode: %s", im.mode)
# 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]
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)
# 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
)
self.buf.seek(and_mask_offset)
mask_data = self.buf.read(total_bytes)
# apply mask image as alpha channel
im = im.convert('RGBA')
im.putalpha(mask)
log.debug("image mode: %s", im.mode)
# 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
)
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)
# 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)
self.buf.seek(and_mask_offset)
maskData = self.buf.read(total_bytes)
return im
#end frame
# 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__
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
class Win32IconImageFile (PIL.ImageFile.ImageFile):
"""
PIL read-only image support for Microsoft .ico files.
"""
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'.
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.
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.
"""
Handles classic, XP and Vista icon formats.
"""
format = 'ICO'
format_description = 'Microsoft icon'
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 _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 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

View File

@ -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

View File

@ -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

View File

@ -1,38 +1,11 @@
#
# coreconfig.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
# Deluge is free software.
# 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.
#
# 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.
#
#
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)

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -1 +1,2 @@
from web import start
assert start # silence pyflakes

View File

@ -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"):

View File

@ -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):

View File

@ -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:

View File

@ -4,7 +4,6 @@
#
import os
import re
import sys
from version import get_version
from subprocess import call
from datetime import datetime
@ -16,7 +15,7 @@ EXCLUSIONS = [
"deluge/tests",
]
webui_js_dir = "deluge/ui/web/js/deluge-all"
infiles_list= "infiles.list"
infiles_list = "infiles.list"
pot_filepath = os.path.join("deluge", "i18n", "deluge.pot")
re_exc_plugin_build = re.compile("deluge\/plugins\/.*\/build")
@ -55,7 +54,7 @@ with open(infiles_list, "wb") as f:
call(xgettext_cmd)
# find javascript files
js_to_translate=[]
js_to_translate = []
for (dirpath, dirnames, filenames) in os.walk(webui_js_dir):
for filename in filenames:
if os.path.splitext(filename)[1] == ".js":

View File

@ -17,3 +17,4 @@ frameworks = CoreFoundation, Foundation, AppKit
[flake8]
max-line-length = 120
builtins = _
ignore = N802

142
setup.py
View File

@ -23,11 +23,11 @@
#
try:
from setuptools import setup, find_packages, Extension
from setuptools import setup, find_packages
except ImportError:
import ez_setup
ez_setup.use_setuptools()
from setuptools import setup, find_packages, Extension
from setuptools import setup, find_packages
import os
import sys
@ -37,7 +37,7 @@ import glob
from version import get_version
from distutils import cmd, sysconfig
from distutils import cmd
from distutils.command.build import build as _build
from distutils.command.clean import clean as _clean
@ -53,12 +53,13 @@ def windows_check():
desktop_data = 'deluge/ui/data/share/applications/deluge.desktop'
class build_trans(cmd.Command):
description = 'Compile .po files into .mo files & create .desktop file'
user_options = [
('build-lib', None, "lib build folder"),
('develop', 'D', 'Compile translations in develop mode (deluge/i18n)')
('build-lib', None, "lib build folder"),
('develop', 'D', 'Compile translations in develop mode (deluge/i18n)')
]
boolean_options = ['develop']
@ -79,17 +80,17 @@ class build_trans(cmd.Command):
if not windows_check():
# creates the translated desktop file
INTLTOOL_MERGE='intltool-merge'
INTLTOOL_MERGE_OPTS='--utf8 --quiet --desktop-style'
desktop_in='deluge/ui/data/share/applications/deluge.desktop.in'
intltool_merge = 'intltool-merge'
intltool_merge_opts = '--utf8 --quiet --desktop-style'
desktop_in = 'deluge/ui/data/share/applications/deluge.desktop.in'
print('Creating desktop file: %s' % desktop_data)
os.system('C_ALL=C ' + '%s '*5 % (INTLTOOL_MERGE, INTLTOOL_MERGE_OPTS, \
po_dir, desktop_in, desktop_data))
os.system('C_ALL=C ' + '%s ' * 5 % (intltool_merge, intltool_merge_opts,
po_dir, desktop_in, desktop_data))
print('Compiling po files from %s...' % po_dir),
for path, names, filenames in os.walk(po_dir):
for f in filenames:
uptoDate = False
upto_date = False
if f.endswith('.po'):
lang = f[:len(f) - 3]
src = os.path.join(path, f)
@ -109,9 +110,9 @@ class build_trans(cmd.Command):
sys.stdout.flush()
msgfmt.make(src, dest)
else:
uptoDate = True
upto_date = True
if uptoDate:
if upto_date:
sys.stdout.write(' po files already upto date. ')
sys.stdout.write('\b\b \nFinished compiling translation files. \n')
@ -120,8 +121,8 @@ class build_plugins(cmd.Command):
description = "Build plugins into .eggs"
user_options = [
('install-dir=', None, "develop install folder"),
('develop', 'D', 'Compile plugins in develop mode')
('install-dir=', None, "develop install folder"),
('develop', 'D', 'Compile plugins in develop mode')
]
boolean_options = ['develop']
@ -134,12 +135,13 @@ class build_plugins(cmd.Command):
def run(self):
# Build the plugin eggs
PLUGIN_PATH = "deluge/plugins/*"
plugin_path = "deluge/plugins/*"
for path in glob.glob(PLUGIN_PATH):
for path in glob.glob(plugin_path):
if os.path.exists(os.path.join(path, "setup.py")):
if self.develop and self.install_dir:
os.system("cd " + path + "&& " + sys.executable + " setup.py develop --install-dir=%s" % self.install_dir)
os.system("cd " + path + "&& " + sys.executable +
" setup.py develop --install-dir=%s" % self.install_dir)
elif self.develop:
os.system("cd " + path + "&& " + sys.executable + " setup.py develop")
else:
@ -159,9 +161,9 @@ class egg_info_plugins(cmd.Command):
def run(self):
# Build the plugin eggs
PLUGIN_PATH = "deluge/plugins/*"
plugin_path = "deluge/plugins/*"
for path in glob.glob(PLUGIN_PATH):
for path in glob.glob(plugin_path):
if os.path.exists(os.path.join(path, "setup.py")):
os.system("cd " + path + "&& " + sys.executable + " setup.py egg_info")
@ -188,6 +190,7 @@ class build_docs(BuildDoc):
return " "
old_import = __builtins__.__import__
def new_import(name, globals={}, locals={}, fromlist=[], level=-1):
try:
return old_import(name, globals, locals, fromlist, level)
@ -205,6 +208,7 @@ class build_docs(BuildDoc):
class build(_build):
sub_commands = [('build_trans', None), ('build_plugins', None)] + _build.sub_commands
def run(self):
# Run all sub-commands (at least those that need to be run)
_build.run(self)
@ -218,7 +222,7 @@ class build(_build):
class clean_plugins(cmd.Command):
description = "Cleans the plugin folders"
user_options = [
('all', 'a', "remove all build output, not just temporary by-products")
('all', 'a', "remove all build output, not just temporary by-products")
]
boolean_options = ['all']
@ -231,9 +235,9 @@ class clean_plugins(cmd.Command):
def run(self):
print("Cleaning the plugin's folders..")
PLUGIN_PATH = "deluge/plugins/*"
plugin_path = "deluge/plugins/*"
for path in glob.glob(PLUGIN_PATH):
for path in glob.glob(plugin_path):
if os.path.exists(os.path.join(path, "setup.py")):
c = "cd " + path + "&& " + sys.executable + " setup.py clean"
if self.all:
@ -245,9 +249,9 @@ class clean_plugins(cmd.Command):
print("Deleting %s" % path)
os.remove(path)
EGG_INFO_DIR_PATH = "deluge/plugins/*/*.egg-info"
egg_info_dir_path = "deluge/plugins/*/*.egg-info"
for path in glob.glob(EGG_INFO_DIR_PATH):
for path in glob.glob(egg_info_dir_path):
# Delete the .egg-info's directories
if path[-9:] == ".egg-info":
print("Deleting %s" % path)
@ -255,9 +259,9 @@ class clean_plugins(cmd.Command):
os.remove(os.path.join(path, fpath))
os.removedirs(path)
ROOT_EGG_INFO_DIR_PATH = "deluge*.egg-info"
root_egg_info_dir_path = "deluge*.egg-info"
for path in glob.glob(ROOT_EGG_INFO_DIR_PATH):
for path in glob.glob(root_egg_info_dir_path):
print("Deleting %s" % path)
for fpath in os.listdir(path):
os.remove(os.path.join(path, fpath))
@ -334,49 +338,49 @@ if windows_check():
# Main setup
setup(
name = "deluge",
version = get_version(prefix='deluge-', suffix='.dev0'),
fullname = "Deluge Bittorrent Client",
description = "Bittorrent Client",
author = "Andrew Resch, Damien Churchill",
author_email = "andrewresch@gmail.com, damoxc@gmail.com",
keywords = "torrent bittorrent p2p fileshare filesharing",
long_description = """Deluge is a bittorrent client that utilizes a
name="deluge",
version=get_version(prefix='deluge-', suffix='.dev0'),
fullname="Deluge Bittorrent Client",
description="Bittorrent Client",
author="Andrew Resch, Damien Churchill",
author_email="andrewresch@gmail.com, damoxc@gmail.com",
keywords="torrent bittorrent p2p fileshare filesharing",
long_description="""Deluge is a bittorrent client that utilizes a
daemon/client model. There are various user interfaces available for
Deluge such as the GTKui, the webui and a console ui. Deluge uses
libtorrent in it's backend to handle the bittorrent protocol.""",
url = "http://deluge-torrent.org",
license = "GPLv3",
cmdclass = cmdclass,
data_files = _data_files,
package_data = {"deluge": ["ui/gtkui/glade/*.glade",
"ui/gtkui/glade/*.ui",
"ui/data/pixmaps/*.png",
"ui/data/pixmaps/*.svg",
"ui/data/pixmaps/*.ico",
"ui/data/pixmaps/*.gif",
"ui/data/pixmaps/flags/*.png",
"plugins/*.egg",
"i18n/*/LC_MESSAGES/*.mo",
"ui/web/index.html",
"ui/web/css/*.css",
"ui/web/icons/*.png",
"ui/web/images/*.gif",
"ui/web/images/*.png",
"ui/web/js/*.js",
"ui/web/js/*/*.js",
"ui/web/js/*/.order",
"ui/web/js/*/*/*.js",
"ui/web/js/*/*/.order",
"ui/web/js/*/*/*/*.js",
"ui/web/render/*.html",
"ui/web/themes/css/*.css",
"ui/web/themes/images/*/*.gif",
"ui/web/themes/images/*/*.png",
"ui/web/themes/images/*/*/*.gif",
"ui/web/themes/images/*/*/*.png"
]},
packages = find_packages(exclude=["plugins", "docs", "tests"]),
namespace_packages = ["deluge", "deluge.plugins"],
entry_points = entry_points
url="http://deluge-torrent.org",
license="GPLv3",
cmdclass=cmdclass,
data_files=_data_files,
package_data={"deluge": ["ui/gtkui/glade/*.glade",
"ui/gtkui/glade/*.ui",
"ui/data/pixmaps/*.png",
"ui/data/pixmaps/*.svg",
"ui/data/pixmaps/*.ico",
"ui/data/pixmaps/*.gif",
"ui/data/pixmaps/flags/*.png",
"plugins/*.egg",
"i18n/*/LC_MESSAGES/*.mo",
"ui/web/index.html",
"ui/web/css/*.css",
"ui/web/icons/*.png",
"ui/web/images/*.gif",
"ui/web/images/*.png",
"ui/web/js/*.js",
"ui/web/js/*/*.js",
"ui/web/js/*/.order",
"ui/web/js/*/*/*.js",
"ui/web/js/*/*/.order",
"ui/web/js/*/*/*/*.js",
"ui/web/render/*.html",
"ui/web/themes/css/*.css",
"ui/web/themes/images/*/*.gif",
"ui/web/themes/images/*/*.png",
"ui/web/themes/images/*/*/*.gif",
"ui/web/themes/images/*/*/*.png"
]},
packages=find_packages(exclude=["plugins", "docs", "tests"]),
namespace_packages=["deluge", "deluge.plugins"],
entry_points=entry_points
)

View File

@ -35,18 +35,20 @@ __all__ = ("get_version")
from subprocess import Popen, PIPE
VERSION_FILE = "RELEASE-VERSION"
def call_git_describe(prefix='', suffix=''):
cmd = 'git describe --tags --match %s[0-9]*' % prefix
def call_git_describe(prefix="", suffix=""):
cmd = "git describe --tags --match %s[0-9]*" % prefix
try:
version = Popen(cmd.split(), stdout=PIPE).communicate()[0]
version = version.strip().replace(prefix, '')
if '-' in version:
version = '.dev'.join(version.replace(suffix,'').split('-')[:2])
version = version.strip().replace(prefix, "")
if "-" in version:
version = ".dev".join(version.replace(suffix, "").split("-")[:2])
return version
except:
return None
def get_version(prefix='', suffix=''):
def get_version(prefix="", suffix=""):
try:
with open(VERSION_FILE, "r") as f:
release_version = f.readline().strip()
@ -67,4 +69,4 @@ def get_version(prefix='', suffix=''):
return version
if __name__ == "__main__":
print get_version(prefix='deluge-', suffix='.dev0')
print get_version(prefix="deluge-", suffix=".dev0")