Hello community,

here is the log from the commit of package python3-CherryPy for 
openSUSE:Factory checked in at 2016-05-25 21:29:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-CherryPy (Old)
 and      /work/SRC/openSUSE:Factory/.python3-CherryPy.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-CherryPy"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-CherryPy/python3-CherryPy.changes        
2016-03-16 10:36:00.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.python3-CherryPy.new/python3-CherryPy.changes   
2016-05-25 21:29:06.000000000 +0200
@@ -1,0 +2,51 @@
+Wed May 25 03:21:55 UTC 2016 - [email protected]
+
+- specfile:
+  * requrie setuptools
+  * no more README file in tar-ball, remove from spec
+
+- update to version 5.4.0:
+  * "cherrypy.test.webtest.WebCase" now honors a 'WEBTEST_INTERACTIVE'
+    environment variable to disable interactive tests (still enabled
+    by default). Set to '0' or 'false' or 'False' to disable
+    interactive tests.
+  * #1408: Fix AttributeError when listiterator was accessed using the
+     "next" attribute.
+  * #748: Removed "cherrypy.lib.sessions.PostgresqlSession".
+  * #1432: Fix errors with redirects to Unicode URLs.
+
+- changes from version 5.3.0:
+  * #1202: Add support for specifying a certificate authority when
+     serving SSL using the built-in SSL support.
+  * Use ssl.create_default_context when available.
+  * #1392: Catch platform-specific socket errors on OS X.
+  * #1386: Fix parsing of URIs containing "://" in the path part.
+
+- changes from version 5.2.0:
+  * #1410: Moved hosting to Github (`cherrypy/cherrypy
+     <https://github.com/cherrypy/cherrypy>`_.
+
+- changes from version 5.1.0:
+  * Bugfix issue #1315 for "test_HTTP11_pipelining" test in Python 3.5
+  * Bugfix issue #1382 regarding the keyword arguments support for
+    Python 3 on the config file.
+  * Bugfix issue #1406 for "test_2_KeyboardInterrupt" test in Python
+    3.5.  by monkey patching the HTTPRequest given a bug on CPython
+    that is affecting the testsuite
+    (https://bugs.python.org/issue23377).
+  * Add additional parameter "raise_subcls" to the tests helpers
+    `openURL` and "CPWebCase.getPage" to have finer control on which
+    exceptions can be raised.
+  * Add support for direct keywords on the calls (e.g. "foo=bar") on
+    the config file under Python 3.
+  * Add additional validation to determine if the process is running
+    as a daemon on "cherrypy.process.plugins.SignalHandler" to allow
+    the execution of the testsuite under CI tools.
+
+-------------------------------------------------------------------
+Sun May  8 06:57:00 UTC 2016 - [email protected]
+
+- specfile:
+  * updated source url to files.pythonhosted.org
+
+-------------------------------------------------------------------

Old:
----
  CherryPy-5.1.0.tar.gz

New:
----
  CherryPy-5.4.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-CherryPy.spec ++++++
--- /var/tmp/diff_new_pack.J13PZg/_old  2016-05-25 21:29:07.000000000 +0200
+++ /var/tmp/diff_new_pack.J13PZg/_new  2016-05-25 21:29:07.000000000 +0200
@@ -17,15 +17,16 @@
 
 
 Name:           python3-CherryPy
-Version:        5.1.0
+Version:        5.4.0
 Release:        0
 Url:            http://www.cherrypy.org
 Summary:        Object-Oriented HTTP framework
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
-Source:         
https://pypi.python.org/packages/source/C/CherryPy/CherryPy-%{version}.tar.gz
+Source:         
https://files.pythonhosted.org/packages/source/C/CherryPy/CherryPy-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildRequires:  python3-devel
+BuildRequires:  python3-setuptools
 BuildArch:      noarch
 
 %description
@@ -48,14 +49,13 @@
 python3 setup.py build
 
 %install
-sed -i 's|\r||' README.txt # Fix wrong EOL encoding
 find . -name sessiondemo.py -type f -exec chmod 0755 {} \; # Fix 
non-executable bit rpmlint warning
 python3 setup.py install --prefix=%{_prefix} --root=%{buildroot}
 mv %{buildroot}%{_bindir}/cherryd 
%{buildroot}%{_bindir}/cherryd-python%{py3_ver}
 
 %files
 %defattr(-,root,root,-)
-%doc README.txt cherrypy/LICENSE.txt
+%doc cherrypy/LICENSE.txt
 %{_bindir}/cherryd-python%{py3_ver}
 %{python3_sitelib}/cherrypy/
 %{python3_sitelib}/CherryPy-%{version}-py%{py3_ver}.egg-info

++++++ CherryPy-5.1.0.tar.gz -> CherryPy-5.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/CherryPy.egg-info/PKG-INFO 
new/CherryPy-5.4.0/CherryPy.egg-info/PKG-INFO
--- old/CherryPy-5.1.0/CherryPy.egg-info/PKG-INFO       2016-03-10 
15:15:36.000000000 +0100
+++ new/CherryPy-5.4.0/CherryPy.egg-info/PKG-INFO       2016-05-11 
02:36:55.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: CherryPy
-Version: 5.1.0
+Version: 5.4.0
 Summary: Object-Oriented HTTP framework
 Home-page: http://www.cherrypy.org
 Author: CherryPy Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/CherryPy.egg-info/SOURCES.txt 
new/CherryPy-5.4.0/CherryPy.egg-info/SOURCES.txt
--- old/CherryPy-5.1.0/CherryPy.egg-info/SOURCES.txt    2016-03-10 
15:15:37.000000000 +0100
+++ new/CherryPy-5.4.0/CherryPy.egg-info/SOURCES.txt    2016-05-11 
02:36:55.000000000 +0200
@@ -1,5 +1,4 @@
 MANIFEST.in
-README.txt
 setup.cfg
 setup.py
 CherryPy.egg-info/PKG-INFO
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/PKG-INFO new/CherryPy-5.4.0/PKG-INFO
--- old/CherryPy-5.1.0/PKG-INFO 2016-03-10 15:15:37.000000000 +0100
+++ new/CherryPy-5.4.0/PKG-INFO 2016-05-11 02:36:55.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: CherryPy
-Version: 5.1.0
+Version: 5.4.0
 Summary: Object-Oriented HTTP framework
 Home-page: http://www.cherrypy.org
 Author: CherryPy Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/README.txt 
new/CherryPy-5.4.0/README.txt
--- old/CherryPy-5.1.0/README.txt       2016-02-04 14:15:56.000000000 +0100
+++ new/CherryPy-5.4.0/README.txt       1970-01-01 01:00:00.000000000 +0100
@@ -1,16 +0,0 @@
-* To install, change to the directory where setup.py is located and type
-  (Python 2.6 or later needed):
-
-    python setup.py install
-
-* To learn how to use it, look at the examples under cherrypy/tutorial/
-  or go to http://www.cherrypy.org for more info.
-
-* To run the regression tests, just go to the cherrypy/test/ directory
-  and type:
-
-    nosetests -s ./
-
-  Or to run individual tests type:
-
-    nosetests -s test_foo.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/LICENSE.txt 
new/CherryPy-5.4.0/cherrypy/LICENSE.txt
--- old/CherryPy-5.1.0/cherrypy/LICENSE.txt     2016-02-04 14:15:56.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/LICENSE.txt     2016-05-11 02:35:35.000000000 
+0200
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2015, CherryPy Team ([email protected])
+Copyright (c) 2004-2016, CherryPy Team ([email protected])
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without 
modification, 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/__init__.py 
new/CherryPy-5.4.0/cherrypy/__init__.py
--- old/CherryPy-5.1.0/cherrypy/__init__.py     2016-03-10 15:15:31.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/__init__.py     2016-05-11 02:35:35.000000000 
+0200
@@ -56,7 +56,10 @@
 These API's are described in the `CherryPy specification 
<https://bitbucket.org/cherrypy/cherrypy/wiki/CherryPySpec>`_.
 """
 
-__version__ = "5.1.0"
+try:
+    import pkg_resources
+except ImportError:
+    pass
 
 from cherrypy._cpcompat import urljoin as _urljoin, urlencode as _urlencode
 from cherrypy._cpcompat import basestring, unicodestr
@@ -88,6 +91,12 @@
     engine = process.bus
 
 
+try:
+    __version__ = pkg_resources.require('cherrypy')[0].version
+except Exception:
+    __version__ = 'unknown'
+
+
 # Timeout monitor. We add two channels to the engine
 # to which cherrypy.Application will publish.
 engine.listeners['before_request'] = set()
@@ -318,7 +327,7 @@
         """Log the given message to the app.log or global log as appropriate.
         """
         # Do NOT use try/except here. See
-        # https://bitbucket.org/cherrypy/cherrypy/issue/945
+        # https://github.com/cherrypy/cherrypy/issues/945
         if hasattr(request, 'app') and hasattr(request.app, 'log'):
             log = request.app.log
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/_cpdispatch.py 
new/CherryPy-5.4.0/cherrypy/_cpdispatch.py
--- old/CherryPy-5.1.0/cherrypy/_cpdispatch.py  2016-02-04 14:15:56.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/_cpdispatch.py  2016-05-11 02:35:35.000000000 
+0200
@@ -422,7 +422,7 @@
                     object_trail.insert(
                         i + 1, ["default", defhandler, conf, segleft])
                     request.config = set_conf()
-                    # See https://bitbucket.org/cherrypy/cherrypy/issue/613
+                    # See https://github.com/cherrypy/cherrypy/issues/613
                     request.is_index = path.endswith("/")
                     return defhandler, fullpath[fullpath_len - segleft:-1]
 
@@ -675,7 +675,7 @@
         result = next_dispatcher(path_info)
 
         # Touch up staticdir config. See
-        # https://bitbucket.org/cherrypy/cherrypy/issue/614.
+        # https://github.com/cherrypy/cherrypy/issues/614.
         section = request.config.get('tools.staticdir.section')
         if section:
             section = section[len(prefix):]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/_cperror.py 
new/CherryPy-5.4.0/cherrypy/_cperror.py
--- old/CherryPy-5.1.0/cherrypy/_cperror.py     2015-03-11 03:34:58.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/_cperror.py     2016-05-11 02:35:35.000000000 
+0200
@@ -253,7 +253,7 @@
             response.headers['Content-Type'] = "text/html;charset=utf-8"
             # "The ... URI SHOULD be given by the Location field
             # in the response."
-            response.headers['Location'] = self.urls[0]
+            response.headers['Location'] = ntob(self.urls[0], 'utf-8')
 
             # "Unless the request method was HEAD, the entity of the response
             # SHOULD contain a short hypertext note with a hyperlink to the
@@ -293,7 +293,7 @@
         elif status == 305:
             # Use Proxy.
             # self.urls[0] should be the URI of the proxy.
-            response.headers['Location'] = self.urls[0]
+            response.headers['Location'] = ntob(self.urls[0], 'utf-8')
             response.body = None
             # Previous code may have set C-L, so we have to reset it.
             response.headers.pop('Content-Length', None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/_cpreqbody.py 
new/CherryPy-5.4.0/cherrypy/_cpreqbody.py
--- old/CherryPy-5.1.0/cherrypy/_cpreqbody.py   2014-07-17 22:26:20.000000000 
+0200
+++ new/CherryPy-5.4.0/cherrypy/_cpreqbody.py   2016-05-11 02:35:35.000000000 
+0200
@@ -940,7 +940,7 @@
 
     # Don't parse the request body at all if the client didn't provide
     # a Content-Type header. See
-    # https://bitbucket.org/cherrypy/cherrypy/issue/790
+    # https://github.com/cherrypy/cherrypy/issues/790
     default_content_type = ''
     """This defines a default ``Content-Type`` to use if no Content-Type header
     is given. The empty string is used for RequestBody, which results in the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/_cptools.py 
new/CherryPy-5.4.0/cherrypy/_cptools.py
--- old/CherryPy-5.1.0/cherrypy/_cptools.py     2016-02-04 14:15:56.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/_cptools.py     2016-05-11 02:35:35.000000000 
+0200
@@ -271,7 +271,7 @@
         body. This is off by default for safety reasons; for example,
         a large upload would block the session, denying an AJAX
         progress meter
-        (`issue <https://bitbucket.org/cherrypy/cherrypy/issue/630>`_).
+        (`issue <https://github.com/cherrypy/cherrypy/issues/630>`_).
 
         When 'explicit' (or any other value), you need to call
         cherrypy.session.acquire_lock() yourself before using
@@ -376,7 +376,7 @@
             body = subhandler(*(vpath + rpcparams), **params)
 
         else:
-            # https://bitbucket.org/cherrypy/cherrypy/issue/533
+            # https://github.com/cherrypy/cherrypy/issues/533
             # if a method is not found, an xmlrpclib.Fault should be returned
             # raising an exception here will do that; see
             # cherrypy.lib.xmlrpcutil.on_error
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/_cpwsgi.py 
new/CherryPy-5.4.0/cherrypy/_cpwsgi.py
--- old/CherryPy-5.1.0/cherrypy/_cpwsgi.py      2016-02-04 14:15:56.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/_cpwsgi.py      2016-05-11 02:35:35.000000000 
+0200
@@ -164,12 +164,12 @@
         self.started_response = True
         return self
 
-    if py3k:
-        def __next__(self):
-            return self.trap(next, self.iter_response)
-    else:
-        def next(self):
-            return self.trap(self.iter_response.next)
+    def __next__(self):
+        return self.trap(next, self.iter_response)
+
+    # todo: https://pythonhosted.org/six/#six.Iterator
+    if not py3k:
+        next = __next__
 
     def close(self):
         if hasattr(self.response, 'close'):
@@ -269,12 +269,12 @@
     def __iter__(self):
         return self
 
-    if py3k:
-        def __next__(self):
-            return next(self.iter_response)
-    else:
-        def next(self):
-            return self.iter_response.next()
+    def __next__(self):
+        return next(self.iter_response)
+
+    # todo: https://pythonhosted.org/six/#six.Iterator
+    if not py3k:
+        next = __next__
 
     def close(self):
         """Close and de-reference the current request and response. (Core)"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/lib/caching.py 
new/CherryPy-5.4.0/cherrypy/lib/caching.py
--- old/CherryPy-5.1.0/cherrypy/lib/caching.py  2014-06-27 22:32:38.000000000 
+0200
+++ new/CherryPy-5.4.0/cherrypy/lib/caching.py  2016-05-11 02:35:35.000000000 
+0200
@@ -353,7 +353,7 @@
             return False
 
         # Copy the response headers. See
-        # https://bitbucket.org/cherrypy/cherrypy/issue/721.
+        # https://github.com/cherrypy/cherrypy/issues/721.
         response.headers = rh = httputil.HeaderMap()
         for k in h:
             dict.__setitem__(rh, k, dict.__getitem__(h, k))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/lib/httputil.py 
new/CherryPy-5.4.0/cherrypy/lib/httputil.py
--- old/CherryPy-5.1.0/cherrypy/lib/httputil.py 2016-02-04 14:15:56.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/lib/httputil.py 2016-05-11 02:35:35.000000000 
+0200
@@ -13,7 +13,7 @@
 from cherrypy._cpcompat import reversed, sorted, unicodestr, unquote_qs
 response_codes = BaseHTTPRequestHandler.responses.copy()
 
-# From https://bitbucket.org/cherrypy/cherrypy/issue/361
+# From https://github.com/cherrypy/cherrypy/issues/361
 response_codes[500] = ('Internal Server Error',
                        'The server encountered an unexpected condition '
                        'which prevented it from fulfilling the request.')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/lib/sessions.py 
new/CherryPy-5.4.0/cherrypy/lib/sessions.py
--- old/CherryPy-5.1.0/cherrypy/lib/sessions.py 2016-02-04 14:15:56.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/lib/sessions.py 2016-05-11 02:35:35.000000000 
+0200
@@ -94,7 +94,6 @@
 import os
 import time
 import threading
-import types
 
 import cherrypy
 from cherrypy._cpcompat import copyitems, pickle, random20, unicodestr
@@ -182,7 +181,7 @@
                     cherrypy.log('Expired or malicious session %r; '
                                  'making a new one' % id, 'TOOLS.SESSIONS')
                 # Expired or malicious session. Make a new one.
-                # See https://bitbucket.org/cherrypy/cherrypy/issue/709.
+                # See https://github.com/cherrypy/cherrypy/issues/709.
                 self.id = None
                 self.missing = True
                 self._regenerate()
@@ -591,93 +590,6 @@
                         and not fname.endswith(self.LOCK_SUFFIX))])
 
 
-class PostgresqlSession(Session):
-
-    """ Implementation of the PostgreSQL backend for sessions. It assumes
-        a table like this::
-
-            create table session (
-                id varchar(40),
-                data text,
-                expiration_time timestamp
-            )
-
-    You must provide your own get_db function.
-    """
-
-    pickle_protocol = pickle.HIGHEST_PROTOCOL
-
-    def __init__(self, id=None, **kwargs):
-        Session.__init__(self, id, **kwargs)
-        self.cursor = self.db.cursor()
-
-    def setup(cls, **kwargs):
-        """Set up the storage system for Postgres-based sessions.
-
-        This should only be called once per process; this will be done
-        automatically when using sessions.init (as the built-in Tool does).
-        """
-        for k, v in kwargs.items():
-            setattr(cls, k, v)
-
-        self.db = self.get_db()
-    setup = classmethod(setup)
-
-    def __del__(self):
-        if self.cursor:
-            self.cursor.close()
-        self.db.commit()
-
-    def _exists(self):
-        # Select session data from table
-        self.cursor.execute('select data, expiration_time from session '
-                            'where id=%s', (self.id,))
-        rows = self.cursor.fetchall()
-        return bool(rows)
-
-    def _load(self):
-        # Select session data from table
-        self.cursor.execute('select data, expiration_time from session '
-                            'where id=%s', (self.id,))
-        rows = self.cursor.fetchall()
-        if not rows:
-            return None
-
-        pickled_data, expiration_time = rows[0]
-        data = pickle.loads(pickled_data)
-        return data, expiration_time
-
-    def _save(self, expiration_time):
-        pickled_data = pickle.dumps(self._data, self.pickle_protocol)
-        self.cursor.execute('update session set data = %s, '
-                            'expiration_time = %s where id = %s',
-                            (pickled_data, expiration_time, self.id))
-
-    def _delete(self):
-        self.cursor.execute('delete from session where id=%s', (self.id,))
-
-    def acquire_lock(self):
-        """Acquire an exclusive lock on the currently-loaded session data."""
-        # We use the "for update" clause to lock the row
-        self.locked = True
-        self.cursor.execute('select id from session where id=%s for update',
-                            (self.id,))
-        if self.debug:
-            cherrypy.log('Lock acquired.', 'TOOLS.SESSIONS')
-
-    def release_lock(self):
-        """Release the lock on the currently-loaded session data."""
-        # We just close the cursor and that will remove the lock
-        #   introduced by the "for update" clause
-        self.cursor.close()
-        self.locked = False
-
-    def clean_up(self):
-        """Clean up expired sessions."""
-        self.cursor.execute('delete from session where expiration_time < %s',
-                            (self.now(),))
-
-
 class MemcachedSession(Session):
 
     # The most popular memcached client for Python isn't thread-safe.
@@ -807,7 +719,7 @@
     """Initialize session object (using cookies).
 
     storage_type
-        One of 'ram', 'file', 'postgresql', 'memcached'. This will be
+        One of 'ram', 'file', memcached'. This will be
         used to look up the corresponding class in cherrypy.lib.sessions
         globals. For example, 'file' will use the FileSession class.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/process/wspbus.py 
new/CherryPy-5.4.0/cherrypy/process/wspbus.py
--- old/CherryPy-5.1.0/cherrypy/process/wspbus.py       2016-02-04 
14:15:56.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/process/wspbus.py       2016-05-11 
02:35:35.000000000 +0200
@@ -85,7 +85,7 @@
 
     def __init__(self, *args, **kwargs):
         # Don't use 'super' here; Exceptions are old-style in Py2.4
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/959
+        # See https://github.com/cherrypy/cherrypy/issues/959
         Exception.__init__(self, *args, **kwargs)
         self._exceptions = list()
 
@@ -317,10 +317,10 @@
             raise
 
         # Waiting for ALL child threads to finish is necessary on OS X.
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/581.
+        # See https://github.com/cherrypy/cherrypy/issues/581.
         # It's also good to let them all shut down before allowing
         # the main thread to call atexit handlers.
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/751.
+        # See https://github.com/cherrypy/cherrypy/issues/751.
         self.log("Waiting for child threads to terminate...")
         for t in threading.enumerate():
             # Validate the we're not trying to join the MainThread
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/helper.py 
new/CherryPy-5.4.0/cherrypy/test/helper.py
--- old/CherryPy-5.1.0/cherrypy/test/helper.py  2016-03-10 15:02:16.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/test/helper.py  2016-05-11 02:35:35.000000000 
+0200
@@ -320,9 +320,14 @@
     do_gc_test = False
 
     def test_gc(self):
-        if self.do_gc_test:
-            self.getPage("/gc/stats")
+        if not self.do_gc_test:
+            return
+
+        self.getPage("/gc/stats")
+        try:
             self.assertBody("Statistics:")
+        except Exception:
+            "Failures occur intermittently. See #1420"
 
     def prefix(self):
         return self.script_name.rstrip("/")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_config_server.py 
new/CherryPy-5.4.0/cherrypy/test/test_config_server.py
--- old/CherryPy-5.1.0/cherrypy/test/test_config_server.py      2014-06-27 
22:32:38.000000000 +0200
+++ new/CherryPy-5.4.0/cherrypy/test/test_config_server.py      2016-05-11 
02:35:35.000000000 +0200
@@ -93,7 +93,7 @@
             self.getPage("/", headers=[('From', "x" * 500)])
             self.assertStatus(413)
 
-        # Test for https://bitbucket.org/cherrypy/cherrypy/issue/421
+        # Test for https://github.com/cherrypy/cherrypy/issues/421
         # (Incorrect border condition in readline of SizeCheckWrapper).
         # This hangs in rev 891 and earlier.
         lines256 = "x" * 248
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_conn.py 
new/CherryPy-5.4.0/cherrypy/test/test_conn.py
--- old/CherryPy-5.1.0/cherrypy/test/test_conn.py       2016-03-10 
15:02:16.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/test/test_conn.py       2016-05-11 
02:35:35.000000000 +0200
@@ -205,7 +205,7 @@
                     self.assertRaises(NotConnected, self.getPage, "/")
 
                 # Try HEAD. See
-                # https://bitbucket.org/cherrypy/cherrypy/issue/864.
+                # https://github.com/cherrypy/cherrypy/issues/864.
                 self.getPage("/stream", method='HEAD')
                 self.assertStatus('200 OK')
                 self.assertBody('')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_core.py 
new/CherryPy-5.4.0/cherrypy/test/test_core.py
--- old/CherryPy-5.1.0/cherrypy/test/test_core.py       2016-02-06 
13:37:35.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/test/test_core.py       2016-05-11 
02:35:35.000000000 +0200
@@ -6,7 +6,7 @@
 import types
 
 import cherrypy
-from cherrypy._cpcompat import IncompleteRead, itervalues, ntob
+from cherrypy._cpcompat import IncompleteRead, itervalues, ntob, ntou
 from cherrypy import _cptools, tools
 from cherrypy.lib import httputil, static
 from cherrypy.test._test_decorators import ExposeExamples
@@ -147,6 +147,10 @@
             def url_with_quote(self):
                 raise cherrypy.HTTPRedirect("/some\"url/that'we/want")
 
+            def url_with_unicode(self):
+                raise cherrypy.HTTPRedirect(ntou("\u0442\u0435\u0441\u0442",
+                                                 'escape'))
+
         def login_redir():
             if not getattr(cherrypy.request, "login", None):
                 raise cherrypy.InternalRedirect("/internalredirect/login")
@@ -403,7 +407,7 @@
         self.assertStatus(('302 Found', '303 See Other'))
 
         # check injection protection
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/1003
+        # See https://github.com/cherrypy/cherrypy/issues/1003
         self.getPage(
             "/redirect/custom?"
             "code=303&url=/foobar/%0d%0aSet-Cookie:%20somecookie=someval")
@@ -431,6 +435,12 @@
         self.assertStatus(303)
         assertValidXHTML()
 
+        # check redirect to url containing unicode characters.
+        self.getPage("/redirect/url_with_unicode")
+        self.assertStatus(303)
+        loc = self.assertHeader('Location')
+        assert loc.endswith("\xd1\x82\xd0\xb5\xd1\x81\xd1\x82")
+
     def test_InternalRedirect(self):
         # InternalRedirect
         self.getPage("/internalredirect/")
@@ -551,7 +561,7 @@
     def skip_if_bad_cookies(self):
         """
         cookies module fails to reject invalid cookies
-        https://bitbucket.org/cherrypy/cherrypy/issues/1405
+        https://github.com/cherrypy/cherrypy/issues/1405
         """
         cookies = sys.modules.get('http.cookies')
         _is_legal_key = getattr(cookies, '_is_legal_key', lambda x: False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_encoding.py 
new/CherryPy-5.4.0/cherrypy/test/test_encoding.py
--- old/CherryPy-5.1.0/cherrypy/test/test_encoding.py   2016-02-04 
14:15:56.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/test/test_encoding.py   2016-05-11 
02:35:35.000000000 +0200
@@ -3,7 +3,7 @@
 import cherrypy
 from cherrypy._cpcompat import BytesIO, IncompleteRead, ntob, ntou
 
-europoundUnicode = ntou('\x80\xa3')
+europoundUnicode = ntou(r'\x00\xa3')
 sing = ntou("\u6bdb\u6cfd\u4e1c: Sing, Little Birdie?", 'escape')
 sing8 = sing.encode('utf-8')
 sing16 = sing.encode('utf-16')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_http.py 
new/CherryPy-5.4.0/cherrypy/test/test_http.py
--- old/CherryPy-5.1.0/cherrypy/test/test_http.py       2016-02-04 
14:15:56.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/test/test_http.py       2016-05-11 
02:35:35.000000000 +0200
@@ -113,7 +113,10 @@
             c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
         else:
             c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
-        with patch.object(c, '_set_content_length'):
+        if hasattr(c, '_set_content_length'): # python 2.6 doesn't have it
+            with patch.object(c, '_set_content_length'):
+                c.request("POST", "/")
+        else:
             c.request("POST", "/")
         response = c.getresponse()
         self.body = response.fp.read()
@@ -147,7 +150,7 @@
     def test_post_filename_with_commas(self):
         '''Testing that we can handle filenames with commas. This was
         reported as a bug in:
-           https://bitbucket.org/cherrypy/cherrypy/issue/1146/'''
+           https://github.com/cherrypy/cherrypy/issues/1146/'''
         # We'll upload a bunch of files with differing names.
         for fname in ['boop.csv', 'foo, bar.csv', 'bar, xxxx.csv', 
'file"name.csv']:
             files = [('myfile', fname, 'yunyeenyunyue')]
@@ -197,7 +200,7 @@
         c = self.make_connection()
         c.putrequest('GET', '/')
         c.putheader('Content-Type', 'text/plain')
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/941
+        # See https://github.com/cherrypy/cherrypy/issues/941
         c._output(ntob('Re, 1.2.3.4#015#012'))
         c.endheaders()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_iterator.py 
new/CherryPy-5.4.0/cherrypy/test/test_iterator.py
--- old/CherryPy-5.1.0/cherrypy/test/test_iterator.py   2014-06-27 
22:32:38.000000000 +0200
+++ new/CherryPy-5.4.0/cherrypy/test/test_iterator.py   2016-05-11 
02:35:35.000000000 +0200
@@ -4,7 +4,7 @@
 class IteratorBase(object):
 
     created = 0
-    datachunk = u'butternut squash' * 256
+    datachunk = 'butternut squash' * 256
 
     @classmethod
     def incr(cls):
@@ -95,6 +95,12 @@
         cherrypy.tree.mount(Root())
 
     def test_iterator(self):
+        try:
+            self._test_iterator()
+        except Exception:
+            "Test fails intermittently. See #1419"
+
+    def _test_iterator(self):
         if cherrypy.server.protocol_version != "HTTP/1.1":
             return self.skip()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_mime.py 
new/CherryPy-5.4.0/cherrypy/test/test_mime.py
--- old/CherryPy-5.1.0/cherrypy/test/test_mime.py       2014-06-27 
22:32:38.000000000 +0200
+++ new/CherryPy-5.4.0/cherrypy/test/test_mime.py       2016-05-11 
02:35:35.000000000 +0200
@@ -74,7 +74,7 @@
             '--X',
             # Test a param with more than one value.
             # See
-            # https://bitbucket.org/cherrypy/cherrypy/issue/1028
+            # https://github.com/cherrypy/cherrypy/issues/1028
             'Content-Disposition: form-data; name="baz"',
             '',
             '111',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_objectmapping.py 
new/CherryPy-5.4.0/cherrypy/test/test_objectmapping.py
--- old/CherryPy-5.1.0/cherrypy/test/test_objectmapping.py      2016-02-04 
14:15:56.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/test/test_objectmapping.py      2016-05-11 
02:35:35.000000000 +0200
@@ -281,7 +281,7 @@
 
         # Make sure /foobar maps to Root.foobar and not to the app
         # mounted at /foo. See
-        # https://bitbucket.org/cherrypy/cherrypy/issue/573
+        # https://github.com/cherrypy/cherrypy/issues/573
         self.getPage("/foobar")
         self.assertBody("bar")
 
@@ -332,7 +332,7 @@
         self.assertBody("default for dir1, param is:('dir2', '5', '3', 'sir')")
 
         # test that extra positional args raises an 404 Not Found
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/733.
+        # See https://github.com/cherrypy/cherrypy/issues/733.
         self.getPage("/dir1/dir2/script_name/extra/stuff")
         self.assertStatus(404)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_proxy.py 
new/CherryPy-5.4.0/cherrypy/test/test_proxy.py
--- old/CherryPy-5.1.0/cherrypy/test/test_proxy.py      2014-06-27 
22:32:38.000000000 +0200
+++ new/CherryPy-5.4.0/cherrypy/test/test_proxy.py      2016-05-11 
02:35:35.000000000 +0200
@@ -131,7 +131,7 @@
             self.assertBody(expected)
 
         # Test trailing slash (see
-        # https://bitbucket.org/cherrypy/cherrypy/issue/562).
+        # https://github.com/cherrypy/cherrypy/issues/562).
         self.getPage("/xhost/", headers=[('X-Host', 'www.example.test')])
         self.assertHeader('Location', "%s://www.example.test/xhost"
                           % self.scheme)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_request_obj.py 
new/CherryPy-5.4.0/cherrypy/test/test_request_obj.py
--- old/CherryPy-5.1.0/cherrypy/test/test_request_obj.py        2016-02-04 
14:15:56.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/test/test_request_obj.py        2016-05-11 
02:35:35.000000000 +0200
@@ -184,7 +184,7 @@
                 return cherrypy.request.headers[headername]
 
             def doubledheaders(self):
-                # From https://bitbucket.org/cherrypy/cherrypy/issue/165:
+                # From https://github.com/cherrypy/cherrypy/issues/165:
                 # "header field names should not be case sensitive sayes the
                 # rfc. if i set a headerfield in complete lowercase i end up
                 # with two header fields, one in lowercase, the other in
@@ -643,7 +643,7 @@
                         "en;q=0.7")
 
         # Test malformed header parsing. See
-        # https://bitbucket.org/cherrypy/cherrypy/issue/763.
+        # https://github.com/cherrypy/cherrypy/issues/763.
         self.getPage("/headerelements/get_elements?headername=Content-Type",
                      # Note the illegal trailing ";"
                      headers=[('Content-Type', 'text/html; charset=utf-8;')])
@@ -652,7 +652,7 @@
 
     def test_repeated_headers(self):
         # Test that two request headers are collapsed into one.
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/542.
+        # See https://github.com/cherrypy/cherrypy/issues/542.
         self.getPage("/headers/Accept-Charset",
                      headers=[("Accept-Charset", "iso-8859-5"),
                               ("Accept-Charset", "unicode-1-1;q=0.8")])
@@ -738,7 +738,7 @@
         self.assertBody(b)
 
         # Request a PUT method with a file body but no Content-Type.
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/790.
+        # See https://github.com/cherrypy/cherrypy/issues/790.
         b = ntob("one thing on top of another")
         self.persistent = True
         try:
@@ -757,7 +757,7 @@
             self.persistent = False
 
         # Request a PUT method with no body whatsoever (not an empty one).
-        # See https://bitbucket.org/cherrypy/cherrypy/issue/650.
+        # See https://github.com/cherrypy/cherrypy/issues/650.
         # Provide a C-T or webtest will provide one (and a C-L) for us.
         h = [("Content-Type", "text/plain")]
         self.getPage("/method/reachable", headers=h, method="PUT")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_static.py 
new/CherryPy-5.4.0/cherrypy/test/test_static.py
--- old/CherryPy-5.1.0/cherrypy/test/test_static.py     2016-02-04 
14:15:56.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/test/test_static.py     2016-05-11 
02:35:35.000000000 +0200
@@ -11,7 +11,7 @@
 # The file size needs to be big enough such that half the size of it
 # won't be socket-buffered (or server-buffered) all in one go. See
 # test_file_stream.
-BIGFILE_SIZE = 1024 * 1024 * 4
+BIGFILE_SIZE = 1024 * 1024 * 20
 
 import cherrypy
 from cherrypy.lib import static
@@ -279,7 +279,9 @@
             #
             # At the time of writing, we seem to have encountered
             # buffer sizes bigger than 512K, so we've increased
-            # BIGFILE_SIZE to 4MB.
+            # BIGFILE_SIZE to 4MB and in 2016 to 20MB.
+            # This test is going to keep failing according to the
+            # improvements in hardware and OS buffers.
             if tell_position >= BIGFILE_SIZE:
                 if read_so_far < (BIGFILE_SIZE / 2):
                     self.fail(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/CherryPy-5.1.0/cherrypy/test/test_wsgi_unix_socket.py 
new/CherryPy-5.4.0/cherrypy/test/test_wsgi_unix_socket.py
--- old/CherryPy-5.1.0/cherrypy/test/test_wsgi_unix_socket.py   2016-02-08 
04:00:22.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/test/test_wsgi_unix_socket.py   2016-05-11 
02:35:35.000000000 +0200
@@ -8,12 +8,13 @@
 from cherrypy.test import helper
 from cherrypy._cpcompat import HTTPConnection
 
+def usocket_path():
+    fd, path = tempfile.mkstemp('cp_test.sock')
+    os.close(fd)
+    os.remove(path)
+    return path
 
-USOCKET_PATH = os.path.join(
-    tempfile.gettempdir(),
-    'cp_test.sock'
-)
-
+USOCKET_PATH = usocket_path()
 
 class USocketHTTPConnection(HTTPConnection):
     """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/test_xmlrpc.py 
new/CherryPy-5.4.0/cherrypy/test/test_xmlrpc.py
--- old/CherryPy-5.1.0/cherrypy/test/test_xmlrpc.py     2014-06-27 
22:32:38.000000000 +0200
+++ new/CherryPy-5.4.0/cherrypy/test/test_xmlrpc.py     2016-05-11 
02:35:35.000000000 +0200
@@ -163,7 +163,7 @@
         else:
             self.fail("Expected xmlrpclib.Fault")
 
-        # https://bitbucket.org/cherrypy/cherrypy/issue/533
+        # https://github.com/cherrypy/cherrypy/issues/533
         # if a method is not found, an xmlrpclib.Fault should be raised
         try:
             proxy.non_method()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/test/webtest.py 
new/CherryPy-5.4.0/cherrypy/test/webtest.py
--- old/CherryPy-5.1.0/cherrypy/test/webtest.py 2016-03-10 15:02:16.000000000 
+0100
+++ new/CherryPy-5.4.0/cherrypy/test/webtest.py 2016-05-11 02:35:35.000000000 
+0200
@@ -23,6 +23,8 @@
 import time
 import traceback
 import types
+import os
+import json
 
 from unittest import *
 from unittest import _TextTestResult
@@ -171,6 +173,19 @@
         return ch
 
 
+# from jaraco.properties
+class NonDataProperty(object):
+    def __init__(self, fget):
+        assert fget is not None, "fget cannot be none"
+        assert callable(fget), "fget must be callable"
+        self.fget = fget
+
+    def __get__(self, obj, objtype=None):
+        if obj is None:
+            return self
+        return self.fget(obj)
+
+
 class WebCase(TestCase):
     HOST = "127.0.0.1"
     PORT = 8000
@@ -270,7 +285,16 @@
             raise ServerError()
         return result
 
-    interactive = True
+    @NonDataProperty
+    def interactive(self):
+        """
+        Load interactivity setting from environment, where
+        the value can be numeric or a string like true or
+        False or 1 or 0.
+        """
+        env_str = os.environ.get('WEBTEST_INTERACTIVE', 'True')
+        return bool(json.loads(env_str.lower()))
+
     console_height = 30
 
     def _handlewebError(self, msg):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/wsgiserver/ssl_builtin.py 
new/CherryPy-5.4.0/cherrypy/wsgiserver/ssl_builtin.py
--- old/CherryPy-5.1.0/cherrypy/wsgiserver/ssl_builtin.py       2014-06-27 
22:32:38.000000000 +0200
+++ new/CherryPy-5.4.0/cherrypy/wsgiserver/ssl_builtin.py       2016-05-11 
02:35:35.000000000 +0200
@@ -33,6 +33,14 @@
 
     private_key = None
     """The filename of the server's private key file."""
+    
+    certificate_chain = None
+    """The filename of the certificate chain file."""
+    
+    """The ssl.SSLContext that will be used to wrap sockets where available
+    (on Python > 2.7.9 / 3.3)
+    """
+    context = None
 
     def __init__(self, certificate, private_key, certificate_chain=None):
         if ssl is None:
@@ -40,6 +48,12 @@
         self.certificate = certificate
         self.private_key = private_key
         self.certificate_chain = certificate_chain
+        if hasattr(ssl, 'create_default_context'):
+            self.context = ssl.create_default_context(
+                purpose=ssl.Purpose.CLIENT_AUTH,
+                cafile=certificate_chain
+            )
+            self.context.load_cert_chain(certificate, private_key)
 
     def bind(self, sock):
         """Wrap and return the given socket."""
@@ -48,10 +62,15 @@
     def wrap(self, sock):
         """Wrap and return the given socket, plus WSGI environ entries."""
         try:
-            s = ssl.wrap_socket(sock, do_handshake_on_connect=True,
-                                server_side=True, certfile=self.certificate,
-                                keyfile=self.private_key,
-                                ssl_version=ssl.PROTOCOL_SSLv23)
+            if self.context is not None:
+                s = self.context.wrap_socket(sock,do_handshake_on_connect=True,
+                                             server_side=True)
+            else:
+                s = ssl.wrap_socket(sock, do_handshake_on_connect=True,
+                                    server_side=True, 
certfile=self.certificate,
+                                    keyfile=self.private_key,
+                                    ssl_version=ssl.PROTOCOL_SSLv23,
+                                    ca_certs=self.certificate_chain)
         except ssl.SSLError:
             e = sys.exc_info()[1]
             if e.errno == ssl.SSL_ERROR_EOF:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/wsgiserver/wsgiserver2.py 
new/CherryPy-5.4.0/cherrypy/wsgiserver/wsgiserver2.py
--- old/CherryPy-5.1.0/cherrypy/wsgiserver/wsgiserver2.py       2016-03-10 
15:15:31.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/wsgiserver/wsgiserver2.py       2016-05-11 
02:35:35.000000000 +0200
@@ -92,6 +92,7 @@
 import traceback as traceback_
 import operator
 from urllib import unquote
+from urlparse import urlparse
 import warnings
 import errno
 import logging
@@ -102,6 +103,10 @@
     # Python 2.6
     import io
 
+try:
+    import pkg_resources
+except ImportError:
+    pass
 
 if 'win' in sys.platform and hasattr(socket, "AF_INET6"):
     if not hasattr(socket, 'IPPROTO_IPV6'):
@@ -113,6 +118,12 @@
 DEFAULT_BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE
 
 
+try:
+    cp_version = pkg_resources.require('cherrypy')[0].version
+except Exception:
+    cp_version = 'unknown'
+
+
 class FauxSocket(object):
 
     """Faux socket with the minimal interface required by pypy"""
@@ -191,6 +202,8 @@
 )
 socket_errors_to_ignore.append("timed out")
 socket_errors_to_ignore.append("The read operation timed out")
+if sys.platform == 'darwin':
+    socket_errors_to_ignore.append(plat_specific_errors("EPROTOTYPE"))
 
 socket_errors_nonblocking = plat_specific_errors(
     'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK')
@@ -297,7 +310,7 @@
             self.bytes_read += len(data)
             self._check_length()
             res.append(data)
-            # See https://bitbucket.org/cherrypy/cherrypy/issue/421
+            # See https://github.com/cherrypy/cherrypy/issues/421
             if len(data) < 256 or data[-1:] == LF:
                 return EMPTY.join(res)
 
@@ -797,7 +810,7 @@
         if self.inheaders.get("Expect", "") == "100-continue":
             # Don't use simple_response here, because it emits headers
             # we don't want. See
-            # https://bitbucket.org/cherrypy/cherrypy/issue/951
+            # https://github.com/cherrypy/cherrypy/issues/951
             msg = self.server.protocol + " 100 Continue\r\n\r\n"
             try:
                 self.conn.wfile.sendall(msg)
@@ -830,15 +843,12 @@
         if uri == ASTERISK:
             return None, None, uri
 
-        i = uri.find('://')
-        if i > 0 and QUESTION_MARK not in uri[:i]:
+        scheme, authority, path, params, query, fragment = urlparse(uri)
+        if scheme and QUESTION_MARK not in scheme:
             # An absoluteURI.
             # If there's a scheme (and it must be http or https), then:
             # http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query
             # ]]
-            scheme, remainder = uri[:i].lower(), uri[i + 3:]
-            authority, path = remainder.split(FORWARD_SLASH, 1)
-            path = FORWARD_SLASH + path
             return scheme, authority, path
 
         if uri.startswith(FORWARD_SLASH):
@@ -1363,7 +1373,7 @@
                 # Don't error if we're between requests; only error
                 # if 1) no request has been started at all, or 2) we're
                 # in the middle of a request.
-                # See https://bitbucket.org/cherrypy/cherrypy/issue/853
+                # See https://github.com/cherrypy/cherrypy/issues/853
                 if (not request_seen) or (req and req.started_request):
                     # Don't bother writing the 408 if the response
                     # has already started being written.
@@ -1656,7 +1666,7 @@
                 except (AssertionError,
                         # Ignore repeated Ctrl-C.
                         # See
-                        # https://bitbucket.org/cherrypy/cherrypy/issue/691.
+                        # https://github.com/cherrypy/cherrypy/issues/691.
                         KeyboardInterrupt):
                     pass
 
@@ -1756,7 +1766,7 @@
     timeout = 10
     """The timeout in seconds for accepted connections (default 10)."""
 
-    version = "CherryPy/5.1.0"
+    version = "CherryPy/" + cp_version
     """A version string for the HTTPServer."""
 
     software = None
@@ -1981,7 +1991,7 @@
 
         # If listening on the IPV6 any address ('::' = IN6ADDR_ANY),
         # activate dual-stack. See
-        # https://bitbucket.org/cherrypy/cherrypy/issue/871.
+        # https://github.com/cherrypy/cherrypy/issues/871.
         if (hasattr(socket, 'AF_INET6') and family == socket.AF_INET6
                 and self.bind_addr[0] in ('::', '::0', '::0.0.0.0')):
             try:
@@ -2075,15 +2085,15 @@
                 # the call, and I *think* I'm reading it right that Python
                 # will then go ahead and poll for and handle the signal
                 # elsewhere. See
-                # https://bitbucket.org/cherrypy/cherrypy/issue/707.
+                # https://github.com/cherrypy/cherrypy/issues/707.
                 return
             if x.args[0] in socket_errors_nonblocking:
                 # Just try again. See
-                # https://bitbucket.org/cherrypy/cherrypy/issue/479.
+                # https://github.com/cherrypy/cherrypy/issues/479.
                 return
             if x.args[0] in socket_errors_to_ignore:
                 # Our socket was closed.
-                # See https://bitbucket.org/cherrypy/cherrypy/issue/686.
+                # See https://github.com/cherrypy/cherrypy/issues/686.
                 return
             raise
 
@@ -2116,7 +2126,7 @@
                     if x.args[0] not in socket_errors_to_ignore:
                         # Changed to use error code and not message
                         # See
-                        # https://bitbucket.org/cherrypy/cherrypy/issue/860.
+                        # https://github.com/cherrypy/cherrypy/issues/860.
                         raise
                 else:
                     # Note that we're explicitly NOT using AI_PASSIVE,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/cherrypy/wsgiserver/wsgiserver3.py 
new/CherryPy-5.4.0/cherrypy/wsgiserver/wsgiserver3.py
--- old/CherryPy-5.1.0/cherrypy/wsgiserver/wsgiserver3.py       2016-03-10 
15:15:31.000000000 +0100
+++ new/CherryPy-5.4.0/cherrypy/wsgiserver/wsgiserver3.py       2016-05-11 
02:35:35.000000000 +0200
@@ -92,6 +92,8 @@
 import traceback as traceback_
 import errno
 import logging
+from urllib.parse import urlparse
+
 try:
     # prefer slower Python-based io module
     import _pyio as io
@@ -99,6 +101,10 @@
     # Python 2.6
     import io
 
+try:
+    import pkg_resources
+except ImportError:
+    pass
 
 if 'win' in sys.platform and hasattr(socket, "AF_INET6"):
     if not hasattr(socket, 'IPPROTO_IPV6'):
@@ -110,6 +116,12 @@
 DEFAULT_BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE
 
 
+try:
+    cp_version = pkg_resources.require('cherrypy')[0].version
+except Exception:
+    cp_version = 'unknown'
+
+
 if sys.version_info >= (3, 0):
     bytestr = bytes
     unicodestr = str
@@ -176,6 +188,8 @@
 )
 socket_errors_to_ignore.append("timed out")
 socket_errors_to_ignore.append("The read operation timed out")
+if sys.platform == 'darwin':
+    socket_errors_to_ignore.append(plat_specific_errors("EPROTOTYPE"))
 
 socket_errors_nonblocking = plat_specific_errors(
     'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK')
@@ -282,7 +296,7 @@
             self.bytes_read += len(data)
             self._check_length()
             res.append(data)
-            # See https://bitbucket.org/cherrypy/cherrypy/issue/421
+            # See https://github.com/cherrypy/cherrypy/issues/421
             if len(data) < 256 or data[-1:] == LF:
                 return EMPTY.join(res)
 
@@ -785,7 +799,7 @@
         if self.inheaders.get(b"Expect", b"") == b"100-continue":
             # Don't use simple_response here, because it emits headers
             # we don't want. See
-            # https://bitbucket.org/cherrypy/cherrypy/issue/951
+            # https://github.com/cherrypy/cherrypy/issues/951
             msg = self.server.protocol.encode(
                 'ascii') + b" 100 Continue\r\n\r\n"
             try:
@@ -819,14 +833,13 @@
         if uri == ASTERISK:
             return None, None, uri
 
-        scheme, sep, remainder = uri.partition(b'://')
-        if sep and QUESTION_MARK not in scheme:
+        scheme, authority, path, params, query, fragment = urlparse(uri)
+        if scheme and QUESTION_MARK not in scheme:
             # An absoluteURI.
             # If there's a scheme (and it must be http or https), then:
             # http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query
             # ]]
-            authority, path_a, path_b = remainder.partition(FORWARD_SLASH)
-            return scheme.lower(), authority, path_a + path_b
+            return scheme, authority, path
 
         if uri.startswith(FORWARD_SLASH):
             # An abs_path.
@@ -1089,7 +1102,7 @@
                 # Don't error if we're between requests; only error
                 # if 1) no request has been started at all, or 2) we're
                 # in the middle of a request.
-                # See https://bitbucket.org/cherrypy/cherrypy/issue/853
+                # See https://github.com/cherrypy/cherrypy/issues/853
                 if (not request_seen) or (req and req.started_request):
                     # Don't bother writing the 408 if the response
                     # has already started being written.
@@ -1378,7 +1391,7 @@
                 except (AssertionError,
                         # Ignore repeated Ctrl-C.
                         # See
-                        # https://bitbucket.org/cherrypy/cherrypy/issue/691.
+                        # https://github.com/cherrypy/cherrypy/issues/691.
                         KeyboardInterrupt):
                     pass
 
@@ -1478,7 +1491,7 @@
     timeout = 10
     """The timeout in seconds for accepted connections (default 10)."""
 
-    version = "CherryPy/5.1.0"
+    version = "CherryPy/" + cp_version
     """A version string for the HTTPServer."""
 
     software = None
@@ -1703,7 +1716,7 @@
 
         # If listening on the IPV6 any address ('::' = IN6ADDR_ANY),
         # activate dual-stack. See
-        # https://bitbucket.org/cherrypy/cherrypy/issue/871.
+        # https://github.com/cherrypy/cherrypy/issues/871.
         if (hasattr(socket, 'AF_INET6') and family == socket.AF_INET6
                 and self.bind_addr[0] in ('::', '::0', '::0.0.0.0')):
             try:
@@ -1797,15 +1810,15 @@
                 # the call, and I *think* I'm reading it right that Python
                 # will then go ahead and poll for and handle the signal
                 # elsewhere. See
-                # https://bitbucket.org/cherrypy/cherrypy/issue/707.
+                # https://github.com/cherrypy/cherrypy/issues/707.
                 return
             if x.args[0] in socket_errors_nonblocking:
                 # Just try again. See
-                # https://bitbucket.org/cherrypy/cherrypy/issue/479.
+                # https://github.com/cherrypy/cherrypy/issues/479.
                 return
             if x.args[0] in socket_errors_to_ignore:
                 # Our socket was closed.
-                # See https://bitbucket.org/cherrypy/cherrypy/issue/686.
+                # See https://github.com/cherrypy/cherrypy/issues/686.
                 return
             raise
 
@@ -1838,7 +1851,7 @@
                     if x.args[0] not in socket_errors_to_ignore:
                         # Changed to use error code and not message
                         # See
-                        # https://bitbucket.org/cherrypy/cherrypy/issue/860.
+                        # https://github.com/cherrypy/cherrypy/issues/860.
                         raise
                 else:
                     # Note that we're explicitly NOT using AI_PASSIVE,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/setup.cfg new/CherryPy-5.4.0/setup.cfg
--- old/CherryPy-5.1.0/setup.cfg        2016-03-10 15:15:37.000000000 +0100
+++ new/CherryPy-5.4.0/setup.cfg        2016-05-11 02:36:55.000000000 +0200
@@ -1,3 +1,12 @@
+[bumpversion]
+current_version = 5.4.0
+commit = True
+tag = True
+
+[aliases]
+clean_egg_info = egg_info -RDb ''
+release = clean_egg_info sdist bdist_wheel
+
 [sdist]
 formats = gztar,zip
 
@@ -8,7 +17,9 @@
 nocapture = True
 
 [egg_info]
-tag_svn_revision = 0
 tag_build = 
 tag_date = 0
+tag_svn_revision = 0
+
+[bumpversion:file:setup.py]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CherryPy-5.1.0/setup.py new/CherryPy-5.4.0/setup.py
--- old/CherryPy-5.1.0/setup.py 2016-03-10 15:15:31.000000000 +0100
+++ new/CherryPy-5.4.0/setup.py 2016-05-11 02:35:35.000000000 +0200
@@ -36,7 +36,7 @@
 # arguments for the setup command
 ###############################################################################
 name = "CherryPy"
-version = "5.1.0"
+version = "5.4.0"
 desc = "Object-Oriented HTTP framework"
 long_desc = "CherryPy is a pythonic, object-oriented HTTP framework"
 classifiers = [


Reply via email to