Bug 2325166 - python-bottle fails to build with Python 3.14: multiple AssertionErrors in tests
Summary: python-bottle fails to build with Python 3.14: multiple AssertionErrors in tests
Keywords:
Status: CLOSED WORKSFORME
Alias: None
Product: Fedora
Classification: Fedora
Component: python-bottle
Version: 42
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: fedepell
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks: PYTHON3.14
TreeView+ depends on / blocked
 
Reported: 2024-11-11 11:26 UTC by Karolina Surma
Modified: 2025-08-27 13:43 UTC (History)
4 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2025-08-27 13:43:50 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Karolina Surma 2024-11-11 11:26:49 UTC
python-bottle fails to build with Python 3.14.0a1.

=================================== FAILURES ===================================
_____________________________ TestRequest.test_url _____________________________

self = <test.test_environ.TestRequest testMethod=test_url>

    def test_url(self):
        """ Environ: URL building """
        request = BaseRequest({'HTTP_HOST':'example.com'})
        self.assertEqual('http://example.com/', request.url)
        request = BaseRequest({'SERVER_NAME':'example.com'})
        self.assertEqual('http://example.com/', request.url)
        request = BaseRequest({'SERVER_NAME':'example.com', 'SERVER_PORT':'81'})
        self.assertEqual('http://example.com:81/', request.url)
        request = BaseRequest({'wsgi.url_scheme':'https', 'SERVER_NAME':'example.com'})
        self.assertEqual('https://example.com/', request.url)
        request = BaseRequest({'HTTP_HOST':'example.com', 'PATH_INFO':'/path',
                               'QUERY_STRING':'1=b&c=d', 'SCRIPT_NAME':'/sp'})
>       self.assertEqual('http://example.com/sp/path?1=b&c=d', request.url)
E       AssertionError: 'http://example.com/sp/path?1=b&c=d' != 'http://example.com/path?1=b&c=d'
E       - http://example.com/sp/path?1=b&c=d
E       ?                    ---
E       + http://example.com/path?1=b&c=d

test/test_environ.py:104: AssertionError
_______________________ TestRedirect.test_relative_path ________________________

self = <test.test_environ.TestRedirect testMethod=test_relative_path>
target = './test.html', result = 'http://127.0.0.1/foo/bar/test.html'
query = None, status = 303
args = {'PATH_INFO': '/bar/baz.html', 'SCRIPT_NAME': '/foo/'}
env = {'PATH_INFO': '/bar/baz.html', 'SCRIPT_NAME': '/foo/', 'SERVER_PROTOCOL': 'HTTP/1.1', 'bottle.request': <LocalRequest: GET http://127.0.0.1/bar/baz.html>, ...}
key = 'PATH_INFO'

    def assertRedirect(self, target, result, query=None, status=303, **args):
        env = {'SERVER_PROTOCOL': 'HTTP/1.1'}
        for key in list(args):
            if key.startswith('wsgi'):
                args[key.replace('_', '.', 1)] = args[key]
                del args[key]
        env.update(args)
        request.bind(env)
        bottle.response.bind()
        try:
>           bottle.redirect(target, **(query or {}))

test/test_environ.py:791: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = './test.html', code = 303

    def redirect(url, code=None):
        """ Aborts execution and causes a 303 or 302 redirect, depending on
            the HTTP protocol version. """
        if not code:
            code = 303 if request.get('SERVER_PROTOCOL') == "HTTP/1.1" else 302
        res = response.copy(cls=HTTPResponse)
        res.status = code
        res.body = ""
        res.set_header('Location', urljoin(request.url, url))
>       raise res
E       bottle.HTTPResponse

bottle.py:2823: HTTPResponse

During handling of the above exception, another exception occurred:

self = <test.test_environ.TestRedirect testMethod=test_relative_path>

    def test_relative_path(self):
        self.assertRedirect('./', 'http://127.0.0.1/')
        self.assertRedirect('./test.html', 'http://127.0.0.1/test.html')
        self.assertRedirect('./test.html', 'http://127.0.0.1/foo/test.html',
                            PATH_INFO='/foo/')
        self.assertRedirect('./test.html', 'http://127.0.0.1/foo/test.html',
                            PATH_INFO='/foo/bar.html')
        self.assertRedirect('./test.html', 'http://127.0.0.1/foo/test.html',
                            SCRIPT_NAME='/foo/')
>       self.assertRedirect('./test.html', 'http://127.0.0.1/foo/bar/test.html',
                            SCRIPT_NAME='/foo/', PATH_INFO='/bar/baz.html')

test/test_environ.py:819: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/test_environ.py:795: in assertRedirect
    self.assertEqual(result, E.headers['Location'])
E   AssertionError: 'http://127.0.0.1/foo/bar/test.html' != 'http://127.0.0.1/bar/test.html'
E   - http://127.0.0.1/foo/bar/test.html
E   ?                  ----
E   + http://127.0.0.1/bar/test.html
________________________ TestRedirect.test_specialchars ________________________

self = <test.test_environ.TestRedirect testMethod=test_specialchars>
target = './te st.html', result = 'http://example.com/a%20a/b%20b/te st.html'
query = None, status = 303
args = {'HTTP_HOST': 'example.com', 'PATH_INFO': '/b b/', 'SCRIPT_NAME': '/a a/'}
env = {'HTTP_HOST': 'example.com', 'PATH_INFO': '/b b/', 'SCRIPT_NAME': '/a a/', 'SERVER_PROTOCOL': 'HTTP/1.1', ...}
key = 'PATH_INFO'

    def assertRedirect(self, target, result, query=None, status=303, **args):
        env = {'SERVER_PROTOCOL': 'HTTP/1.1'}
        for key in list(args):
            if key.startswith('wsgi'):
                args[key.replace('_', '.', 1)] = args[key]
                del args[key]
        env.update(args)
        request.bind(env)
        bottle.response.bind()
        try:
>           bottle.redirect(target, **(query or {}))

test/test_environ.py:791: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = './te st.html', code = 303

    def redirect(url, code=None):
        """ Aborts execution and causes a 303 or 302 redirect, depending on
            the HTTP protocol version. """
        if not code:
            code = 303 if request.get('SERVER_PROTOCOL') == "HTTP/1.1" else 302
        res = response.copy(cls=HTTPResponse)
        res.status = code
        res.body = ""
        res.set_header('Location', urljoin(request.url, url))
>       raise res
E       bottle.HTTPResponse

bottle.py:2823: HTTPResponse

During handling of the above exception, another exception occurred:

self = <test.test_environ.TestRedirect testMethod=test_specialchars>

    def test_specialchars(self):
        ''' The target URL is not quoted automatically. '''
>       self.assertRedirect('./te st.html',
                            'http://example.com/a%20a/b%20b/te st.html',
                            HTTP_HOST='example.com', SCRIPT_NAME='/a a/', PATH_INFO='/b b/')

test/test_environ.py:871: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/test_environ.py:795: in assertRedirect
    self.assertEqual(result, E.headers['Location'])
E   AssertionError: 'http://example.com/a%20a/b%20b/te st.html' != 'http://example.com/b%20b/te st.html'
E   - http://example.com/a%20a/b%20b/te st.html
E   ?                    ------
E   + http://example.com/b%20b/te st.html
______________________ TestAppMounting.test_mount_get_url ______________________

self = <test.test_mount.TestAppMounting testMethod=test_mount_get_url>

    def test_mount_get_url(self):
        @self.subapp.route('/test', name="test")
        def route():
            return bottle.url("test")
    
        self.app.mount('/test/', self.subapp)
>       self.assertBody('/test/test', '/test/test')

test/test_mount.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/tools.py:135: in assertBody
    self.assertEqual(tob(body), self.urlopen(route, **kargs)['body'])
E   AssertionError: b'/test/test' != b'test/test'
_________________________ TestRouteDecorator.test_name _________________________

self = <test.test_wsgi.TestRouteDecorator testMethod=test_name>

    def test_name(self):
        @bottle.route(name='foo')
        def test(x=5): return 'ok'
>       self.assertEqual('/test/6', bottle.url('foo', x=6))
E       AssertionError: '/test/6' != 'test/6'
E       - /test/6
E       ? -
E       + test/6

test/test_wsgi.py:401: AssertionError
________________________ TestDecorators.test_routebuild ________________________

self = <test.test_wsgi.TestDecorators testMethod=test_routebuild>

    def test_routebuild(self):
        """ WSGI: Test route builder """
        def foo(): pass
        bottle.route('/a/<b>/c', name='named')(foo)
        bottle.request.environ['SCRIPT_NAME'] = ''
>       self.assertEqual('/a/xxx/c', bottle.url('named', b='xxx'))
E       AssertionError: '/a/xxx/c' != 'a/xxx/c'
E       - /a/xxx/c
E       ? -
E       + a/xxx/c

test/test_wsgi.py:454: AssertionError
=========================== short test summary info ============================
FAILED test/test_environ.py::TestRequest::test_url - AssertionError: 'http://...
FAILED test/test_environ.py::TestRedirect::test_relative_path - AssertionErro...
FAILED test/test_environ.py::TestRedirect::test_specialchars - AssertionError...
FAILED test/test_mount.py::TestAppMounting::test_mount_get_url - AssertionErr...
FAILED test/test_wsgi.py::TestRouteDecorator::test_name - AssertionError: '/t...
FAILED test/test_wsgi.py::TestDecorators::test_routebuild - AssertionError: '...
======================== 6 failed, 349 passed in 0.83s =========================

https://docs.python.org/3.14/whatsnew/3.14.html

For the build logs, see:
https://copr-be.cloud.fedoraproject.org/results/@python/python3.14/fedora-rawhide-x86_64/08189188-python-bottle/

For all our attempts to build python-bottle with Python 3.14, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.14/package/python-bottle/

Testing and mass rebuild of packages is happening in copr.
You can follow these instructions to test locally in mock if your package builds with Python 3.14:
https://copr.fedorainfracloud.org/coprs/g/python/python3.14/

Let us know here if you have any questions.

Python 3.14 is planned to be included in Fedora 43.
To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.14.
A build failure prevents us from testing all dependent packages (transitive [Build]Requires),
so if this package is required a lot, it's important for us to get it fixed soon.

We'd appreciate help from the people who know this package best,
but if you don't want to work on this now, let us know so we can try to work around it on our side.

Comment 1 fedepell 2024-12-09 16:05:56 UTC
@mhroncok do you think this may relate to https://github.com/python/cpython/pull/125876 ? I see the first tests especially just miss random pieces passed as a list :?

Comment 2 Miro Hrončok 2024-12-10 10:55:27 UTC
I don't think so. Why do you assume it's related?

Comment 3 fedepell 2024-12-10 13:13:27 UTC
The top 3 tests failing seem to be always missing a variable from the passed test environment (which is a list), specifically SCRIPT_NAME. But at a first analysis there didn't seem to be something special with it, but maybe there is. Some of the tests (before the failing ones) that use it, as well work. Seems just when there is a certain amount of vars.

The ones after seem to be just missing a separator.

Will recheck, thanks for your feedback :)

Comment 4 Aoife Moloney 2025-02-26 13:15:35 UTC
This bug appears to have been reported against 'rawhide' during the Fedora Linux 42 development cycle.
Changing version to 42.

Comment 5 Karolina Surma 2025-08-27 13:43:50 UTC
python-bottle-0.13.4-3.fc43 built successfully.


Note You need to log in before you can comment on or make changes to this bug.