Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to filter warnings due to call stack and partial #3503

Open
gitlab-importer opened this issue Jul 4, 2021 · 2 comments
Open

Unable to filter warnings due to call stack and partial #3503

gitlab-importer opened this issue Jul 4, 2021 · 2 comments

Comments

@gitlab-importer
Copy link

In Heptapod by @jaraco on Jul 4, 2021, 23:53

importlib_metadata 3.9 introduced this deprecation. As you can see in the call, the warning is issued with a stacklevel of 2, and on CPython, this stack level causes the warning to attach to the correct caller of the deprecated methods. On PyPy, however, the call stack is different and thus the errors can't be ignored based on the module where the usage occurs.

I've replicated the issue with this script:

__requires__ = ['importlib_metadata >= 3.9']

import warnings

import importlib_metadata as md


def lookup():
    md.entry_points().get('foo')


def main():
    warnings.filterwarnings('error')
    warnings.filterwarnings('ignore', category=DeprecationWarning, module='__main__')
    lookup()


__name__ == '__main__' and main()

Run it with CPython and it passes, but run it with PyPy and it fails with:

Traceback (most recent call last):
  File "test_suppress_warning.py", line 18, in <module>
    __name__ == '__main__' and main()
  File "test_suppress_warning.py", line 15, in main
    lookup()
  File "test_suppress_warning.py", line 9, in lookup
    md.entry_points().get('foo')
  File "/usr/local/Cellar/pypy3/7.3.4/libexec/site-packages/importlib_metadata/__init__.py", line 405, in get
    self._warn()
  File "/usr/local/Cellar/pypy3/7.3.4/libexec/lib_pypy/_functools.py", line 80, in __call__
    return self._func(*(self._args + fargs), **fkeywords)
DeprecationWarning: SelectableGroups dict interface is deprecated. Use select.

The exception occurs because the 'ignore' filter failed to match the caller's module.

The issue can be replicated without importlib_metadata with these two files:

# other.py
import functools
import warnings

do_warn = functools.partial(
    warnings.warn,
    "Do something else",
    DeprecationWarning,
    stacklevel=2,
)


def lookup():
    do_warn()
# test.py
import warnings

from other import lookup


def main():
    warnings.filterwarnings('error')
    warnings.filterwarnings('ignore', category=DeprecationWarning, module='__main__')
    lookup()


__name__ == '__main__' and main()

Run pypy test.py and it fails, but succeeds on CPython.

Traceback (most recent call last):
  File "test_suppress_warning.py", line 12, in <module>
    __name__ == '__main__' and main()
  File "test_suppress_warning.py", line 9, in main
    lookup()
  File "/Users/jaraco/code/public/pypa/setuptools/other.py", line 13, in lookup
    do_warn()
  File "/usr/local/Cellar/pypy3/7.3.4/libexec/lib_pypy/_functools.py", line 80, in __call__
    return self._func(*(self._args + fargs), **fkeywords)
DeprecationWarning: Do something else

The impact of this mismatch is that users wishing to suppress this deprecation warning are unable to do so consistently across CPython and PyPy and moreover are unable to address the deprecation warning by caller (the module always looks like importlib_metadata on PyPy).

Is there anything to be done?

@gitlab-importer
Copy link
Author

In Heptapod by @jaraco on Jul 4, 2021, 23:59

Oh. Now that I think about it, the solution might be to set different stack levels based on Python implementations:

# other.py
import functools
import warnings
import platform


is_pypy = platform.python_implementation() == 'PyPy'


do_warn = functools.partial(
    warnings.warn,
    "Do something else",
    DeprecationWarning,
    stacklevel=2 + is_pypy,
)


def lookup():
    do_warn()

With this change, now the behavior is the same on both Pythons. Is that the best approach?

@gitlab-importer
Copy link
Author

In Heptapod by @jaraco on Jul 5, 2021, 01:21

I opened python/importlib_metadata#327 to track the workaround, and I've demonstrated that the workaround works.

I'm still interested in feedback on the underlying behavior. Is it something that PyPy would want to address? I'm not even sure I know how it could. Happy to answer questions or explore solutions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant