Hello community,

here is the log from the commit of package python-bottle for openSUSE:Factory 
checked in at 2017-04-19 18:05:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-bottle (Old)
 and      /work/SRC/openSUSE:Factory/.python-bottle.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-bottle"

Wed Apr 19 18:05:34 2017 rev:12 rq:483405 version:0.12.13

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-bottle/python-bottle.changes      
2014-05-21 16:22:06.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python-bottle.new/python-bottle.changes 
2017-04-19 18:05:38.405854087 +0200
@@ -1,0 +2,27 @@
+Wed Mar 29 15:24:50 UTC 2017 - [email protected]
+
+- update pdf doc file.
+
+-------------------------------------------------------------------
+Thu Mar 23 18:09:54 UTC 2017 - [email protected]
+
+- update for singlespec
+- use automation for docs
+- update to 0.12.13
+  * bugfix release
+  * fixed TypeError on unicode WSGI headers
+  * fixed get_header on FileUpload
+  * fixed crlf header injection (CVE-2016-9964)
+  * switch to setuptools for build
+  * allow multiline dict/list/set comprehensions in templates
+  * allow unicode keys in ConfigDict
+
+-------------------------------------------------------------------
+Sun Apr 26 18:21:13 UTC 2015 - [email protected]
+
+- update to version 0.12.8: no upstream changelog
+- update bottle-docs.pdf
+- point the source URL of the pdf to the project homepage
+- create of separate subpackage for the pdf documentation
+
+-------------------------------------------------------------------

Old:
----
  bottle-0.12.7.tar.gz

New:
----
  bottle-0.12.13.tar.gz

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

Other differences:
------------------
++++++ python-bottle.spec ++++++
--- /var/tmp/diff_new_pack.zqTMq3/_old  2017-04-19 18:05:39.165746597 +0200
+++ /var/tmp/diff_new_pack.zqTMq3/_new  2017-04-19 18:05:39.169746031 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-bottle
 #
-# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,22 +16,22 @@
 #
 
 
+%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-bottle
-Version:        0.12.7
+Version:        0.12.13
 Release:        0
 Url:            http://bottlepy.org/
 Summary:        Fast and simple WSGI-framework for small web-applications
 License:        MIT
 Group:          Development/Languages/Python
-Source:         
http://pypi.python.org/packages/source/b/bottle/bottle-%{version}.tar.gz
-Source1:        bottle-docs.pdf
-BuildRequires:  python-base
+Source:         
https://files.pythonhosted.org/packages/source/b/bottle/bottle-%{version}.tar.gz
+Source1:        http://bottlepy.org/docs/0.12/bottle-docs.pdf
+BuildRequires:  %{python_module setuptools}
+BuildRequires:  python-rpm-macros
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-%if 0%{?suse_version} && 0%{?suse_version} <= 1110
-%{!?python_sitelib: %global python_sitelib %(python -c "from 
distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%else
 BuildArch:      noarch
-%endif
+
+%python_subpackages
 
 %description
 Bottle is a fast and simple micro-framework for small web-applications. It 
@@ -40,21 +40,43 @@
 template engines. All in a single file and with no dependencies other than the
 Python Standard Library.
 
+%package -n %{name}-doc
+Summary:        Documentation for %{name}
+Group:          Documentation/Other
+Requires:       %{name} = %{version}
+Provides:       %{python_module bottle-doc = %{version}}
+
+%description -n %{name}-doc
+Bottle is a fast and simple micro-framework for small web-applications. It
+offers request dispatching (Routes) with url parameter support, Templates, a
+built-in HTTP Server and adapters for many third party WSGI/HTTP-server and
+template engines. All in a single file and with no dependencies other than the
+Python Standard Library.
+
+This subpackage contains the PDF documentation for %{name}.
+
 %prep
 %setup -q -n bottle-%{version}
 cp %{SOURCE1} .
 
 %build
-python setup.py build
+%python_build
 
 %install
-python setup.py install --prefix=%{_prefix} --root=%{buildroot}
+%python_install
+%python_clone %{buildroot}%{_bindir}/bottle.py
 
-%files
+%files %{python_files}
 %defattr(-,root,root,-)
-%doc README.rst bottle-docs.pdf
-%{_bindir}/bottle.py
+%doc README.rst
+%{_bindir}/bottle.py-%{python_bin_suffix}
+%python3_only %{_bindir}/bottle.py
 %{python_sitelib}/bottle.py*
-%{python_sitelib}/bottle-%{version}-py%{py_ver}.egg-info
+%pycache_only %{python_sitelib}/__pycache__
+%{python_sitelib}/bottle-%{version}-py%{python_version}.egg-info
+
+%files -n %{name}-doc
+%defattr(-,root,root,-)
+%doc bottle-docs.pdf
 
 %changelog

++++++ bottle-0.12.7.tar.gz -> bottle-0.12.13.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/MANIFEST.in 
new/bottle-0.12.13/MANIFEST.in
--- old/bottle-0.12.7/MANIFEST.in       1970-01-01 01:00:00.000000000 +0100
+++ new/bottle-0.12.13/MANIFEST.in      2016-07-05 12:08:44.000000000 +0200
@@ -0,0 +1,6 @@
+include bottle.py
+include setup.py
+include README.rst
+include LICENSE.txt
+include test/views/*.tpl
+include test/*.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/PKG-INFO new/bottle-0.12.13/PKG-INFO
--- old/bottle-0.12.7/PKG-INFO  2014-04-29 19:25:40.000000000 +0200
+++ new/bottle-0.12.13/PKG-INFO 2017-01-09 13:33:49.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: bottle
-Version: 0.12.7
+Version: 0.12.13
 Summary: Fast and simple WSGI-framework for small web-applications.
 Home-page: http://bottlepy.org/
 Author: Marcel Hellkamp
@@ -15,7 +15,7 @@
         
         Homepage and documentation: http://bottlepy.org/
         
-        Copyright (c) 2013, Marcel Hellkamp.
+        Copyright (c) 2016, Marcel Hellkamp.
         License: MIT (see LICENSE for details)
         
 Platform: any
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/bottle.egg-info/PKG-INFO 
new/bottle-0.12.13/bottle.egg-info/PKG-INFO
--- old/bottle-0.12.7/bottle.egg-info/PKG-INFO  1970-01-01 01:00:00.000000000 
+0100
+++ new/bottle-0.12.13/bottle.egg-info/PKG-INFO 2017-01-09 13:33:48.000000000 
+0100
@@ -0,0 +1,37 @@
+Metadata-Version: 1.1
+Name: bottle
+Version: 0.12.13
+Summary: Fast and simple WSGI-framework for small web-applications.
+Home-page: http://bottlepy.org/
+Author: Marcel Hellkamp
+Author-email: [email protected]
+License: MIT
+Description: 
+        Bottle is a fast and simple micro-framework for small web 
applications. It
+        offers request dispatching (Routes) with url parameter support, 
templates,
+        a built-in HTTP Server and adapters for many third party 
WSGI/HTTP-server and
+        template engines - all in a single file and with no dependencies other 
than the
+        Python Standard Library.
+        
+        Homepage and documentation: http://bottlepy.org/
+        
+        Copyright (c) 2016, Marcel Hellkamp.
+        License: MIT (see LICENSE for details)
+        
+Platform: any
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI 
Tools/Libraries
+Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server
+Classifier: Topic :: Software Development :: Libraries :: Application 
Frameworks
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Programming Language :: Python :: 3.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/bottle.egg-info/SOURCES.txt 
new/bottle-0.12.13/bottle.egg-info/SOURCES.txt
--- old/bottle-0.12.7/bottle.egg-info/SOURCES.txt       1970-01-01 
01:00:00.000000000 +0100
+++ new/bottle-0.12.13/bottle.egg-info/SOURCES.txt      2017-01-09 
13:33:48.000000000 +0100
@@ -0,0 +1,46 @@
+MANIFEST.in
+README.rst
+bottle.py
+setup.py
+bottle.egg-info/PKG-INFO
+bottle.egg-info/SOURCES.txt
+bottle.egg-info/dependency_links.txt
+bottle.egg-info/top_level.txt
+test/servertest.py
+test/test_auth.py
+test/test_config.py
+test/test_configdict.py
+test/test_contextlocals.py
+test/test_environ.py
+test/test_fileupload.py
+test/test_formsdict.py
+test/test_importhook.py
+test/test_jinja2.py
+test/test_mako.py
+test/test_mdict.py
+test/test_mount.py
+test/test_outputfilter.py
+test/test_plugins.py
+test/test_resources.py
+test/test_route.py
+test/test_router.py
+test/test_securecookies.py
+test/test_sendfile.py
+test/test_server.py
+test/test_stpl.py
+test/test_wsgi.py
+test/testall.py
+test/tools.py
+test/views/jinja2_base.tpl
+test/views/jinja2_inherit.tpl
+test/views/jinja2_simple.tpl
+test/views/mako_base.tpl
+test/views/mako_inherit.tpl
+test/views/mako_simple.tpl
+test/views/stpl_include.tpl
+test/views/stpl_no_vars.tpl
+test/views/stpl_simple.tpl
+test/views/stpl_t2base.tpl
+test/views/stpl_t2inc.tpl
+test/views/stpl_t2main.tpl
+test/views/stpl_unicode.tpl
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/bottle.egg-info/dependency_links.txt 
new/bottle-0.12.13/bottle.egg-info/dependency_links.txt
--- old/bottle-0.12.7/bottle.egg-info/dependency_links.txt      1970-01-01 
01:00:00.000000000 +0100
+++ new/bottle-0.12.13/bottle.egg-info/dependency_links.txt     2017-01-09 
13:33:48.000000000 +0100
@@ -0,0 +1 @@
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/bottle.egg-info/top_level.txt 
new/bottle-0.12.13/bottle.egg-info/top_level.txt
--- old/bottle-0.12.7/bottle.egg-info/top_level.txt     1970-01-01 
01:00:00.000000000 +0100
+++ new/bottle-0.12.13/bottle.egg-info/top_level.txt    2017-01-09 
13:33:48.000000000 +0100
@@ -0,0 +1 @@
+bottle
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/bottle.py new/bottle-0.12.13/bottle.py
--- old/bottle-0.12.7/bottle.py 2014-04-29 19:24:14.000000000 +0200
+++ new/bottle-0.12.13/bottle.py        2017-01-09 13:31:53.000000000 +0100
@@ -9,14 +9,14 @@
 
 Homepage and documentation: http://bottlepy.org/
 
-Copyright (c) 2013, Marcel Hellkamp.
+Copyright (c) 2016, Marcel Hellkamp.
 License: MIT (see LICENSE for details)
 """
 
 from __future__ import with_statement
 
 __author__ = 'Marcel Hellkamp'
-__version__ = '0.12.7'
+__version__ = '0.12.13'
 __license__ = 'MIT'
 
 # The gevent server adapter needs to patch some modules before they are 
imported
@@ -1117,7 +1117,10 @@
             exhaustion. '''
         ctype = self.environ.get('CONTENT_TYPE', '').lower().split(';')[0]
         if ctype == 'application/json':
-            return json_loads(self._get_body_string())
+            b = self._get_body_string()
+            if not b:
+                return None
+            return json_loads(b)
         return None
 
     def _iter_body(self, read, bufsize):
@@ -1154,7 +1157,7 @@
                 maxread -= len(part)
             if read(2) != rn:
                 raise err
-            
+
     @DictProperty('environ', 'bottle.request.body', read_only=True)
     def _body(self):
         body_iter = self._iter_chunked if self.chunked else self._iter_body
@@ -1395,28 +1398,36 @@
         self.environ['bottle.request.ext.%s'%name] = value
 
 
+def _hkey(key):
+    if '\n' in key or '\r' in key or '\0' in key:
+        raise ValueError("Header names must not contain control characters: 
%r" % key)
+    return key.title().replace('_', '-')
+
 
+def _hval(value):
+    value = tonat(value)
+    if '\n' in value or '\r' in value or '\0' in value:
+        raise ValueError("Header value must not contain control characters: 
%r" % value)
+    return value
 
-def _hkey(s):
-    return s.title().replace('_','-')
 
 
 class HeaderProperty(object):
-    def __init__(self, name, reader=None, writer=str, default=''):
+    def __init__(self, name, reader=None, writer=None, default=''):
         self.name, self.default = name, default
         self.reader, self.writer = reader, writer
         self.__doc__ = 'Current value of the %r header.' % name.title()
 
     def __get__(self, obj, cls):
         if obj is None: return self
-        value = obj.headers.get(self.name, self.default)
+        value = obj.get_header(self.name, self.default)
         return self.reader(value) if self.reader else value
 
     def __set__(self, obj, value):
-        obj.headers[self.name] = self.writer(value)
+        obj[self.name] = self.writer(value) if self.writer else value
 
     def __delete__(self, obj):
-        del obj.headers[self.name]
+        del obj[self.name]
 
 
 class BaseResponse(object):
@@ -1469,7 +1480,7 @@
         copy._headers = dict((k, v[:]) for (k, v) in self._headers.items())
         if self._cookies:
             copy._cookies = SimpleCookie()
-            copy._cookies.load(self._cookies.output())
+            copy._cookies.load(self._cookies.output(header=''))
         return copy
 
     def __iter__(self):
@@ -1523,7 +1534,7 @@
     def __contains__(self, name): return _hkey(name) in self._headers
     def __delitem__(self, name):  del self._headers[_hkey(name)]
     def __getitem__(self, name):  return self._headers[_hkey(name)][-1]
-    def __setitem__(self, name, value): self._headers[_hkey(name)] = 
[str(value)]
+    def __setitem__(self, name, value): self._headers[_hkey(name)] = 
[_hval(value)]
 
     def get_header(self, name, default=None):
         ''' Return the value of a previously defined header. If there is no
@@ -1533,11 +1544,11 @@
     def set_header(self, name, value):
         ''' Create a new response header, replacing any previously defined
             headers with the same name. '''
-        self._headers[_hkey(name)] = [str(value)]
+        self._headers[_hkey(name)] = [_hval(value)]
 
     def add_header(self, name, value):
         ''' Add an additional response header, not removing duplicates. '''
-        self._headers.setdefault(_hkey(name), []).append(str(value))
+        self._headers.setdefault(_hkey(name), []).append(_hval(value))
 
     def iter_headers(self):
         ''' Yield (header, value) tuples, skipping headers that are not
@@ -1918,7 +1929,6 @@
             return super(FormsDict, self).__getattr__(name)
         return self.getunicode(name, default=default)
 
-
 class HeaderDict(MultiDict):
     """ A case-insensitive version of :class:`MultiDict` that defaults to
         replace the old value instead of appending it. """
@@ -1930,15 +1940,14 @@
     def __contains__(self, key): return _hkey(key) in self.dict
     def __delitem__(self, key): del self.dict[_hkey(key)]
     def __getitem__(self, key): return self.dict[_hkey(key)][-1]
-    def __setitem__(self, key, value): self.dict[_hkey(key)] = [str(value)]
-    def append(self, key, value):
-        self.dict.setdefault(_hkey(key), []).append(str(value))
-    def replace(self, key, value): self.dict[_hkey(key)] = [str(value)]
+    def __setitem__(self, key, value): self.dict[_hkey(key)] = [_hval(value)]
+    def append(self, key, value): self.dict.setdefault(_hkey(key), 
[]).append(_hval(value))
+    def replace(self, key, value): self.dict[_hkey(key)] = [_hval(value)]
     def getall(self, key): return self.dict.get(_hkey(key)) or []
     def get(self, key, default=None, index=-1):
         return MultiDict.get(self, _hkey(key), default, index)
     def filter(self, names):
-        for name in [_hkey(n) for n in names]:
+        for name in (_hkey(n) for n in names):
             if name in self.dict:
                 del self.dict[name]
 
@@ -2094,7 +2103,7 @@
     def load_dict(self, source, namespace='', make_namespaces=False):
         ''' Import values from a dictionary structure. Nesting can be used to
             represent namespaces.
-            
+
             >>> ConfigDict().load_dict({'name': {'space': {'key': 'value'}}})
             {'name.space.key': 'value'}
         '''
@@ -2104,7 +2113,7 @@
             if not isinstance(source, dict):
                 raise TypeError('Source is not a dict (r)' % type(key))
             for key, value in source.items():
-                if not isinstance(key, str):
+                if not isinstance(key, basestring):
                     raise TypeError('Key is not a string (%r)' % type(key))
                 full_key = prefix + '.' + key if prefix else key
                 if isinstance(value, dict):
@@ -2120,7 +2129,7 @@
             namespace. Apart from that it works just as the usual 
dict.update().
             Example: ``update('some.namespace', key='value')`` '''
         prefix = ''
-        if a and isinstance(a[0], str):
+        if a and isinstance(a[0], basestring):
             prefix = a[0].strip('.') + '.'
             a = a[1:]
         for key, value in dict(*a, **ka).items():
@@ -2132,7 +2141,7 @@
         return self[key]
 
     def __setitem__(self, key, value):
-        if not isinstance(key, str):
+        if not isinstance(key, basestring):
             raise TypeError('Key has type %r (not a string)' % type(key))
 
         value = self.meta_get(key, 'filter', lambda x: x)(value)
@@ -2346,11 +2355,15 @@
     content_type = HeaderProperty('Content-Type')
     content_length = HeaderProperty('Content-Length', reader=int, default=-1)
 
+    def get_header(self, name, default=None):
+        """ Return the value of a header within the mulripart part. """
+        return self.headers.get(name, default)
+
     @cached_property
     def filename(self):
         ''' Name of the file on the client file system, but normalized to 
ensure
             file system compatibility. An empty filename is returned as 
'empty'.
-            
+
             Only ASCII letters, digits, dashes, underscores and dots are
             allowed in the final filename. Accents are removed, if possible.
             Whitespace is replaced by a single dash. Leading or tailing dots
@@ -2774,20 +2787,20 @@
         from cherrypy import wsgiserver
         self.options['bind_addr'] = (self.host, self.port)
         self.options['wsgi_app'] = handler
-        
+
         certfile = self.options.get('certfile')
         if certfile:
             del self.options['certfile']
         keyfile = self.options.get('keyfile')
         if keyfile:
             del self.options['keyfile']
-        
+
         server = wsgiserver.CherryPyWSGIServer(**self.options)
         if certfile:
             server.ssl_certificate = certfile
         if keyfile:
             server.ssl_private_key = keyfile
-        
+
         try:
             server.start()
         finally:
@@ -3412,15 +3425,19 @@
     _re_inl = _re_tok.replace('|\\n','') # We re-use this string pattern later
     # 2: Comments (until end of line, but not the newline itself)
     _re_tok += '|(#.*)'
-    # 3,4: Keywords that start or continue a python block (only start of line)
+    # 3,4: Open and close grouping tokens
+    _re_tok += '|([\[\{\(])'
+    _re_tok += '|([\]\}\)])'
+    # 5,6: Keywords that start or continue a python block (only start of line)
     _re_tok += '|^([ \\t]*(?:if|for|while|with|try|def|class)\\b)' \
                '|^([ \\t]*(?:elif|else|except|finally)\\b)'
-    # 5: Our special 'end' keyword (but only if it stands alone)
+    # 7: Our special 'end' keyword (but only if it stands alone)
     _re_tok += '|((?:^|;)[ \\t]*end[ \\t]*(?=(?:%(block_close)s[ 
\\t]*)?\\r?$|;|#))'
-    # 6: A customizable end-of-code-block template token (only end of line)
-    _re_tok += '|(%(block_close)s[ \\t]*(?=$))'
-    # 7: And finally, a single newline. The 8th token is 'everything else'
+    # 8: A customizable end-of-code-block template token (only end of line)
+    _re_tok += '|(%(block_close)s[ \\t]*(?=\\r?$))'
+    # 9: And finally, a single newline. The 10th token is 'everything else'
     _re_tok += '|(\\r?\\n)'
+
     # Match the start tokens of code areas in a template
     _re_split = '(?m)^[ \t]*(\\\\?)((%(line_start)s)|(%(block_start)s))(%%?)'
     # Match inline statements (may contain python strings)
@@ -3434,6 +3451,7 @@
         self.code_buffer, self.text_buffer = [], []
         self.lineno, self.offset = 1, 0
         self.indent, self.indent_mod = 0, 0
+        self.paren_depth = 0
 
     def get_syntax(self):
         ''' Tokens as a space separated string (default: <% %> % {{ }}) '''
@@ -3490,8 +3508,8 @@
                 return
             code_line += self.source[self.offset:self.offset+m.start()]
             self.offset += m.end()
-            _str, _com, _blk1, _blk2, _end, _cend, _nl = m.groups()
-            if code_line and (_blk1 or _blk2): # a if b else c
+            _str, _com, _po, _pc, _blk1, _blk2, _end, _cend, _nl = m.groups()
+            if (code_line or self.paren_depth > 0) and (_blk1 or _blk2): # a 
if b else c
                 code_line += _blk1 or _blk2
                 continue
             if _str:    # Python string
@@ -3500,6 +3518,15 @@
                 comment = _com
                 if multiline and _com.strip().endswith(self._tokens[1]):
                     multiline = False # Allow end-of-block in comments
+            elif _po:  # open parenthesis
+                self.paren_depth += 1
+                code_line += _po
+            elif _pc:  # close parenthesis
+                if self.paren_depth > 0:
+                    # we could check for matching parentheses here, but it's
+                    # easier to leave that to python - just check counts
+                    self.paren_depth -= 1
+                code_line += _pc
             elif _blk1: # Start-block keyword (if/for/while/def/try/...)
                 code_line, self.indent_mod = _blk1, -1
                 self.indent += 1
@@ -3642,6 +3669,7 @@
 #: A dict to map HTTP status codes (e.g. 404) to phrases (e.g. 'Not Found')
 HTTP_CODES = httplib.responses
 HTTP_CODES[418] = "I'm a teapot" # RFC 2324
+HTTP_CODES[422] = "Unprocessable Entity" # RFC 4918
 HTTP_CODES[428] = "Precondition Required"
 HTTP_CODES[429] = "Too Many Requests"
 HTTP_CODES[431] = "Request Header Fields Too Large"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/setup.cfg new/bottle-0.12.13/setup.cfg
--- old/bottle-0.12.7/setup.cfg 1970-01-01 01:00:00.000000000 +0100
+++ new/bottle-0.12.13/setup.cfg        2017-01-09 13:33:49.000000000 +0100
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/setup.py new/bottle-0.12.13/setup.py
--- old/bottle-0.12.7/setup.py  2014-04-29 19:23:59.000000000 +0200
+++ new/bottle-0.12.13/setup.py 2017-01-09 13:19:52.000000000 +0100
@@ -2,7 +2,7 @@
 
 import sys
 import os
-from distutils.core import setup
+from setuptools import setup
 
 if sys.version_info < (2,5):
     raise NotImplementedError("Sorry, you need at least Python 2.5 or Python 
3.x to use bottle.")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/test/test_configdict.py 
new/bottle-0.12.13/test/test_configdict.py
--- old/bottle-0.12.7/test/test_configdict.py   2014-04-29 19:23:59.000000000 
+0200
+++ new/bottle-0.12.13/test/test_configdict.py  2017-01-09 13:19:52.000000000 
+0100
@@ -75,6 +75,19 @@
         self.assertRaises(TypeError, lambda: setitem(c, 5, 6))
         self.assertRaises(TypeError, lambda: c.load_dict({5:6}))
 
+    def test_issue720(self):
+        """Accept unicode keys."""
+        try:
+            key = unichr(12354)
+        except NameError:
+            key = chr(12354)
+        c = ConfigDict()
+        c.load_dict({key: 'value'})
+        self.assertEqual('value', c[key])
+        c = ConfigDict()
+        c.load_dict({key: {'subkey': 'value'}})
+        self.assertEqual('value', c[key + '.subkey'])
+
 
 if __name__ == '__main__': #pragma: no cover
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/test/test_environ.py 
new/bottle-0.12.13/test/test_environ.py
--- old/bottle-0.12.7/test/test_environ.py      2014-04-29 17:13:16.000000000 
+0200
+++ new/bottle-0.12.13/test/test_environ.py     2017-01-09 13:30:30.000000000 
+0100
@@ -3,6 +3,7 @@
 
 import unittest
 import sys
+
 import bottle
 from bottle import request, tob, touni, tonat, json_dumps, _e, HTTPError, 
parse_date
 import tools
@@ -11,6 +12,18 @@
 
 from bottle import BaseRequest, BaseResponse, LocalRequest
 
+
+try:
+    from itertools import product
+except ImportError:
+    def product(*args):
+        pools = map(tuple, args)
+        result = [[]]
+        for pool in pools:
+            result = [x + [y] for x in result for y in pool]
+        for prod in result:
+            yield tuple(prod)
+
 class TestRequest(unittest.TestCase):
 
     def test_app_property(self):
@@ -394,6 +407,14 @@
         e['CONTENT_LENGTH'] = str(len(json_dumps(test)))
         self.assertEqual(BaseRequest(e).json, None)
 
+    def test_json_header_empty_body(self):
+        """Request Content-Type is application/json but body is empty"""
+        e = {'CONTENT_TYPE': 'application/json'}
+        wsgiref.util.setup_testing_defaults(e)
+        wsgiref.util.setup_testing_defaults(e)
+        e['CONTENT_LENGTH'] = "0"
+        self.assertEqual(BaseRequest(e).json, None)
+
     def test_isajax(self):
         e = {}
         wsgiref.util.setup_testing_defaults(e)
@@ -646,6 +667,30 @@
         self.assertEqual('5', response['x-test'])
         response['x-test'] = None
         self.assertEqual('None', response['x-test'])
+        response['x-test'] = touni('瓶')
+        self.assertEqual(tonat(touni('瓶')), response['x-test'])
+
+    def test_prevent_control_characters_in_headers(self):
+        masks = '{}test', 'test{}', 'te{}st'
+        tests = '\n', '\r', '\n\r', '\0'
+
+        # Test HeaderDict
+        apis = 'append', 'replace', '__setitem__', 'setdefault'
+        for api, mask, test in product(apis, masks, tests):
+            hd = bottle.HeaderDict()
+            func = getattr(hd, api)
+            value = mask.replace("{}", test)
+            self.assertRaises(ValueError, func, value, "test-value")
+            self.assertRaises(ValueError, func, "test-name", value)
+
+        # Test functions on BaseResponse
+        apis = 'add_header', 'set_header', '__setitem__'
+        for api, mask, test in product(apis, masks, tests):
+            rs = bottle.BaseResponse()
+            func = getattr(rs, api)
+            value = mask.replace("{}", test)
+            self.assertRaises(ValueError, func, value, "test-value")
+            self.assertRaises(ValueError, func, "test-name", value)
 
     def test_expires_header(self):
         import datetime
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/test/test_fileupload.py 
new/bottle-0.12.13/test/test_fileupload.py
--- old/bottle-0.12.7/test/test_fileupload.py   2014-04-29 17:13:16.000000000 
+0200
+++ new/bottle-0.12.13/test/test_fileupload.py  2017-01-09 13:19:52.000000000 
+0100
@@ -4,7 +4,7 @@
 import unittest
 import sys, os.path
 import bottle
-from bottle import FileUpload, BytesIO
+from bottle import FileUpload, BytesIO, tob
 import tempfile
 
 class TestFileUpload(unittest.TestCase):
@@ -14,6 +14,10 @@
     def test_raw_filename(self):
         self.assertEqual(FileUpload(None, None, 'x/x').raw_filename, 'x/x')
 
+    def test_content_type(self):
+        fu = FileUpload(None, None, None, {"Content-type": "text/plain"})
+        self.assertEqual(fu.content_type, 'text/plain')
+
     def assertFilename(self, bad, good):
         fu = FileUpload(None, None, bad)
         self.assertEqual(fu.filename, good)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/bottle-0.12.7/test/test_stpl.py 
new/bottle-0.12.13/test/test_stpl.py
--- old/bottle-0.12.7/test/test_stpl.py 2014-04-29 19:23:59.000000000 +0200
+++ new/bottle-0.12.13/test/test_stpl.py        2017-01-09 13:19:52.000000000 
+0100
@@ -303,6 +303,9 @@
             18
         '''
         self.assertRenders(source, result)
+        source_wineol = '<% a = 5\r\nb = 6\r\nc = 7\r\n%>\r\n{{a+b+c}}'
+        result_wineol = '18'
+        self.assertRenders(source_wineol, result_wineol)
 
     def test_multiline_ignore_eob_in_string(self):
         source = '''
@@ -375,6 +378,18 @@
         '''
         self.assertRenders(source, result)
 
+    def test_multiline_comprehensions_in_code_line(self):
+        self.assertRenders(source='''
+            % a = [
+            %    (i + 1)
+            %    for i in range(5)
+            %    if i%2 == 0
+            % ]
+            {{a}}
+        ''', result='''
+            [1, 3, 5]
+        ''')
+
 if __name__ == '__main__': #pragma: no cover
     unittest.main()
 

++++++ bottle-docs.pdf ++++++
(binary differes)


Reply via email to