Skip to content

Using 'filterwarnings' hides ModuleNotFoundErrors #9218

@di

Description

@di

From time to time on https://github.com/pypa/warehouse, we have an issue where pytest invocation fails due to ModuleNotFoundErrors in our source, but the actual ModuleNotFoundError is hidden by our usage of filterwarnings.

Our pyproject.toml configuration specifies a warning to ignore:

[tool.pytest.ini_options]
filterwarnings = [
    'ignore::warehouse.packaging.services.InsecureStorageWarning',
]

Invoking pytest raises an exception:

$ python -m pytest
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/local/lib/python3.8/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/opt/warehouse/lib/python3.8/site-packages/pytest/__main__.py", line 5, in <module>
    raise SystemExit(pytest.console_main())
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/config/__init__.py", line 185, in console_main
    code = main()
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/config/__init__.py", line 143, in main
    config = _prepareconfig(args, plugins)
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/config/__init__.py", line 318, in _prepareconfig
    config = pluginmanager.hook.pytest_cmdline_parse(
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_callers.py", line 55, in _multicall
    gen.send(outcome)
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/helpconfig.py", line 100, in pytest_cmdline_parse
    config: Config = outcome.get_result()
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_result.py", line 60, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/config/__init__.py", line 1003, in pytest_cmdline_parse
    self.parse(args)
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/config/__init__.py", line 1283, in parse
    self._preparse(args, addopts=addopts)
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/config/__init__.py", line 1191, in _preparse
    self.hook.pytest_load_initial_conftests(
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_callers.py", line 60, in _multicall
    return outcome.get_result()
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_result.py", line 60, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/opt/warehouse/lib/python3.8/site-packages/pluggy/_callers.py", line 34, in _multicall
    next(gen)  # first yield
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/warnings.py", line 136, in pytest_load_initial_conftests
    with catch_warnings_for_item(
  File "/usr/local/lib/python3.8/contextlib.py", line 113, in __enter__
    return next(self.gen)
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/warnings.py", line 52, in catch_warnings_for_item
    apply_warning_filters(config_filters, cmdline_filters)
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/config/__init__.py", line 1603, in apply_warning_filters
    warnings.filterwarnings(*parse_warning_filter(arg, escape=False))
  File "/opt/warehouse/lib/python3.8/site-packages/_pytest/config/__init__.py", line 1579, in parse_warning_filter
    category: Type[Warning] = warnings._getcategory(category_)  # type: ignore[attr-defined]
  File "/usr/local/lib/python3.8/warnings.py", line 262, in _getcategory
    raise _OptionError("invalid module name: %r" % (module,)) from None
warnings._OptionError: invalid module name: 'warehouse.packaging.services'

However the actual issue is that there is some ModuleNotFoundError happening that we need to fix:

$ python warehouse/packaging/services.py
Traceback (most recent call last):
  File "warehouse/packaging/services.py", line 23, in <module>
    from warehouse.packaging.interfaces import IDocsStorage, IFileStorage
  File "/opt/warehouse/src/warehouse/packaging/__init__.py", line 17, in <module>
    from warehouse.accounts.models import Email, User
  File "/opt/warehouse/src/warehouse/accounts/__init__.py", line 28, in <module>
    from warehouse.accounts.services import (
  File "/opt/warehouse/src/warehouse/accounts/services.py", line 29, in <module>
    import warehouse.utils.webauthn as webauthn
  File "/opt/warehouse/src/warehouse/utils/webauthn.py", line 18, in <module>
    from webauthn.webauthn import (
ModuleNotFoundError: No module named 'webauthn.webauthn'

Ideally, invoking pytest would raise the ModuleNotFoundError or something similar, instead of a unhelpful warnings._OptionError.

This could be done by attempting to import the class in question before calling this line:

category: Type[Warning] = warnings._getcategory(category_) # type: ignore[attr-defined]

This happens with this set of requirements, on Python 3.8 (but also other Python and pytest versions).

(Somewhat related: #7877 and #8343)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions