qutebrowser / qutebrowser

A keyboard-driven, vim-like browser based on Python and Qt.
https://www.qutebrowser.org/
GNU General Public License v3.0
9.45k stars 1.01k forks source link

Python 3.13 #8205

Open The-Compiler opened 1 month ago

The-Compiler commented 1 month ago

Running into various issues when trying to run the testsuite against Python 3.13 Beta 1. See comments below.

The-Compiler commented 1 month ago

typing_extensions incompatibility

[...]
  File ".../python3.13/site-packages/pytest_bdd/steps.py", line 54, in <module>
    P = ParamSpec("P")
  File ".../python3.13/site-packages/typing_extensions.py", line 1512, in __new__
    _set_default(paramspec, default)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File ".../python3.13/site-packages/typing_extensions.py", line 1375, in _set_default
    type_param.__default__ = None
    ^^^^^^^^^^^^^^^^^^^^^^
AttributeError: attribute '__default__' of 'typing.ParamSpec' objects is not writable

Fixed with pip install --pre typing_extensions to upgrade to 4.12.0rc1.

The-Compiler commented 1 month ago

Bad file descriptors in cheroot

Occasionally, end2end tests fail because the server logs:

Exception ignored in: <function IOBase.__del__ at 0x73b2a0e01bc0>
Traceback (most recent call last):
  File "/usr/lib/python3.13/_pyio.py", line 418, in __del__
    self.close()
  File "/usr/lib/python3.13/_pyio.py", line 1313, in close
    self.flush()
  File "/usr/lib/python3.13/_pyio.py", line 1274, in flush
    self._flush_unlocked()
  File ".../python3.13/site-packages/cheroot/makefile.py", line 33, in _flush_unlocked
    n = self.raw.write(bytes(self._write_buf))
  File "/usr/lib/python3.13/socket.py", line 724, in write
    return self._sock.send(b)
OSError: [Errno 9] Bad file descriptor
The-Compiler commented 1 month ago

Segfault in unit tests

When running tests/unit, we semi-consistently get a segfault in tests/unit/mainwindow/test_messageview.py (but apparently not always?!).

Stack trace is somewhat useless currently:

``` #0 0x000075537d07ce76 in ??? () at /usr/lib/libpython3.13.so.1.0 #1 0x000075537ce88e2b in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #2 0x000075537d020b76 in ??? () at /usr/lib/libpython3.13.so.1.0 #3 0x000075537cfe47f3 in PyObject_GetAttr () at /usr/lib/libpython3.13.so.1.0 #4 0x000075537ce8cf0b in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #5 0x000075537d151e55 in ??? () at /usr/lib/libpython3.13.so.1.0 #6 0x000075537d151e9a in ??? () at /usr/lib/libpython3.13.so.1.0 #7 0x000075537d001522 in ??? () at /usr/lib/libpython3.13.so.1.0 #8 0x000075537d001cc7 in PySequence_List () at /usr/lib/libpython3.13.so.1.0 #9 0x000075537d001e38 in PySequence_Fast () at /usr/lib/libpython3.13.so.1.0 #10 0x000075537d001f8f in PyUnicode_Join () at /usr/lib/libpython3.13.so.1.0 #11 0x000075537ce8466c in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #12 0x000075537cf706b5 in ??? () at /usr/lib/libpython3.13.so.1.0 #13 0x000075537cf657c4 in _PyObject_MakeTpCall () at /usr/lib/libpython3.13.so.1.0 #14 0x000075537ce86ad0 in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #15 0x000075537cf65ae5 in ??? () at /usr/lib/libpython3.13.so.1.0 #16 0x000075537cf65ca0 in ??? () at /usr/lib/libpython3.13.so.1.0 #17 0x000075537cffed15 in ??? () at /usr/lib/libpython3.13.so.1.0 #18 0x000075537cf78d5f in ??? () at /usr/lib/libpython3.13.so.1.0 #19 0x000075537cf657c4 in _PyObject_MakeTpCall () at /usr/lib/libpython3.13.so.1.0 #20 0x000075537ce8611a in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #21 0x000075537cf65ae5 in ??? () at /usr/lib/libpython3.13.so.1.0 #22 0x000075537cf65ca0 in ??? () at /usr/lib/libpython3.13.so.1.0 #23 0x000075537cffeb75 in ??? () at /usr/lib/libpython3.13.so.1.0 #24 0x000075537cf657c4 in _PyObject_MakeTpCall () at /usr/lib/libpython3.13.so.1.0 #25 0x000075537ce8611a in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #26 0x000075537cf65ae5 in ??? () at /usr/lib/libpython3.13.so.1.0 #27 0x000075537cf65ca0 in ??? () at /usr/lib/libpython3.13.so.1.0 #28 0x000075537cffeb75 in ??? () at /usr/lib/libpython3.13.so.1.0 #29 0x000075537cf6f44b in ??? () at /usr/lib/libpython3.13.so.1.0 #30 0x000075537ce80967 in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #31 0x000075537cf65ae5 in ??? () at /usr/lib/libpython3.13.so.1.0 #32 0x000075537cf65ca0 in ??? () at /usr/lib/libpython3.13.so.1.0 #33 0x000075537cffeb75 in ??? () at /usr/lib/libpython3.13.so.1.0 #34 0x000075537cf657c4 in _PyObject_MakeTpCall () at /usr/lib/libpython3.13.so.1.0 #35 0x000075537ce8611a in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #36 0x000075537cf65ae5 in ??? () at /usr/lib/libpython3.13.so.1.0 #37 0x000075537cf65ca0 in ??? () at /usr/lib/libpython3.13.so.1.0 #38 0x000075537cffeb75 in ??? () at /usr/lib/libpython3.13.so.1.0 #39 0x000075537cf657c4 in _PyObject_MakeTpCall () at /usr/lib/libpython3.13.so.1.0 #40 0x000075537ce8611a in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #41 0x000075537cf65ae5 in ??? () at /usr/lib/libpython3.13.so.1.0 #42 0x000075537cf65ca0 in ??? () at /usr/lib/libpython3.13.so.1.0 #43 0x000075537cffeb75 in ??? () at /usr/lib/libpython3.13.so.1.0 #44 0x000075537cf657c4 in _PyObject_MakeTpCall () at /usr/lib/libpython3.13.so.1.0 #45 0x000075537ce8611a in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #46 0x000075537d154351 in PyEval_EvalCode () at /usr/lib/libpython3.13.so.1.0 #47 0x000075537d164964 in ??? () at /usr/lib/libpython3.13.so.1.0 #48 0x000075537cf16f59 in ??? () at /usr/lib/libpython3.13.so.1.0 #49 0x000075537cf6a019 in PyObject_Vectorcall () at /usr/lib/libpython3.13.so.1.0 #50 0x000075537ce80b3b in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.13.so.1.0 #51 0x000075537d14ce58 in ??? () at /usr/lib/libpython3.13.so.1.0 #52 0x000075537d15d2b2 in Py_RunMain () at /usr/lib/libpython3.13.so.1.0 #53 0x000075537cc43cd0 in ??? () at /usr/lib/libc.so.6 #54 0x000075537cc43d8a in __libc_start_main () at /usr/lib/libc.so.6 #55 0x00005e6f999f2055 in _start () ```

Currently building a --with-pydebug Python to investigate further.

The-Compiler commented 1 month ago

Weird str.replace failures

Perhaps related to above (memory corruption?). Does not reproduce when rerunning just test_messageview.py alone..

_______________________________________________________ test_show_message_twice_after_first_disappears _______________________________________________________
tests/unit/mainwindow/test_messageview.py:158: Failure: Qt messages with level WARNING or above emitted
-------------------------------------------------------------------- Captured Qt messages --------------------------------------------------------------------
QtWarningMsg: Could not parse stylesheet of object Message(0x5e6fa16ca7f0)
QtWarningMsg: Could not parse stylesheet of object Message(0x5e6fa16ca7f0)
QtWarningMsg: Could not parse stylesheet of object Message(0x5e6fa16ca7f0)
QtWarningMsg: Could not parse stylesheet of object Message(0x5e6fa2906ef0)
QtWarningMsg: Could not parse stylesheet of object Message(0x5e6fa2906ef0)
QtWarningMsg: Could not parse stylesheet of object Message(0x5e6fa2906ef0)
--------------------------------------------------------------------- Captured log setup ---------------------------------------------------------------------
DEBUG    config:config.py:336 Config option changed: messages.timeout = 100
--------------------------------------------------------------------- Captured log call ----------------------------------------------------------------------
VDEBUG   config:log.py:97 stylesheet for Message: 
            padding-top: 2px;
            padding-bottom: 2px;

                background-color: black;
                color: white;
                font: 10pt config.py;
                border-bottom: 1px solid #333333

VDEBUG   config:log.py:97 stylesheet for Message: 
            padding-top: 2px;
            padding-bottom: 2px;

                background-color: black;
                color: white;
                font: 10pt config.py;
                border-bottom: 1px solid #333333

tests/unit/mainwindow/test_messageview.py F

__________________________________________________________ test_changing_timer_with_messages_shown ___________________________________________________________

qtbot = <pytestqt.qtbot.QtBot object at 0x7552ae9d6200>, view = <qutebrowser.mainwindow.messageview.MessageView object at 0x7552acd7fb10>
config_stub = <qutebrowser.config.config.Config object at 0x7552acbe6170>

    def test_changing_timer_with_messages_shown(qtbot, view, config_stub):
        """When we change messages.timeout, the timer should be restarted."""
        config_stub.val.messages.timeout = 900000  # 15s
>       view.show_message(message.MessageInfo(usertypes.MessageLevel.info, 'test'))

tests/unit/mainwindow/test_messageview.py:172: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
qutebrowser/mainwindow/messageview.py:148: in show_message
    widget = Message.from_info(info)
qutebrowser/mainwindow/messageview.py:71: in from_info
    return cls(
qutebrowser/mainwindow/messageview.py:62: in __init__
    stylesheet.set_register(self, qss, update=False)
qutebrowser/config/stylesheet.py:32: in set_register
    observer.register()
qutebrowser/config/stylesheet.py:97: in register
    qss = self._get_stylesheet()
qutebrowser/config/stylesheet.py:86: in _get_stylesheet
    return _render_stylesheet(self._stylesheet)
qutebrowser/config/stylesheet.py:41: in _render_stylesheet
    return template.render(conf=config.val)
.tox/py313-pyqt66/lib/python3.13/site-packages/jinja2/environment.py:1304: in render
    self.environment.handle_exception()
.tox/py313-pyqt66/lib/python3.13/site-packages/jinja2/environment.py:939: in handle_exception
    raise rewrite_traceback_stack(source=source)
<template>:7: in top-level template code
    ???
qutebrowser/utils/jinja.py:117: in getattr
    return getattr(obj, attribute)
qutebrowser/config/config.py:633: in __getattr__
    return self._config.get(name)
qutebrowser/config/config.py:385: in get
    return opt.typ.to_py(obj)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <qutebrowser.config.configtypes.Font completions=None none_ok=False>, value = 'default_size default_family'

    def to_py(self, value: _StrUnset) -> _StrUnsetNone:
        self._basic_py_validation(value, str)
        if isinstance(value, usertypes.Unset):
            return value
        elif not value:
            return None

        if not self.font_regex.fullmatch(value):  # pragma: no cover
            # This should never happen, as the regex always matches everything
            # as family.
            raise configexc.ValidationError(value, "must be a valid font")

        if (value.endswith(' default_family') and
                self.default_family is not None):
>           value = value.replace('default_family', self.default_family)
E           TypeError: replace() argument 2 must be str, not +

qutebrowser/config/configtypes.py:1244: TypeError
The-Compiler commented 1 day ago

Logging private API change

    @pytest.fixture(autouse=True)
    def restore_loggers():
        """Fixture to save/restore the logging state.

        Based on CPython's Lib/test/test_logging.py.
        """
        logging.captureWarnings(False)
        logger_dict = logging.getLogger().manager.loggerDict
>       logging._acquireLock()
E       AttributeError: module 'logging' has no attribute '_acquireLock'

for all tests in tests/unit/utils/test_log.py due to:

Looks like using it as context manager works even in older Python versions.