Mayil-AI-Sandbox / loguru-Jan2023

MIT License
0 stars 0 forks source link

The test suite crashes pytest on Python 3.11.0b1 (hashtag654) #68

Closed vikramsubramanian closed 2 weeks ago

vikramsubramanian commented 2 weeks ago
$ tox -e py311
GLOB sdist-make: /tmp/loguru/setup.py
py311 create: /tmp/loguru/.tox/py311
py311 inst: /tmp/loguru/.tox/.tmp/package/1/loguru-0.6.0.zip
py311 installed: alabaster==0.7.12,attrs==21.4.0,Babel==2.10.1,black==22.3.0,certifi==2021.10.8,charset-normalizer==2.0.12,click==8.1.3,colorama==0.4.4,coverage==6.3.2,distlib==0.3.4,docutils==0.16,filelock==3.6.0,flake8==4.0.1,freezegun==1.1.0,idna==3.3,imagesize==1.3.0,iniconfig==1.1.1,isort==5.10.1,Jinja2==3.1.2,livereload==2.6.3,loguru==0.6.0,MarkupSafe==2.1.1,mccabe==0.6.1,mypy-extensions==0.4.3,packaging==21.3,pathspec==0.9.0,platformdirs==2.5.2,pluggy==1.0.0,py==1.11.0,pycodestyle==2.8.0,pyflakes==2.4.0,Pygments==2.12.0,pyparsing==3.0.9,pytest==7.1.2,pytest-cov==3.0.0,python-dateutil==2.8.2,pytz==2022.1,requests==2.27.1,six==1.16.0,snowballstemmer==2.2.0,Sphinx==4.5.0,sphinx-autobuild==2021.3.14,sphinx-rtd-theme==1.0.0,sphinxcontrib-applehelp==1.0.2,sphinxcontrib-devhelp==1.0.2,sphinxcontrib-htmlhelp==2.0.0,sphinxcontrib-jsmath==1.0.1,sphinxcontrib-qthelp==1.0.3,sphinxcontrib-serializinghtml==1.1.5,toml==0.10.2,tomli==2.0.1,tornado==6.1,tox==3.25.0,urllib3==1.26.9,virtualenv==20.14.1
py311 run-test-pre: PYTHONHASHSEED='300318784'
py311 run-test: commands[0] | flake8 --exit-zero loguru tests docs setup.py
py311 run-test: commands[1] | pytest --cov loguru/ --cov-report=xml
========================================================= test session starts =========================================================
platform linux -- Python 3.11.0b1, pytest-7.1.2, pluggy-1.0.0
cachedir: .tox/py311/.pytest_cache
rootdir: /tmp/loguru, configfile: tox.ini
plugins: cov-3.0.0
collected 1392 items                                                                                                                  

tests/test_activation.py ..............................                                                                         [  2%]
tests/test_add_option_backtrace.py .                                                                                            [  2%]
tests/test_add_option_catch.py ...........                                                                                      [  3%]
tests/test_add_option_colorize.py ...........................................................                                   [  7%]
tests/test_add_option_diagnose.py .                                                                                             [  7%]
tests/test_add_option_enqueue.py ............s                                                                                  [  8%]
tests/test_add_option_filter.py .......................................................                                         [ 12%]
tests/test_add_option_format.py ....................                                                                            [ 13%]
tests/test_add_option_kwargs.py .......                                                                                         [ 14%]
tests/test_add_option_level.py ..........                                                                                       [ 14%]
tests/test_add_option_serialize.py .........                                                                                    [ 15%]
tests/test_add_sinks.py .......................................................                                                 [ 19%]
tests/test_ansimarkup_basic.py ........................................................................................         [ 25%]
tests/test_ansimarkup_extended.py ............................................................................................  [ 32%]
tests/test_bind.py .........                                                                                                    [ 33%]
tests/test_configure.py ................                                                                                        [ 34%]
tests/test_contextualize.py ..............                                                                                      [ 35%]
tests/test_coroutine_sink.py ...............................                                                                    [ 37%]
tests/test_datetime.py ................................                                                                         [ 39%]
tests/test_deepcopy.py ....                                                                                                     [ 40%]
tests/test_defaults.py .............                                                                                            [ 40%]
tests/test_exceptions_catch.py ..................................................                                               [ 44%]
tests/test_exceptions_formatting.py ............................................................................                [ 50%]
tests/test_filesink_compression.py ......................................................                                       [ 53%]
tests/test_filesink_delay.py ..........                                                                                         [ 54%]
tests/test_filesink_permissions.py ..........                                                                                   [ 55%]
tests/test_filesink_retention.py .................................................                                              [ 58%]
tests/test_filesink_rotation.py .........
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/main.py", line 268, in wrap_session
INTERNALERROR>     session.exitstatus = doit(config, session) or 0
INTERNALERROR>                          ^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/main.py", line 322, in _main
INTERNALERROR>     config.hook.pytest_runtestloop(session=session)
INTERNALERROR>     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/main.py", line 347, in pytest_runtestloop
INTERNALERROR>     item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR>     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/runner.py", line 111, in pytest_runtest_protocol
INTERNALERROR>     runtestprotocol(item, nextitem=nextitem)
INTERNALERROR>     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/runner.py", line 124, in runtestprotocol
INTERNALERROR>     rep = call_and_report(item, "setup", log)
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/runner.py", line 221, in call_and_report
INTERNALERROR>     report: TestReport = hook.pytest_runtest_makereport(item=item, call=call)
INTERNALERROR>                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 55, in _multicall
INTERNALERROR>     gen.send(outcome)
INTERNALERROR>     ^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/skipping.py", line 265, in pytest_runtest_makereport
INTERNALERROR>     rep = outcome.get_result()
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/runner.py", line 365, in pytest_runtest_makereport
INTERNALERROR>     return TestReport.from_item_and_call(item, call)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/reports.py", line 347, in from_item_and_call
INTERNALERROR>     longrepr = item._repr_failure_py(
INTERNALERROR>                ^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/nodes.py", line 447, in _repr_failure_py
INTERNALERROR>     self._prunetraceback(excinfo)
INTERNALERROR>     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/python.py", line 1769, in _prunetraceback
INTERNALERROR>     path, firstlineno = code.path, code.firstlineno
INTERNALERROR>                         ^^^^^^^^^
INTERNALERROR>   File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/_code/code.py", line 95, in path
INTERNALERROR>     if not p.exists():
INTERNALERROR>            ^^^^^^^^^^
INTERNALERROR>   File "/usr/lib/python3.11/pathlib.py", line 1233, in exists
INTERNALERROR>     self.stat()
INTERNALERROR>     ^^^^^^^^^^^
INTERNALERROR>   File "/usr/lib/python3.11/pathlib.py", line 1011, in stat
INTERNALERROR>     return os.stat(self, follow_symlinks=follow_symlinks)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR> TypeError: monkeypatch_filesystem.<locals>.monkeypatch_filesystem.<locals>.patched_stat() got an unexpected keyword argument 'follow_symlinks'
Traceback (most recent call last):
  File "/tmp/loguru/.tox/py311/bin/pytest", line 8, in <module>
    sys.exit(console_main())
             ^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/config/__init__.py", line 187, in console_main
    code = main()
           ^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/config/__init__.py", line 164, in main
    ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 60, in _multicall
    return outcome.get_result()
           ^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
    raise ex[1].with_traceback(ex[2])
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/main.py", line 315, in pytest_cmdline_main
    return wrap_session(config, _main)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/main.py", line 303, in wrap_session
    config.hook.pytest_sessionfinish(
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 55, in _multicall
    gen.send(outcome)
    ^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/terminal.py", line 798, in pytest_sessionfinish
    outcome.get_result()
    ^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
    raise ex[1].with_traceback(ex[2])
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/cacheprovider.py", line 433, in pytest_sessionfinish
    config.cache.set("cache/nodeids", sorted(self.cached_nodeids))
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/cacheprovider.py", line 177, in set
    if path.parent.is_dir():
       ^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/pathlib.py", line 1248, in is_dir
    return S_ISDIR(self.stat().st_mode)
                   ^^^^^^^^^^^
  File "/usr/lib/python3.11/pathlib.py", line 1011, in stat
    return os.stat(self, follow_symlinks=follow_symlinks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: monkeypatch_filesystem.<locals>.monkeypatch_filesystem.<locals>.patched_stat() got an unexpected keyword argument 'follow_symlinks'
Exception ignored in atexit callback: <function cleanup_numbered_dir at 0x7fb8aab2c220>
Traceback (most recent call last):
  File "/tmp/loguru/.tox/py311/lib/python3.11/site-packages/_pytest/pathlib.py", line 344, in cleanup_numbered_dir
    for path in root.glob("garbage-*"):
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/pathlib.py", line 951, in glob
    for p in selector.select_from(self):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/pathlib.py", line 320, in select_from
    if not is_dir(parent_path):
           ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/pathlib.py", line 1248, in is_dir
    return S_ISDIR(self.stat().st_mode)
                   ^^^^^^^^^^^
  File "/usr/lib/python3.11/pathlib.py", line 1011, in stat
    return os.stat(self, follow_symlinks=follow_symlinks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: monkeypatch_filesystem.<locals>.monkeypatch_filesystem.<locals>.patched_stat() got an unexpected keyword argument 'follow_symlinks'
ERROR: InvocationError for command /tmp/loguru/.tox/py311/bin/pytest --cov loguru/ --cov-report=xml (exited with code 1)
_______________________________________________________________ summary _______________________________________________________________
ERROR:   py311: commands failed
vikramsubramanian commented 2 weeks ago

Thanks for pointing this out. :+1:

I'll investigate it and fix it before official 3.11 release.

vikramsubramanian commented 2 weeks ago

Fixed on master. The 3.11 version was also added to CI tests.

The reported error due to patched_stat() was an easy fix (missing arguments).

However, the 3.11 version also "breaks" the InterceptHandler implementation due to Users must update their existing InterceptHandler while upgrading to 3.11 (replace logging.currentframe() with sys._getframe()).

vikramsubramanian commented 2 weeks ago

can you please create a release that has this fix? We're currently rebuilding all Python packages against 3.11 on Arch Linux and I am now running into this problem.

vikramsubramanian commented 2 weeks ago

I just published 0.7.0.

vikramsubramanian commented 2 weeks ago

The same problem afflicted me a whole aftertoon ...

vikramsubramanian commented 2 weeks ago

Users must update their existing InterceptHandler while upgrading to 3.11 (replace logging.currentframe() with sys._getframe()).

All my QA tools including my IDE warns against using _getframe() as it's an [implementation detail]( which I tend to agree on.

So I looked for an alternative and came up with this, where we immediatly start on the 6th frame. Based on my testing using this method and the current method, I get the same results (please confirm).

depth = 6
frame: FrameType | None = inspect.getouterframes(inspect.currentframe())[depth].frame

Would this be a better choice to use for the InterceptHandler() example as it's more robust?

vikramsubramanian commented 2 weeks ago

The point of using _getframe(6) was to access the 6th frame directly and avoid iterating through intermediate frames. Using inspect.getouterframes() will cause them to be iterated and indexed anyway, so we could as well just refactor InterceptHandler to start iteration at the 1st frame.

hashtag Find caller from where originated the logged message.
frame, depth = inspect.currentframe(), 0
while frame and (depth == 0 or frame.f_code.co_filename == logging.__file__):
    frame = frame.f_back
    depth += 1

This looks a bit more straightforward. This shouldn't impact performance too much. Eventually, I plan to replace InterceptHandler with a built-in logger.bridge() method anyway.