Repository: 0x022b/transmissionrpc-ng (language: python)

Issue:
The Black code style
Use [The Black](https://github.com/psf/black) code style throughout the code base to normalise the code formatting.


Discussion / hints:

Fix patch:
diff --git a/.flake8 b/.flake8
index 8d947dc..8965fde 100644
--- a/.flake8
+++ b/.flake8
@@ -1,2 +1,4 @@
 [flake8]
-extend-ignore = E241,E501
+max-line-length = 80
+select = C,E,F,W,B,B950
+ignore = E203,E501,W503
diff --git a/contrib/helical.py b/contrib/helical.py
index ba3fea6..fb5c7aa 100644
--- a/contrib/helical.py
+++ b/contrib/helical.py
@@ -6,6 +6,7 @@
 import socket, urllib2, urlparse, base64, shlex
 import logging
 from optparse import OptionParser
+
 try:
     import readline
 except:
@@ -15,31 +16,34 @@
 from transmissionrpc.utils import *
 from transmissionrpc.constants import DEFAULT_PORT
 
-__author__    = u'Erik Svensson <erik.public@gmail.com>'
-__version__   = u'0.2'
-__copyright__ = u'Copyright (c) 2008 Erik Svensson'
-__license__   = u'MIT'
+__author__ = u"Erik Svensson <erik.public@gmail.com>"
+__version__ = u"0.2"
+__copyright__ = u"Copyright (c) 2008 Erik Svensson"
+__license__ = u"MIT"
+
 
 class Helical(cmd.Cmd):
     def __init__(self):
         cmd.Cmd.__init__(self)
-        self.intro = u'Helical %s' % (__version__)
-        self.doc_leader = u'''
+        self.intro = u"Helical %s" % (__version__)
+        self.doc_leader = u"""
 Helical is a command line interface that communicates with Transmission
 bittorent client through json-rpc. To run helical in interactive mode
 start without a command.
-'''
+"""
 
     def connect(self, address=None, port=None, username=None, password=None):
         self.tc = transmissionrpc.Client(address, port, username, password)
         urlo = urlparse.urlparse(self.tc.url)
         if urlo.port:
-            self.prompt = u'Helical %s:%d> ' % (urlo.hostname, urlo.port)
+            self.prompt = u"Helical %s:%d> " % (urlo.hostname, urlo.port)
         else:
-            self.prompt = u'Helical %s> ' % (urlo.hostname)
+            self.prompt = u"Helical %s> " % (urlo.hostname)
 
     def arg_tokenize(self, argstr):
-        return [unicode(token, 'utf-8') for token in shlex.split(argstr.encode('utf-8'))] or ['']
+        return [
+            unicode(token, "utf-8") for token in shlex.split(argstr.encode("utf-8"))
+        ] or [""]
 
     def word_complete(self, text, words):
         suggestions = []
@@ -59,36 +63,39 @@ def _complete_torrent(self, name, offset):
 
     def _complete_torrent_command(self, text, line, begidx, endidx):
         args = self.arg_tokenize(line)
-        item = args[-1] if len(args) > 1 else ''
+        item = args[-1] if len(args) > 1 else ""
         return self._complete_torrent(item, endidx - begidx)
 
     def help_quit(self):
-        print(u'quit|exit\n')
-        print(u'Exit to shell.\n')
+        print(u"quit|exit\n")
+        print(u"Exit to shell.\n")
 
     def do_quit(self, line):
-        sys.exit('')
-    #Alias
+        sys.exit("")
+
+    # Alias
     do_exit = do_quit
     help_exit = help_quit
     do_EOF = do_quit
 
     def help_add(self):
-        print(u'add <torrent file or url> [<target dir> paused=(yes|no) peer-limit=#]\n')
-        print(u'Add a torrent to the transfer list.\n')
+        print(
+            u"add <torrent file or url> [<target dir> paused=(yes|no) peer-limit=#]\n"
+        )
+        print(u"Add a torrent to the transfer list.\n")
 
     def do_add(self, line):
         args = self.arg_tokenize(line)
 
         if len(args) == 0:
-            print(u'Specify a torrent file or url')
+            print(u"Specify a torrent file or url")
             return
 
         torrent_url = args[0]
         args = args[1:]
         torrent_file = None
         if os.path.exists(torrent_url):
-            torrent_file = open(torrent_url, 'r')
+            torrent_file = open(torrent_url, "r")
         else:
             try:
                 torrent_file = urllib2.urlopen(torrent_url)
@@ -102,13 +109,13 @@ def do_add(self, line):
         if len(args) > 0:
             for arg in args:
                 try:
-                    (k,v) = arg.split('=')
+                    (k, v) = arg.split("=")
                     add_args[str(k)] = str(v)
                 except:
-                    if 'download_dir' not in add_args:
+                    if "download_dir" not in add_args:
                         try:
                             os.mkdir(arg)
-                            add_args['target'] = arg
+                            add_args["target"] = arg
                             continue
                         except:
                             pass
@@ -124,86 +131,88 @@ def do_magnet(self, line):
         args = self.arg_tokenize(line)
 
         if len(args) == 0:
-            print(u'Specify a torrent file or url')
+            print(u"Specify a torrent file or url")
             return
 
         torrent_url = args[0]
-        
+
         try:
             self.tc.add_uri(torrent_url)
         except transmissionrpc.TransmissionError, e:
             print(u'Failed to add torrent "%s"' % e)
-            
+
     def complete_remove(self, text, line, begidx, endidx):
         return self._complete_torrent_command(text, line, begidx, endidx)
 
     def help_remove(self):
-        print(u'remove <torrent id> [,<torrent id>, ...]\n')
-        print(u'Remove one or more torrents from the transfer list.\n')
+        print(u"remove <torrent id> [,<torrent id>, ...]\n")
+        print(u"Remove one or more torrents from the transfer list.\n")
 
     def do_remove(self, line):
         args = self.arg_tokenize(line)
         if len(args) == 0:
-            raise ValueError(u'No torrent id')
+            raise ValueError(u"No torrent id")
         self.tc.remove(args)
 
     def complete_start(self, text, line, begidx, endidx):
         return self._complete_torrent_command(text, line, begidx, endidx)
 
     def help_start(self):
-        print(u'start <torrent id> [,<torrent id>, ...]\n')
-        print(u'Start one or more queued torrent transfers.\n')
+        print(u"start <torrent id> [,<torrent id>, ...]\n")
+        print(u"Start one or more queued torrent transfers.\n")
 
     def do_start(self, line):
         args = self.arg_tokenize(line)
         if len(args) == 0:
-            raise ValueError(u'No torrent id')
+            raise ValueError(u"No torrent id")
         self.tc.start(args)
 
     def complete_stop(self, text, line, begidx, endidx):
         return self._complete_torrent_command(text, line, begidx, endidx)
 
     def help_stop(self):
-        print(u'stop <torrent id> [,<torrent id>, ...]\n')
-        print(u'Stop one or more active torrent transfers.\n')
+        print(u"stop <torrent id> [,<torrent id>, ...]\n")
+        print(u"Stop one or more active torrent transfers.\n")
 
     def do_stop(self, line):
         args = self.arg_tokenize(line)
         if len(args) == 0:
-            raise ValueError(u'No torrent id')
+            raise ValueError(u"No torrent id")
         self.tc.stop(args)
 
     def complete_verify(self, text, line, begidx, endidx):
         return self._complete_torrent_command(text, line, begidx, endidx)
 
     def help_verify(self):
-        print(u'verify <torrent id> [,<torrent id>, ...]\n')
-        print(u'Verify one or more torrent transfers.\n')
+        print(u"verify <torrent id> [,<torrent id>, ...]\n")
+        print(u"Verify one or more torrent transfers.\n")
 
     def do_verify(self, line):
         args = self.arg_tokenize(line)
         if len(args) == 0:
-            raise ValueError(u'No torrent id')
+            raise ValueError(u"No torrent id")
         self.tc.verify(args)
 
     def complete_info(self, text, line, begidx, endidx):
         return self._complete_torrent_command(text, line, begidx, endidx)
 
     def help_info(self):
-        print(u'info [<torrent id>, ...]\n')
-        print(u'Get details for a torrent. If no torrent id is provided, all torrents are displayed.\n')
+        print(u"info [<torrent id>, ...]\n")
+        print(
+            u"Get details for a torrent. If no torrent id is provided, all torrents are displayed.\n"
+        )
 
     def do_info(self, line):
         args = self.arg_tokenize(line)
         if len(args) == 0:
-            raise ValueError(u'No torrent id')
+            raise ValueError(u"No torrent id")
         result = self.tc.info(args)
         for id, torrent in result.iteritems():
             print(self._torrent_detail(torrent))
 
     def help_list(self):
-        print(u'list\n')
-        print(u'List all torrent transfers.\n')
+        print(u"list\n")
+        print(u"List all torrent transfers.\n")
 
     def do_list(self, line):
         args = self.arg_tokenize(line)
@@ -211,16 +220,16 @@ def do_list(self, line):
         self._list_torrents(result)
 
     def help_files(self):
-        print(u'files [<torrent id>, ...]\n')
-        print(u'Get the file list for one or more torrents\n')
+        print(u"files [<torrent id>, ...]\n")
+        print(u"Get the file list for one or more torrents\n")
 
     def do_files(self, line):
         args = self.arg_tokenize(line)
         result = self.tc.get_files(args)
         for tid, files in result.iteritems():
-            print('torrent id: %d' % tid)
+            print("torrent id: %d" % tid)
             for fid, file in files.iteritems():
-                print('  %d: %s' % (fid, file['name']))
+                print("  %d: %s" % (fid, file["name"]))
 
     def do_set(self, line):
         args = self.arg_tokenize(line)
@@ -231,7 +240,7 @@ def do_set(self, line):
         if len(args) > 0:
             for arg in args:
                 try:
-                    (k,v) = arg.split(u'=')
+                    (k, v) = arg.split(u"=")
                     set_args[str(k)] = str(v)
                     add_ids = False
                 except:
@@ -243,22 +252,22 @@ def do_set(self, line):
             result = self.tc.change(ids, **set_args)
 
     def complete_session(self, text, line, begidx, endidx):
-        return self.word_complete(text, [u'get', u'set', u'stats'])
+        return self.word_complete(text, [u"get", u"set", u"stats"])
 
     def help_session(self):
-        print(u'session (get|stats)\n')
-        print(u'Get session parameters or session statistics.\n')
+        print(u"session (get|stats)\n")
+        print(u"Get session parameters or session statistics.\n")
 
     def do_session(self, line):
         args = self.arg_tokenize(line)
-        if len(args[0]) == 0 or args[0] == u'get':
+        if len(args[0]) == 0 or args[0] == u"get":
             self.tc.get_session()
             print(self.tc.session)
-        elif args[0] == u'stats':
+        elif args[0] == u"stats":
             print(self.tc.session_stats())
 
     def do_request(self, line):
-        (method, sep, args) = line.partition(' ')
+        (method, sep, args) = line.partition(" ")
         try:
             args = eval(args)
         except SyntaxError:
@@ -277,104 +286,114 @@ def _list_torrents(self, torrents):
                 print(self._torrent_brief(torrent))
 
     def _torrent_brief_header(self):
-        return u' Id   Done   ETA           Status       Download     Upload       Ratio  Name'
+        return u" Id   Done   ETA           Status       Download     Upload       Ratio  Name"
 
     def _torrent_brief(self, torrent):
-        s = u'% 3d: ' % (torrent.id)
+        s = u"% 3d: " % (torrent.id)
         try:
-            s += u'%5.1f%%' % torrent.progress
+            s += u"%5.1f%%" % torrent.progress
         except:
             pass
         try:
-            s += u' %- 13s' % torrent.format_eta()
+            s += u" %- 13s" % torrent.format_eta()
         except:
-            s += u' -            '
+            s += u" -            "
         try:
-            s += u' %- 12s' % torrent.status
+            s += u" %- 12s" % torrent.status
         except:
-            s += u' -status     '
+            s += u" -status     "
             pass
         try:
-            s += u' %6.1f %- 5s' % format_speed(torrent.rateDownload)
-            s += u' %6.1f %- 5s' % format_speed(torrent.rateUpload)
+            s += u" %6.1f %- 5s" % format_speed(torrent.rateDownload)
+            s += u" %6.1f %- 5s" % format_speed(torrent.rateUpload)
         except:
-            s += u' -rate      '
-            s += u' -rate      '
+            s += u" -rate      "
+            s += u" -rate      "
             pass
         try:
-            s += u' %4.2f  ' % torrent.ratio
+            s += u" %4.2f  " % torrent.ratio
         except:
-            s += u' -ratio'
+            s += u" -ratio"
             pass
-        s += u' ' + torrent.name
+        s += u" " + torrent.name
         return s
 
     def _torrent_detail(self, torrent):
-        s = ''
-        s +=   '            id: ' + str(torrent.fields['id'])
-        s += '\n          name: ' + torrent.fields['name']
-        s += '\n          hash: ' + torrent.fields['hashString']
-        s += '\n'
-        try: # size
-            f = ''
-            f += '\n      progress: %.2f%%' % torrent.progress
-            f += '\n         total: %.2f %s' % format_size(torrent.totalSize)
-            f += '\n      reqested: %.2f %s' % format_size(torrent.sizeWhenDone)
-            f += '\n     remaining: %.2f %s' % format_size(torrent.leftUntilDone)
-            f += '\n      verified: %.2f %s' % format_size(torrent.haveValid)
-            f += '\n  not verified: %.2f %s' % format_size(torrent.haveUnchecked)
-            s += f + '\n'
+        s = ""
+        s += "            id: " + str(torrent.fields["id"])
+        s += "\n          name: " + torrent.fields["name"]
+        s += "\n          hash: " + torrent.fields["hashString"]
+        s += "\n"
+        try:  # size
+            f = ""
+            f += "\n      progress: %.2f%%" % torrent.progress
+            f += "\n         total: %.2f %s" % format_size(torrent.totalSize)
+            f += "\n      reqested: %.2f %s" % format_size(torrent.sizeWhenDone)
+            f += "\n     remaining: %.2f %s" % format_size(torrent.leftUntilDone)
+            f += "\n      verified: %.2f %s" % format_size(torrent.haveValid)
+            f += "\n  not verified: %.2f %s" % format_size(torrent.haveUnchecked)
+            s += f + "\n"
         except KeyError:
             pass
-        try: # activity
-            f = ''
-            f += '\n        status: ' + str(torrent.status)
-            f += '\n      download: %.2f %s' % format_speed(torrent.rateDownload)
-            f += '\n        upload: %.2f %s' % format_speed(torrent.rateUpload)
-            f += '\n     available: %.2f %s' % format_size(torrent.desiredAvailable)
-            f += '\ndownload peers: ' + str(torrent.peersSendingToUs)
-            f += '\n  upload peers: ' + str(torrent.peersGettingFromUs)
-            s += f + '\n'
+        try:  # activity
+            f = ""
+            f += "\n        status: " + str(torrent.status)
+            f += "\n      download: %.2f %s" % format_speed(torrent.rateDownload)
+            f += "\n        upload: %.2f %s" % format_speed(torrent.rateUpload)
+            f += "\n     available: %.2f %s" % format_size(torrent.desiredAvailable)
+            f += "\ndownload peers: " + str(torrent.peersSendingToUs)
+            f += "\n  upload peers: " + str(torrent.peersGettingFromUs)
+            s += f + "\n"
         except KeyError:
             pass
-        try: # history
-            f = ''
-            f += '\n         ratio: %.2f' % torrent.ratio
-            f += '\n    downloaded: %.2f %s' % format_size(torrent.downloadedEver)
-            f += '\n      uploaded: %.2f %s' % format_size(torrent.uploadedEver)
-            f += '\n        active: ' + format_timestamp(torrent.activityDate)
-            f += '\n         added: ' + format_timestamp(torrent.addedDate)
-            f += '\n       started: ' + format_timestamp(torrent.startDate)
-            f += '\n          done: ' + format_timestamp(torrent.doneDate)
-            s += f + '\n'
+        try:  # history
+            f = ""
+            f += "\n         ratio: %.2f" % torrent.ratio
+            f += "\n    downloaded: %.2f %s" % format_size(torrent.downloadedEver)
+            f += "\n      uploaded: %.2f %s" % format_size(torrent.uploadedEver)
+            f += "\n        active: " + format_timestamp(torrent.activityDate)
+            f += "\n         added: " + format_timestamp(torrent.addedDate)
+            f += "\n       started: " + format_timestamp(torrent.startDate)
+            f += "\n          done: " + format_timestamp(torrent.doneDate)
+            s += f + "\n"
         except KeyError:
             pass
         return s
 
+
 def main(args=None):
     """Main entry point"""
     if sys.version_info[0] <= 2 and sys.version_info[1] <= 5:
         socket.setdefaulttimeout(30)
     if args is None:
         args = sys.argv[1:]
-    parser = OptionParser(usage='Usage: %prog [options] [[address]:[port]] [command]')
-    parser.add_option('-u', '--username', dest='username',
-                    help='Athentication username.')
-    parser.add_option('-p', '--password', dest='password',
-                    help='Athentication password.')
-    parser.add_option('-d', '--debug', dest='debug',
-                    help='Enable debug messages.', action="store_true")
+    parser = OptionParser(usage="Usage: %prog [options] [[address]:[port]] [command]")
+    parser.add_option(
+        "-u", "--username", dest="username", help="Athentication username."
+    )
+    parser.add_option(
+        "-p", "--password", dest="password", help="Athentication password."
+    )
+    parser.add_option(
+        "-d",
+        "--debug",
+        dest="debug",
+        help="Enable debug messages.",
+        action="store_true",
+    )
     (values, args) = parser.parse_args(args)
-    commands = [cmd[3:] for cmd in itertools.ifilter(lambda c: c[:3] == 'do_', dir(Helical))]
-    address = 'localhost'
+    commands = [
+        cmd[3:] for cmd in itertools.ifilter(lambda c: c[:3] == "do_", dir(Helical))
+    ]
+    address = "localhost"
     port = DEFAULT_PORT
     command = None
     if values.debug:
-        logger = logging.getLogger('transmissionrpc')
+        logger = logging.getLogger("transmissionrpc")
         logger.setLevel(logging.DEBUG)
         loghandler = logging.StreamHandler()
         loghandler.setLevel(logging.DEBUG)
-        logging.getLogger('transmissionrpc').addHandler(loghandler)
+        logging.getLogger("transmissionrpc").addHandler(loghandler)
     for arg in args:
         if arg in commands:
             command = arg
@@ -393,13 +412,16 @@ def main(args=None):
         return
 
     if command:
-        command_args = u' '.join([u'"%s"' % arg for arg in args[args.index(command)+1:]])
+        command_args = u" ".join(
+            [u'"%s"' % arg for arg in args[args.index(command) + 1 :]]
+        )
         helical.onecmd(command + command_args)
     else:
         try:
             helical.cmdloop()
         except KeyboardInterrupt:
-            helical.do_quit('')
+            helical.do_quit("")
+
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     sys.exit(main())
diff --git a/doc/conf.py b/doc/conf.py
index 8fb9c38..6669a30 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -15,70 +15,70 @@
 
 import sys, os, os.path
 
-sys.path.append(os.path.abspath(u'..'))
+sys.path.append(os.path.abspath(u".."))
 
 # If your extensions are in another directory, add it here. If the directory
 # is relative to the documentation root, use os.path.abspath to make it
 # absolute, like shown here.
-#sys.path.append(os.path.abspath('some/directory'))
+# sys.path.append(os.path.abspath('some/directory'))
 
 # General configuration
 # ---------------------
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest']
+extensions = ["sphinx.ext.autodoc", "sphinx.ext.doctest"]
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['.templates']
+templates_path = [".templates"]
 
 # The suffix of source filenames.
-source_suffix = '.rst'
+source_suffix = ".rst"
 
 # The master toctree document.
-master_doc = 'index'
+master_doc = "index"
 
 # General substitutions.
-project = 'Transmission RPC'
-copyright = '2008-2014, Erik Svensson'
+project = "Transmission RPC"
+copyright = "2008-2014, Erik Svensson"
 
 # The default replacements for |version| and |release|, also used in various
 # other places throughout the built documents.
 #
 # The short X.Y version.
-version = '0.12'
+version = "0.12"
 # The full version, including alpha/beta/rc tags.
-release = '0.12'
+release = "0.12"
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
-#today = ''
+# today = ''
 # Else, today_fmt is used as the format for a strftime call.
-today_fmt = '%B %d, %Y'
+today_fmt = "%B %d, %Y"
 
 # List of documents that shouldn't be included in the build.
-#unused_docs = []
+# unused_docs = []
 
 # List of directories, relative to source directories, that shouldn't be searched
 # for source files.
-#exclude_dirs = []
+# exclude_dirs = []
 
 # The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
+# default_role = None
 
 # If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
 
 # If true, the current module name will be prepended to all description
 # unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
 
 # If true, sectionauthor and moduleauthor directives will be shown in the
 # output. They are ignored by default.
-#show_authors = False
+# show_authors = False
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'friendly'
+pygments_style = "friendly"
 
 
 # Options for HTML output
@@ -87,98 +87,104 @@
 # The style sheet to use for HTML and HTML Help pages. A file of that name
 # must exist either in Sphinx' static/ path, or in one of the custom paths
 # given in html_static_path.
-html_style = 'style.css'
+html_style = "style.css"
 
 # The name for this set of Sphinx documents.  If None, it defaults to
 # "<project> v<release> documentation".
-#html_title = None
+# html_title = None
 
 # A shorter title for the navigation bar.  Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
 
 # The name of an image file (within the static path) to place at the top of
 # the sidebar.
-#html_logo = None
+# html_logo = None
 
 # The name of an image file (within the static path) to use as favicon of the
 # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
 # pixels large.
-#html_favicon = None
+# html_favicon = None
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+html_static_path = ["_static"]
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
-html_last_updated_fmt = '%b %d, %Y'
+html_last_updated_fmt = "%b %d, %Y"
 
 # If true, SmartyPants will be used to convert quotes and dashes to
 # typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
 
 # Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
 
 # Additional templates that should be rendered to pages, maps page names to
 # template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
 
 # If false, no module index is generated.
-#html_use_modindex = True
+# html_use_modindex = True
 
 # If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
 
 # If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
 
 # If true, the reST sources are included in the HTML build as _sources/<name>.
-#html_copy_source = True
+# html_copy_source = True
 
 # If true, an OpenSearch description file will be output, and all pages will
 # contain a <link> tag referring to it.  The value of this option must be the
 # base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
 
 # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = ''
+# html_file_suffix = ''
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'trdoc'
+htmlhelp_basename = "trdoc"
 
 
 # Options for LaTeX output
 # ------------------------
 
 # The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
+# latex_paper_size = 'letter'
 
 # The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
+# latex_font_size = '10pt'
 
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, document class [howto/manual]).
 latex_documents = [
-  ('index', 'Transmission.tex', 'Transmission Documentation', 'Erik Svensson', 'manual'),
+    (
+        "index",
+        "Transmission.tex",
+        "Transmission Documentation",
+        "Erik Svensson",
+        "manual",
+    ),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
 # the title page.
-#latex_logo = None
+# latex_logo = None
 
 # For "manual" documents, if this is true, then toplevel headings are parts,
 # not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
 
 # Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
+# latex_preamble = ''
 
 # Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
 
 # If false, no module index is generated.
-#latex_use_modindex = True
+# latex_use_modindex = True
 
-autoclass_content = 'both'
+autoclass_content = "both"
diff --git a/setup.py b/setup.py
index 839c781..ff8b273 100644
--- a/setup.py
+++ b/setup.py
@@ -10,23 +10,23 @@
     long_description = fh.read()
 
 setup(
-    name='transmissionrpc-ng',
-    version='0.14.1',
-    author='Janne K',
-    author_email='0x022b@gmail.com',
-    description='Python module that implements the Transmission BitTorent client RPC protocol.',
+    name="transmissionrpc-ng",
+    version="0.14.0",
+    author="Janne K",
+    author_email="0x022b@gmail.com",
+    description="Python module that implements the Transmission BitTorent client RPC protocol.",
     long_description=long_description,
     long_description_content_type="text/markdown",
-    url='https://github.com/0x022b/transmissionrpc-ng',
-    keywords='transmission bittorent torrent',
-    packages=['transmissionrpc'],
+    url="https://github.com/0x022b/transmissionrpc-ng",
+    keywords="transmission bittorent torrent",
+    packages=["transmissionrpc"],
     test_suite="test",
     zip_safe=True,
     classifiers=[
-        'Intended Audience :: Developers',
-        'License :: OSI Approved :: MIT License',
-        'Topic :: Communications :: File Sharing',
-        'Topic :: Internet'
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: MIT License",
+        "Topic :: Communications :: File Sharing",
+        "Topic :: Internet",
     ],
-    python_requires='>=3.6',
+    python_requires=">=3.6",
 )
diff --git a/transmissionrpc/__init__.py b/transmissionrpc/__init__.py
index 2ee2750..5299a4d 100644
--- a/transmissionrpc/__init__.py
+++ b/transmissionrpc/__init__.py
@@ -2,6 +2,7 @@
 # Copyright (c) 2008-2014 Erik Svensson <erik.public@gmail.com>
 # Copyright (c) 2019 Janne K <0x022b@gmail.com>
 # Licensed under the MIT license.
+# flake8: noqa
 
 from transmissionrpc.constants import (
     DEFAULT_PORT,
@@ -9,13 +10,13 @@
     PRIORITY,
     RATIO_LIMIT,
     LOGGER,
-)  # noqa: F401
-from transmissionrpc.error import TransmissionError, HTTPHandlerError  # noqa: F401
-from transmissionrpc.httphandler import HTTPHandler, DefaultHTTPHandler  # noqa: F401
-from transmissionrpc.torrent import Torrent  # noqa: F401
-from transmissionrpc.session import Session  # noqa: F401
-from transmissionrpc.client import Client  # noqa: F401
-from transmissionrpc.utils import add_stdout_logger, add_file_logger  # noqa: F401
+)
+from transmissionrpc.error import TransmissionError, HTTPHandlerError
+from transmissionrpc.httphandler import HTTPHandler, DefaultHTTPHandler
+from transmissionrpc.torrent import Torrent
+from transmissionrpc.session import Session
+from transmissionrpc.client import Client
+from transmissionrpc.utils import add_stdout_logger, add_file_logger
 
 __author__ = "Janne K <0x022b@gmail.com>"
 __version_major__ = 0
diff --git a/transmissionrpc/client.py b/transmissionrpc/client.py
index 132cb65..968b116 100644
--- a/transmissionrpc/client.py
+++ b/transmissionrpc/client.py
@@ -20,7 +20,14 @@
 
 from transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT
 from transmissionrpc.error import TransmissionError, HTTPHandlerError
-from transmissionrpc.utils import LOGGER, get_arguments, make_rpc_name, argument_value_convert, rpc_bool, is_logger_configured
+from transmissionrpc.utils import (
+    LOGGER,
+    get_arguments,
+    make_rpc_name,
+    argument_value_convert,
+    rpc_bool,
+    is_logger_configured,
+)
 from transmissionrpc.httphandler import DefaultHTTPHandler
 from transmissionrpc.torrent import Torrent
 from transmissionrpc.session import Session
@@ -30,7 +37,7 @@ def debug_httperror(error):
     """
     Log the Transmission RPC HTTP error.
     """
-    if sys.platform == 'win32':
+    if sys.platform == "win32":
         msg = error.message.decode(sys.stdout.encoding)
     else:
         msg = error.message
@@ -41,15 +48,15 @@ def debug_httperror(error):
     LOGGER.debug(
         json.dumps(
             {
-                'response': {
-                    'url': error.url,
-                    'code': error.code,
-                    'msg': msg,
-                    'headers': error.headers,
-                    'data': data,
+                "response": {
+                    "url": error.url,
+                    "code": error.code,
+                    "msg": msg,
+                    "headers": error.headers,
+                    "data": data,
                 }
             },
-            indent=2
+            indent=2,
         )
     )
 
@@ -67,7 +74,7 @@ def parse_torrent_id(arg):
     elif isinstance(arg, str):
         try:
             torrent_id = int(arg)
-            if torrent_id >= 2**31:
+            if torrent_id >= 2 ** 31:
                 torrent_id = None
         except (ValueError, TypeError):
             pass
@@ -90,7 +97,7 @@ def parse_torrent_ids(args):
     if args is None:
         pass
     elif isinstance(args, str):
-        for item in re.split('[ ,]+', args):
+        for item in re.split("[ ,]+", args):
             if not item:
                 continue
             addition = None
@@ -99,7 +106,7 @@ def parse_torrent_ids(args):
                 addition = [torrent_id]
             if not addition:
                 # handle index ranges i.e. 5:10
-                match = re.match(r'^(\d+):(\d+)$', item)
+                match = re.match(r"^(\d+):(\d+)$", item)
                 if match:
                     try:
                         idx_from = int(match.group(1))
@@ -108,7 +115,7 @@ def parse_torrent_ids(args):
                     except ValueError:
                         pass
             if not addition:
-                raise ValueError('Invalid torrent id, \"%s\"' % item)
+                raise ValueError('Invalid torrent id, "%s"' % item)
             ids.extend(addition)
     elif isinstance(args, (list, tuple)):
         for item in args:
@@ -116,7 +123,7 @@ def parse_torrent_ids(args):
     else:
         torrent_id = parse_torrent_id(args)
         if torrent_id is None:
-            raise ValueError('Invalid torrent id')
+            raise ValueError("Invalid torrent id")
         else:
             ids = [torrent_id]
     return ids
@@ -127,48 +134,63 @@ class Client:
     Client is the class handling the Transmission JSON-RPC client protocol.
     """
 
-    def __init__(self, address='localhost', port=DEFAULT_PORT, user=None, password=None, http_handler=None, timeout=None):
+    def __init__(
+        self,
+        address="localhost",
+        port=DEFAULT_PORT,
+        user=None,
+        password=None,
+        http_handler=None,
+        timeout=None,
+    ):
         if isinstance(timeout, (int, float)):
             self._query_timeout = float(timeout)
         else:
             self._query_timeout = DEFAULT_TIMEOUT
         urlo = urlparse(address)
-        if urlo.scheme == '':
-            base_url = 'http://' + address + ':' + str(port)
-            self.url = base_url + '/transmission/rpc'
+        if urlo.scheme == "":
+            base_url = "http://" + address + ":" + str(port)
+            self.url = base_url + "/transmission/rpc"
         else:
             if urlo.port:
-                self.url = urlo.scheme + '://' + urlo.hostname + \
-                    ':' + str(urlo.port) + urlo.path
+                self.url = (
+                    urlo.scheme
+                    + "://"
+                    + urlo.hostname
+                    + ":"
+                    + str(urlo.port)
+                    + urlo.path
+                )
             else:
-                self.url = urlo.scheme + '://' + urlo.hostname + urlo.path
+                self.url = urlo.scheme + "://" + urlo.hostname + urlo.path
             LOGGER.info('Using custom URL "%s".', self.url)
             if urlo.username and urlo.password:
                 user = urlo.username
                 password = urlo.password
             elif urlo.username or urlo.password:
                 LOGGER.warning(
-                    'Either user or password missing, not using authentication.')
+                    "Either user or password missing, not using authentication."
+                )
         if http_handler is None:
             self.http_handler = DefaultHTTPHandler()
         else:
-            if hasattr(http_handler, 'set_authentication') and hasattr(http_handler, 'request'):
+            if hasattr(http_handler, "set_authentication") and hasattr(
+                http_handler, "request"
+            ):
                 self.http_handler = http_handler
             else:
-                raise ValueError('Invalid HTTP handler.')
+                raise ValueError("Invalid HTTP handler.")
         if user and password:
             self.http_handler.set_authentication(self.url, user, password)
         elif user or password:
-            LOGGER.warning(
-                'Either user or password missing, not using authentication.')
+            LOGGER.warning("Either user or password missing, not using authentication.")
         self._sequence = 0
         self.session = None
         self.session_id = 0
         self.server_version = None
         self.protocol_version = None
         self.get_session()
-        self.torrent_get_arguments = get_arguments(
-            'torrent-get', self.rpc_version)
+        self.torrent_get_arguments = get_arguments("torrent-get", self.rpc_version)
 
     def _get_timeout(self):
         """
@@ -188,14 +210,15 @@ def _del_timeout(self):
         """
         self._query_timeout = DEFAULT_TIMEOUT
 
-    timeout = property(_get_timeout, _set_timeout,
-                       _del_timeout, doc="HTTP query timeout.")
+    timeout = property(
+        _get_timeout, _set_timeout, _del_timeout, doc="HTTP query timeout."
+    )
 
     def _http_query(self, query, timeout=None):
         """
         Query Transmission through HTTP.
         """
-        headers = {'x-transmission-session-id': str(self.session_id)}
+        headers = {"x-transmission-session-id": str(self.session_id)}
         result = {}
         request_count = 0
         if timeout is None:
@@ -203,112 +226,131 @@ def _http_query(self, query, timeout=None):
         use_logger = is_logger_configured()
         while True:
             if use_logger:
-                LOGGER.debug(json.dumps(
-                    {'url': self.url, 'headers': headers, 'query': query, 'timeout': timeout}, indent=2))
+                LOGGER.debug(
+                    json.dumps(
+                        {
+                            "url": self.url,
+                            "headers": headers,
+                            "query": query,
+                            "timeout": timeout,
+                        },
+                        indent=2,
+                    )
+                )
             try:
-                result = self.http_handler.request(
-                    self.url, query, headers, timeout)
+                result = self.http_handler.request(self.url, query, headers, timeout)
                 break
             except HTTPHandlerError as error:
                 if error.code == 409:
                     if use_logger:
                         LOGGER.info(
-                            'Server responded with 409, trying to set session-id.')
+                            "Server responded with 409, trying to set session-id."
+                        )
                     if request_count > 1:
-                        raise TransmissionError(
-                            'Session ID negotiation failed.', error)
+                        raise TransmissionError("Session ID negotiation failed.", error)
                     session_id = None
                     for key in list(error.headers.keys()):
-                        if key.lower() == 'x-transmission-session-id':
+                        if key.lower() == "x-transmission-session-id":
                             session_id = error.headers[key]
                             self.session_id = session_id
                             headers = {
-                                'x-transmission-session-id': str(self.session_id)}
+                                "x-transmission-session-id": str(self.session_id)
+                            }
                     if session_id is None:
                         if use_logger:
                             debug_httperror(error)
-                        raise TransmissionError('Unknown conflict.', error)
+                        raise TransmissionError("Unknown conflict.", error)
                 else:
                     if use_logger:
                         debug_httperror(error)
-                    raise TransmissionError('Request failed.', error)
+                    raise TransmissionError("Request failed.", error)
             request_count += 1
         return result
 
-    def _request(self, method, arguments=None, ids=None, require_ids=False, timeout=None):
+    def _request(
+        self, method, arguments=None, ids=None, require_ids=False, timeout=None
+    ):
         """
         Send json-rpc request to Transmission using http POST
         """
         if not isinstance(method, str):
-            raise ValueError('request takes method as string')
+            raise ValueError("request takes method as string")
         if arguments is None:
             arguments = {}
         if not isinstance(arguments, dict):
-            raise ValueError('request takes arguments as dict')
+            raise ValueError("request takes arguments as dict")
         ids = parse_torrent_ids(ids)
         if ids:
-            arguments['ids'] = ids
+            arguments["ids"] = ids
         elif require_ids:
-            raise ValueError('request require ids')
+            raise ValueError("request require ids")
         use_logger = is_logger_configured()
 
         query = json.dumps(
-            {'tag': self._sequence, 'method': method, 'arguments': arguments})
+            {"tag": self._sequence, "method": method, "arguments": arguments}
+        )
         self._sequence += 1
         start = time.time()
         http_data = self._http_query(query, timeout)
         if isinstance(http_data, bytes):
-            http_data = str(http_data, encoding='utf-8', errors='replace')
-        http_data = ''.join(list(filter(
-            lambda c: unicodedata.category(c)[0] != 'C', http_data)))
+            http_data = str(http_data, encoding="utf-8", errors="replace")
+        http_data = "".join(
+            list(filter(lambda c: unicodedata.category(c)[0] != "C", http_data))
+        )
         elapsed = time.time() - start
         if use_logger:
-            LOGGER.info('http request took %.3f s', elapsed)
+            LOGGER.info("http request took %.3f s", elapsed)
 
         try:
             data = json.loads(http_data)
         except ValueError as error:
             if use_logger:
-                LOGGER.error('Error: %s', str(error))
+                LOGGER.error("Error: %s", str(error))
                 LOGGER.error('Request: "%s"', query)
                 LOGGER.error('HTTP data: "%s"', http_data)
             raise
 
         if use_logger:
             LOGGER.debug(json.dumps(data, indent=2))
-        if 'result' in data:
-            if data['result'] != 'success':
+        if "result" in data:
+            if data["result"] != "success":
                 raise TransmissionError(
-                    'Query failed with result \"%s\".' % (data['result']))
+                    'Query failed with result "%s".' % (data["result"])
+                )
         else:
-            raise TransmissionError('Query failed without result.')
+            raise TransmissionError("Query failed without result.")
 
         results = {}
-        if method == 'torrent-get':
-            for item in data['arguments']['torrents']:
-                results[item['id']] = Torrent(self, item)
-                if self.protocol_version == 2 and 'peers' not in item:
+        if method == "torrent-get":
+            for item in data["arguments"]["torrents"]:
+                results[item["id"]] = Torrent(self, item)
+                if self.protocol_version == 2 and "peers" not in item:
                     self.protocol_version = 1
-        elif method == 'torrent-add':
+        elif method == "torrent-add":
             item = None
-            if 'torrent-added' in data['arguments']:
-                item = data['arguments']['torrent-added']
-            elif 'torrent-duplicate' in data['arguments']:
-                item = data['arguments']['torrent-duplicate']
+            if "torrent-added" in data["arguments"]:
+                item = data["arguments"]["torrent-added"]
+            elif "torrent-duplicate" in data["arguments"]:
+                item = data["arguments"]["torrent-duplicate"]
             if item:
-                results[item['id']] = Torrent(self, item)
+                results[item["id"]] = Torrent(self, item)
             else:
-                raise TransmissionError('Invalid torrent-add response.')
-        elif method == 'session-get':
-            self._update_session(data['arguments'])
-        elif method == 'session-stats':
+                raise TransmissionError("Invalid torrent-add response.")
+        elif method == "session-get":
+            self._update_session(data["arguments"])
+        elif method == "session-stats":
             # older versions of T has the return data in "session-stats"
-            if 'session-stats' in data['arguments']:
-                self._update_session(data['arguments']['session-stats'])
+            if "session-stats" in data["arguments"]:
+                self._update_session(data["arguments"]["session-stats"])
             else:
-                self._update_session(data['arguments'])
-        elif method in ('port-test', 'blocklist-update', 'free-space', 'torrent-rename-path'):
-            results = data['arguments']
+                self._update_session(data["arguments"])
+        elif method in (
+            "port-test",
+            "blocklist-update",
+            "free-space",
+            "torrent-rename-path",
+        ):
+            results = data["arguments"]
         else:
             return None
 
@@ -329,15 +371,14 @@ def _update_server_version(self):
             version_major = 1
             version_minor = 30
             version_changeset = 0
-            version_parser = re.compile(r'(\d).(\d+) \((\d+)\)')
-            if hasattr(self.session, 'version'):
+            version_parser = re.compile(r"(\d).(\d+) \((\d+)\)")
+            if hasattr(self.session, "version"):
                 match = version_parser.match(self.session.version)
                 if match:
                     version_major = int(match.group(1))
                     version_minor = int(match.group(2))
                     version_changeset = match.group(3)
-            self.server_version = (
-                version_major, version_minor, version_changeset)
+            self.server_version = (version_major, version_minor, version_changeset)
 
     @property
     def rpc_version(self):
@@ -346,14 +387,18 @@ def rpc_version(self):
         """
         if self.protocol_version is None:
             # Ugly fix for 2.20 - 2.22 reporting rpc-version 11, but having new arguments
-            if self.server_version and (self.server_version[0] == 2 and self.server_version[1] in [20, 21, 22]):
+            if self.server_version and (
+                self.server_version[0] == 2 and self.server_version[1] in [20, 21, 22]
+            ):
                 self.protocol_version = 12
             # Ugly fix for 2.12 reporting rpc-version 10, but having new arguments
-            elif self.server_version and (self.server_version[0] == 2 and self.server_version[1] == 12):
+            elif self.server_version and (
+                self.server_version[0] == 2 and self.server_version[1] == 12
+            ):
                 self.protocol_version = 11
-            elif hasattr(self.session, 'rpc_version'):
+            elif hasattr(self.session, "rpc_version"):
                 self.protocol_version = self.session.rpc_version
-            elif hasattr(self.session, 'version'):
+            elif hasattr(self.session, "version"):
                 self.protocol_version = 3
             else:
                 self.protocol_version = 2
@@ -364,8 +409,11 @@ def _rpc_version_warning(self, version):
         Add a warning to the log if the Transmission RPC version is lower then the provided version.
         """
         if self.rpc_version < version:
-            LOGGER.warning('Using feature not supported by server. RPC version for server %d, feature introduced in %d.',
-                           self.rpc_version, version)
+            LOGGER.warning(
+                "Using feature not supported by server. RPC version for server %d, feature introduced in %d.",
+                self.rpc_version,
+                version,
+            )
 
     def add_torrent(self, torrent, timeout=None, **kwargs):
         """
@@ -390,47 +438,47 @@ def add_torrent(self, torrent, timeout=None, **kwargs):
         Returns a Torrent object with the fields.
         """
         if torrent is None:
-            raise ValueError('add_torrent requires data or a URI.')
+            raise ValueError("add_torrent requires data or a URI.")
         torrent_data = None
         parsed_uri = urlparse(torrent)
-        if parsed_uri.scheme in ['ftp', 'ftps', 'http', 'https']:
+        if parsed_uri.scheme in ["ftp", "ftps", "http", "https"]:
             # there has been some problem with T's built in torrent fetcher,
             # use a python one instead
             try:
                 torrent_file = urlopen(torrent)
-                if torrent_file.info().get('Content-Encoding') == 'gzip':
+                if torrent_file.info().get("Content-Encoding") == "gzip":
                     torrent_data = gzip.decompress(torrent_file.read())
                 else:
                     torrent_data = torrent_file.read()
-                torrent_data = base64.b64encode(torrent_data).decode('utf-8')
+                torrent_data = base64.b64encode(torrent_data).decode("utf-8")
             except HTTPError as e:
                 # follow links that directly redirect to a magnet (redirects to
                 # non-http/ftp files return a 302 error)
-                if e.code == 302 and e.url.startswith('magnet:'):
+                if e.code == 302 and e.url.startswith("magnet:"):
                     return self.add_torrent(e.url, timeout=timeout, **kwargs)
                 else:
                     raise e
-        if parsed_uri.scheme in ['file']:
+        if parsed_uri.scheme in ["file"]:
             filepath = torrent
             # uri decoded different on linux / windows ?
             if parsed_uri.path:
                 filepath = parsed_uri.path
             elif parsed_uri.netloc:
                 filepath = parsed_uri.netloc
-            if filepath.endswith('.gz'):
-                with gzip.open(filepath, 'rb') as torrent_file:
+            if filepath.endswith(".gz"):
+                with gzip.open(filepath, "rb") as torrent_file:
                     torrent_data = torrent_file.read()
             else:
-                with open(filepath, 'rb') as torrent_file:
+                with open(filepath, "rb") as torrent_file:
                     torrent_data = torrent_file.read()
-            torrent_data = base64.b64encode(torrent_data).decode('utf-8')
+            torrent_data = base64.b64encode(torrent_data).decode("utf-8")
         if not torrent_data:
-            if torrent.endswith('.torrent') or torrent.startswith('magnet:'):
+            if torrent.endswith(".torrent") or torrent.startswith("magnet:"):
                 torrent_data = None
             else:
                 might_be_base64 = False
                 try:
-                    base64.b64decode(torrent.encode('utf-8'))
+                    base64.b64decode(torrent.encode("utf-8"))
                     might_be_base64 = True
                 except Exception:
                     pass
@@ -438,15 +486,16 @@ def add_torrent(self, torrent, timeout=None, **kwargs):
                     torrent_data = torrent
         args = {}
         if torrent_data:
-            args = {'metainfo': torrent_data}
+            args = {"metainfo": torrent_data}
         else:
-            args = {'filename': torrent}
+            args = {"filename": torrent}
         for key, value in list(kwargs.items()):
             argument = make_rpc_name(key)
             (arg, val) = argument_value_convert(
-                'torrent-add', argument, value, self.rpc_version)
+                "torrent-add", argument, value, self.rpc_version
+            )
             args[arg] = val
-        return list(self._request('torrent-add', args, timeout=timeout).values())[0]
+        return list(self._request("torrent-add", args, timeout=timeout).values())[0]
 
     def remove_torrent(self, ids, delete_data=False, timeout=None):
         """
@@ -454,40 +503,46 @@ def remove_torrent(self, ids, delete_data=False, timeout=None):
         delete_data is True, otherwise not.
         """
         self._rpc_version_warning(3)
-        self._request('torrent-remove',
-                      {'delete-local-data': rpc_bool(delete_data)}, ids, True, timeout=timeout)
+        self._request(
+            "torrent-remove",
+            {"delete-local-data": rpc_bool(delete_data)},
+            ids,
+            True,
+            timeout=timeout,
+        )
 
     def start_torrent(self, ids, bypass_queue=False, timeout=None):
         """Start torrent(s) with provided id(s)"""
-        method = 'torrent-start'
+        method = "torrent-start"
         if bypass_queue and self.rpc_version >= 14:
-            method = 'torrent-start-now'
+            method = "torrent-start-now"
         self._request(method, {}, ids, True, timeout=timeout)
 
     def start_all(self, bypass_queue=False, timeout=None):
         """Start all torrents respecting the queue order"""
         torrent_list = self.get_torrents()
-        method = 'torrent-start'
+        method = "torrent-start"
         if self.rpc_version >= 14:
             if bypass_queue:
-                method = 'torrent-start-now'
+                method = "torrent-start-now"
             torrent_list = sorted(
-                torrent_list, key=operator.attrgetter('queuePosition'))
+                torrent_list, key=operator.attrgetter("queuePosition")
+            )
         ids = [x.id for x in torrent_list]
         self._request(method, {}, ids, True, timeout=timeout)
 
     def stop_torrent(self, ids, timeout=None):
         """stop torrent(s) with provided id(s)"""
-        self._request('torrent-stop', {}, ids, True, timeout=timeout)
+        self._request("torrent-stop", {}, ids, True, timeout=timeout)
 
     def verify_torrent(self, ids, timeout=None):
         """verify torrent(s) with provided id(s)"""
-        self._request('torrent-verify', {}, ids, True, timeout=timeout)
+        self._request("torrent-verify", {}, ids, True, timeout=timeout)
 
     def reannounce_torrent(self, ids, timeout=None):
         """Reannounce torrent(s) with provided id(s)"""
         self._rpc_version_warning(5)
-        self._request('torrent-reannounce', {}, ids, True, timeout=timeout)
+        self._request("torrent-reannounce", {}, ids, True, timeout=timeout)
 
     def get_torrent(self, torrent_id, arguments=None, timeout=None):
         """
@@ -503,7 +558,12 @@ def get_torrent(self, torrent_id, arguments=None, timeout=None):
         if torrent_id is None:
             raise ValueError("Invalid id")
         result = self._request(
-            'torrent-get', {'fields': arguments}, torrent_id, require_ids=True, timeout=timeout)
+            "torrent-get",
+            {"fields": arguments},
+            torrent_id,
+            require_ids=True,
+            timeout=timeout,
+        )
         if torrent_id in result:
             return result[torrent_id]
         else:
@@ -520,7 +580,11 @@ def get_torrents(self, ids=None, arguments=None, timeout=None):
         """
         if not arguments:
             arguments = self.torrent_get_arguments
-        return list(self._request('torrent-get', {'fields': arguments}, ids, timeout=timeout).values())
+        return list(
+            self._request(
+                "torrent-get", {"fields": arguments}, ids, timeout=timeout
+            ).values()
+        )
 
     def get_files(self, ids=None, timeout=None):
         """
@@ -546,9 +610,10 @@ def get_files(self, ids=None, timeout=None):
                 ...
             }
         """
-        fields = ['id', 'name', 'hashString', 'files', 'priorities', 'wanted']
+        fields = ["id", "name", "hashString", "files", "priorities", "wanted"]
         request_result = self._request(
-            'torrent-get', {'fields': fields}, ids, timeout=timeout)
+            "torrent-get", {"fields": fields}, ids, timeout=timeout
+        )
         result = {}
         for tid, torrent in list(request_result.items()):
             result[tid] = torrent.files()
@@ -575,7 +640,7 @@ def set_files(self, items, timeout=None):
             }
         """
         if not isinstance(items, dict):
-            raise ValueError('Invalid file description')
+            raise ValueError("Invalid file description")
         for tid, files in list(items.items()):
             if not isinstance(files, dict):
                 continue
@@ -587,30 +652,28 @@ def set_files(self, items, timeout=None):
             for fid, file_desc in list(files.items()):
                 if not isinstance(file_desc, dict):
                     continue
-                if 'selected' in file_desc and file_desc['selected']:
+                if "selected" in file_desc and file_desc["selected"]:
                     wanted.append(fid)
                 else:
                     unwanted.append(fid)
-                if 'priority' in file_desc:
-                    if file_desc['priority'] == 'high':
+                if "priority" in file_desc:
+                    if file_desc["priority"] == "high":
                         high.append(fid)
-                    elif file_desc['priority'] == 'normal':
+                    elif file_desc["priority"] == "normal":
                         normal.append(fid)
-                    elif file_desc['priority'] == 'low':
+                    elif file_desc["priority"] == "low":
                         low.append(fid)
-            args = {
-                'timeout': timeout
-            }
+            args = {"timeout": timeout}
             if high:
-                args['priority_high'] = high
+                args["priority_high"] = high
             if normal:
-                args['priority_normal'] = normal
+                args["priority_normal"] = normal
             if low:
-                args['priority_low'] = low
+                args["priority_low"] = low
             if wanted:
-                args['files_wanted'] = wanted
+                args["files_wanted"] = wanted
             if unwanted:
-                args['files_unwanted'] = unwanted
+                args["files_unwanted"] = unwanted
             self.change_torrent([tid], **args)
 
     def change_torrent(self, ids, timeout=None, **kwargs):
@@ -655,25 +718,26 @@ def change_torrent(self, ids, timeout=None, **kwargs):
         for key, value in list(kwargs.items()):
             argument = make_rpc_name(key)
             (arg, val) = argument_value_convert(
-                'torrent-set', argument, value, self.rpc_version)
+                "torrent-set", argument, value, self.rpc_version
+            )
             args[arg] = val
 
         if args:
-            self._request('torrent-set', args, ids, True, timeout=timeout)
+            self._request("torrent-set", args, ids, True, timeout=timeout)
         else:
             ValueError("No arguments to set")
 
     def move_torrent_data(self, ids, location, timeout=None):
         """Move torrent data to the new location."""
         self._rpc_version_warning(6)
-        args = {'location': location, 'move': True}
-        self._request('torrent-set-location', args, ids, True, timeout=timeout)
+        args = {"location": location, "move": True}
+        self._request("torrent-set-location", args, ids, True, timeout=timeout)
 
     def locate_torrent_data(self, ids, location, timeout=None):
         """Locate torrent data at the provided location."""
         self._rpc_version_warning(6)
-        args = {'location': location, 'move': False}
-        self._request('torrent-set-location', args, ids, True, timeout=timeout)
+        args = {"location": location, "move": False}
+        self._request("torrent-set-location", args, ids, True, timeout=timeout)
 
     def rename_torrent_path(self, torrent_id, location, name, timeout=None):
         """
@@ -687,41 +751,38 @@ def rename_torrent_path(self, torrent_id, location, name, timeout=None):
         dirname = os.path.dirname(name)
         if dirname:
             raise ValueError("Target name cannot contain a path delimiter")
-        args = {'path': location, 'name': name}
-        result = self._request('torrent-rename-path',
-                               args, torrent_id, True, timeout=timeout)
-        return (result['path'], result['name'])
+        args = {"path": location, "name": name}
+        result = self._request(
+            "torrent-rename-path", args, torrent_id, True, timeout=timeout
+        )
+        return (result["path"], result["name"])
 
     def queue_top(self, ids, timeout=None):
         """Move transfer to the top of the queue."""
         self._rpc_version_warning(14)
-        self._request('queue-move-top', ids=ids,
-                      require_ids=True, timeout=timeout)
+        self._request("queue-move-top", ids=ids, require_ids=True, timeout=timeout)
 
     def queue_bottom(self, ids, timeout=None):
         """Move transfer to the bottom of the queue."""
         self._rpc_version_warning(14)
-        self._request('queue-move-bottom', ids=ids,
-                      require_ids=True, timeout=timeout)
+        self._request("queue-move-bottom", ids=ids, require_ids=True, timeout=timeout)
 
     def queue_up(self, ids, timeout=None):
         """Move transfer up in the queue."""
         self._rpc_version_warning(14)
-        self._request('queue-move-up', ids=ids,
-                      require_ids=True, timeout=timeout)
+        self._request("queue-move-up", ids=ids, require_ids=True, timeout=timeout)
 
     def queue_down(self, ids, timeout=None):
         """Move transfer down in the queue."""
         self._rpc_version_warning(14)
-        self._request('queue-move-down', ids=ids,
-                      require_ids=True, timeout=timeout)
+        self._request("queue-move-down", ids=ids, require_ids=True, timeout=timeout)
 
     def get_session(self, timeout=None):
         """
         Get session parameters. See the Session class for more information.
         """
         if self.session is None:
-            self._request('session-get', timeout=timeout)
+            self._request("session-get", timeout=timeout)
             self._update_server_version()
         return self.session
 
@@ -784,21 +845,26 @@ def set_session(self, timeout=None, **kwargs):
         """
         args = {}
         for key, value in list(kwargs.items()):
-            if key == 'encryption' and value not in ['required', 'preferred', 'tolerated']:
-                raise ValueError('Invalid encryption value')
+            if key == "encryption" and value not in [
+                "required",
+                "preferred",
+                "tolerated",
+            ]:
+                raise ValueError("Invalid encryption value")
             argument = make_rpc_name(key)
             (arg, val) = argument_value_convert(
-                'session-set', argument, value, self.rpc_version)
+                "session-set", argument, value, self.rpc_version
+            )
             args[arg] = val
         if args:
-            self._request('session-set', args, timeout=timeout)
+            self._request("session-set", args, timeout=timeout)
 
     def blocklist_update(self, timeout=None):
         """Update block list. Returns the size of the block list."""
         self._rpc_version_warning(5)
-        result = self._request('blocklist-update', timeout=timeout)
-        if 'blocklist-size' in result:
-            return result['blocklist-size']
+        result = self._request("blocklist-update", timeout=timeout)
+        if "blocklist-size" in result:
+            return result["blocklist-size"]
         return None
 
     def port_test(self, timeout=None):
@@ -807,9 +873,9 @@ def port_test(self, timeout=None):
         outside world.
         """
         self._rpc_version_warning(5)
-        result = self._request('port-test', timeout=timeout)
-        if 'port-is-open' in result:
-            return result['port-is-open']
+        result = self._request("port-test", timeout=timeout)
+        if "port-is-open" in result:
+            return result["port-is-open"]
         return None
 
     def free_space(self, path, timeout=None):
@@ -817,12 +883,12 @@ def free_space(self, path, timeout=None):
         Get the ammount of free space (in bytes) at the provided location.
         """
         self._rpc_version_warning(15)
-        result = self._request('free-space', {'path': path}, timeout=timeout)
-        if result['path'] == path:
-            return result['size-bytes']
+        result = self._request("free-space", {"path": path}, timeout=timeout)
+        if result["path"] == path:
+            return result["size-bytes"]
         return None
 
     def session_stats(self, timeout=None):
         """Get session statistics"""
-        self._request('session-stats', timeout=timeout)
+        self._request("session-stats", timeout=timeout)
         return self.session
diff --git a/transmissionrpc/constants.py b/transmissionrpc/constants.py
index 2ff530d..f35f9c9 100644
--- a/transmissionrpc/constants.py
+++ b/transmissionrpc/constants.py
@@ -6,7 +6,7 @@
 
 import logging
 
-LOGGER = logging.getLogger('transmissionrpc')
+LOGGER = logging.getLogger("transmissionrpc")
 LOGGER.setLevel(logging.ERROR)
 
 
@@ -26,31 +26,37 @@ def mirror_dict(source):
 TR_PRI_NORMAL = 0
 TR_PRI_HIGH = 1
 
-PRIORITY = mirror_dict({
-    'low': TR_PRI_LOW,
-    'normal': TR_PRI_NORMAL,
-    'high': TR_PRI_HIGH
-})
+PRIORITY = mirror_dict(
+    {"low": TR_PRI_LOW, "normal": TR_PRI_NORMAL, "high": TR_PRI_HIGH}
+)
 
-TR_RATIOLIMIT_GLOBAL = 0     # follow the global settings
-TR_RATIOLIMIT_SINGLE = 1     # override the global settings, seeding until a certain ratio
+TR_RATIOLIMIT_GLOBAL = 0  # follow the global settings
+TR_RATIOLIMIT_SINGLE = 1  # override the global settings, seeding until a certain ratio
 TR_RATIOLIMIT_UNLIMITED = 2  # override the global settings, seeding regardless of ratio
 
-RATIO_LIMIT = mirror_dict({
-    'global': TR_RATIOLIMIT_GLOBAL,
-    'single': TR_RATIOLIMIT_SINGLE,
-    'unlimited': TR_RATIOLIMIT_UNLIMITED
-})
+RATIO_LIMIT = mirror_dict(
+    {
+        "global": TR_RATIOLIMIT_GLOBAL,
+        "single": TR_RATIOLIMIT_SINGLE,
+        "unlimited": TR_RATIOLIMIT_UNLIMITED,
+    }
+)
 
-TR_IDLELIMIT_GLOBAL = 0     # follow the global settings
-TR_IDLELIMIT_SINGLE = 1     # override the global settings, seeding until a certain idle time
-TR_IDLELIMIT_UNLIMITED = 2  # override the global settings, seeding regardless of activity
+TR_IDLELIMIT_GLOBAL = 0  # follow the global settings
+TR_IDLELIMIT_SINGLE = (
+    1  # override the global settings, seeding until a certain idle time
+)
+TR_IDLELIMIT_UNLIMITED = (
+    2  # override the global settings, seeding regardless of activity
+)
 
-IDLE_LIMIT = mirror_dict({
-    'global': TR_RATIOLIMIT_GLOBAL,
-    'single': TR_RATIOLIMIT_SINGLE,
-    'unlimited': TR_RATIOLIMIT_UNLIMITED
-})
+IDLE_LIMIT = mirror_dict(
+    {
+        "global": TR_RATIOLIMIT_GLOBAL,
+        "single": TR_RATIOLIMIT_SINGLE,
+        "unlimited": TR_RATIOLIMIT_UNLIMITED,
+    }
+)
 
 # A note on argument maps
 # These maps are used to verify *-set methods. The information is structured in
@@ -63,236 +69,1440 @@ def mirror_dict(source):
 
 # Arguments for torrent methods
 TORRENT_ARGS = {
-    'get': {
-        'activityDate':                 ('number', 1, None, None, None, 'Last time of upload or download activity.'),
-        'addedDate':                    ('number', 1, None, None, None, 'The date when this torrent was first added.'),
-        'announceResponse':             ('string', 1, 7, None, None, 'The announce message from the tracker.'),
-        'announceURL':                  ('string', 1, 7, None, None, 'Current announce URL.'),
-        'bandwidthPriority':            ('number', 5, None, None, None, 'Bandwidth priority. Low (-1), Normal (0) or High (1).'),
-        'comment':                      ('string', 1, None, None, None, 'Torrent comment.'),
-        'corruptEver':                  ('number', 1, None, None, None, 'Number of bytes of corrupt data downloaded.'),
-        'creator':                      ('string', 1, None, None, None, 'Torrent creator.'),
-        'dateCreated':                  ('number', 1, None, None, None, 'Torrent creation date.'),
-        'desiredAvailable':             ('number', 1, None, None, None, 'Number of bytes avalable and left to be downloaded.'),
-        'doneDate':                     ('number', 1, None, None, None, 'The date when the torrent finished downloading.'),
-        'downloadDir':                  ('string', 4, None, None, None, 'The directory path where the torrent is downloaded to.'),
-        'downloadedEver':               ('number', 1, None, None, None, 'Number of bytes of good data downloaded.'),
-        'downloaders':                  ('number', 4, 7, None, None, 'Number of downloaders.'),
-        'downloadLimit':                ('number', 1, None, None, None, 'Download limit in Kbps.'),
-        'downloadLimited':              ('boolean', 5, None, None, None, 'Download limit is enabled'),
-        'downloadLimitMode':            ('number', 1, 5, None, None, 'Download limit mode. 0 means global, 1 means signle, 2 unlimited.'),
-        'error':                        ('number', 1, None, None, None, 'Kind of error. 0 means OK, 1 means tracker warning, 2 means tracker error, 3 means local error.'),
-        'errorString':                  ('number', 1, None, None, None, 'Error message.'),
-        'eta':                          ('number', 1, None, None, None, 'Estimated number of seconds left when downloading or seeding. -1 means not available and -2 means unknown.'),
-        'etaIdle':                      ('number', 15, None, None, None, 'Estimated number of seconds left until the idle time limit is reached. -1 means not available and -2 means unknown.'),
-        'files':                        ('array', 1, None, None, None, 'Array of file object containing key, bytesCompleted, length and name.'),
-        'fileStats':                    ('array', 5, None, None, None, 'Aray of file statistics containing bytesCompleted, wanted and priority.'),
-        'hashString':                   ('string', 1, None, None, None, 'Hashstring unique for the torrent even between sessions.'),
-        'haveUnchecked':                ('number', 1, None, None, None, 'Number of bytes of partial pieces.'),
-        'haveValid':                    ('number', 1, None, None, None, 'Number of bytes of checksum verified data.'),
-        'honorsSessionLimits':          ('boolean', 5, None, None, None, 'True if session upload limits are honored'),
-        'id':                           ('number', 1, None, None, None, 'Session unique torrent id.'),
-        'isFinished':                   ('boolean', 9, None, None, None, 'True if the torrent is finished. Downloaded and seeded.'),
-        'isPrivate':                    ('boolean', 1, None, None, None, 'True if the torrent is private.'),
-        'isStalled':                    ('boolean', 14, None, None, None, 'True if the torrent has stalled (been idle for a long time).'),
-        'lastAnnounceTime':             ('number', 1, 7, None, None, 'The time of the last announcement.'),
-        'lastScrapeTime':               ('number', 1, 7, None, None, 'The time af the last successful scrape.'),
-        'leechers':                     ('number', 1, 7, None, None, 'Number of leechers.'),
-        'leftUntilDone':                ('number', 1, None, None, None, 'Number of bytes left until the download is done.'),
-        'magnetLink':                   ('string', 7, None, None, None, 'The magnet link for this torrent.'),
-        'manualAnnounceTime':           ('number', 1, None, None, None, 'The time until you manually ask for more peers.'),
-        'maxConnectedPeers':            ('number', 1, None, None, None, 'Maximum of connected peers.'),
-        'metadataPercentComplete':      ('number', 7, None, None, None, 'Download progress of metadata. 0.0 to 1.0.'),
-        'name':                         ('string', 1, None, None, None, 'Torrent name.'),
-        'nextAnnounceTime':             ('number', 1, 7, None, None, 'Next announce time.'),
-        'nextScrapeTime':               ('number', 1, 7, None, None, 'Next scrape time.'),
-        'peer-limit':                   ('number', 5, None, None, None, 'Maximum number of peers.'),
-        'peers':                        ('array', 2, None, None, None, 'Array of peer objects.'),
-        'peersConnected':               ('number', 1, None, None, None, 'Number of peers we are connected to.'),
-        'peersFrom':                    ('object', 1, None, None, None, 'Object containing download peers counts for different peer types.'),
-        'peersGettingFromUs':           ('number', 1, None, None, None, 'Number of peers we are sending data to.'),
-        'peersKnown':                   ('number', 1, 13, None, None, 'Number of peers that the tracker knows.'),
-        'peersSendingToUs':             ('number', 1, None, None, None, 'Number of peers sending to us'),
-        'percentDone':                  ('double', 5, None, None, None, 'Download progress of selected files. 0.0 to 1.0.'),
-        'pieces':                       ('string', 5, None, None, None, 'String with base64 encoded bitfield indicating finished pieces.'),
-        'pieceCount':                   ('number', 1, None, None, None, 'Number of pieces.'),
-        'pieceSize':                    ('number', 1, None, None, None, 'Number of bytes in a piece.'),
-        'priorities':                   ('array', 1, None, None, None, 'Array of file priorities.'),
-        'queuePosition':                ('number', 14, None, None, None, 'The queue position.'),
-        'rateDownload':                 ('number', 1, None, None, None, 'Download rate in bps.'),
-        'rateUpload':                   ('number', 1, None, None, None, 'Upload rate in bps.'),
-        'recheckProgress':              ('double', 1, None, None, None, 'Progress of recheck. 0.0 to 1.0.'),
-        'secondsDownloading':           ('number', 15, None, None, None, ''),
-        'secondsSeeding':               ('number', 15, None, None, None, ''),
-        'scrapeResponse':               ('string', 1, 7, None, None, 'Scrape response message.'),
-        'scrapeURL':                    ('string', 1, 7, None, None, 'Current scrape URL'),
-        'seeders':                      ('number', 1, 7, None, None, 'Number of seeders reported by the tracker.'),
-        'seedIdleLimit':                ('number', 10, None, None, None, 'Idle limit in minutes.'),
-        'seedIdleMode':                 ('number', 10, None, None, None, 'Use global (0), torrent (1), or unlimited (2) limit.'),
-        'seedRatioLimit':               ('double', 5, None, None, None, 'Seed ratio limit.'),
-        'seedRatioMode':                ('number', 5, None, None, None, 'Use global (0), torrent (1), or unlimited (2) limit.'),
-        'sizeWhenDone':                 ('number', 1, None, None, None, 'Size of the torrent download in bytes.'),
-        'startDate':                    ('number', 1, None, None, None, 'The date when the torrent was last started.'),
-        'status':                       ('number', 1, None, None, None, 'Current status, see source'),
-        'swarmSpeed':                   ('number', 1, 7, None, None, 'Estimated speed in Kbps in the swarm.'),
-        'timesCompleted':               ('number', 1, 7, None, None, 'Number of successful downloads reported by the tracker.'),
-        'trackers':                     ('array', 1, None, None, None, 'Array of tracker objects.'),
-        'trackerStats':                 ('object', 7, None, None, None, 'Array of object containing tracker statistics.'),
-        'totalSize':                    ('number', 1, None, None, None, 'Total size of the torrent in bytes'),
-        'torrentFile':                  ('string', 5, None, None, None, 'Path to .torrent file.'),
-        'uploadedEver':                 ('number', 1, None, None, None, 'Number of bytes uploaded, ever.'),
-        'uploadLimit':                  ('number', 1, None, None, None, 'Upload limit in Kbps'),
-        'uploadLimitMode':              ('number', 1, 5, None, None, 'Upload limit mode. 0 means global, 1 means signle, 2 unlimited.'),
-        'uploadLimited':                ('boolean', 5, None, None, None, 'Upload limit enabled.'),
-        'uploadRatio':                  ('double', 1, None, None, None, 'Seed ratio.'),
-        'wanted':                       ('array', 1, None, None, None, 'Array of booleans indicated wanted files.'),
-        'webseeds':                     ('array', 1, None, None, None, 'Array of webseeds objects'),
-        'webseedsSendingToUs':          ('number', 1, None, None, None, 'Number of webseeds seeding to us.'),
+    "get": {
+        "activityDate": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Last time of upload or download activity.",
+        ),
+        "addedDate": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "The date when this torrent was first added.",
+        ),
+        "announceResponse": (
+            "string",
+            1,
+            7,
+            None,
+            None,
+            "The announce message from the tracker.",
+        ),
+        "announceURL": ("string", 1, 7, None, None, "Current announce URL."),
+        "bandwidthPriority": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Bandwidth priority. Low (-1), Normal (0) or High (1).",
+        ),
+        "comment": ("string", 1, None, None, None, "Torrent comment."),
+        "corruptEver": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of bytes of corrupt data downloaded.",
+        ),
+        "creator": ("string", 1, None, None, None, "Torrent creator."),
+        "dateCreated": ("number", 1, None, None, None, "Torrent creation date."),
+        "desiredAvailable": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of bytes avalable and left to be downloaded.",
+        ),
+        "doneDate": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "The date when the torrent finished downloading.",
+        ),
+        "downloadDir": (
+            "string",
+            4,
+            None,
+            None,
+            None,
+            "The directory path where the torrent is downloaded to.",
+        ),
+        "downloadedEver": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of bytes of good data downloaded.",
+        ),
+        "downloaders": ("number", 4, 7, None, None, "Number of downloaders."),
+        "downloadLimit": ("number", 1, None, None, None, "Download limit in Kbps."),
+        "downloadLimited": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "Download limit is enabled",
+        ),
+        "downloadLimitMode": (
+            "number",
+            1,
+            5,
+            None,
+            None,
+            "Download limit mode. 0 means global, 1 means signle, 2 unlimited.",
+        ),
+        "error": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Kind of error. 0 means OK, 1 means tracker warning, 2 means tracker error, 3 means local error.",
+        ),
+        "errorString": ("number", 1, None, None, None, "Error message."),
+        "eta": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Estimated number of seconds left when downloading or seeding. -1 means not available and -2 means unknown.",
+        ),
+        "etaIdle": (
+            "number",
+            15,
+            None,
+            None,
+            None,
+            "Estimated number of seconds left until the idle time limit is reached. -1 means not available and -2 means unknown.",
+        ),
+        "files": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "Array of file object containing key, bytesCompleted, length and name.",
+        ),
+        "fileStats": (
+            "array",
+            5,
+            None,
+            None,
+            None,
+            "Aray of file statistics containing bytesCompleted, wanted and priority.",
+        ),
+        "hashString": (
+            "string",
+            1,
+            None,
+            None,
+            None,
+            "Hashstring unique for the torrent even between sessions.",
+        ),
+        "haveUnchecked": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of bytes of partial pieces.",
+        ),
+        "haveValid": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of bytes of checksum verified data.",
+        ),
+        "honorsSessionLimits": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "True if session upload limits are honored",
+        ),
+        "id": ("number", 1, None, None, None, "Session unique torrent id."),
+        "isFinished": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            "True if the torrent is finished. Downloaded and seeded.",
+        ),
+        "isPrivate": (
+            "boolean",
+            1,
+            None,
+            None,
+            None,
+            "True if the torrent is private.",
+        ),
+        "isStalled": (
+            "boolean",
+            14,
+            None,
+            None,
+            None,
+            "True if the torrent has stalled (been idle for a long time).",
+        ),
+        "lastAnnounceTime": (
+            "number",
+            1,
+            7,
+            None,
+            None,
+            "The time of the last announcement.",
+        ),
+        "lastScrapeTime": (
+            "number",
+            1,
+            7,
+            None,
+            None,
+            "The time af the last successful scrape.",
+        ),
+        "leechers": ("number", 1, 7, None, None, "Number of leechers."),
+        "leftUntilDone": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of bytes left until the download is done.",
+        ),
+        "magnetLink": (
+            "string",
+            7,
+            None,
+            None,
+            None,
+            "The magnet link for this torrent.",
+        ),
+        "manualAnnounceTime": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "The time until you manually ask for more peers.",
+        ),
+        "maxConnectedPeers": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Maximum of connected peers.",
+        ),
+        "metadataPercentComplete": (
+            "number",
+            7,
+            None,
+            None,
+            None,
+            "Download progress of metadata. 0.0 to 1.0.",
+        ),
+        "name": ("string", 1, None, None, None, "Torrent name."),
+        "nextAnnounceTime": ("number", 1, 7, None, None, "Next announce time."),
+        "nextScrapeTime": ("number", 1, 7, None, None, "Next scrape time."),
+        "peer-limit": ("number", 5, None, None, None, "Maximum number of peers."),
+        "peers": ("array", 2, None, None, None, "Array of peer objects."),
+        "peersConnected": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of peers we are connected to.",
+        ),
+        "peersFrom": (
+            "object",
+            1,
+            None,
+            None,
+            None,
+            "Object containing download peers counts for different peer types.",
+        ),
+        "peersGettingFromUs": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of peers we are sending data to.",
+        ),
+        "peersKnown": (
+            "number",
+            1,
+            13,
+            None,
+            None,
+            "Number of peers that the tracker knows.",
+        ),
+        "peersSendingToUs": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of peers sending to us",
+        ),
+        "percentDone": (
+            "double",
+            5,
+            None,
+            None,
+            None,
+            "Download progress of selected files. 0.0 to 1.0.",
+        ),
+        "pieces": (
+            "string",
+            5,
+            None,
+            None,
+            None,
+            "String with base64 encoded bitfield indicating finished pieces.",
+        ),
+        "pieceCount": ("number", 1, None, None, None, "Number of pieces."),
+        "pieceSize": ("number", 1, None, None, None, "Number of bytes in a piece."),
+        "priorities": ("array", 1, None, None, None, "Array of file priorities."),
+        "queuePosition": ("number", 14, None, None, None, "The queue position."),
+        "rateDownload": ("number", 1, None, None, None, "Download rate in bps."),
+        "rateUpload": ("number", 1, None, None, None, "Upload rate in bps."),
+        "recheckProgress": (
+            "double",
+            1,
+            None,
+            None,
+            None,
+            "Progress of recheck. 0.0 to 1.0.",
+        ),
+        "secondsDownloading": ("number", 15, None, None, None, ""),
+        "secondsSeeding": ("number", 15, None, None, None, ""),
+        "scrapeResponse": ("string", 1, 7, None, None, "Scrape response message."),
+        "scrapeURL": ("string", 1, 7, None, None, "Current scrape URL"),
+        "seeders": (
+            "number",
+            1,
+            7,
+            None,
+            None,
+            "Number of seeders reported by the tracker.",
+        ),
+        "seedIdleLimit": ("number", 10, None, None, None, "Idle limit in minutes."),
+        "seedIdleMode": (
+            "number",
+            10,
+            None,
+            None,
+            None,
+            "Use global (0), torrent (1), or unlimited (2) limit.",
+        ),
+        "seedRatioLimit": ("double", 5, None, None, None, "Seed ratio limit."),
+        "seedRatioMode": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Use global (0), torrent (1), or unlimited (2) limit.",
+        ),
+        "sizeWhenDone": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Size of the torrent download in bytes.",
+        ),
+        "startDate": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "The date when the torrent was last started.",
+        ),
+        "status": ("number", 1, None, None, None, "Current status, see source"),
+        "swarmSpeed": (
+            "number",
+            1,
+            7,
+            None,
+            None,
+            "Estimated speed in Kbps in the swarm.",
+        ),
+        "timesCompleted": (
+            "number",
+            1,
+            7,
+            None,
+            None,
+            "Number of successful downloads reported by the tracker.",
+        ),
+        "trackers": ("array", 1, None, None, None, "Array of tracker objects."),
+        "trackerStats": (
+            "object",
+            7,
+            None,
+            None,
+            None,
+            "Array of object containing tracker statistics.",
+        ),
+        "totalSize": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Total size of the torrent in bytes",
+        ),
+        "torrentFile": ("string", 5, None, None, None, "Path to .torrent file."),
+        "uploadedEver": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of bytes uploaded, ever.",
+        ),
+        "uploadLimit": ("number", 1, None, None, None, "Upload limit in Kbps"),
+        "uploadLimitMode": (
+            "number",
+            1,
+            5,
+            None,
+            None,
+            "Upload limit mode. 0 means global, 1 means signle, 2 unlimited.",
+        ),
+        "uploadLimited": ("boolean", 5, None, None, None, "Upload limit enabled."),
+        "uploadRatio": ("double", 1, None, None, None, "Seed ratio."),
+        "wanted": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "Array of booleans indicated wanted files.",
+        ),
+        "webseeds": ("array", 1, None, None, None, "Array of webseeds objects"),
+        "webseedsSendingToUs": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Number of webseeds seeding to us.",
+        ),
     },
-    'set': {
-        'bandwidthPriority':            ('number', 5, None, None, None, 'Priority for this transfer.'),
-        'downloadLimit':                ('number', 5, None, 'speed-limit-down', None, 'Set the speed limit for download in Kib/s.'),
-        'downloadLimited':              ('boolean', 5, None, 'speed-limit-down-enabled', None, 'Enable download speed limiter.'),
-        'files-wanted':                 ('array', 1, None, None, None, "A list of file id's that should be downloaded."),
-        'files-unwanted':               ('array', 1, None, None, None, "A list of file id's that shouldn't be downloaded."),
-        'honorsSessionLimits':          ('boolean', 5, None, None, None, "Enables or disables the transfer to honour the upload limit set in the session."),
-        'location':                     ('array', 1, None, None, None, 'Local download location.'),
-        'peer-limit':                   ('number', 1, None, None, None, 'The peer limit for the torrents.'),
-        'priority-high':                ('array', 1, None, None, None, "A list of file id's that should have high priority."),
-        'priority-low':                 ('array', 1, None, None, None, "A list of file id's that should have normal priority."),
-        'priority-normal':              ('array', 1, None, None, None, "A list of file id's that should have low priority."),
-        'queuePosition':                ('number', 14, None, None, None, 'Position of this transfer in its queue.'),
-        'seedIdleLimit':                ('number', 10, None, None, None, 'Seed inactivity limit in minutes.'),
-        'seedIdleMode':                 ('number', 10, None, None, None, 'Seed inactivity mode. 0 = Use session limit, 1 = Use transfer limit, 2 = Disable limit.'),
-        'seedRatioLimit':               ('double', 5, None, None, None, 'Seeding ratio.'),
-        'seedRatioMode':                ('number', 5, None, None, None, 'Which ratio to use. 0 = Use session limit, 1 = Use transfer limit, 2 = Disable limit.'),
-        'speed-limit-down':             ('number', 1, 5, None, 'downloadLimit', 'Set the speed limit for download in Kib/s.'),
-        'speed-limit-down-enabled':     ('boolean', 1, 5, None, 'downloadLimited', 'Enable download speed limiter.'),
-        'speed-limit-up':               ('number', 1, 5, None, 'uploadLimit', 'Set the speed limit for upload in Kib/s.'),
-        'speed-limit-up-enabled':       ('boolean', 1, 5, None, 'uploadLimited', 'Enable upload speed limiter.'),
-        'trackerAdd':                   ('array', 10, None, None, None, 'Array of string with announce URLs to add.'),
-        'trackerRemove':                ('array', 10, None, None, None, 'Array of ids of trackers to remove.'),
-        'trackerReplace':               ('array', 10, None, None, None, 'Array of (id, url) tuples where the announce URL should be replaced.'),
-        'uploadLimit':                  ('number', 5, None, 'speed-limit-up', None, 'Set the speed limit for upload in Kib/s.'),
-        'uploadLimited':                ('boolean', 5, None, 'speed-limit-up-enabled', None, 'Enable upload speed limiter.'),
+    "set": {
+        "bandwidthPriority": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Priority for this transfer.",
+        ),
+        "downloadLimit": (
+            "number",
+            5,
+            None,
+            "speed-limit-down",
+            None,
+            "Set the speed limit for download in Kib/s.",
+        ),
+        "downloadLimited": (
+            "boolean",
+            5,
+            None,
+            "speed-limit-down-enabled",
+            None,
+            "Enable download speed limiter.",
+        ),
+        "files-wanted": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that should be downloaded.",
+        ),
+        "files-unwanted": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that shouldn't be downloaded.",
+        ),
+        "honorsSessionLimits": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "Enables or disables the transfer to honour the upload limit set in the session.",
+        ),
+        "location": ("array", 1, None, None, None, "Local download location."),
+        "peer-limit": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "The peer limit for the torrents.",
+        ),
+        "priority-high": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that should have high priority.",
+        ),
+        "priority-low": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that should have normal priority.",
+        ),
+        "priority-normal": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that should have low priority.",
+        ),
+        "queuePosition": (
+            "number",
+            14,
+            None,
+            None,
+            None,
+            "Position of this transfer in its queue.",
+        ),
+        "seedIdleLimit": (
+            "number",
+            10,
+            None,
+            None,
+            None,
+            "Seed inactivity limit in minutes.",
+        ),
+        "seedIdleMode": (
+            "number",
+            10,
+            None,
+            None,
+            None,
+            "Seed inactivity mode. 0 = Use session limit, 1 = Use transfer limit, 2 = Disable limit.",
+        ),
+        "seedRatioLimit": ("double", 5, None, None, None, "Seeding ratio."),
+        "seedRatioMode": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Which ratio to use. 0 = Use session limit, 1 = Use transfer limit, 2 = Disable limit.",
+        ),
+        "speed-limit-down": (
+            "number",
+            1,
+            5,
+            None,
+            "downloadLimit",
+            "Set the speed limit for download in Kib/s.",
+        ),
+        "speed-limit-down-enabled": (
+            "boolean",
+            1,
+            5,
+            None,
+            "downloadLimited",
+            "Enable download speed limiter.",
+        ),
+        "speed-limit-up": (
+            "number",
+            1,
+            5,
+            None,
+            "uploadLimit",
+            "Set the speed limit for upload in Kib/s.",
+        ),
+        "speed-limit-up-enabled": (
+            "boolean",
+            1,
+            5,
+            None,
+            "uploadLimited",
+            "Enable upload speed limiter.",
+        ),
+        "trackerAdd": (
+            "array",
+            10,
+            None,
+            None,
+            None,
+            "Array of string with announce URLs to add.",
+        ),
+        "trackerRemove": (
+            "array",
+            10,
+            None,
+            None,
+            None,
+            "Array of ids of trackers to remove.",
+        ),
+        "trackerReplace": (
+            "array",
+            10,
+            None,
+            None,
+            None,
+            "Array of (id, url) tuples where the announce URL should be replaced.",
+        ),
+        "uploadLimit": (
+            "number",
+            5,
+            None,
+            "speed-limit-up",
+            None,
+            "Set the speed limit for upload in Kib/s.",
+        ),
+        "uploadLimited": (
+            "boolean",
+            5,
+            None,
+            "speed-limit-up-enabled",
+            None,
+            "Enable upload speed limiter.",
+        ),
+    },
+    "add": {
+        "bandwidthPriority": (
+            "number",
+            8,
+            None,
+            None,
+            None,
+            "Priority for this transfer.",
+        ),
+        "download-dir": (
+            "string",
+            1,
+            None,
+            None,
+            None,
+            "The directory where the downloaded contents will be saved in.",
+        ),
+        "cookies": ("string", 13, None, None, None, "One or more HTTP cookie(s)."),
+        "filename": (
+            "string",
+            1,
+            None,
+            None,
+            None,
+            "A file path or URL to a torrent file or a magnet link.",
+        ),
+        "files-wanted": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that should be downloaded.",
+        ),
+        "files-unwanted": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that shouldn't be downloaded.",
+        ),
+        "metainfo": (
+            "string",
+            1,
+            None,
+            None,
+            None,
+            "The content of a torrent file, base64 encoded.",
+        ),
+        "paused": (
+            "boolean",
+            1,
+            None,
+            None,
+            None,
+            "If True, does not start the transfer when added.",
+        ),
+        "peer-limit": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Maximum number of peers allowed.",
+        ),
+        "priority-high": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that should have high priority.",
+        ),
+        "priority-low": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that should have low priority.",
+        ),
+        "priority-normal": (
+            "array",
+            1,
+            None,
+            None,
+            None,
+            "A list of file id's that should have normal priority.",
+        ),
     },
-    'add': {
-        'bandwidthPriority':            ('number', 8, None, None, None, 'Priority for this transfer.'),
-        'download-dir':                 ('string', 1, None, None, None, 'The directory where the downloaded contents will be saved in.'),
-        'cookies':                      ('string', 13, None, None, None, 'One or more HTTP cookie(s).'),
-        'filename':                     ('string', 1, None, None, None, "A file path or URL to a torrent file or a magnet link."),
-        'files-wanted':                 ('array', 1, None, None, None, "A list of file id's that should be downloaded."),
-        'files-unwanted':               ('array', 1, None, None, None, "A list of file id's that shouldn't be downloaded."),
-        'metainfo':                     ('string', 1, None, None, None, 'The content of a torrent file, base64 encoded.'),
-        'paused':                       ('boolean', 1, None, None, None, 'If True, does not start the transfer when added.'),
-        'peer-limit':                   ('number', 1, None, None, None, 'Maximum number of peers allowed.'),
-        'priority-high':                ('array', 1, None, None, None, "A list of file id's that should have high priority."),
-        'priority-low':                 ('array', 1, None, None, None, "A list of file id's that should have low priority."),
-        'priority-normal':              ('array', 1, None, None, None, "A list of file id's that should have normal priority."),
-    }
 }
 
 # Arguments for session methods
 SESSION_ARGS = {
-    'get': {
-        "alt-speed-down":               ('number', 5, None, None, None, 'Alternate session download speed limit (in Kib/s).'),
-        "alt-speed-enabled":            ('boolean', 5, None, None, None, 'True if alternate global download speed limiter is ebabled.'),
-        "alt-speed-time-begin":         ('number', 5, None, None, None, 'Time when alternate speeds should be enabled. Minutes after midnight.'),
-        "alt-speed-time-enabled":       ('boolean', 5, None, None, None, 'True if alternate speeds scheduling is enabled.'),
-        "alt-speed-time-end":           ('number', 5, None, None, None, 'Time when alternate speeds should be disabled. Minutes after midnight.'),
-        "alt-speed-time-day":           ('number', 5, None, None, None, 'Days alternate speeds scheduling is enabled.'),
-        "alt-speed-up":                 ('number', 5, None, None, None, 'Alternate session upload speed limit (in Kib/s)'),
-        "blocklist-enabled":            ('boolean', 5, None, None, None, 'True when blocklist is enabled.'),
-        "blocklist-size":               ('number', 5, None, None, None, 'Number of rules in the blocklist'),
-        "blocklist-url":                ('string', 11, None, None, None, 'Location of the block list. Updated with blocklist-update.'),
-        "cache-size-mb":                ('number', 10, None, None, None, 'The maximum size of the disk cache in MB'),
-        "config-dir":                   ('string', 8, None, None, None, 'location of transmissions configuration directory'),
-        "dht-enabled":                  ('boolean', 6, None, None, None, 'True if DHT enabled.'),
-        "download-dir":                 ('string', 1, None, None, None, 'The download directory.'),
-        "download-dir-free-space":      ('number', 12, None, None, None, 'Free space in the download directory, in bytes'),
-        "download-queue-size":          ('number', 14, None, None, None, 'Number of slots in the download queue.'),
-        "download-queue-enabled":       ('boolean', 14, None, None, None, 'True if the download queue is enabled.'),
-        "encryption":                   ('string', 1, None, None, None, 'Encryption mode, one of ``required``, ``preferred`` or ``tolerated``.'),
-        "idle-seeding-limit":           ('number', 10, None, None, None, 'Seed inactivity limit in minutes.'),
-        "idle-seeding-limit-enabled":   ('boolean', 10, None, None, None, 'True if the seed activity limit is enabled.'),
-        "incomplete-dir":               ('string', 7, None, None, None, 'The path to the directory for incomplete torrent transfer data.'),
-        "incomplete-dir-enabled":       ('boolean', 7, None, None, None, 'True if the incomplete dir is enabled.'),
-        "lpd-enabled":                  ('boolean', 9, None, None, None, 'True if local peer discovery is enabled.'),
-        "peer-limit":                   ('number', 1, 5, None, 'peer-limit-global', 'Maximum number of peers.'),
-        "peer-limit-global":            ('number', 5, None, 'peer-limit', None, 'Maximum number of peers.'),
-        "peer-limit-per-torrent":       ('number', 5, None, None, None, 'Maximum number of peers per transfer.'),
-        "pex-allowed":                  ('boolean', 1, 5, None, 'pex-enabled', 'True if PEX is allowed.'),
-        "pex-enabled":                  ('boolean', 5, None, 'pex-allowed', None, 'True if PEX is enabled.'),
-        "port":                         ('number', 1, 5, None, 'peer-port', 'Peer port.'),
-        "peer-port":                    ('number', 5, None, 'port', None, 'Peer port.'),
-        "peer-port-random-on-start":    ('boolean', 5, None, None, None, 'Enables randomized peer port on start of Transmission.'),
-        "port-forwarding-enabled":      ('boolean', 1, None, None, None, 'True if port forwarding is enabled.'),
-        "queue-stalled-minutes":        ('number', 14, None, None, None, 'Number of minutes of idle that marks a transfer as stalled.'),
-        "queue-stalled-enabled":        ('boolean', 14, None, None, None, 'True if stalled tracking of transfers is enabled.'),
-        "rename-partial-files":         ('boolean', 8, None, None, None, 'True if ".part" is appended to incomplete files'),
-        "rpc-version":                  ('number', 4, None, None, None, 'Transmission RPC API Version.'),
-        "rpc-version-minimum":          ('number', 4, None, None, None, 'Minimum accepted RPC API Version.'),
-        "script-torrent-done-enabled":  ('boolean', 9, None, None, None, 'True if the done script is enabled.'),
-        "script-torrent-done-filename": ('string', 9, None, None, None, 'Filename of the script to run when the transfer is done.'),
-        "seedRatioLimit":               ('double', 5, None, None, None, 'Seed ratio limit. 1.0 means 1:1 download and upload ratio.'),
-        "seedRatioLimited":             ('boolean', 5, None, None, None, 'True if seed ration limit is enabled.'),
-        "seed-queue-size":              ('number', 14, None, None, None, 'Number of slots in the upload queue.'),
-        "seed-queue-enabled":           ('boolean', 14, None, None, None, 'True if upload queue is enabled.'),
-        "speed-limit-down":             ('number', 1, None, None, None, 'Download speed limit (in Kib/s).'),
-        "speed-limit-down-enabled":     ('boolean', 1, None, None, None, 'True if the download speed is limited.'),
-        "speed-limit-up":               ('number', 1, None, None, None, 'Upload speed limit (in Kib/s).'),
-        "speed-limit-up-enabled":       ('boolean', 1, None, None, None, 'True if the upload speed is limited.'),
-        "start-added-torrents":         ('boolean', 9, None, None, None, 'When true uploaded torrents will start right away.'),
-        "trash-original-torrent-files": ('boolean', 9, None, None, None, 'When true added .torrent files will be deleted.'),
-        'units':                        ('object', 10, None, None, None, 'An object containing units for size and speed.'),
-        'utp-enabled':                  ('boolean', 13, None, None, None, 'True if Micro Transport Protocol (UTP) is enabled.'),
-        "version":                      ('string', 3, None, None, None, 'Transmission version.'),
+    "get": {
+        "alt-speed-down": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Alternate session download speed limit (in Kib/s).",
+        ),
+        "alt-speed-enabled": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "True if alternate global download speed limiter is ebabled.",
+        ),
+        "alt-speed-time-begin": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Time when alternate speeds should be enabled. Minutes after midnight.",
+        ),
+        "alt-speed-time-enabled": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "True if alternate speeds scheduling is enabled.",
+        ),
+        "alt-speed-time-end": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Time when alternate speeds should be disabled. Minutes after midnight.",
+        ),
+        "alt-speed-time-day": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Days alternate speeds scheduling is enabled.",
+        ),
+        "alt-speed-up": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Alternate session upload speed limit (in Kib/s)",
+        ),
+        "blocklist-enabled": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "True when blocklist is enabled.",
+        ),
+        "blocklist-size": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Number of rules in the blocklist",
+        ),
+        "blocklist-url": (
+            "string",
+            11,
+            None,
+            None,
+            None,
+            "Location of the block list. Updated with blocklist-update.",
+        ),
+        "cache-size-mb": (
+            "number",
+            10,
+            None,
+            None,
+            None,
+            "The maximum size of the disk cache in MB",
+        ),
+        "config-dir": (
+            "string",
+            8,
+            None,
+            None,
+            None,
+            "location of transmissions configuration directory",
+        ),
+        "dht-enabled": ("boolean", 6, None, None, None, "True if DHT enabled."),
+        "download-dir": ("string", 1, None, None, None, "The download directory."),
+        "download-dir-free-space": (
+            "number",
+            12,
+            None,
+            None,
+            None,
+            "Free space in the download directory, in bytes",
+        ),
+        "download-queue-size": (
+            "number",
+            14,
+            None,
+            None,
+            None,
+            "Number of slots in the download queue.",
+        ),
+        "download-queue-enabled": (
+            "boolean",
+            14,
+            None,
+            None,
+            None,
+            "True if the download queue is enabled.",
+        ),
+        "encryption": (
+            "string",
+            1,
+            None,
+            None,
+            None,
+            "Encryption mode, one of ``required``, ``preferred`` or ``tolerated``.",
+        ),
+        "idle-seeding-limit": (
+            "number",
+            10,
+            None,
+            None,
+            None,
+            "Seed inactivity limit in minutes.",
+        ),
+        "idle-seeding-limit-enabled": (
+            "boolean",
+            10,
+            None,
+            None,
+            None,
+            "True if the seed activity limit is enabled.",
+        ),
+        "incomplete-dir": (
+            "string",
+            7,
+            None,
+            None,
+            None,
+            "The path to the directory for incomplete torrent transfer data.",
+        ),
+        "incomplete-dir-enabled": (
+            "boolean",
+            7,
+            None,
+            None,
+            None,
+            "True if the incomplete dir is enabled.",
+        ),
+        "lpd-enabled": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            "True if local peer discovery is enabled.",
+        ),
+        "peer-limit": (
+            "number",
+            1,
+            5,
+            None,
+            "peer-limit-global",
+            "Maximum number of peers.",
+        ),
+        "peer-limit-global": (
+            "number",
+            5,
+            None,
+            "peer-limit",
+            None,
+            "Maximum number of peers.",
+        ),
+        "peer-limit-per-torrent": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Maximum number of peers per transfer.",
+        ),
+        "pex-allowed": (
+            "boolean",
+            1,
+            5,
+            None,
+            "pex-enabled",
+            "True if PEX is allowed.",
+        ),
+        "pex-enabled": (
+            "boolean",
+            5,
+            None,
+            "pex-allowed",
+            None,
+            "True if PEX is enabled.",
+        ),
+        "port": ("number", 1, 5, None, "peer-port", "Peer port."),
+        "peer-port": ("number", 5, None, "port", None, "Peer port."),
+        "peer-port-random-on-start": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "Enables randomized peer port on start of Transmission.",
+        ),
+        "port-forwarding-enabled": (
+            "boolean",
+            1,
+            None,
+            None,
+            None,
+            "True if port forwarding is enabled.",
+        ),
+        "queue-stalled-minutes": (
+            "number",
+            14,
+            None,
+            None,
+            None,
+            "Number of minutes of idle that marks a transfer as stalled.",
+        ),
+        "queue-stalled-enabled": (
+            "boolean",
+            14,
+            None,
+            None,
+            None,
+            "True if stalled tracking of transfers is enabled.",
+        ),
+        "rename-partial-files": (
+            "boolean",
+            8,
+            None,
+            None,
+            None,
+            'True if ".part" is appended to incomplete files',
+        ),
+        "rpc-version": ("number", 4, None, None, None, "Transmission RPC API Version."),
+        "rpc-version-minimum": (
+            "number",
+            4,
+            None,
+            None,
+            None,
+            "Minimum accepted RPC API Version.",
+        ),
+        "script-torrent-done-enabled": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            "True if the done script is enabled.",
+        ),
+        "script-torrent-done-filename": (
+            "string",
+            9,
+            None,
+            None,
+            None,
+            "Filename of the script to run when the transfer is done.",
+        ),
+        "seedRatioLimit": (
+            "double",
+            5,
+            None,
+            None,
+            None,
+            "Seed ratio limit. 1.0 means 1:1 download and upload ratio.",
+        ),
+        "seedRatioLimited": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "True if seed ration limit is enabled.",
+        ),
+        "seed-queue-size": (
+            "number",
+            14,
+            None,
+            None,
+            None,
+            "Number of slots in the upload queue.",
+        ),
+        "seed-queue-enabled": (
+            "boolean",
+            14,
+            None,
+            None,
+            None,
+            "True if upload queue is enabled.",
+        ),
+        "speed-limit-down": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Download speed limit (in Kib/s).",
+        ),
+        "speed-limit-down-enabled": (
+            "boolean",
+            1,
+            None,
+            None,
+            None,
+            "True if the download speed is limited.",
+        ),
+        "speed-limit-up": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Upload speed limit (in Kib/s).",
+        ),
+        "speed-limit-up-enabled": (
+            "boolean",
+            1,
+            None,
+            None,
+            None,
+            "True if the upload speed is limited.",
+        ),
+        "start-added-torrents": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            "When true uploaded torrents will start right away.",
+        ),
+        "trash-original-torrent-files": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            "When true added .torrent files will be deleted.",
+        ),
+        "units": (
+            "object",
+            10,
+            None,
+            None,
+            None,
+            "An object containing units for size and speed.",
+        ),
+        "utp-enabled": (
+            "boolean",
+            13,
+            None,
+            None,
+            None,
+            "True if Micro Transport Protocol (UTP) is enabled.",
+        ),
+        "version": ("string", 3, None, None, None, "Transmission version."),
     },
-    'set': {
-        "alt-speed-down":               ('number', 5, None, None, None, 'Alternate session download speed limit (in Kib/s).'),
-        "alt-speed-enabled":            ('boolean', 5, None, None, None, 'Enables alternate global download speed limiter.'),
-        "alt-speed-time-begin":         ('number', 5, None, None, None, 'Time when alternate speeds should be enabled. Minutes after midnight.'),
-        "alt-speed-time-enabled":       ('boolean', 5, None, None, None, 'Enables alternate speeds scheduling.'),
-        "alt-speed-time-end":           ('number', 5, None, None, None, 'Time when alternate speeds should be disabled. Minutes after midnight.'),
-        "alt-speed-time-day":           ('number', 5, None, None, None, 'Enables alternate speeds scheduling these days.'),
-        "alt-speed-up":                 ('number', 5, None, None, None, 'Alternate session upload speed limit (in Kib/s).'),
-        "blocklist-enabled":            ('boolean', 5, None, None, None, 'Enables the block list'),
-        "blocklist-url":                ('string', 11, None, None, None, 'Location of the block list. Updated with blocklist-update.'),
-        "cache-size-mb":                ('number', 10, None, None, None, 'The maximum size of the disk cache in MB'),
-        "dht-enabled":                  ('boolean', 6, None, None, None, 'Enables DHT.'),
-        "download-dir":                 ('string', 1, None, None, None, 'Set the session download directory.'),
-        "download-queue-size":          ('number', 14, None, None, None, 'Number of slots in the download queue.'),
-        "download-queue-enabled":       ('boolean', 14, None, None, None, 'Enables download queue.'),
-        "encryption":                   ('string', 1, None, None, None, 'Set the session encryption mode, one of ``required``, ``preferred`` or ``tolerated``.'),
-        "idle-seeding-limit":           ('number', 10, None, None, None, 'The default seed inactivity limit in minutes.'),
-        "idle-seeding-limit-enabled":   ('boolean', 10, None, None, None, 'Enables the default seed inactivity limit'),
-        "incomplete-dir":               ('string', 7, None, None, None, 'The path to the directory of incomplete transfer data.'),
-        "incomplete-dir-enabled":       ('boolean', 7, None, None, None, 'Enables the incomplete transfer data directory. Otherwise data for incomplete transfers are stored in the download target.'),
-        "lpd-enabled":                  ('boolean', 9, None, None, None, 'Enables local peer discovery for public torrents.'),
-        "peer-limit":                   ('number', 1, 5, None, 'peer-limit-global', 'Maximum number of peers.'),
-        "peer-limit-global":            ('number', 5, None, 'peer-limit', None, 'Maximum number of peers.'),
-        "peer-limit-per-torrent":       ('number', 5, None, None, None, 'Maximum number of peers per transfer.'),
-        "pex-allowed":                  ('boolean', 1, 5, None, 'pex-enabled', 'Allowing PEX in public torrents.'),
-        "pex-enabled":                  ('boolean', 5, None, 'pex-allowed', None, 'Allowing PEX in public torrents.'),
-        "port":                         ('number', 1, 5, None, 'peer-port', 'Peer port.'),
-        "peer-port":                    ('number', 5, None, 'port', None, 'Peer port.'),
-        "peer-port-random-on-start":    ('boolean', 5, None, None, None, 'Enables randomized peer port on start of Transmission.'),
-        "port-forwarding-enabled":      ('boolean', 1, None, None, None, 'Enables port forwarding.'),
-        "rename-partial-files":         ('boolean', 8, None, None, None, 'Appends ".part" to incomplete files'),
-        "queue-stalled-minutes":        ('number', 14, None, None, None, 'Number of minutes of idle that marks a transfer as stalled.'),
-        "queue-stalled-enabled":        ('boolean', 14, None, None, None, 'Enable tracking of stalled transfers.'),
-        "script-torrent-done-enabled":  ('boolean', 9, None, None, None, 'Whether or not to call the "done" script.'),
-        "script-torrent-done-filename": ('string', 9, None, None, None, 'Filename of the script to run when the transfer is done.'),
-        "seed-queue-size":              ('number', 14, None, None, None, 'Number of slots in the upload queue.'),
-        "seed-queue-enabled":           ('boolean', 14, None, None, None, 'Enables upload queue.'),
-        "seedRatioLimit":               ('double', 5, None, None, None, 'Seed ratio limit. 1.0 means 1:1 download and upload ratio.'),
-        "seedRatioLimited":             ('boolean', 5, None, None, None, 'Enables seed ration limit.'),
-        "speed-limit-down":             ('number', 1, None, None, None, 'Download speed limit (in Kib/s).'),
-        "speed-limit-down-enabled":     ('boolean', 1, None, None, None, 'Enables download speed limiting.'),
-        "speed-limit-up":               ('number', 1, None, None, None, 'Upload speed limit (in Kib/s).'),
-        "speed-limit-up-enabled":       ('boolean', 1, None, None, None, 'Enables upload speed limiting.'),
-        "start-added-torrents":         ('boolean', 9, None, None, None, 'Added torrents will be started right away.'),
-        "trash-original-torrent-files": ('boolean', 9, None, None, None, 'The .torrent file of added torrents will be deleted.'),
-        'utp-enabled':                  ('boolean', 13, None, None, None, 'Enables Micro Transport Protocol (UTP).'),
+    "set": {
+        "alt-speed-down": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Alternate session download speed limit (in Kib/s).",
+        ),
+        "alt-speed-enabled": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "Enables alternate global download speed limiter.",
+        ),
+        "alt-speed-time-begin": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Time when alternate speeds should be enabled. Minutes after midnight.",
+        ),
+        "alt-speed-time-enabled": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "Enables alternate speeds scheduling.",
+        ),
+        "alt-speed-time-end": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Time when alternate speeds should be disabled. Minutes after midnight.",
+        ),
+        "alt-speed-time-day": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Enables alternate speeds scheduling these days.",
+        ),
+        "alt-speed-up": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Alternate session upload speed limit (in Kib/s).",
+        ),
+        "blocklist-enabled": ("boolean", 5, None, None, None, "Enables the block list"),
+        "blocklist-url": (
+            "string",
+            11,
+            None,
+            None,
+            None,
+            "Location of the block list. Updated with blocklist-update.",
+        ),
+        "cache-size-mb": (
+            "number",
+            10,
+            None,
+            None,
+            None,
+            "The maximum size of the disk cache in MB",
+        ),
+        "dht-enabled": ("boolean", 6, None, None, None, "Enables DHT."),
+        "download-dir": (
+            "string",
+            1,
+            None,
+            None,
+            None,
+            "Set the session download directory.",
+        ),
+        "download-queue-size": (
+            "number",
+            14,
+            None,
+            None,
+            None,
+            "Number of slots in the download queue.",
+        ),
+        "download-queue-enabled": (
+            "boolean",
+            14,
+            None,
+            None,
+            None,
+            "Enables download queue.",
+        ),
+        "encryption": (
+            "string",
+            1,
+            None,
+            None,
+            None,
+            "Set the session encryption mode, one of ``required``, ``preferred`` or ``tolerated``.",
+        ),
+        "idle-seeding-limit": (
+            "number",
+            10,
+            None,
+            None,
+            None,
+            "The default seed inactivity limit in minutes.",
+        ),
+        "idle-seeding-limit-enabled": (
+            "boolean",
+            10,
+            None,
+            None,
+            None,
+            "Enables the default seed inactivity limit",
+        ),
+        "incomplete-dir": (
+            "string",
+            7,
+            None,
+            None,
+            None,
+            "The path to the directory of incomplete transfer data.",
+        ),
+        "incomplete-dir-enabled": (
+            "boolean",
+            7,
+            None,
+            None,
+            None,
+            "Enables the incomplete transfer data directory. Otherwise data for incomplete transfers are stored in the download target.",
+        ),
+        "lpd-enabled": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            "Enables local peer discovery for public torrents.",
+        ),
+        "peer-limit": (
+            "number",
+            1,
+            5,
+            None,
+            "peer-limit-global",
+            "Maximum number of peers.",
+        ),
+        "peer-limit-global": (
+            "number",
+            5,
+            None,
+            "peer-limit",
+            None,
+            "Maximum number of peers.",
+        ),
+        "peer-limit-per-torrent": (
+            "number",
+            5,
+            None,
+            None,
+            None,
+            "Maximum number of peers per transfer.",
+        ),
+        "pex-allowed": (
+            "boolean",
+            1,
+            5,
+            None,
+            "pex-enabled",
+            "Allowing PEX in public torrents.",
+        ),
+        "pex-enabled": (
+            "boolean",
+            5,
+            None,
+            "pex-allowed",
+            None,
+            "Allowing PEX in public torrents.",
+        ),
+        "port": ("number", 1, 5, None, "peer-port", "Peer port."),
+        "peer-port": ("number", 5, None, "port", None, "Peer port."),
+        "peer-port-random-on-start": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "Enables randomized peer port on start of Transmission.",
+        ),
+        "port-forwarding-enabled": (
+            "boolean",
+            1,
+            None,
+            None,
+            None,
+            "Enables port forwarding.",
+        ),
+        "rename-partial-files": (
+            "boolean",
+            8,
+            None,
+            None,
+            None,
+            'Appends ".part" to incomplete files',
+        ),
+        "queue-stalled-minutes": (
+            "number",
+            14,
+            None,
+            None,
+            None,
+            "Number of minutes of idle that marks a transfer as stalled.",
+        ),
+        "queue-stalled-enabled": (
+            "boolean",
+            14,
+            None,
+            None,
+            None,
+            "Enable tracking of stalled transfers.",
+        ),
+        "script-torrent-done-enabled": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            'Whether or not to call the "done" script.',
+        ),
+        "script-torrent-done-filename": (
+            "string",
+            9,
+            None,
+            None,
+            None,
+            "Filename of the script to run when the transfer is done.",
+        ),
+        "seed-queue-size": (
+            "number",
+            14,
+            None,
+            None,
+            None,
+            "Number of slots in the upload queue.",
+        ),
+        "seed-queue-enabled": (
+            "boolean",
+            14,
+            None,
+            None,
+            None,
+            "Enables upload queue.",
+        ),
+        "seedRatioLimit": (
+            "double",
+            5,
+            None,
+            None,
+            None,
+            "Seed ratio limit. 1.0 means 1:1 download and upload ratio.",
+        ),
+        "seedRatioLimited": (
+            "boolean",
+            5,
+            None,
+            None,
+            None,
+            "Enables seed ration limit.",
+        ),
+        "speed-limit-down": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Download speed limit (in Kib/s).",
+        ),
+        "speed-limit-down-enabled": (
+            "boolean",
+            1,
+            None,
+            None,
+            None,
+            "Enables download speed limiting.",
+        ),
+        "speed-limit-up": (
+            "number",
+            1,
+            None,
+            None,
+            None,
+            "Upload speed limit (in Kib/s).",
+        ),
+        "speed-limit-up-enabled": (
+            "boolean",
+            1,
+            None,
+            None,
+            None,
+            "Enables upload speed limiting.",
+        ),
+        "start-added-torrents": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            "Added torrents will be started right away.",
+        ),
+        "trash-original-torrent-files": (
+            "boolean",
+            9,
+            None,
+            None,
+            None,
+            "The .torrent file of added torrents will be deleted.",
+        ),
+        "utp-enabled": (
+            "boolean",
+            13,
+            None,
+            None,
+            None,
+            "Enables Micro Transport Protocol (UTP).",
+        ),
     },
 }
diff --git a/transmissionrpc/error.py b/transmissionrpc/error.py
index e74287d..b5c0c50 100644
--- a/transmissionrpc/error.py
+++ b/transmissionrpc/error.py
@@ -10,7 +10,7 @@ class TransmissionError(Exception):
     communication with Transmission. It is a subclass of Exception.
     """
 
-    def __init__(self, message='', original=None):
+    def __init__(self, message="", original=None):
         Exception.__init__(self)
         self.message = message
         self.original = original
@@ -18,7 +18,11 @@ def __init__(self, message='', original=None):
     def __str__(self):
         if self.original:
             original_name = type(self.original).__name__
-            return '%s Original exception: %s, "%s"' % (self.message, original_name, str(self.original))
+            return '%s Original exception: %s, "%s"' % (
+                self.message,
+                original_name,
+                str(self.original),
+            )
         else:
             return self.message
 
@@ -29,13 +33,15 @@ class HTTPHandlerError(Exception):
     the HTTP handler. It is a subclass of Exception.
     """
 
-    def __init__(self, httpurl=None, httpcode=None, httpmsg=None, httpheaders=None, httpdata=None):
+    def __init__(
+        self, httpurl=None, httpcode=None, httpmsg=None, httpheaders=None, httpdata=None
+    ):
         Exception.__init__(self)
-        self.url = ''
+        self.url = ""
         self.code = 600
-        self.message = ''
+        self.message = ""
         self.headers = {}
-        self.data = ''
+        self.data = ""
         if isinstance(httpurl, str):
             self.url = httpurl
         if isinstance(httpcode, int):
@@ -48,10 +54,10 @@ def __init__(self, httpurl=None, httpcode=None, httpmsg=None, httpheaders=None,
             self.data = httpdata
 
     def __repr__(self):
-        return '<HTTPHandlerError %d, %s>' % (self.code, self.message)
+        return "<HTTPHandlerError %d, %s>" % (self.code, self.message)
 
     def __str__(self):
-        return 'HTTPHandlerError %d: %s' % (self.code, self.message)
+        return "HTTPHandlerError %d: %s" % (self.code, self.message)
 
     def __unicode__(self):
-        return 'HTTPHandlerError %d: %s' % (self.code, self.message)
+        return "HTTPHandlerError %d: %s" % (self.code, self.message)
diff --git a/transmissionrpc/httphandler.py b/transmissionrpc/httphandler.py
index 7391093..d6a2bec 100644
--- a/transmissionrpc/httphandler.py
+++ b/transmissionrpc/httphandler.py
@@ -26,7 +26,8 @@ def set_authentication(self, uri, login, password):
          * password, the authentication password.
         """
         raise NotImplementedError(
-            "Bad HTTPHandler, failed to implement set_authentication.")
+            "Bad HTTPHandler, failed to implement set_authentication."
+        )
 
     def request(self, url, query, headers, timeout):
         """
@@ -37,8 +38,7 @@ def request(self, url, query, headers, timeout):
          * headers, a dictionary of headers to send.
          * timeout, requested request timeout in seconds.
         """
-        raise NotImplementedError(
-            "Bad HTTPHandler, failed to implement request.")
+        raise NotImplementedError("Bad HTTPHandler, failed to implement request.")
 
 
 class DefaultHTTPHandler(HTTPHandler):
@@ -55,9 +55,9 @@ def _response_encoding(self, headers):
 
         # Figure out what encoding was sent with the response, if any.
         # Check against lowercased header name.
-        if headers and 'content-type' in headers:
-            content_type = headers['content-type'].lower()
-            match = re.search(r'charset=(\S+)', content_type)
+        if headers and "content-type" in headers:
+            content_type = headers["content-type"].lower()
+            match = re.search(r"charset=(\S+)", content_type)
             if match:
                 encoding = match.group(1)
 
@@ -65,7 +65,7 @@ def _response_encoding(self, headers):
             # Default encoding for HTML is iso-8859-1.
             # Other content types may have different default encoding,
             # or in case of binary data, may have no encoding at all.
-            encoding = 'iso-8859-1'
+            encoding = "iso-8859-1"
 
         return encoding
 
@@ -73,15 +73,15 @@ def _response_headers(self, buffer):
         headers = {}
 
         # HTTP standard specifies that headers are encoded in iso-8859-1.
-        for line in buffer.getvalue().decode('iso-8859-1').splitlines():
+        for line in buffer.getvalue().decode("iso-8859-1").splitlines():
             # Header lines include the first status line (HTTP/1.x ...).
             # We are going to ignore all lines that don't have a colon in them.
             # This will botch headers that are split on multiple lines...
-            if ':' not in line:
+            if ":" not in line:
                 continue
 
             # Break the header line into header name and value.
-            name, value = line.split(':', 1)
+            name, value = line.split(":", 1)
 
             # Remove whitespace that may be present.
             # Header lines include the trailing newline, and there may be
@@ -101,13 +101,14 @@ def _response_headers(self, buffer):
 
     def set_authentication(self, uri, login, password):
         self._authorization = b64encode(
-            bytearray('{}:{}'.format(login, password), 'utf-8')).decode('utf-8')
+            bytearray("{}:{}".format(login, password), "utf-8")
+        ).decode("utf-8")
 
     def request(self, url, query, headers, timeout):
-        request_headers = ['{}: {}'.format(k, v) for k, v in headers.items()]
+        request_headers = ["{}: {}".format(k, v) for k, v in headers.items()]
 
         if self._authorization:
-            request_headers += ['Authorization: Basic {}'.format(self._authorization)]
+            request_headers += ["Authorization: Basic {}".format(self._authorization)]
 
         buf1, buf2 = BytesIO(), BytesIO()
         c = pycurl.Curl()
@@ -129,4 +130,5 @@ def request(self, url, query, headers, timeout):
             return response_body
         else:
             raise HTTPHandlerError(
-                url, response_code, None, response_headers, response_body)
+                url, response_code, None, response_headers, response_body
+            )
diff --git a/transmissionrpc/session.py b/transmissionrpc/session.py
index fe3180f..f13c2a3 100644
--- a/transmissionrpc/session.py
+++ b/transmissionrpc/session.py
@@ -26,10 +26,10 @@ def __getattr__(self, name):
         try:
             return self._fields[name].value
         except KeyError:
-            raise AttributeError('No attribute %s' % name)
+            raise AttributeError("No attribute %s" % name)
 
     def __str__(self):
-        text = ''
+        text = ""
         for key in sorted(self._fields.keys()):
             text += "% 32s: %s\n" % (key[-32:], self._fields[key].value)
         return text
@@ -40,16 +40,16 @@ def _update_fields(self, other):
         """
         if isinstance(other, dict):
             for key, value in list(other.items()):
-                self._fields[key.replace('-', '_')] = Field(value, False)
+                self._fields[key.replace("-", "_")] = Field(value, False)
         elif isinstance(other, Session):
             for key in list(other._fields.keys()):
                 self._fields[key] = Field(other._fields[key].value, False)
         else:
-            raise ValueError('Cannot update with supplied data')
+            raise ValueError("Cannot update with supplied data")
 
     def _dirty_fields(self):
         """Enumerate changed fields"""
-        outgoing_keys = ['peer_port', 'pex_enabled']
+        outgoing_keys = ["peer_port", "pex_enabled"]
         fields = []
         for key in outgoing_keys:
             if key in self._fields and self._fields[key].dirty:
@@ -82,32 +82,37 @@ def _get_peer_port(self):
         """
         Get the peer port.
         """
-        return self._fields['peer_port'].value
+        return self._fields["peer_port"].value
 
     def _set_peer_port(self, port):
         """
         Set the peer port.
         """
         if isinstance(port, int):
-            self._fields['peer_port'] = Field(port, True)
+            self._fields["peer_port"] = Field(port, True)
             self._push()
         else:
             raise ValueError("Not a valid limit")
 
-    peer_port = property(_get_peer_port, _set_peer_port,
-                         None, "Peer port. This is a mutator.")
+    peer_port = property(
+        _get_peer_port, _set_peer_port, None, "Peer port. This is a mutator."
+    )
 
     def _get_pex_enabled(self):
         """Is peer exchange enabled?"""
-        return self._fields['pex_enabled'].value
+        return self._fields["pex_enabled"].value
 
     def _set_pex_enabled(self, enabled):
         """Enable/disable peer exchange."""
         if isinstance(enabled, bool):
-            self._fields['pex_enabled'] = Field(enabled, True)
+            self._fields["pex_enabled"] = Field(enabled, True)
             self._push()
         else:
             raise TypeError("Not a valid type")
 
-    pex_enabled = property(_get_pex_enabled, _set_pex_enabled,
-                           None, "Enable peer exchange. This is a mutator.")
+    pex_enabled = property(
+        _get_pex_enabled,
+        _set_pex_enabled,
+        None,
+        "Enable peer exchange. This is a mutator.",
+    )
diff --git a/transmissionrpc/torrent.py b/transmissionrpc/torrent.py
index c40b14a..ac67b95 100644
--- a/transmissionrpc/torrent.py
+++ b/transmissionrpc/torrent.py
@@ -13,11 +13,11 @@
 def get_status_old(code):
     """Get the torrent status using old status codes"""
     mapping = {
-        (1 << 0): 'check pending',
-        (1 << 1): 'checking',
-        (1 << 2): 'downloading',
-        (1 << 3): 'seeding',
-        (1 << 4): 'stopped',
+        (1 << 0): "check pending",
+        (1 << 1): "checking",
+        (1 << 2): "downloading",
+        (1 << 3): "seeding",
+        (1 << 4): "stopped",
     }
     return mapping[code]
 
@@ -25,13 +25,13 @@ def get_status_old(code):
 def get_status_new(code):
     """Get the torrent status using new status codes"""
     mapping = {
-        0: 'stopped',
-        1: 'check pending',
-        2: 'checking',
-        3: 'download pending',
-        4: 'downloading',
-        5: 'seed pending',
-        6: 'seeding',
+        0: "stopped",
+        1: "check pending",
+        2: "checking",
+        3: "download pending",
+        4: "downloading",
+        5: "seed pending",
+        6: "seeding",
     }
     return mapping[code]
 
@@ -45,8 +45,8 @@ class Torrent:
     """
 
     def __init__(self, client, fields):
-        if 'id' not in fields:
-            raise ValueError('Torrent requires an id')
+        if "id" not in fields:
+            raise ValueError("Torrent requires an id")
         self._fields = {}
         self._update_fields(fields)
         self._incoming_pending = False
@@ -59,8 +59,8 @@ def _get_name_string(self, codec=None):
             codec = sys.getdefaultencoding()
         name = None
         # try to find name
-        if 'name' in self._fields:
-            name = self._fields['name'].value
+        if "name" in self._fields:
+            name = self._fields["name"].value
         # if name is unicode, try to decode
         if isinstance(name, str):
             try:
@@ -70,19 +70,19 @@ def _get_name_string(self, codec=None):
         return name
 
     def __repr__(self):
-        tid = self._fields['id'].value
+        tid = self._fields["id"].value
         name = self._get_name_string()
         if isinstance(name, str):
-            return '<Torrent %d \"%s\">' % (tid, name)
+            return '<Torrent %d "%s">' % (tid, name)
         else:
-            return '<Torrent %d>' % (tid)
+            return "<Torrent %d>" % (tid)
 
     def __str__(self):
         name = self._get_name_string()
         if isinstance(name, str):
-            return 'Torrent \"%s\"' % (name)
+            return 'Torrent "%s"' % (name)
         else:
-            return 'Torrent'
+            return "Torrent"
 
     def __copy__(self):
         return Torrent(self._client, self._fields)
@@ -91,7 +91,7 @@ def __getattr__(self, name):
         try:
             return self._fields[name].value
         except KeyError:
-            raise AttributeError('No attribute %s' % name)
+            raise AttributeError("No attribute %s" % name)
 
     def _rpc_version(self):
         """Get the Transmission RPC API version."""
@@ -101,8 +101,19 @@ def _rpc_version(self):
 
     def _dirty_fields(self):
         """Enumerate changed fields"""
-        outgoing_keys = ['bandwidthPriority', 'downloadLimit', 'downloadLimited', 'peer_limit', 'queuePosition',
-                         'seedIdleLimit', 'seedIdleMode', 'seedRatioLimit', 'seedRatioMode', 'uploadLimit', 'uploadLimited']
+        outgoing_keys = [
+            "bandwidthPriority",
+            "downloadLimit",
+            "downloadLimited",
+            "peer_limit",
+            "queuePosition",
+            "seedIdleLimit",
+            "seedIdleMode",
+            "seedRatioLimit",
+            "seedRatioMode",
+            "uploadLimit",
+            "uploadLimited",
+        ]
         fields = []
         for key in outgoing_keys:
             if key in self._fields and self._fields[key].dirty:
@@ -125,17 +136,17 @@ def _update_fields(self, other):
         """
         if isinstance(other, dict):
             for key, value in list(other.items()):
-                self._fields[key.replace('-', '_')] = Field(value, False)
+                self._fields[key.replace("-", "_")] = Field(value, False)
         elif isinstance(other, Torrent):
             for key in list(other._fields.keys()):
                 self._fields[key] = Field(other._fields[key].value, False)
         else:
-            raise ValueError('Cannot update with supplied data')
+            raise ValueError("Cannot update with supplied data")
         self._incoming_pending = False
 
     def _status(self):
         """Get the torrent status"""
-        code = self._fields['status'].value
+        code = self._fields["status"].value
         if self._rpc_version() >= 14:
             return get_status_new(code)
         else:
@@ -161,20 +172,21 @@ def files(self):
             }
         """
         result = {}
-        if 'files' in self._fields:
-            files = self._fields['files'].value
+        if "files" in self._fields:
+            files = self._fields["files"].value
             indices = list(range(len(files)))
-            priorities = self._fields['priorities'].value
-            wanted = self._fields['wanted'].value
+            priorities = self._fields["priorities"].value
+            wanted = self._fields["wanted"].value
             for item in zip(indices, files, priorities, wanted):
                 selected = True if item[3] else False
                 priority = PRIORITY[item[2]]
                 result[item[0]] = {
-                    'selected': selected,
-                    'priority': priority,
-                    'size': item[1]['length'],
-                    'name': item[1]['name'],
-                    'completed': item[1]['bytesCompleted']}
+                    "selected": selected,
+                    "priority": priority,
+                    "size": item[1]["length"],
+                    "name": item[1]["name"],
+                    "completed": item[1]["bytesCompleted"],
+                }
         return result
 
     @property
@@ -190,8 +202,8 @@ def status(self):
     def progress(self):
         """Get the download progress in percent."""
         try:
-            size = self._fields['sizeWhenDone'].value
-            left = self._fields['leftUntilDone'].value
+            size = self._fields["sizeWhenDone"].value
+            left = self._fields["leftUntilDone"].value
             return 100.0 * (size - left) / float(size)
         except ZeroDivisionError:
             return 0.0
@@ -199,36 +211,36 @@ def progress(self):
     @property
     def ratio(self):
         """Get the upload/download ratio."""
-        return float(self._fields['uploadRatio'].value)
+        return float(self._fields["uploadRatio"].value)
 
     @property
     def eta(self):
         """Get the "eta" as datetime.timedelta."""
-        eta = self._fields['eta'].value
+        eta = self._fields["eta"].value
         if eta >= 0:
             return datetime.timedelta(seconds=eta)
         else:
-            raise ValueError('eta not valid')
+            raise ValueError("eta not valid")
 
     @property
     def date_active(self):
         """Get the attribute "activityDate" as datetime.datetime."""
-        return datetime.datetime.fromtimestamp(self._fields['activityDate'].value)
+        return datetime.datetime.fromtimestamp(self._fields["activityDate"].value)
 
     @property
     def date_added(self):
         """Get the attribute "addedDate" as datetime.datetime."""
-        return datetime.datetime.fromtimestamp(self._fields['addedDate'].value)
+        return datetime.datetime.fromtimestamp(self._fields["addedDate"].value)
 
     @property
     def date_started(self):
         """Get the attribute "startDate" as datetime.datetime."""
-        return datetime.datetime.fromtimestamp(self._fields['startDate'].value)
+        return datetime.datetime.fromtimestamp(self._fields["startDate"].value)
 
     @property
     def date_done(self):
         """Get the attribute "doneDate" as datetime.datetime. returns None if "doneDate" is invalid."""
-        done_date = self._fields['doneDate'].value
+        done_date = self._fields["doneDate"].value
         # Transmission might forget to set doneDate which is initialized to zero, so if doneDate is zero return None
         if done_date == 0:
             return None
@@ -243,11 +255,11 @@ def format_eta(self):
         * If eta is -2 the result is 'unknown'
         * Otherwise eta is formatted as <days> <hours>:<minutes>:<seconds>.
         """
-        eta = self._fields['eta'].value
+        eta = self._fields["eta"].value
         if eta == -1:
-            return 'not available'
+            return "not available"
         elif eta == -2:
-            return 'unknown'
+            return "unknown"
         else:
             return format_timedelta(self.eta)
 
@@ -256,8 +268,8 @@ def _get_download_limit(self):
         Get the download limit.
         Can be a number or None.
         """
-        if self._fields['downloadLimited'].value:
-            return self._fields['downloadLimit'].value
+        if self._fields["downloadLimited"].value:
+            return self._fields["downloadLimit"].value
         else:
             return None
 
@@ -267,43 +279,48 @@ def _set_download_limit(self, limit):
         Can be a number, 'session' or None.
         """
         if isinstance(limit, int):
-            self._fields['downloadLimited'] = Field(True, True)
-            self._fields['downloadLimit'] = Field(limit, True)
+            self._fields["downloadLimited"] = Field(True, True)
+            self._fields["downloadLimit"] = Field(limit, True)
             self._push()
         elif limit is None:
-            self._fields['downloadLimited'] = Field(False, True)
+            self._fields["downloadLimited"] = Field(False, True)
             self._push()
         else:
             raise ValueError("Not a valid limit")
 
-    download_limit = property(_get_download_limit, _set_download_limit,
-                              None, "Download limit in Kbps or None. This is a mutator.")
+    download_limit = property(
+        _get_download_limit,
+        _set_download_limit,
+        None,
+        "Download limit in Kbps or None. This is a mutator.",
+    )
 
     def _get_peer_limit(self):
         """
         Get the peer limit.
         """
-        return self._fields['peer_limit'].value
+        return self._fields["peer_limit"].value
 
     def _set_peer_limit(self, limit):
         """
         Set the peer limit.
         """
         if isinstance(limit, int):
-            self._fields['peer_limit'] = Field(limit, True)
+            self._fields["peer_limit"] = Field(limit, True)
             self._push()
         else:
             raise ValueError("Not a valid limit")
 
-    peer_limit = property(_get_peer_limit, _set_peer_limit,
-                          None, "Peer limit. This is a mutator.")
+    peer_limit = property(
+        _get_peer_limit, _set_peer_limit, None, "Peer limit. This is a mutator."
+    )
 
     def _get_priority(self):
         """
         Get the priority as string.
         Can be one of 'low', 'normal', 'high'.
         """
-        return PRIORITY[self._fields['bandwidthPriority'].value]
+        return PRIORITY[self._fields["bandwidthPriority"].value]
 
     def _set_priority(self, priority):
         """
@@ -311,49 +328,60 @@ def _set_priority(self, priority):
         Can be one of 'low', 'normal', 'high'.
         """
         if isinstance(priority, str):
-            self._fields['bandwidthPriority'] = Field(PRIORITY[priority], True)
+            self._fields["bandwidthPriority"] = Field(PRIORITY[priority], True)
             self._push()
 
-    priority = property(_get_priority, _set_priority, None,
-                        "Bandwidth priority as string. Can be one of 'low', 'normal', 'high'. This is a mutator.")
+    priority = property(
+        _get_priority,
+        _set_priority,
+        None,
+        "Bandwidth priority as string. Can be one of 'low', 'normal', 'high'. This is a mutator.",
+    )
 
     def _get_seed_idle_limit(self):
         """
         Get the seed idle limit in minutes.
         """
-        return self._fields['seedIdleLimit'].value
+        return self._fields["seedIdleLimit"].value
 
     def _set_seed_idle_limit(self, limit):
         """
         Set the seed idle limit in minutes.
         """
         if isinstance(limit, int):
-            self._fields['seedIdleLimit'] = Field(limit, True)
+            self._fields["seedIdleLimit"] = Field(limit, True)
             self._push()
         else:
             raise ValueError("Not a valid limit")
 
-    seed_idle_limit = property(_get_seed_idle_limit, _set_seed_idle_limit, None,
-                               "Torrent seed idle limit in minutes. Also see seed_idle_mode. This is a mutator.")
+    seed_idle_limit = property(
+        _get_seed_idle_limit,
+        _set_seed_idle_limit,
+        None,
+        "Torrent seed idle limit in minutes. Also see seed_idle_mode. This is a mutator.",
+    )
 
     def _get_seed_idle_mode(self):
         """
         Get the seed ratio mode as string. Can be one of 'global', 'single' or 'unlimited'.
         """
-        return IDLE_LIMIT[self._fields['seedIdleMode'].value]
+        return IDLE_LIMIT[self._fields["seedIdleMode"].value]
 
     def _set_seed_idle_mode(self, mode):
         """
         Set the seed ratio mode as string. Can be one of 'global', 'single' or 'unlimited'.
         """
         if isinstance(mode, str):
-            self._fields['seedIdleMode'] = Field(IDLE_LIMIT[mode], True)
+            self._fields["seedIdleMode"] = Field(IDLE_LIMIT[mode], True)
             self._push()
         else:
             raise ValueError("Not a valid limit")
 
-    seed_idle_mode = property(_get_seed_idle_mode, _set_seed_idle_mode, None,
-                              """
+    seed_idle_mode = property(
+        _get_seed_idle_mode,
+        _set_seed_idle_mode,
+        None,
+        """
         Seed idle mode as string. Can be one of 'global', 'single' or 'unlimited'.
 
          * global, use session seed idle limit.
@@ -361,46 +389,53 @@ def _set_seed_idle_mode(self, mode):
          * unlimited, no seed idle limit.
 
         This is a mutator.
-        """
-                              )
+        """,
+    )
 
     def _get_seed_ratio_limit(self):
         """
         Get the seed ratio limit as float.
         """
-        return float(self._fields['seedRatioLimit'].value)
+        return float(self._fields["seedRatioLimit"].value)
 
     def _set_seed_ratio_limit(self, limit):
         """
         Set the seed ratio limit as float.
         """
         if isinstance(limit, (int, float)) and limit >= 0.0:
-            self._fields['seedRatioLimit'] = Field(float(limit), True)
+            self._fields["seedRatioLimit"] = Field(float(limit), True)
             self._push()
         else:
             raise ValueError("Not a valid limit")
 
-    seed_ratio_limit = property(_get_seed_ratio_limit, _set_seed_ratio_limit, None,
-                                "Torrent seed ratio limit as float. Also see seed_ratio_mode. This is a mutator.")
+    seed_ratio_limit = property(
+        _get_seed_ratio_limit,
+        _set_seed_ratio_limit,
+        None,
+        "Torrent seed ratio limit as float. Also see seed_ratio_mode. This is a mutator.",
+    )
 
     def _get_seed_ratio_mode(self):
         """
         Get the seed ratio mode as string. Can be one of 'global', 'single' or 'unlimited'.
         """
-        return RATIO_LIMIT[self._fields['seedRatioMode'].value]
+        return RATIO_LIMIT[self._fields["seedRatioMode"].value]
 
     def _set_seed_ratio_mode(self, mode):
         """
         Set the seed ratio mode as string. Can be one of 'global', 'single' or 'unlimited'.
         """
         if isinstance(mode, str):
-            self._fields['seedRatioMode'] = Field(RATIO_LIMIT[mode], True)
+            self._fields["seedRatioMode"] = Field(RATIO_LIMIT[mode], True)
             self._push()
         else:
             raise ValueError("Not a valid limit")
 
-    seed_ratio_mode = property(_get_seed_ratio_mode, _set_seed_ratio_mode, None,
-                               """
+    seed_ratio_mode = property(
+        _get_seed_ratio_mode,
+        _set_seed_ratio_mode,
+        None,
+        """
         Seed ratio mode as string. Can be one of 'global', 'single' or 'unlimited'.
 
          * global, use session seed ratio limit.
@@ -408,16 +443,16 @@ def _set_seed_ratio_mode(self, mode):
          * unlimited, no seed ratio limit.
 
         This is a mutator.
-        """
-                               )
+        """,
+    )
 
     def _get_upload_limit(self):
         """
         Get the upload limit.
         Can be a number or None.
         """
-        if self._fields['uploadLimited'].value:
-            return self._fields['uploadLimit'].value
+        if self._fields["uploadLimited"].value:
+            return self._fields["uploadLimit"].value
         else:
             return None
 
@@ -427,22 +462,26 @@ def _set_upload_limit(self, limit):
         Can be a number, 'session' or None.
         """
         if isinstance(limit, int):
-            self._fields['uploadLimited'] = Field(True, True)
-            self._fields['uploadLimit'] = Field(limit, True)
+            self._fields["uploadLimited"] = Field(True, True)
+            self._fields["uploadLimit"] = Field(limit, True)
             self._push()
         elif limit is None:
-            self._fields['uploadLimited'] = Field(False, True)
+            self._fields["uploadLimited"] = Field(False, True)
             self._push()
         else:
             raise ValueError("Not a valid limit")
 
-    upload_limit = property(_get_upload_limit, _set_upload_limit,
-                            None, "Upload limit in Kbps or None. This is a mutator.")
+    upload_limit = property(
+        _get_upload_limit,
+        _set_upload_limit,
+        None,
+        "Upload limit in Kbps or None. This is a mutator.",
+    )
 
     def _get_queue_position(self):
         """Get the queue position for this torrent."""
         if self._rpc_version() >= 14:
-            return self._fields['queuePosition'].value
+            return self._fields["queuePosition"].value
         else:
             return 0
 
@@ -450,7 +489,7 @@ def _set_queue_position(self, position):
         """Set the queue position for this torrent."""
         if self._rpc_version() >= 14:
             if isinstance(position, int):
-                self._fields['queuePosition'] = Field(position, True)
+                self._fields["queuePosition"] = Field(position, True)
                 self._push()
             else:
                 raise ValueError("Not a valid position")
@@ -458,7 +497,8 @@ def _set_queue_position(self, position):
             pass
 
     queue_position = property(
-        _get_queue_position, _set_queue_position, None, "Queue position")
+        _get_queue_position, _set_queue_position, None, "Queue position"
+    )
 
     def update(self, timeout=None):
         """Update the torrent information."""
@@ -471,8 +511,7 @@ def start(self, bypass_queue=False, timeout=None):
         Start the torrent.
         """
         self._incoming_pending = True
-        self._client.start_torrent(
-            self.id, bypass_queue=bypass_queue, timeout=timeout)
+        self._client.start_torrent(self.id, bypass_queue=bypass_queue, timeout=timeout)
 
     def stop(self, timeout=None):
         """Stop the torrent."""
diff --git a/transmissionrpc/utils.py b/transmissionrpc/utils.py
index 91a7d95..06bb8b5 100644
--- a/transmissionrpc/utils.py
+++ b/transmissionrpc/utils.py
@@ -10,7 +10,7 @@
 import transmissionrpc.constants as constants
 from transmissionrpc.constants import LOGGER
 
-UNITS = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']
+UNITS = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]
 
 
 def format_size(size):
@@ -30,7 +30,7 @@ def format_speed(size):
     Format bytes per second speed into IEC prefixes, B/s, KiB/s, MiB/s ...
     """
     (size, unit) = format_size(size)
-    return (size, unit + '/s')
+    return (size, unit + "/s")
 
 
 def format_timedelta(delta):
@@ -39,7 +39,7 @@ def format_timedelta(delta):
     """
     minutes, seconds = divmod(delta.seconds, 60)
     hours, minutes = divmod(minutes, 60)
-    return '%d %02d:%02d:%02d' % (delta.days, hours, minutes, seconds)
+    return "%d %02d:%02d:%02d" % (delta.days, hours, minutes, seconds)
 
 
 def format_timestamp(timestamp, utc=False):
@@ -51,23 +51,24 @@ def format_timestamp(timestamp, utc=False):
             dt_timestamp = datetime.datetime.utcfromtimestamp(timestamp)
         else:
             dt_timestamp = datetime.datetime.fromtimestamp(timestamp)
-        return dt_timestamp.isoformat(' ')
+        return dt_timestamp.isoformat(" ")
     else:
-        return '-'
+        return "-"
 
 
 class INetAddressError(Exception):
     """
     Error parsing / generating a internet address.
     """
+
     pass
 
 
-def inet_address(address, default_port, default_address='localhost'):
+def inet_address(address, default_port, default_address="localhost"):
     """
     Parse internet address.
     """
-    addr = address.split(':')
+    addr = address.split(":")
     if len(addr) == 1:
         try:
             port = int(addr[0])
@@ -101,17 +102,17 @@ def rpc_bool(arg):
         try:
             arg = bool(int(arg))
         except ValueError:
-            arg = arg.lower() in ['true', 'yes']
+            arg = arg.lower() in ["true", "yes"]
     return 1 if bool(arg) else 0
 
 
 TR_TYPE_MAP = {
-    'number': int,
-    'string': str,
-    'double': float,
-    'boolean': rpc_bool,
-    'array': list,
-    'object': dict
+    "number": int,
+    "string": str,
+    "double": float,
+    "boolean": rpc_bool,
+    "array": list,
+    "object": dict,
 }
 
 
@@ -119,23 +120,23 @@ def make_python_name(name):
     """
     Convert Transmission RPC name to python compatible name.
     """
-    return name.replace('-', '_')
+    return name.replace("-", "_")
 
 
 def make_rpc_name(name):
     """
     Convert python compatible name to Transmission RPC name.
     """
-    return name.replace('_', '-')
+    return name.replace("_", "-")
 
 
 def argument_value_convert(method, argument, value, rpc_version):
     """
     Check and fix Transmission RPC issues with regards to methods, arguments and values.
     """
-    if method in ('torrent-add', 'torrent-get', 'torrent-set'):
+    if method in ("torrent-add", "torrent-get", "torrent-set"):
         args = constants.TORRENT_ARGS[method[-3:]]
-    elif method in ('session-get', 'session-set'):
+    elif method in ("session-get", "session-set"):
         args = constants.SESSION_ARGS[method[-3:]]
     else:
         return ValueError('Method "%s" not supported' % (method))
@@ -155,26 +156,29 @@ def argument_value_convert(method, argument, value, rpc_version):
                 if replacement:
                     LOGGER.warning(
                         'Replacing requested argument "%s" with "%s".'
-                        % (argument, replacement))
+                        % (argument, replacement)
+                    )
                     argument = replacement
                     info = args[argument]
                 else:
                     raise ValueError(
                         'Method "%s" Argument "%s" does not exist in version %d.'
-                        % (method, argument, rpc_version))
+                        % (method, argument, rpc_version)
+                    )
         return (argument, TR_TYPE_MAP[info[0]](value))
     else:
-        raise ValueError('Argument "%s" does not exists for method "%s".',
-                         (argument, method))
+        raise ValueError(
+            'Argument "%s" does not exists for method "%s".', (argument, method)
+        )
 
 
 def get_arguments(method, rpc_version):
     """
     Get arguments for method in specified Transmission RPC version.
     """
-    if method in ('torrent-add', 'torrent-get', 'torrent-set'):
+    if method in ("torrent-add", "torrent-get", "torrent-set"):
         args = constants.TORRENT_ARGS[method[-3:]]
-    elif method in ('session-get', 'session-set'):
+    elif method in ("session-get", "session-set"):
         args = constants.SESSION_ARGS[method[-3:]]
     else:
         return ValueError('Method "%s" not supported' % (method))
@@ -194,18 +198,22 @@ def is_logger_configured():
     """
     Check if there are any logging handlers.
     """
-    trpc_logger = logging.getLogger('transmissionrpc')
+    trpc_logger = logging.getLogger("transmissionrpc")
     return len(trpc_logger.handlers) > 0
 
 
-def add_stdout_logger(level='debug'):
+def add_stdout_logger(level="debug"):
     """
     Add a stdout target for the transmissionrpc logging.
     """
-    levels = {'debug': logging.DEBUG, 'info': logging.INFO,
-              'warning': logging.WARNING, 'error': logging.ERROR}
+    levels = {
+        "debug": logging.DEBUG,
+        "info": logging.INFO,
+        "warning": logging.WARNING,
+        "error": logging.ERROR,
+    }
 
-    trpc_logger = logging.getLogger('transmissionrpc')
+    trpc_logger = logging.getLogger("transmissionrpc")
     loghandler = logging.StreamHandler()
     if level in list(levels.keys()):
         loglevel = levels[level]
@@ -214,15 +222,19 @@ def add_stdout_logger(level='debug'):
     trpc_logger.addHandler(loghandler)
 
 
-def add_file_logger(filepath, level='debug'):
+def add_file_logger(filepath, level="debug"):
     """
     Add a stdout target for the transmissionrpc logging.
     """
-    levels = {'debug': logging.DEBUG, 'info': logging.INFO,
-              'warning': logging.WARNING, 'error': logging.ERROR}
+    levels = {
+        "debug": logging.DEBUG,
+        "info": logging.INFO,
+        "warning": logging.WARNING,
+        "error": logging.ERROR,
+    }
 
-    trpc_logger = logging.getLogger('transmissionrpc')
-    loghandler = logging.FileHandler(filepath, encoding='utf-8')
+    trpc_logger = logging.getLogger("transmissionrpc")
+    loghandler = logging.FileHandler(filepath, encoding="utf-8")
     if level in list(levels.keys()):
         loglevel = levels[level]
         trpc_logger.setLevel(loglevel)
@@ -230,4 +242,4 @@ def add_file_logger(filepath, level='debug'):
     trpc_logger.addHandler(loghandler)
 
 
-Field = namedtuple('Field', ['value', 'dirty'])
+Field = namedtuple("Field", ["value", "dirty"])


Test patch:
diff --git a/test/__init__.py b/test/__init__.py
index cec2dc9..e61a763 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -7,7 +7,9 @@
 
 
 def test():
-    tests = unittest.TestSuite([top.suite(), utils.suite(), torrent.suite(), client.suite()])
+    tests = unittest.TestSuite(
+        [top.suite(), utils.suite(), torrent.suite(), client.suite()]
+    )
     result = unittest.TestResult()
     tests.run(result)
     for e in result.errors:
diff --git a/test/client.py b/test/client.py
index c073ce1..b203690 100644
--- a/test/client.py
+++ b/test/client.py
@@ -16,32 +16,32 @@
 
 
 def tree_differences(a, b):
-    return node_differences(a, b, '.')
+    return node_differences(a, b, ".")
 
 
 def node_differences(a, b, root):
     errors = []
     if isinstance(a, dict) and isinstance(b, dict):
         for k, v in iter(a.items()):
-            node = root + '.' + k
+            node = root + "." + k
             if k not in b:
-                errors.append('Field %s missing from b at %s' % (k, node))
+                errors.append("Field %s missing from b at %s" % (k, node))
             else:
                 errors.extend(node_differences(a[k], b[k], node))
         for k, v in iter(b.items()):
-            node = root + '.' + k
+            node = root + "." + k
             if k not in a:
-                errors.append('Field %s missing from a at %s' % (k, node))
+                errors.append("Field %s missing from a at %s" % (k, node))
     elif isinstance(a, list) and isinstance(b, list):
         for v in a:
             if v not in b:
-                errors.append('Value %s missing from b at %s' % (v[0:32], root))
+                errors.append("Value %s missing from b at %s" % (v[0:32], root))
         for v in b:
             if v not in a:
-                errors.append('Value %s missing from a at %s' % (v[0:32], root))
+                errors.append("Value %s missing from a at %s" % (v[0:32], root))
     else:
         if a != b:
-            errors.append('Value %s != %s at %s' % (a[0:32], b[0:32], root))
+            errors.append("Value %s != %s at %s" % (a[0:32], b[0:32], root))
     return errors
 
 
@@ -53,40 +53,40 @@ def __init__(self, test_name=None):
         self.tests = None
         self.test_index = 0
         if test_name:
-            test_file = test_name + '.json'
+            test_file = test_name + ".json"
             here = os.path.dirname(os.path.abspath(__file__))
-            test_path = os.path.join(here, 'data', test_file)
-            fd = open(test_path, 'r')
+            test_path = os.path.join(here, "data", test_file)
+            fd = open(test_path, "r")
             test_data = json.load(fd)
             fd.close()
-            if 'test sequence' in test_data:
-                self.tests = test_data['test sequence']
+            if "test sequence" in test_data:
+                self.tests = test_data["test sequence"]
 
     def set_authentication(self, url, user, password):
         urlo = urlparse(url)
-        if urlo.scheme == '':
-            raise ValueError('URL should have a scheme.')
+        if urlo.scheme == "":
+            raise ValueError("URL should have a scheme.")
         else:
             self.url = url
         if user and password:
             if isinstance(user, str):
                 self.user = user
             else:
-                raise TypeError('Invalid type for user.')
+                raise TypeError("Invalid type for user.")
             if isinstance(password, str):
                 self.password = password
             else:
-                raise TypeError('Invalid type for password.')
+                raise TypeError("Invalid type for password.")
         elif user or password:
-            raise ValueError('User AND password or neither.')
+            raise ValueError("User AND password or neither.")
 
     def request(self, url, query, headers, timeout):
         response = {}
         if self.url and self.url != url:
-            raise ValueError('New URL?!')
+            raise ValueError("New URL?!")
         urlo = urlparse(url)
-        if urlo.scheme == '':
-            raise ValueError('URL should have a scheme.')
+        if urlo.scheme == "":
+            raise ValueError("URL should have a scheme.")
         else:
             self.url = url
         q = json.loads(query)
@@ -94,50 +94,72 @@ def request(self, url, query, headers, timeout):
         if self.tests:
             test_data = self.tests[self.test_index]
             self.test_index += 1
-            errors = tree_differences(test_data['request'], q)
+            errors = tree_differences(test_data["request"], q)
             if len(errors) > 0:
-                errors = '\n\t'.join(errors)
-                raise Exception('Invalid request\n%s\n%s\n. Errors: %s\n' % (json.dumps(q, indent=2), json.dumps(test_data['request'], indent=2), errors))
-            if 'response' in test_data:
-                response = test_data['response']
+                errors = "\n\t".join(errors)
+                raise Exception(
+                    "Invalid request\n%s\n%s\n. Errors: %s\n"
+                    % (
+                        json.dumps(q, indent=2),
+                        json.dumps(test_data["request"], indent=2),
+                        errors,
+                    )
+                )
+            if "response" in test_data:
+                response = test_data["response"]
         else:
-            response['tag'] = int(q['tag'])
-            response['result'] = 'success'
+            response["tag"] = int(q["tag"])
+            response["result"] = "success"
         return json.dumps(response)
 
 
 def createClient(*args, **kwargs):
     test_name = None
-    if 'test_name' in kwargs:
-        test_name = kwargs['test_name']
-        del kwargs['test_name']
-    kwargs['http_handler'] = TestHTTPHandler(test_name)
+    if "test_name" in kwargs:
+        test_name = kwargs["test_name"]
+        del kwargs["test_name"]
+    kwargs["http_handler"] = TestHTTPHandler(test_name)
     return Client(*args, **kwargs)
 
 
 class ClientTest(unittest.TestCase):
-
     def testConstruction(self):
-        tc = createClient(test_name='construction')
-        self.assertEqual(tc.url, 'http://localhost:%d/transmission/rpc' % (transmissionrpc.constants.DEFAULT_PORT))
-        tc = createClient('127.0.0.1', 7000, user='user', password='secret', test_name='construction')
-        self.assertEqual(tc.url, 'http://127.0.0.1:7000/transmission/rpc')
-        tc = createClient('127.0.0.1', 7000, user='user', password='secret', test_name='construction')
-        self.assertEqual(tc.url, 'http://127.0.0.1:7000/transmission/rpc')
-        tc = createClient('127.0.0.1', 7000, user='user', test_name='construction')
-        self.assertEqual(tc.url, 'http://127.0.0.1:7000/transmission/rpc')
-        tc = createClient('127.0.0.1', 7000, password='secret', test_name='construction')
-        self.assertEqual(tc.url, 'http://127.0.0.1:7000/transmission/rpc')
-        tc = createClient('127.0.0.1', 7000, password='secret', timeout=0.1, test_name='construction')
-        self.assertEqual(tc.url, 'http://127.0.0.1:7000/transmission/rpc')
+        tc = createClient(test_name="construction")
+        self.assertEqual(
+            tc.url,
+            "http://localhost:%d/transmission/rpc"
+            % (transmissionrpc.constants.DEFAULT_PORT),
+        )
+        tc = createClient(
+            "127.0.0.1", 7000, user="user", password="secret", test_name="construction"
+        )
+        self.assertEqual(tc.url, "http://127.0.0.1:7000/transmission/rpc")
+        tc = createClient(
+            "127.0.0.1", 7000, user="user", password="secret", test_name="construction"
+        )
+        self.assertEqual(tc.url, "http://127.0.0.1:7000/transmission/rpc")
+        tc = createClient("127.0.0.1", 7000, user="user", test_name="construction")
+        self.assertEqual(tc.url, "http://127.0.0.1:7000/transmission/rpc")
+        tc = createClient(
+            "127.0.0.1", 7000, password="secret", test_name="construction"
+        )
+        self.assertEqual(tc.url, "http://127.0.0.1:7000/transmission/rpc")
+        tc = createClient(
+            "127.0.0.1", 7000, password="secret", timeout=0.1, test_name="construction"
+        )
+        self.assertEqual(tc.url, "http://127.0.0.1:7000/transmission/rpc")
         self.assertEqual(tc.timeout, 0.1)
-        tc = createClient('127.0.0.1', 7000, password='secret', timeout=10, test_name='construction')
+        tc = createClient(
+            "127.0.0.1", 7000, password="secret", timeout=10, test_name="construction"
+        )
         self.assertEqual(tc.timeout, 10.0)
-        tc = createClient('127.0.0.1', 7000, password='secret', timeout=10, test_name='construction')
+        tc = createClient(
+            "127.0.0.1", 7000, password="secret", timeout=10, test_name="construction"
+        )
         self.assertEqual(tc.timeout, 10.0)
 
     def testTimeoutProperty(self):
-        tc = createClient('127.0.0.1', 12345, timeout=10, test_name='construction')
+        tc = createClient("127.0.0.1", 12345, timeout=10, test_name="construction")
         self.assertEqual(tc.timeout, 10.0)
         tc.timeout = 0.1
         self.assertEqual(tc.timeout, 0.1)
@@ -147,194 +169,254 @@ def testTimeoutProperty(self):
         self.assertEqual(tc.timeout, 100.0)
         del tc.timeout
         self.assertEqual(tc.timeout, transmissionrpc.constants.DEFAULT_TIMEOUT)
-        tc.timeout = '100.1'
+        tc.timeout = "100.1"
         self.assertEqual(tc.timeout, 100.1)
-        self.assertRaises(ValueError, tc._set_timeout, '10 years')
+        self.assertRaises(ValueError, tc._set_timeout, "10 years")
 
     def testAddTorrent(self):
-        data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data')
-
-        tc = createClient(test_name='add_torrent_base64')
-        torrent_path = os.path.join(data_path, 'ubuntu-12.04.2-alternate-amd64.iso.torrent')
-        with open(torrent_path, 'rb') as data:
-            data_b64 = base64.b64encode(data.read()).decode('utf-8')
+        data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
+
+        tc = createClient(test_name="add_torrent_base64")
+        torrent_path = os.path.join(
+            data_path, "ubuntu-12.04.2-alternate-amd64.iso.torrent"
+        )
+        with open(torrent_path, "rb") as data:
+            data_b64 = base64.b64encode(data.read()).decode("utf-8")
         r = tc.add_torrent(data_b64)
         self.assertEqual(r.id, 0)
-        self.assertEqual(r.hashString, 'a21c45469c565f3fb9595e4e9707e6e9d45abca6')
-        self.assertEqual(r.name, 'ubuntu-12.04.2-alternate-amd64.iso')
+        self.assertEqual(r.hashString, "a21c45469c565f3fb9595e4e9707e6e9d45abca6")
+        self.assertEqual(r.name, "ubuntu-12.04.2-alternate-amd64.iso")
 
-        tc = createClient(test_name='adduri')
+        tc = createClient(test_name="adduri")
         self.assertRaises(ValueError, tc.add_torrent, None)
 
-        r = tc.add_torrent('torrent.txt', paused=False, download_dir='/var/downloads', peer_limit=1)
+        r = tc.add_torrent(
+            "torrent.txt", paused=False, download_dir="/var/downloads", peer_limit=1
+        )
         self.assertEqual(r.id, 0)
-        self.assertEqual(r.hashString, 'A000')
-        self.assertEqual(r.name, 'testtransfer0')
-
-        r = tc.add_torrent('file://' + os.path.join(data_path, 'torrent.txt'), paused=True, download_dir='/tmp', peer_limit=200)
+        self.assertEqual(r.hashString, "A000")
+        self.assertEqual(r.name, "testtransfer0")
+
+        r = tc.add_torrent(
+            "file://" + os.path.join(data_path, "torrent.txt"),
+            paused=True,
+            download_dir="/tmp",
+            peer_limit=200,
+        )
         self.assertEqual(r.id, 1)
-        self.assertEqual(r.hashString, 'A001')
-        self.assertEqual(r.name, 'testtransfer1')
+        self.assertEqual(r.hashString, "A001")
+        self.assertEqual(r.name, "testtransfer1")
 
-        r = tc.add_torrent('file://' + os.path.join(data_path, 'ubuntu-12.04.2-alternate-amd64.iso.torrent'))
+        r = tc.add_torrent(
+            "file://"
+            + os.path.join(data_path, "ubuntu-12.04.2-alternate-amd64.iso.torrent")
+        )
         self.assertEqual(r.id, 2)
-        self.assertEqual(r.hashString, 'a21c45469c565f3fb9595e4e9707e6e9d45abca6')
-        self.assertEqual(r.name, 'ubuntu-12.04.2-alternate-amd64.iso')
+        self.assertEqual(r.hashString, "a21c45469c565f3fb9595e4e9707e6e9d45abca6")
+        self.assertEqual(r.name, "ubuntu-12.04.2-alternate-amd64.iso")
 
-        r = tc.add_torrent('file://' + os.path.join(data_path, 'ubuntu-12.04.2-alternate-amd64.iso.torrent.gz'))
+        r = tc.add_torrent(
+            "file://"
+            + os.path.join(data_path, "ubuntu-12.04.2-alternate-amd64.iso.torrent.gz")
+        )
         self.assertEqual(r.id, 3)
-        self.assertEqual(r.hashString, 'a21c45469c565f3fb9595e4e9707e6e9d45abca6')
-        self.assertEqual(r.name, 'ubuntu-12.04.2-alternate-amd64.iso')
+        self.assertEqual(r.hashString, "a21c45469c565f3fb9595e4e9707e6e9d45abca6")
+        self.assertEqual(r.name, "ubuntu-12.04.2-alternate-amd64.iso")
 
     def testRemoveTorrent(self):
-        tc = createClient(test_name='remove')
+        tc = createClient(test_name="remove")
 
-        tc.remove_torrent(['b000', 2, 3])
+        tc.remove_torrent(["b000", 2, 3])
         tc.remove_torrent(1, delete_data=True)
-        tc.remove_torrent('b002', delete_data=False)
+        tc.remove_torrent("b002", delete_data=False)
 
     def testStartTorrent(self):
-        tc = createClient(test_name='start')
+        tc = createClient(test_name="start")
 
-        tc.start_torrent(['abcdef', 20, 30])
+        tc.start_torrent(["abcdef", 20, 30])
         tc.start_torrent(1)
-        tc.start_torrent('a0123456789')
+        tc.start_torrent("a0123456789")
 
     def testStopTorrent(self):
-        tc = createClient(test_name='stop')
+        tc = createClient(test_name="stop")
 
         tc.stop_torrent(2)
-        tc.stop_torrent('bad')
-        tc.stop_torrent(['bad', 'ba5', '30', 20])
+        tc.stop_torrent("bad")
+        tc.stop_torrent(["bad", "ba5", "30", 20])
 
     def testVerifyTorrent(self):
-        tc = createClient(test_name='verify')
+        tc = createClient(test_name="verify")
 
         tc.verify_torrent(10000)
-        tc.verify_torrent('d')
-        tc.verify_torrent(['a', 'b', 'c'])
+        tc.verify_torrent("d")
+        tc.verify_torrent(["a", "b", "c"])
 
     def testGetTorrent(self):
-        tc = createClient(test_name='get_torrent')
+        tc = createClient(test_name="get_torrent")
         torrent = tc.get_torrent(2)
         self.assertEqual(torrent.id, 2)
-        self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-        self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+        self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+        self.assertEqual(torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca")
 
-        tc = createClient(test_name='get_torrent_hash')
-        torrent = tc.get_torrent('ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+        tc = createClient(test_name="get_torrent_hash")
+        torrent = tc.get_torrent("ab8ea951c022d4745a9b06ab8020b952a52b71ca")
         self.assertEqual(torrent.id, 2)
-        self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-        self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+        self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+        self.assertEqual(torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca")
 
     def testGetTorrents(self):
-        tc = createClient(test_name='info')
+        tc = createClient(test_name="info")
         r = tc.get_torrents()
         for torrent in r:
             if torrent.id == 2:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-                self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+                self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+                self.assertEqual(
+                    torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca"
+                )
             elif torrent.id == 3:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-alternate-i386.iso')
-                self.assertEqual(torrent.hashString, 'a33e98826003515e46ef5075fcbf4914b307abe2')
+                self.assertEqual(torrent.name, "ubuntu-10.04-alternate-i386.iso")
+                self.assertEqual(
+                    torrent.hashString, "a33e98826003515e46ef5075fcbf4914b307abe2"
+                )
             else:
                 self.fail("Unknown torrent")
 
     def testGetTorrentsRange(self):
-        tc = createClient(test_name='get_torrents_2to3')
+        tc = createClient(test_name="get_torrents_2to3")
         r = tc.get_torrents([2, 3])
         for torrent in r:
             if torrent.id == 2:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-                self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+                self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+                self.assertEqual(
+                    torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca"
+                )
             elif torrent.id == 3:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-alternate-i386.iso')
-                self.assertEqual(torrent.hashString, 'a33e98826003515e46ef5075fcbf4914b307abe2')
+                self.assertEqual(torrent.name, "ubuntu-10.04-alternate-i386.iso")
+                self.assertEqual(
+                    torrent.hashString, "a33e98826003515e46ef5075fcbf4914b307abe2"
+                )
             else:
                 self.fail("Unknown torrent")
 
-        tc = createClient(test_name='get_torrents_2to3')
+        tc = createClient(test_name="get_torrents_2to3")
         r = tc.get_torrents("2:3")
         for torrent in r:
             if torrent.id == 2:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-                self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+                self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+                self.assertEqual(
+                    torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca"
+                )
             elif torrent.id == 3:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-alternate-i386.iso')
-                self.assertEqual(torrent.hashString, 'a33e98826003515e46ef5075fcbf4914b307abe2')
+                self.assertEqual(torrent.name, "ubuntu-10.04-alternate-i386.iso")
+                self.assertEqual(
+                    torrent.hashString, "a33e98826003515e46ef5075fcbf4914b307abe2"
+                )
             else:
                 self.fail("Unknown torrent")
 
-        tc = createClient(test_name='get_torrents_2to3')
+        tc = createClient(test_name="get_torrents_2to3")
         r = tc.get_torrents("2,3")
         for torrent in r:
             if torrent.id == 2:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-                self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+                self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+                self.assertEqual(
+                    torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca"
+                )
             elif torrent.id == 3:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-alternate-i386.iso')
-                self.assertEqual(torrent.hashString, 'a33e98826003515e46ef5075fcbf4914b307abe2')
+                self.assertEqual(torrent.name, "ubuntu-10.04-alternate-i386.iso")
+                self.assertEqual(
+                    torrent.hashString, "a33e98826003515e46ef5075fcbf4914b307abe2"
+                )
             else:
                 self.fail("Unknown torrent")
 
-        tc = createClient(test_name='get_torrents_2to3')
+        tc = createClient(test_name="get_torrents_2to3")
         r = tc.get_torrents("2 3")
         for torrent in r:
             if torrent.id == 2:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-                self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+                self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+                self.assertEqual(
+                    torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca"
+                )
             elif torrent.id == 3:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-alternate-i386.iso')
-                self.assertEqual(torrent.hashString, 'a33e98826003515e46ef5075fcbf4914b307abe2')
+                self.assertEqual(torrent.name, "ubuntu-10.04-alternate-i386.iso")
+                self.assertEqual(
+                    torrent.hashString, "a33e98826003515e46ef5075fcbf4914b307abe2"
+                )
             else:
                 self.fail("Unknown torrent")
 
     def testGetTorrentsHashes(self):
-        tc = createClient(test_name='get_torrents_hashes')
-        r = tc.get_torrents(["ab8ea951c022d4745a9b06ab8020b952a52b71ca", "a33e98826003515e46ef5075fcbf4914b307abe2"])
+        tc = createClient(test_name="get_torrents_hashes")
+        r = tc.get_torrents(
+            [
+                "ab8ea951c022d4745a9b06ab8020b952a52b71ca",
+                "a33e98826003515e46ef5075fcbf4914b307abe2",
+            ]
+        )
         for torrent in r:
             if torrent.id == 2:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-                self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+                self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+                self.assertEqual(
+                    torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca"
+                )
             elif torrent.id == 3:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-alternate-i386.iso')
-                self.assertEqual(torrent.hashString, 'a33e98826003515e46ef5075fcbf4914b307abe2')
+                self.assertEqual(torrent.name, "ubuntu-10.04-alternate-i386.iso")
+                self.assertEqual(
+                    torrent.hashString, "a33e98826003515e46ef5075fcbf4914b307abe2"
+                )
             else:
                 self.fail("Unknown torrent")
 
-        tc = createClient(test_name='get_torrents_hashes')
-        r = tc.get_torrents("ab8ea951c022d4745a9b06ab8020b952a52b71ca,a33e98826003515e46ef5075fcbf4914b307abe2")
+        tc = createClient(test_name="get_torrents_hashes")
+        r = tc.get_torrents(
+            "ab8ea951c022d4745a9b06ab8020b952a52b71ca,a33e98826003515e46ef5075fcbf4914b307abe2"
+        )
         for torrent in r:
             if torrent.id == 2:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-                self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+                self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+                self.assertEqual(
+                    torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca"
+                )
             elif torrent.id == 3:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-alternate-i386.iso')
-                self.assertEqual(torrent.hashString, 'a33e98826003515e46ef5075fcbf4914b307abe2')
+                self.assertEqual(torrent.name, "ubuntu-10.04-alternate-i386.iso")
+                self.assertEqual(
+                    torrent.hashString, "a33e98826003515e46ef5075fcbf4914b307abe2"
+                )
             else:
                 self.fail("Unknown torrent")
 
-        tc = createClient(test_name='get_torrents_hashes')
-        r = tc.get_torrents("ab8ea951c022d4745a9b06ab8020b952a52b71ca a33e98826003515e46ef5075fcbf4914b307abe2")
+        tc = createClient(test_name="get_torrents_hashes")
+        r = tc.get_torrents(
+            "ab8ea951c022d4745a9b06ab8020b952a52b71ca a33e98826003515e46ef5075fcbf4914b307abe2"
+        )
         for torrent in r:
             if torrent.id == 2:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-server-amd64.iso')
-                self.assertEqual(torrent.hashString, 'ab8ea951c022d4745a9b06ab8020b952a52b71ca')
+                self.assertEqual(torrent.name, "ubuntu-10.04-server-amd64.iso")
+                self.assertEqual(
+                    torrent.hashString, "ab8ea951c022d4745a9b06ab8020b952a52b71ca"
+                )
             elif torrent.id == 3:
-                self.assertEqual(torrent.name, 'ubuntu-10.04-alternate-i386.iso')
-                self.assertEqual(torrent.hashString, 'a33e98826003515e46ef5075fcbf4914b307abe2')
+                self.assertEqual(torrent.name, "ubuntu-10.04-alternate-i386.iso")
+                self.assertEqual(
+                    torrent.hashString, "a33e98826003515e46ef5075fcbf4914b307abe2"
+                )
             else:
                 self.fail("Unknown torrent")
 
     def testParseId(self):
         from transmissionrpc.client import parse_torrent_id
+
         self.assertEqual(parse_torrent_id(None), None)
         self.assertEqual(parse_torrent_id(10), 10)
         self.assertEqual(parse_torrent_id(10.0), 10)
         self.assertEqual(parse_torrent_id(10.5), None)
         self.assertEqual(parse_torrent_id("10"), 10)
         self.assertEqual(parse_torrent_id("A"), "A")
-        self.assertEqual(parse_torrent_id("a21c45469c565f3fb9595e4e9707e6e9d45abca6"), "a21c45469c565f3fb9595e4e9707e6e9d45abca6")
+        self.assertEqual(
+            parse_torrent_id("a21c45469c565f3fb9595e4e9707e6e9d45abca6"),
+            "a21c45469c565f3fb9595e4e9707e6e9d45abca6",
+        )
         self.assertEqual(parse_torrent_id("T"), None)
         self.assertEqual(parse_torrent_id([10]), None)
         self.assertEqual(parse_torrent_id((10, 11)), None)
@@ -342,12 +424,16 @@ def testParseId(self):
 
     def testParseIds(self):
         from transmissionrpc.client import parse_torrent_ids
+
         self.assertEqual(parse_torrent_ids(None), [])
         self.assertEqual(parse_torrent_ids(10), [10])
         self.assertEqual(parse_torrent_ids(10.0), [10])
         self.assertEqual(parse_torrent_ids("10"), [10])
         self.assertEqual(parse_torrent_ids("A"), ["A"])
-        self.assertEqual(parse_torrent_ids("a21c45469c565f3fb9595e4e9707e6e9d45abca6"), ["a21c45469c565f3fb9595e4e9707e6e9d45abca6"])
+        self.assertEqual(
+            parse_torrent_ids("a21c45469c565f3fb9595e4e9707e6e9d45abca6"),
+            ["a21c45469c565f3fb9595e4e9707e6e9d45abca6"],
+        )
         self.assertEqual(parse_torrent_ids(",, "), [])
         self.assertEqual(parse_torrent_ids("1,2,3"), [1, 2, 3])
         self.assertEqual(parse_torrent_ids("1:3"), [1, 2, 3])
diff --git a/test/torrent.py b/test/torrent.py
index dfc77c2..e729d3e 100644
--- a/test/torrent.py
+++ b/test/torrent.py
@@ -24,76 +24,82 @@ def assertPropertyException(self, exception, object, property):
 
     def testConstruction(self):
         self.assertRaises(ValueError, Torrent, None, {})
-        Torrent(None, {'id': 42})
+        Torrent(None, {"id": 42})
 
     def testAttributes(self):
-        torrent = Torrent(None, {'id': 42})
-        self.assertTrue(hasattr(torrent, 'id'))
+        torrent = Torrent(None, {"id": 42})
+        self.assertTrue(hasattr(torrent, "id"))
         self.assertEqual(torrent.id, 42)
-        self.assertPropertyException(KeyError, torrent, 'status')
-        self.assertPropertyException(KeyError, torrent, 'progress')
-        self.assertPropertyException(KeyError, torrent, 'ratio')
-        self.assertPropertyException(KeyError, torrent, 'eta')
-        self.assertPropertyException(KeyError, torrent, 'date_active')
-        self.assertPropertyException(KeyError, torrent, 'date_added')
-        self.assertPropertyException(KeyError, torrent, 'date_started')
-        self.assertPropertyException(KeyError, torrent, 'date_done')
+        self.assertPropertyException(KeyError, torrent, "status")
+        self.assertPropertyException(KeyError, torrent, "progress")
+        self.assertPropertyException(KeyError, torrent, "ratio")
+        self.assertPropertyException(KeyError, torrent, "eta")
+        self.assertPropertyException(KeyError, torrent, "date_active")
+        self.assertPropertyException(KeyError, torrent, "date_added")
+        self.assertPropertyException(KeyError, torrent, "date_started")
+        self.assertPropertyException(KeyError, torrent, "date_done")
 
         self.assertRaises(KeyError, torrent.format_eta)
         self.assertEqual(torrent.files(), {})
 
         data = {
-            'id': 1,
-            'status': 4,
-            'sizeWhenDone': 1000,
-            'leftUntilDone': 500,
-            'uploadedEver': 1000,
-            'downloadedEver': 2000,
-            'uploadRatio': 0.5,
-            'eta': 3600,
-            'activityDate': time.mktime((2008, 12, 11, 11, 15, 30, 0, 0, -1)),
-            'addedDate': time.mktime((2008, 12, 11, 8, 5, 10, 0, 0, -1)),
-            'startDate': time.mktime((2008, 12, 11, 9, 10, 5, 0, 0, -1)),
-            'doneDate': time.mktime((2008, 12, 11, 10, 0, 15, 0, 0, -1)),
+            "id": 1,
+            "status": 4,
+            "sizeWhenDone": 1000,
+            "leftUntilDone": 500,
+            "uploadedEver": 1000,
+            "downloadedEver": 2000,
+            "uploadRatio": 0.5,
+            "eta": 3600,
+            "activityDate": time.mktime((2008, 12, 11, 11, 15, 30, 0, 0, -1)),
+            "addedDate": time.mktime((2008, 12, 11, 8, 5, 10, 0, 0, -1)),
+            "startDate": time.mktime((2008, 12, 11, 9, 10, 5, 0, 0, -1)),
+            "doneDate": time.mktime((2008, 12, 11, 10, 0, 15, 0, 0, -1)),
         }
 
         torrent = Torrent(None, data)
         self.assertEqual(torrent.id, 1)
         self.assertEqual(torrent.leftUntilDone, 500)
-        self.assertEqual(torrent.status, 'downloading')
+        self.assertEqual(torrent.status, "downloading")
         self.assertEqual(torrent.progress, 50.0)
         self.assertEqual(torrent.ratio, 0.5)
         self.assertEqual(torrent.eta, datetime.timedelta(seconds=3600))
-        self.assertEqual(torrent.date_active, datetime.datetime(2008, 12, 11, 11, 15, 30))
+        self.assertEqual(
+            torrent.date_active, datetime.datetime(2008, 12, 11, 11, 15, 30)
+        )
         self.assertEqual(torrent.date_added, datetime.datetime(2008, 12, 11, 8, 5, 10))
-        self.assertEqual(torrent.date_started, datetime.datetime(2008, 12, 11, 9, 10, 5))
+        self.assertEqual(
+            torrent.date_started, datetime.datetime(2008, 12, 11, 9, 10, 5)
+        )
         self.assertEqual(torrent.date_done, datetime.datetime(2008, 12, 11, 10, 0, 15))
 
-        self.assertEqual(torrent.format_eta(), transmissionrpc.utils.format_timedelta(torrent.eta))
+        self.assertEqual(
+            torrent.format_eta(), transmissionrpc.utils.format_timedelta(torrent.eta)
+        )
 
-        torrent = Torrent(None, {'id': 42, 'eta': -1})
-        self.assertPropertyException(ValueError, torrent, 'eta')
+        torrent = Torrent(None, {"id": 42, "eta": -1})
+        self.assertPropertyException(ValueError, torrent, "eta")
 
         data = {
-            'id': 1,
-            'status': 4,
-            'sizeWhenDone': 1000,
-            'leftUntilDone': 500,
-            'uploadedEver': 1000,
-            'downloadedEver': 2000,
-            'uploadRatio': 0.5,
-            'eta': 3600,
-            'activityDate': time.mktime((2008, 12, 11, 11, 15, 30, 0, 0, -1)),
-            'addedDate': time.mktime((2008, 12, 11, 8, 5, 10, 0, 0, -1)),
-            'startDate': time.mktime((2008, 12, 11, 9, 10, 5, 0, 0, -1)),
-            'doneDate': 0,
+            "id": 1,
+            "status": 4,
+            "sizeWhenDone": 1000,
+            "leftUntilDone": 500,
+            "uploadedEver": 1000,
+            "downloadedEver": 2000,
+            "uploadRatio": 0.5,
+            "eta": 3600,
+            "activityDate": time.mktime((2008, 12, 11, 11, 15, 30, 0, 0, -1)),
+            "addedDate": time.mktime((2008, 12, 11, 8, 5, 10, 0, 0, -1)),
+            "startDate": time.mktime((2008, 12, 11, 9, 10, 5, 0, 0, -1)),
+            "doneDate": 0,
         }
 
         torrent = Torrent(None, data)
         self.assertEqual(torrent.date_done, None)
 
     def testUnicode(self):
-        torrent = Torrent(None, {'id': 42, 'name': 'あみ'})
+        torrent = Torrent(None, {"id": 42, "name": "あみ"})
         self.assertEqual(torrent.id, 42)
         repr(torrent)
         str(torrent)
diff --git a/test/utils.py b/test/utils.py
index cf75234..77b9a05 100644
--- a/test/utils.py
+++ b/test/utils.py
@@ -10,14 +10,14 @@
 class utils(unittest.TestCase):
     def testFormatSize(self):
         table = {
-            512: (512, 'B'),
-            1024: (1.0, 'KiB'),
-            1048575: (1023.999, 'KiB'),
-            1048576: (1.0, 'MiB'),
-            1073741824: (1.0, 'GiB'),
-            1099511627776: (1.0, 'TiB'),
-            1125899906842624: (1.0, 'PiB'),
-            1152921504606846976: (1.0, 'EiB'),
+            512: (512, "B"),
+            1024: (1.0, "KiB"),
+            1048575: (1023.999, "KiB"),
+            1048576: (1.0, "MiB"),
+            1073741824: (1.0, "GiB"),
+            1099511627776: (1.0, "TiB"),
+            1125899906842624: (1.0, "PiB"),
+            1152921504606846976: (1.0, "EiB"),
         }
         for size, expected in iter(table.items()):
             result = tu.format_size(size)
@@ -26,14 +26,14 @@ def testFormatSize(self):
 
     def testFormatSpeed(self):
         table = {
-            512: (512, 'B/s'),
-            1024: (1.0, 'KiB/s'),
-            1048575: (1023.999, 'KiB/s'),
-            1048576: (1.0, 'MiB/s'),
-            1073741824: (1.0, 'GiB/s'),
-            1099511627776: (1.0, 'TiB/s'),
-            1125899906842624: (1.0, 'PiB/s'),
-            1152921504606846976: (1.0, 'EiB/s'),
+            512: (512, "B/s"),
+            1024: (1.0, "KiB/s"),
+            1048575: (1023.999, "KiB/s"),
+            1048576: (1.0, "MiB/s"),
+            1073741824: (1.0, "GiB/s"),
+            1099511627776: (1.0, "TiB/s"),
+            1125899906842624: (1.0, "PiB/s"),
+            1152921504606846976: (1.0, "EiB/s"),
         }
         for size, expected in iter(table.items()):
             result = tu.format_speed(size)
@@ -42,51 +42,51 @@ def testFormatSpeed(self):
 
     def testFormatTimedelta(self):
         table = {
-            datetime.timedelta(0, 0): '0 00:00:00',
-            datetime.timedelta(0, 10): '0 00:00:10',
-            datetime.timedelta(0, 60): '0 00:01:00',
-            datetime.timedelta(0, 61): '0 00:01:01',
-            datetime.timedelta(0, 3661): '0 01:01:01',
-            datetime.timedelta(1, 3661): '1 01:01:01',
-            datetime.timedelta(13, 65660): '13 18:14:20',
+            datetime.timedelta(0, 0): "0 00:00:00",
+            datetime.timedelta(0, 10): "0 00:00:10",
+            datetime.timedelta(0, 60): "0 00:01:00",
+            datetime.timedelta(0, 61): "0 00:01:01",
+            datetime.timedelta(0, 3661): "0 01:01:01",
+            datetime.timedelta(1, 3661): "1 01:01:01",
+            datetime.timedelta(13, 65660): "13 18:14:20",
         }
         for delta, expected in iter(table.items()):
             self.assertEqual(tu.format_timedelta(delta), expected)
 
     def testFormatTimestamp(self):
         table = {
-            0: '-',
-            1: '1970-01-01 00:00:01',
-            1129135532: '2005-10-12 16:45:32',
+            0: "-",
+            1: "1970-01-01 00:00:01",
+            1129135532: "2005-10-12 16:45:32",
         }
         for timestamp, expected in iter(table.items()):
             self.assertEqual(tu.format_timestamp(timestamp, utc=True), expected)
 
     def testInetAddress(self):
         table = {
-            ('127.0.0.1:80', 2000): ('127.0.0.1', 80),
-            ('127.0.0.1', 2000): ('127.0.0.1', 2000),
-            (':80', 2000): ('localhost', 80),
-            (':80', 2000, '127.0.0.1'): ('127.0.0.1', 80),
-            ('0.0.0.0:443', 2000): ('0.0.0.0', 443),
-            ('localhost:443', 2000): ('localhost', 443),
+            ("127.0.0.1:80", 2000): ("127.0.0.1", 80),
+            ("127.0.0.1", 2000): ("127.0.0.1", 2000),
+            (":80", 2000): ("localhost", 80),
+            (":80", 2000, "127.0.0.1"): ("127.0.0.1", 80),
+            ("0.0.0.0:443", 2000): ("0.0.0.0", 443),
+            ("localhost:443", 2000): ("localhost", 443),
         }
         for args, expected in iter(table.items()):
             self.assertEqual(tu.inet_address(*args), expected)
 
-        self.assertRaises(tu.INetAddressError, tu.inet_address, '256.256.256.256', 2000)
+        self.assertRaises(tu.INetAddressError, tu.inet_address, "256.256.256.256", 2000)
 
     def testRPCBool(self):
         table = {
             0: 0,
             1: 1,
             1000: 1,
-            'true': 1,
-            'Yes': 1,
-            'truE': 1,
-            'baka': 0,
-            'false': 0,
-            'no': 0,
+            "true": 1,
+            "Yes": 1,
+            "truE": 1,
+            "baka": 0,
+            "false": 0,
+            "no": 0,
             True: 1,
             False: 0,
         }
@@ -99,5 +99,5 @@ def suite():
     return suite
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     unittest.main()