diff --git a/.travis.yml b/.travis.yml
index 2aeb4b579d4a2d707a105ae59eb7f0daf27c0941..d73d91226656d5b30fdf88eea1f765751f7e43c0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,6 @@
 sudo: false
 language: python
 python:
-  - "2.6"
   - "2.7"
   - "3.3"
   - "3.4"
diff --git a/README.rst b/README.rst
index 73cf948ff500f85c54779adde7ccf3bd7c85a4ff..d99a91256bfba49a4149ace3600a09f0274deaf1 100644
--- a/README.rst
+++ b/README.rst
@@ -36,7 +36,7 @@ mwclient
 
 mwclient is a lightweight Python client library to the `MediaWiki API <https://mediawiki.org/wiki/API>`_
 which provides access to most API functionality.
-It works with Python 2.6, 2.7, 3.3 and above, and supports MediaWiki 1.16 and above.
+It works with Python 2.7, 3.3 and above, and supports MediaWiki 1.16 and above.
 For functions not available in the current MediaWiki, a ``MediaWikiVersionError`` is raised.
 
 The current stable `version 0.8.1 <https://github.com/mwclient/mwclient/archive/v0.8.1.zip>`_
@@ -53,7 +53,7 @@ can be installed from GitHub:
 
     $ pip install git+git://github.com/mwclient/mwclient.git
 
-Please see the 
+Please see the
 `release notes <https://github.com/mwclient/mwclient/blob/master/RELEASE-NOTES.md>`_
 for a list of changes.
 
@@ -111,7 +111,7 @@ without their two-letter prefix. Exceptions to this rule:
 * ``categorymembers`` is implemented as ``Category.members``
 * ``deletedrevs`` is ``deletedrevisions``
 * ``usercontribs`` is ``usercontributions``
-* First parameters of ``search`` and ``usercontributions`` are ``search`` and ``user`` 
+* First parameters of ``search`` and ``usercontributions`` are ``search`` and ``user``
   respectively
 
 Properties and generators are implemented as Python generators.
diff --git a/docs/source/index.rst b/docs/source/index.rst
index ec549df7331d3c6b864ed38a74596c6ee8f1c6d4..aa2eb2f0f6e56c278fa8393938f10b919b0a8b5e 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -8,8 +8,7 @@ mwclient: lightweight MediaWiki client
 
 Mwclient is a :ref:`MIT licensed <license>` client library to the `MediaWiki API`_
 that should work well with both Wikimedia wikis and other wikis running
-MediaWiki 1.16 or above. It supports Python 2.6 and above
-(tested with Python 2.6, 2.7, 3.3 and 3.4).
+MediaWiki 1.16 or above. It works with Python 2.7 and 3.3+.
 
 .. _install:
 
diff --git a/docs/source/user/connecting.rst b/docs/source/user/connecting.rst
index 1cd5dce309d2dffb1064cf5959faba93d132fb35..d1a85eb9f7600e4d29accb063f446cb941c68c93 100644
--- a/docs/source/user/connecting.rst
+++ b/docs/source/user/connecting.rst
@@ -38,9 +38,11 @@ If you are connecting to a Wikimedia site, you should follow the
 `Wikimedia User-Agent policy <https://meta.wikimedia.org/wiki/User-Agent_policy>`_
 and identify your tool like so:
 
-    >>> ua = 'MyCoolTool. Run by User:Xyz. Using mwclient/' + mwclient.__ver__
+    >>> ua = 'MyCoolTool/0.2 run by User:Xyz'
     >>> site = mwclient.Site('test.wikipedia.org', clients_useragent=ua)
 
+Mwclient will append `' - MwClient/{version} ({url})'` to the User-Agent string.
+
 .. _auth:
 
 Authenticating
diff --git a/mwclient/client.py b/mwclient/client.py
index ebbb1d05f17a26360e889f8632210c4e856c8c64..4c868098912debd8f53d1f685739340a9ac4b41e 100644
--- a/mwclient/client.py
+++ b/mwclient/client.py
@@ -4,12 +4,7 @@ import logging
 from six import text_type
 import six
 
-try:
-    # Python 2.7+
-    from collections import OrderedDict
-except ImportError:
-    # Python 2.6
-    from ordereddict import OrderedDict
+from collections import OrderedDict
 
 try:
     import json
@@ -94,9 +89,15 @@ class Site(object):
         if pool is None:
             self.connection = requests.Session()
             self.connection.auth = auth
-            self.connection.headers['User-Agent'] = 'MwClient/' + __ver__ + ' (https://github.com/mwclient/mwclient)'
-            if clients_useragent:
-                self.connection.headers['User-Agent'] = clients_useragent + ' - ' + self.connection.headers['User-Agent']
+
+            prefix = '{} - '.format(clients_useragent) if clients_useragent else ''
+            self.connection.headers['User-Agent'] = (
+                '{prefix}MwClient/{ver} ({url})'.format(
+                    prefix=prefix,
+                    ver=__ver__,
+                    url='https://github.com/mwclient/mwclient'
+                )
+            )
         else:
             self.connection = pool
 
@@ -121,7 +122,7 @@ class Site(object):
                     raise errors.OAuthAuthorizationError(e.code, e.info)
 
                 # Private wiki, do init after login
-                if e.args[0] not in (u'unknown_action', u'readapidenied'):
+                if e.args[0] not in {u'unknown_action', u'readapidenied'}:
                     raise
 
     def site_init(self):
@@ -136,33 +137,18 @@ class Site(object):
             return
 
         meta = self.api('query', meta='siteinfo|userinfo',
-                        siprop='general|namespaces', uiprop='groups|rights', retry_on_error=False)
+                        siprop='general|namespaces', uiprop='groups|rights',
+                        retry_on_error=False)
 
         # Extract site info
         self.site = meta['query']['general']
-        self.namespaces = dict(((i['id'], i.get('*', '')) for i in six.itervalues(meta['query']['namespaces'])))
+        self.namespaces = {
+            namespace['id']: namespace.get('*', '')
+            for namespace in six.itervalues(meta['query']['namespaces'])
+        }
         self.writeapi = 'writeapi' in self.site
 
-        # Determine version
-        if self.site['generator'].startswith('MediaWiki '):
-            version = self.site['generator'][10:].split('.')
-
-            def split_num(s):
-                i = 0
-                while i < len(s):
-                    if s[i] < '0' or s[i] > '9':
-                        break
-                    i += 1
-                if s[i:]:
-                    return (int(s[:i]), s[i:], )
-                else:
-                    return (int(s[:i]), )
-            self.version = sum((split_num(s) for s in version), ())
-
-            if len(self.version) < 2:
-                raise errors.MediaWikiVersionError('Unknown MediaWiki %s' % '.'.join(version))
-        else:
-            raise errors.MediaWikiVersionError('Unknown generator %s' % self.site['generator'])
+        self.version = self.version_tuple_from_generator(self.site['generator'])
 
         # Require MediaWiki version >= 1.16
         self.require(1, 16)
@@ -174,9 +160,50 @@ class Site(object):
         self.rights = userinfo.get('rights', [])
         self.initialized = True
 
-    default_namespaces = {0: u'', 1: u'Talk', 2: u'User', 3: u'User talk', 4: u'Project', 5: u'Project talk',
-                          6: u'Image', 7: u'Image talk', 8: u'MediaWiki', 9: u'MediaWiki talk', 10: u'Template', 11: u'Template talk',
-                          12: u'Help', 13: u'Help talk', 14: u'Category', 15: u'Category talk', -1: u'Special', -2: u'Media'}
+    @staticmethod
+    def version_tuple_from_generator(string, prefix='MediaWiki '):
+        """Return a version tuple from a MediaWiki Generator string
+
+        Example: "MediaWiki 1.5.1" → (1, 5, 1)
+
+        :param prefix: the expected prefix of the string
+        """
+        if not string.startswith(prefix):
+            raise errors.MediaWikiVersionError('Unknown generator {}'.format(string))
+
+        version = string[len(prefix):].split('.')
+
+        def split_num(s):
+            """Split the string on the first non-digit character.
+
+            :return: a tuple of the digit part as int and, if
+            available, the rest of the string.
+            """
+            i = 0
+            while i < len(s):
+                if s[i] < '0' or s[i] > '9':
+                    break
+                i += 1
+            if s[i:]:
+                return (int(s[:i]), s[i:], )
+            else:
+                return (int(s[:i]), )
+
+        version_tuple = sum((split_num(s) for s in version), ())
+
+        if len(version_tuple) < 2:
+            raise errors.MediaWikiVersionError('Unknown MediaWiki {}'
+                                               .format('.'.join(version)))
+
+        return version_tuple
+
+    default_namespaces = {
+        0: u'', 1: u'Talk', 2: u'User', 3: u'User talk', 4: u'Project',
+        5: u'Project talk', 6: u'Image', 7: u'Image talk', 8: u'MediaWiki',
+        9: u'MediaWiki talk', 10: u'Template', 11: u'Template talk', 12: u'Help',
+        13: u'Help talk', 14: u'Category', 15: u'Category talk',
+        -1: u'Special', -2: u'Media'
+    }
 
     def __repr__(self):
         return "<Site object '%s%s'>" % (self.host, self.path)
@@ -239,7 +266,8 @@ class Site(object):
         self.hasmsg = 'messages' in userinfo
         self.logged_in = 'anon' not in userinfo
         if 'error' in info:
-            if info['error']['code'] in (u'internal_api_error_DBConnectionError', u'internal_api_error_DBQueryError'):
+            if info['error']['code'] in {u'internal_api_error_DBConnectionError',
+                                         u'internal_api_error_DBQueryError'}:
                 sleeper.sleep()
                 return False
             if '*' in info['error']:
@@ -252,8 +280,8 @@ class Site(object):
     @staticmethod
     def _query_string(*args, **kwargs):
         kwargs.update(args)
-        qs1 = [(k, v) for k, v in six.iteritems(kwargs) if k not in ('wpEditToken', 'token')]
-        qs2 = [(k, v) for k, v in six.iteritems(kwargs) if k in ('wpEditToken', 'token')]
+        qs1 = [(k, v) for k, v in six.iteritems(kwargs) if k not in {'wpEditToken', 'token'}]
+        qs2 = [(k, v) for k, v in six.iteritems(kwargs) if k in {'wpEditToken', 'token'}]
         return OrderedDict(qs1 + qs2)
 
     def raw_call(self, script, data, files=None, retry_on_error=True):
@@ -291,10 +319,12 @@ class Site(object):
             fullurl = '{scheme}://{host}{url}'.format(scheme=scheme, host=host, url=url)
 
             try:
-                stream = self.connection.post(fullurl, data=data, files=files, headers=headers, **self.requests)
+                stream = self.connection.post(fullurl, data=data, files=files,
+                                              headers=headers, **self.requests)
                 if stream.headers.get('x-database-lag'):
                     wait_time = int(stream.headers.get('retry-after'))
-                    log.warning('Database lag exceeds max lag. Waiting for %d seconds', wait_time)
+                    log.warning('Database lag exceeds max lag. '
+                                'Waiting for {} seconds'.format(wait_time))
                     sleeper.sleep(wait_time)
                 elif stream.status_code == 200:
                     return stream.text
@@ -303,7 +333,10 @@ class Site(object):
                 else:
                     if not retry_on_error:
                         stream.raise_for_status()
-                    log.warning('Received %s response: %s. Retrying in a moment.', stream.status_code, stream.text)
+                    log.warning('Received {status} response: {text}. '
+                                'Retrying in a moment.'
+                                .format(status=stream.status_code,
+                                        text=stream.text))
                     sleeper.sleep()
 
             except requests.exceptions.ConnectionError:
@@ -349,8 +382,12 @@ class Site(object):
             if self.version[:2] >= (major, minor):
                 return True
             elif raise_error:
-                raise errors.MediaWikiVersionError('Requires version %s.%s, current version is %s.%s'
-                                                   % ((major, minor) + self.version[:2]))
+                raise errors.MediaWikiVersionError(
+                    'Requires version {required[0]}.{required[1]}, '
+                    'current version is {current[0]}.{current[1]}'
+                    .format(required=(major, minor),
+                            current=(self.version[:2]))
+                )
             else:
                 return False
         else:
@@ -426,7 +463,7 @@ class Site(object):
         if self.version[:2] >= (1, 24):
             # The 'csrf' (cross-site request forgery) token introduced in 1.24 replaces
             # the majority of older tokens, like edittoken and movetoken.
-            if type not in ['watch', 'patrol', 'rollback', 'userrights']:
+            if type not in {'watch', 'patrol', 'rollback', 'userrights'}:
                 type = 'csrf'
 
         if type not in self.tokens:
@@ -543,7 +580,8 @@ class Site(object):
             if self.handle_api_result(info, kwargs=predata, sleeper=sleeper):
                 return info.get('upload', {})
 
-    def parse(self, text=None, title=None, page=None, prop=None, redirects=False, mobileformat=False):
+    def parse(self, text=None, title=None, page=None, prop=None,
+              redirects=False, mobileformat=False):
         kwargs = {}
         if text is not None:
             kwargs['text'] = text
@@ -573,46 +611,59 @@ class Site(object):
         """Retrieve all pages on the wiki as a generator."""
 
         pfx = listing.List.get_prefix('ap', generator)
-        kwargs = dict(listing.List.generate_kwargs(pfx, ('from', start), ('to', end), prefix=prefix,
-                                                   minsize=minsize, maxsize=maxsize, prtype=prtype, prlevel=prlevel,
-                                                   namespace=namespace, filterredir=filterredir, dir=dir,
-                                                   filterlanglinks=filterlanglinks))
-        return listing.List.get_list(generator)(self, 'allpages', 'ap', limit=limit, return_values='title', **kwargs)
+        kwargs = dict(listing.List.generate_kwargs(
+            pfx, ('from', start), ('to', end), prefix=prefix,
+            minsize=minsize, maxsize=maxsize, prtype=prtype, prlevel=prlevel,
+            namespace=namespace, filterredir=filterredir, dir=dir,
+            filterlanglinks=filterlanglinks,
+        ))
+        return listing.List.get_list(generator)(self, 'allpages', 'ap',
+                                                limit=limit, return_values='title',
+                                                **kwargs)
 
     def allimages(self, start=None, prefix=None, minsize=None, maxsize=None, limit=None,
                   dir='ascending', sha1=None, sha1base36=None, generator=True, end=None):
         """Retrieve all images on the wiki as a generator."""
 
         pfx = listing.List.get_prefix('ai', generator)
-        kwargs = dict(listing.List.generate_kwargs(pfx, ('from', start), ('to', end), prefix=prefix,
-                                                   minsize=minsize, maxsize=maxsize,
-                                                   dir=dir, sha1=sha1, sha1base36=sha1base36))
-        return listing.List.get_list(generator)(self, 'allimages', 'ai', limit=limit, return_values='timestamp|url', **kwargs)
+        kwargs = dict(listing.List.generate_kwargs(
+            pfx, ('from', start), ('to', end), prefix=prefix,
+            minsize=minsize, maxsize=maxsize,
+            dir=dir, sha1=sha1, sha1base36=sha1base36,
+        ))
+        return listing.List.get_list(generator)(self, 'allimages', 'ai', limit=limit,
+                                                return_values='timestamp|url',
+                                                **kwargs)
 
     def alllinks(self, start=None, prefix=None, unique=False, prop='title',
                  namespace='0', limit=None, generator=True, end=None):
         """Retrieve a list of all links on the wiki as a generator."""
 
         pfx = listing.List.get_prefix('al', generator)
-        kwargs = dict(listing.List.generate_kwargs(pfx, ('from', start), ('to', end), prefix=prefix,
+        kwargs = dict(listing.List.generate_kwargs(pfx, ('from', start), ('to', end),
+                                                   prefix=prefix,
                                                    prop=prop, namespace=namespace))
         if unique:
             kwargs[pfx + 'unique'] = '1'
-        return listing.List.get_list(generator)(self, 'alllinks', 'al', limit=limit, return_values='title', **kwargs)
+        return listing.List.get_list(generator)(self, 'alllinks', 'al', limit=limit,
+                                                return_values='title', **kwargs)
 
-    def allcategories(self, start=None, prefix=None, dir='ascending', limit=None, generator=True,
-                      end=None):
+    def allcategories(self, start=None, prefix=None, dir='ascending', limit=None,
+                      generator=True, end=None):
         """Retrieve all categories on the wiki as a generator."""
 
         pfx = listing.List.get_prefix('ac', generator)
-        kwargs = dict(listing.List.generate_kwargs(pfx, ('from', start), ('to', end), prefix=prefix, dir=dir))
-        return listing.List.get_list(generator)(self, 'allcategories', 'ac', limit=limit, **kwargs)
+        kwargs = dict(listing.List.generate_kwargs(pfx, ('from', start), ('to', end),
+                                                   prefix=prefix, dir=dir))
+        return listing.List.get_list(generator)(self, 'allcategories', 'ac', limit=limit,
+                                                **kwargs)
 
     def allusers(self, start=None, prefix=None, group=None, prop=None, limit=None,
                  witheditsonly=False, activeusers=False, rights=None, end=None):
         """Retrieve all users on the wiki as a generator."""
 
-        kwargs = dict(listing.List.generate_kwargs('au', ('from', start), ('to', end), prefix=prefix,
+        kwargs = dict(listing.List.generate_kwargs('au', ('from', start), ('to', end),
+                                                   prefix=prefix,
                                                    group=group, prop=prop,
                                                    rights=rights,
                                                    witheditsonly=witheditsonly,
@@ -675,15 +726,18 @@ class Site(object):
                   dir='older', user=None, title=None, limit=None, action=None):
         """Retrieve logevents as a generator."""
         kwargs = dict(listing.List.generate_kwargs('le', prop=prop, type=type, start=start,
-                                                   end=end, dir=dir, user=user, title=title, action=action))
+                                                   end=end, dir=dir, user=user,
+                                                   title=title, action=action))
         return listing.List(self, 'logevents', 'le', limit=limit, **kwargs)
 
-    def checkuserlog(self, user=None, target=None, limit=10, dir='older', start=None, end=None):
+    def checkuserlog(self, user=None, target=None, limit=10, dir='older',
+                     start=None, end=None):
         """Retrieve checkuserlog items as a generator."""
 
         kwargs = dict(listing.List.generate_kwargs('cul', target=target, start=start,
                                                    end=end, dir=dir, user=user))
-        return listing.NestedList('entries', self, 'checkuserlog', 'cul', limit=limit, **kwargs)
+        return listing.NestedList('entries', self, 'checkuserlog', 'cul',
+                                  limit=limit, **kwargs)
 
     # def protectedtitles requires 1.15
     def random(self, namespace, limit=20):
@@ -705,7 +759,8 @@ class Site(object):
         List recent changes to the wiki, à la Special:Recentchanges.
         """
         kwargs = dict(listing.List.generate_kwargs('rc', start=start, end=end, dir=dir,
-                                                   namespace=namespace, prop=prop, show=show, type=type,
+                                                   namespace=namespace, prop=prop,
+                                                   show=show, type=type,
                                                    toponly='1' if toponly else None))
         return listing.List(self, 'recentchanges', 'rc', limit=limit, **kwargs)
 
@@ -774,7 +829,8 @@ class Site(object):
         Returns:
             mwclient.listings.List: Search results iterator
         """
-        kwargs = dict(listing.List.generate_kwargs('sr', search=search, namespace=namespace, what=what))
+        kwargs = dict(listing.List.generate_kwargs('sr', search=search,
+                                                   namespace=namespace, what=what))
         if redirects:
             kwargs['srredirects'] = '1'
         return listing.List(self, 'search', 'sr', limit=limit, **kwargs)
@@ -787,7 +843,8 @@ class Site(object):
         API doc: https://www.mediawiki.org/wiki/API:Usercontribs
         """
         kwargs = dict(listing.List.generate_kwargs('uc', user=user, start=start, end=end,
-                                                   dir=dir, namespace=namespace, prop=prop, show=show))
+                                                   dir=dir, namespace=namespace,
+                                                   prop=prop, show=show))
         return listing.List(self, 'usercontribs', 'uc', limit=limit, **kwargs)
 
     def users(self, users, prop='blockinfo|groups|editcount'):
@@ -808,7 +865,8 @@ class Site(object):
         """
 
         kwargs = dict(listing.List.generate_kwargs('wl', start=start, end=end,
-                                                   namespace=namespace, dir=dir, prop=prop, show=show))
+                                                   namespace=namespace, dir=dir,
+                                                   prop=prop, show=show))
         if allrev:
             kwargs['wlallrev'] = '1'
         return listing.List(self, 'watchlist', 'wl', limit=limit, **kwargs)
diff --git a/mwclient/errors.py b/mwclient/errors.py
index bf5d2cb00127a56e89eda08bb6a6a75f733031ec..3dcc83a6044934789b96691da4f8006dd071e891 100644
--- a/mwclient/errors.py
+++ b/mwclient/errors.py
@@ -19,7 +19,7 @@ class APIError(MwClientError):
     def __init__(self, code, info, kwargs):
         self.code = code
         self.info = info
-        MwClientError.__init__(self, code, info, kwargs)
+        super(APIError, self).__init__(code, info, kwargs)
 
 
 class InsufficientPermission(MwClientError):
@@ -75,7 +75,7 @@ class InvalidResponse(MwClientError):
                        'you used the correct hostname. If you did, the server might ' + \
                        'be wrongly configured or experiencing temporary problems.'
         self.response_text = response_text
-        MwClientError.__init__(self, self.message, response_text)
+        super(InvalidResponse, self).__init__(self.message, response_text)
 
     def __str__(self):
         return self.message
diff --git a/mwclient/ex.py b/mwclient/ex.py
index c0b1eaebcef32f453f06732a584ac08e4805660f..959599c30ffc91a4ff80c206a482cf65362e5a64 100644
--- a/mwclient/ex.py
+++ b/mwclient/ex.py
@@ -47,11 +47,14 @@ class ConfiguredSite(client.Site):
 
         do_login = 'username' in self.config and 'password' in self.config
 
-        client.Site.__init__(self, host=self.config['host'],
-                             path=self.config['path'], ext=self.config.get('ext', '.php'),
-                             do_init=not do_login,
-                             retry_timeout=self.config.get('retry_timeout', 30),
-                             max_retries=self.config.get('max_retries', -1))
+        super(ConfiguredSite, self).__init__(
+            host=self.config['host'],
+            path=self.config['path'],
+            ext=self.config.get('ext', '.php'),
+            do_init=not do_login,
+            retry_timeout=self.config.get('retry_timeout', 30),
+            max_retries=self.config.get('max_retries', -1),
+        )
 
         if do_login:
             self.login(self.config['username'],
diff --git a/mwclient/image.py b/mwclient/image.py
index 83dbfd67ac20d6d4c33118466d30dcb09e1b4ed6..828ff4c71211d4fddb9254729ffd3bf607198e77 100644
--- a/mwclient/image.py
+++ b/mwclient/image.py
@@ -5,7 +5,7 @@ import mwclient.page
 class Image(mwclient.page.Page):
 
     def __init__(self, site, name, info=None):
-        mwclient.page.Page.__init__(self, site, name, info,
+        super(Image, self).__init__(site, name, info,
                                     extra_properties={'imageinfo': (('iiprop', 'timestamp|user|comment|url|size|sha1|metadata|archivename'), )})
         self.imagerepository = self._info.get('imagerepository', '')
         self.imageinfo = self._info.get('imageinfo', ({}, ))[0]
diff --git a/mwclient/listing.py b/mwclient/listing.py
index b47e03f9db3ba4c806c154d6681255504894c34f..2e626e710b90384966d49d0bc09e58087bb72604 100644
--- a/mwclient/listing.py
+++ b/mwclient/listing.py
@@ -7,8 +7,16 @@ import mwclient.image
 
 
 class List(object):
+    """Base class for lazy object iteration
 
-    def __init__(self, site, list_name, prefix, limit=None, return_values=None, max_items=None, *args, **kwargs):
+    This is a class providing lazy iteration.  This means that the
+    content is loaded in chunks as long as the response hints at
+    continuing content.
+    """
+
+    def __init__(self, site, list_name, prefix,
+                 limit=None, return_values=None, max_items=None,
+                 *args, **kwargs):
         # NOTE: Fix limit
         self.site = site
         self.list_name = list_name
@@ -57,14 +65,32 @@ class List(object):
             if self.last:
                 raise StopIteration
             self.load_chunk()
-            return List.__next__(self, full=full)
+            return self.__next__(full=full)
 
-    def next(self, full=False):
+    def next(self, *args, **kwargs):
         """ For Python 2.x support """
-        return self.__next__(full)
+        return self.__next__(*args, **kwargs)
 
     def load_chunk(self):
-        data = self.site.api('query', (self.generator, self.list_name), *[(text_type(k), v) for k, v in six.iteritems(self.args)])
+        """Query a new chunk of data
+
+        If the query is empty, `raise StopIteration`.
+
+        Else, update the iterator accordingly.
+
+        If 'continue' is in the response, it is added to `self.args`
+        (new style continuation, added in MediaWiki 1.21).
+
+        If not, but 'query-continue' is in the response, query its
+        item called `self.list_name` and add this to `self.args` (old
+        style continuation).
+
+        Else, set `self.last` to True.
+        """
+        data = self.site.api(
+            'query', (self.generator, self.list_name),
+            *[(text_type(k), v) for k, v in six.iteritems(self.args)]
+        )
         if not data:
             # Non existent page
             raise StopIteration
@@ -82,6 +108,7 @@ class List(object):
             self.last = True
 
     def set_iter(self, data):
+        """Set `self._iter` to the API response `data`."""
         if self.result_member not in data['query']:
             self._iter = iter(six.moves.range(0))
         elif type(data['query'][self.result_member]) is list:
@@ -101,22 +128,16 @@ class List(object):
 
     @staticmethod
     def get_prefix(prefix, generator=False):
-        if generator:
-            return 'g' + prefix
-        else:
-            return prefix
+        return ('g' if generator else '') + prefix
 
     @staticmethod
     def get_list(generator=False):
-        if generator:
-            return GeneratorList
-        else:
-            return List
+        return GeneratorList if generator else List
 
 
 class NestedList(List):
     def __init__(self, nested_param, *args, **kwargs):
-        List.__init__(self, *args, **kwargs)
+        super(NestedList, self).__init__(*args, **kwargs)
         self.nested_param = nested_param
 
     def set_iter(self, data):
@@ -126,7 +147,8 @@ class NestedList(List):
 class GeneratorList(List):
 
     def __init__(self, site, list_name, prefix, *args, **kwargs):
-        List.__init__(self, site, list_name, prefix, *args, **kwargs)
+        super(GeneratorList, self).__init__(site, list_name, prefix,
+                                            *args, **kwargs)
 
         self.args['g' + self.prefix + 'limit'] = self.args[self.prefix + 'limit']
         del self.args[self.prefix + 'limit']
@@ -140,22 +162,18 @@ class GeneratorList(List):
         self.page_class = mwclient.page.Page
 
     def __next__(self):
-        info = List.__next__(self, full=True)
+        info = super(GeneratorList, self).__next__(full=True)
         if info['ns'] == 14:
             return Category(self.site, u'', info)
         if info['ns'] == 6:
             return mwclient.image.Image(self.site, u'', info)
         return mwclient.page.Page(self.site, u'', info)
 
-    def next(self):
-        """ For Python 2.x support """
-        return self.__next__()
-
     def load_chunk(self):
         # Put this here so that the constructor does not fail
         # on uninitialized sites
         self.args['iiprop'] = 'timestamp|user|comment|url|size|sha1|metadata|archivename'
-        return List.load_chunk(self)
+        return super(GeneratorList, self).load_chunk()
 
 
 class Category(mwclient.page.Page, GeneratorList):
@@ -192,30 +210,54 @@ class PageList(GeneratorList):
         if end:
             kwargs['gapto'] = end
 
-        GeneratorList.__init__(self, site, 'allpages', 'ap',
-                               gapnamespace=text_type(namespace), gapfilterredir=redirects, **kwargs)
+        super(PageList, self).__init__(site, 'allpages', 'ap',
+                                       gapnamespace=text_type(namespace),
+                                       gapfilterredir=redirects,
+                                       **kwargs)
 
     def __getitem__(self, name):
         return self.get(name, None)
 
     def get(self, name, info=()):
-        if self.namespace == 14:
-            return Category(self.site, self.site.namespaces[14] + ':' + name, info)
-        elif self.namespace == 6:
-            return mwclient.image.Image(self.site, self.site.namespaces[6] + ':' + name, info)
-        elif self.namespace != 0:
-            return mwclient.page.Page(self.site, self.site.namespaces[self.namespace] + ':' + name, info)
+        """Return the page of name `name` as an object.
+
+        If self.namespace is not zero, use {namespace}:{name} as the
+        page name, otherwise guess the namespace from the name using
+        `self.guess_namespace`.
+
+        :rtype: One of Category, Image, or Page (default), according
+        to the namespace.
+        """
+        if self.namespace != 0:
+            full_page_name = u"{namespace}:{name}".format(
+                namespace=self.site.namespaces[self.namespace],
+                name=name,
+            )
+            namespace = self.namespace
         else:
-            # Guessing page class
-            if type(name) is not int:
+            full_page_name = name
+            try:
                 namespace = self.guess_namespace(name)
-                if namespace == 14:
-                    return Category(self.site, name, info)
-                elif namespace == 6:
-                    return mwclient.image.Image(self.site, name, info)
-            return mwclient.page.Page(self.site, name, info)
+            except AttributeError:
+                # raised when `namespace` doesn't have a `startswith` attribute
+                namespace = 0
+
+        cls = {
+            14: Category,
+            6: mwclient.image.Image,
+        }.get(namespace, mwclient.page.Page)
+
+        return cls(self.site, full_page_name, info)
 
     def guess_namespace(self, name):
+        """Guess the namespace from name
+
+        If name starts with any of the site's namespaces' names or
+        default_namespaces, use that.  Else, return zero.
+
+        :param name: The pagename as a string (having `.startswith`)
+        :return: the id of the guessed namespace or zero.
+        """
         for ns in self.site.namespaces:
             if ns == 0:
                 continue
@@ -230,7 +272,9 @@ class PageList(GeneratorList):
 class PageProperty(List):
 
     def __init__(self, page, prop, prefix, *args, **kwargs):
-        List.__init__(self, page.site, prop, prefix, titles=page.name, *args, **kwargs)
+        super(PageProperty, self).__init__(page.site, prop, prefix,
+                                           titles=page.name,
+                                           *args, **kwargs)
         self.page = page
         self.generator = 'prop'
 
@@ -245,7 +289,9 @@ class PageProperty(List):
 class PagePropertyGenerator(GeneratorList):
 
     def __init__(self, page, prop, prefix, *args, **kwargs):
-        GeneratorList.__init__(self, page.site, prop, prefix, titles=page.name, *args, **kwargs)
+        super(PagePropertyGenerator, self).__init__(page.site, prop, prefix,
+                                                    titles=page.name,
+                                                    *args, **kwargs)
         self.page = page
 
 
@@ -254,4 +300,4 @@ class RevisionsIterator(PageProperty):
     def load_chunk(self):
         if 'rvstartid' in self.args and 'rvstart' in self.args:
             del self.args['rvstart']
-        return PageProperty.load_chunk(self)
+        return super(RevisionsIterator, self).load_chunk()
diff --git a/mwclient/page.py b/mwclient/page.py
index 7c0e601b452696eb54cca74698488ab462fca19b..dba423b7290385d3349011ae70762dd68ea4e50a 100644
--- a/mwclient/page.py
+++ b/mwclient/page.py
@@ -47,7 +47,11 @@ class Page(object):
         self.revision = info.get('lastrevid', 0)
         self.exists = 'missing' not in info
         self.length = info.get('length')
-        self.protection = dict([(i['type'], (i['level'], i['expiry'])) for i in info.get('protection', ()) if i])
+        self.protection = {
+            i['type']: (i['level'], i['expiry'])
+            for i in info.get('protection', ())
+            if i
+        }
         self.redirect = 'redirect' in info
         self.pageid = info.get('pageid', None)
         self.contentmodel = info.get('contentmodel', None)
@@ -117,14 +121,17 @@ class Page(object):
 
     def get_expanded(self):
         """Deprecated. Use page.text(expandtemplates=True) instead"""
-        warnings.warn("page.get_expanded() was deprecated in mwclient 0.7.0 and will be removed in 0.8.0, use page.text(expandtemplates=True) instead.",
+        warnings.warn("page.get_expanded() was deprecated in mwclient 0.7.0 "
+                      "and will be removed in 0.8.0, "
+                      "use page.text(expandtemplates=True) instead.",
                       category=DeprecationWarning, stacklevel=2)
 
         return self.text(expandtemplates=True)
 
     def edit(self, *args, **kwargs):
         """Deprecated. Use page.text() instead"""
-        warnings.warn("page.edit() was deprecated in mwclient 0.7.0 and will be removed in 0.8.0, please use page.text() instead.",
+        warnings.warn("page.edit() was deprecated in mwclient 0.7.0 "
+                      "and will be removed in 0.8.0, please use page.text() instead.",
                       category=DeprecationWarning, stacklevel=2)
         return self.text(*args, **kwargs)
 
@@ -154,7 +161,8 @@ class Page(object):
         if cache and key in self._textcache:
             return self._textcache[key]
 
-        revs = self.revisions(prop='content|timestamp', limit=1, section=section, expandtemplates=expandtemplates)
+        revs = self.revisions(prop='content|timestamp', limit=1, section=section,
+                              expandtemplates=expandtemplates)
         try:
             rev = next(revs)
             text = rev['*']
@@ -175,10 +183,13 @@ class Page(object):
         """
         if not self.site.logged_in and self.site.force_login:
             # Should we really check for this?
-            raise mwclient.errors.LoginError(self.site, 'By default, mwclient protects you from ' +
-                                             'accidentally editing without being logged in. If you ' +
-                                             'actually want to edit without logging in, you can set ' +
-                                             'force_login on the Site object to False.')
+            raise mwclient.errors.LoginError(
+                self.site,
+                'By default, mwclient protects you from accidentally editing '
+                'without being logged in. '
+                'If you actually want to edit without logging in, '
+                'you can set force_login on the Site object to False.'
+            )
         if self.site.blocked:
             raise mwclient.errors.UserBlocked(self.site.blocked)
         if not self.can('edit'):
@@ -234,8 +245,9 @@ class Page(object):
     def handle_edit_error(self, e, summary):
         if e.code == 'editconflict':
             raise mwclient.errors.EditError(self, summary, e.info)
-        elif e.code in ('protectedtitle', 'cantcreate', 'cantcreate-anon', 'noimageredirect-anon',
-                        'noimageredirect', 'noedit-anon', 'noedit'):
+        elif e.code in {'protectedtitle', 'cantcreate', 'cantcreate-anon',
+                        'noimageredirect-anon', 'noimageredirect', 'noedit-anon',
+                        'noedit'}:
             raise mwclient.errors.ProtectedPageError(self, e.code, e.info)
         else:
             raise
@@ -300,7 +312,8 @@ class Page(object):
     # def watch: requires 1.14
 
     # Properties
-    def backlinks(self, namespace=None, filterredir='all', redirect=False, limit=None, generator=True):
+    def backlinks(self, namespace=None, filterredir='all', redirect=False,
+                  limit=None, generator=True):
         """
         List pages that link to the current page, similar to Special:Whatlinkshere.
 
@@ -308,12 +321,17 @@ class Page(object):
 
         """
         prefix = mwclient.listing.List.get_prefix('bl', generator)
-        kwargs = dict(mwclient.listing.List.generate_kwargs(prefix, namespace=namespace, filterredir=filterredir))
+        kwargs = dict(mwclient.listing.List.generate_kwargs(
+            prefix, namespace=namespace, filterredir=filterredir,
+        ))
         if redirect:
             kwargs['%sredirect' % prefix] = '1'
         kwargs[prefix + 'title'] = self.name
 
-        return mwclient.listing.List.get_list(generator)(self.site, 'backlinks', 'bl', limit=limit, return_values='title', **kwargs)
+        return mwclient.listing.List.get_list(generator)(
+            self.site, 'backlinks', 'bl', limit=limit, return_values='title',
+            **kwargs
+        )
 
     def categories(self, generator=True):
         """
@@ -326,7 +344,8 @@ class Page(object):
             return mwclient.listing.PagePropertyGenerator(self, 'categories', 'cl')
         else:
             # TODO: return sortkey if wanted
-            return mwclient.listing.PageProperty(self, 'categories', 'cl', return_values='title')
+            return mwclient.listing.PageProperty(self, 'categories', 'cl',
+                                                 return_values='title')
 
     def embeddedin(self, namespace=None, filterredir='all', limit=None, generator=True):
         """
@@ -345,10 +364,14 @@ class Page(object):
             mwclient.listings.List: Page iterator
         """
         prefix = mwclient.listing.List.get_prefix('ei', generator)
-        kwargs = dict(mwclient.listing.List.generate_kwargs(prefix, namespace=namespace, filterredir=filterredir))
+        kwargs = dict(mwclient.listing.List.generate_kwargs(prefix, namespace=namespace,
+                                                            filterredir=filterredir))
         kwargs[prefix + 'title'] = self.name
 
-        return mwclient.listing.List.get_list(generator)(self.site, 'embeddedin', 'ei', limit=limit, return_values='title', **kwargs)
+        return mwclient.listing.List.get_list(generator)(
+            self.site, 'embeddedin', 'ei', limit=limit, return_values='title',
+            **kwargs
+        )
 
     def extlinks(self):
         """
@@ -369,7 +392,8 @@ class Page(object):
         if generator:
             return mwclient.listing.PagePropertyGenerator(self, 'images', '')
         else:
-            return mwclient.listing.PageProperty(self, 'images', '', return_values='title')
+            return mwclient.listing.PageProperty(self, 'images', '',
+                                                 return_values='title')
 
     def iwlinks(self):
         """
@@ -378,7 +402,8 @@ class Page(object):
         API doc: https://www.mediawiki.org/wiki/API:Iwlinks
 
         """
-        return mwclient.listing.PageProperty(self, 'iwlinks', 'iw', return_values=('prefix', '*'))
+        return mwclient.listing.PageProperty(self, 'iwlinks', 'iw',
+                                             return_values=('prefix', '*'))
 
     def langlinks(self, **kwargs):
         """
@@ -387,7 +412,9 @@ class Page(object):
         API doc: https://www.mediawiki.org/wiki/API:Langlinks
 
         """
-        return mwclient.listing.PageProperty(self, 'langlinks', 'll', return_values=('lang', '*'), **kwargs)
+        return mwclient.listing.PageProperty(self, 'langlinks', 'll',
+                                             return_values=('lang', '*'),
+                                             **kwargs)
 
     def links(self, namespace=None, generator=True, redirects=False):
         """
@@ -404,11 +431,13 @@ class Page(object):
         if generator:
             return mwclient.listing.PagePropertyGenerator(self, 'links', 'pl', **kwargs)
         else:
-            return mwclient.listing.PageProperty(self, 'links', 'pl', return_values='title', **kwargs)
+            return mwclient.listing.PageProperty(self, 'links', 'pl', return_values='title',
+                                                 **kwargs)
 
     def revisions(self, startid=None, endid=None, start=None, end=None,
                   dir='older', user=None, excludeuser=None, limit=50,
-                  prop='ids|timestamp|flags|comment|user', expandtemplates=False, section=None,
+                  prop='ids|timestamp|flags|comment|user',
+                  expandtemplates=False, section=None,
                   diffto=None):
         """
         List revisions of the current page.
@@ -445,7 +474,8 @@ class Page(object):
         if section is not None:
             kwargs['rvsection'] = section
 
-        return mwclient.listing.RevisionsIterator(self, 'revisions', 'rv', limit=limit, **kwargs)
+        return mwclient.listing.RevisionsIterator(self, 'revisions', 'rv', limit=limit,
+                                                  **kwargs)
 
     def templates(self, namespace=None, generator=True):
         """
@@ -457,6 +487,8 @@ class Page(object):
         prefix = mwclient.listing.List.get_prefix('tl', generator)
         kwargs = dict(mwclient.listing.List.generate_kwargs(prefix, namespace=namespace))
         if generator:
-            return mwclient.listing.PagePropertyGenerator(self, 'templates', prefix, **kwargs)
+            return mwclient.listing.PagePropertyGenerator(self, 'templates', prefix,
+                                                          **kwargs)
         else:
-            return mwclient.listing.PageProperty(self, 'templates', prefix, return_values='title', **kwargs)
+            return mwclient.listing.PageProperty(self, 'templates', prefix,
+                                                 return_values='title', **kwargs)
diff --git a/setup.py b/setup.py
index 4f5da5b77bdd7e13b207fdcf4b7bab2499912880..66fd3958c1a4ed4a948a2499021b3b1f1696b796 100644
--- a/setup.py
+++ b/setup.py
@@ -44,7 +44,6 @@ setup(name='mwclient',
       long_description=README,
       classifiers=[
           'Programming Language :: Python',
-          'Programming Language :: Python :: 2.6',
           'Programming Language :: Python :: 2.7',
           'Programming Language :: Python :: 3.3',
           'Programming Language :: Python :: 3.4',
diff --git a/tox.ini b/tox.ini
index d1ce86c6a687d8a2fc3762b3f1786249ebbdd29a..ba8f673edc6f21641ddf50d309b166783f5b438c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,8 +1,13 @@
 [tox]
-envlist = py26,py27,py34
+envlist = py27,py34,py35
 [testenv]
 deps=pytest
     pytest-pep8
     responses
     mock
 commands=py.test -v --pep8 mwclient tests
+
+[flake8]
+max-line-length=90
+[pep8]
+max-line-length=90