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

Warning at interpreter exit triggers flood of “ImportWarning: sys.meta_path is empty” #65248

Closed
vadmium opened this issue Mar 24, 2014 · 13 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@vadmium
Copy link
Member

vadmium commented Mar 24, 2014

BPO 21049
Nosy @brettcannon, @pitrou, @vadmium, @pquentin
Superseder
  • bpo-21052: Consider dropping ImportWarning for empty sys.path_hooks and sys.meta_path
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2014-03-24.18:48:22.797>
    created_at = <Date 2014-03-24.06:25:35.387>
    labels = ['type-bug']
    title = 'Warning at interpreter exit triggers flood of \xe2\x80\x9cImportWarning: sys.meta_path is empty\xe2\x80\x9d'
    updated_at = <Date 2014-10-10.14:56:19.749>
    user = 'https://github.com/vadmium'

    bugs.python.org fields:

    activity = <Date 2014-10-10.14:56:19.749>
    actor = 'brett.cannon'
    assignee = 'none'
    closed = True
    closed_date = <Date 2014-03-24.18:48:22.797>
    closer = 'brett.cannon'
    components = []
    creation = <Date 2014-03-24.06:25:35.387>
    creator = 'martin.panter'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 21049
    keywords = []
    message_count = 13.0
    messages = ['214671', '214690', '214697', '214699', '214701', '214704', '214707', '227029', '227426', '228827', '228835', '228875', '229003']
    nosy_count = 4.0
    nosy_names = ['brett.cannon', 'pitrou', 'martin.panter', 'Quentin.Pradet']
    pr_nums = []
    priority = 'normal'
    resolution = 'wont fix'
    stage = None
    status = 'closed'
    superseder = '21052'
    type = 'behavior'
    url = 'https://bugs.python.org/issue21049'
    versions = ['Python 3.5']

    @vadmium
    Copy link
    Member Author

    vadmium commented Mar 24, 2014

    With the code included below, and warnings enabled, I see a flood of unexpected ImportWarnings as the interpreter exits. The issue is seen with Python 3.4.0, but apparently not with 3.3.5.

    The issue originally happened with code using the Py Socks library <https://github.com/Anorov/PySocks\>, which I interrupted because the connect() call was hanging. I have reduced it down to the following code:

    import _socket
    
    class socket(_socket.socket):
        def __init__(self):
            _socket.socket.__init__(self)
            self.attr = self.__init__
            raise Exception()
    
    socket()
    Output from running this code:
    [vadmium@localhost tmp]$ python3 -Wall script.py
    /usr/lib/python3.4/site.py:333: DeprecationWarning: "site-python" directories will not be supported in 3.5 anymore
      DeprecationWarning)
    Traceback (most recent call last):
      File "script.py", line 9, in <module>
        socket()
      File "script.py", line 7, in __init__
        raise Exception()
    Exception
    sys:1: ResourceWarning: unclosed <socket object, fd=3, family=2, type=1, proto=0>
    /tmp/<frozen>:2127: ImportWarning: sys.meta_path is empty
    /tmp/<frozen>:2127: ImportWarning: sys.meta_path is empty
    . . .
    [About two hundred lines]
    . . .
    /tmp/<frozen>:2127: ImportWarning: sys.meta_path is empty
    /tmp/<frozen>:2127: ImportWarning: sys.meta_path is empty
    [Exit 1]
    [vadmium@localhost tmp]$ 

    These seem to be conditions necessary to produce the issue:

    • Instantiate a subclass of “_socket.socket”
    • Assign a bound method to an attribute of the socket object
    • Save the socket object in a local variable of a function, __init__() in my demonstration
    • Raise an exception from the function holding the socket object

    @vadmium vadmium added the type-bug An unexpected behavior, bug, or error label Mar 24, 2014
    @brettcannon
    Copy link
    Member

    This might be a shutdown issue. If you print out what module is being imported at the time of the warning its 'io' and it's only coming up after the script has exited (you will notice the warnings come up after the traceback is printed). My guess is some cleanup code that gets called a lot is trying to import io after shutdown cleanup has blasted sys.meta_path.

    I should also mention that if you raise an exception instead of print the warning nothing shows up, which is another indicator that this is a shutdown-related issue since that could quite easily consume the exception.

    Antoine, any ideas on what might be going on?

    @pitrou
    Copy link
    Member

    pitrou commented Mar 24, 2014

    Well, basically some sys attributes (including meta_path) are cleaned during shutdown, so if some code executes afterwards and tries to import something, importlib will complain that meta_path is empty.

    Unless the warning is genuinely useful, I would suggest simply removing it.

    Printing warnings during import can also degenerate into an infinite recursion, if printing the warning needs to import a module, for example:

    ./python -Wa -c "import sys; sys.meta_path = None; import logging"

    @pitrou
    Copy link
    Member

    pitrou commented Mar 24, 2014

    For a more detailed analysis:

    • the warning gets printed very late because the socket is caught in a reference cycle (self.attr = self), which itself is tied to the exception traceback
    • when the socket is collected, it tries to print a ResourceWarning because it hasn't been closed explicitly (just add self.close() in the constructor to make it disappear)
    • when trying to print the ResourceWarning, it probably wants to import linecache or something, and that breaks

    The only remaining mystery is why there are 200 lines and not just one :-)

    @brettcannon
    Copy link
    Member

    So the import warnings were added for sys.meta_path and sys.path_hooks because prior to Python 3.3 you could empty out those values and import would continue to work, but with importlib that stopped being the case. My thinking was that it would be easier to debug if you got that warning instead of your imports entirely failing and wondering what was going on. But perhaps sys.path_hooks and sys.meta_path are known well enough at this point that the warnings are superfluous. I'll open a separate bug to track that discussion.

    @pitrou
    Copy link
    Member

    pitrou commented Mar 24, 2014

    Of course the use case presented here is very contrived, so we can also choose to not fix it.

    @brettcannon
    Copy link
    Member

    Sure, I'm fine with closing this as "Won't Fix" based on the cause being an edge case and rely on issue bpo-21052 to discuss the value of the ImportWarning.

    Thanks for the report, Martin.

    @vadmium
    Copy link
    Member Author

    vadmium commented Sep 18, 2014

    My original demonstration was distilled from a real world case. I get this issue with other real world cases too, so I am expanding the title to reflect what I think is going on. This problem seems to be caused by a ResourceWarning triggered from a garbage cycle being freed just before Python exits. The flood of ImportWarning lines makes it annoying to scroll up to see what other ResourceWarning messages, exceptions, etc you are missing out on.

    Much simpler one-liner demonstration adapted from Message 222403 (because class definitions create garbage cycles in my experience):

    python3 -Wall -c 'class C: a = open("/dev/null")'

    The best workaround is probably to use “python -Wdefault” rather than “python -Wall”. Then you only get one ImportWarning line.

    I suspect the problem might be caused by a recursive loop between emitting a warning and importing something, as Antoine hinted. Calling sys.setrecursionlimit(30) reduces the flood to 5 lines. Unfortunately my modifications to “importlib/_bootstrap.py” and “warnings.py” on my OS are not having any effect, otherwise I might try to make a patch.

    Perhaps if it is not appropriate for the ImportWarning to be removed, could the code printing out the warning be changed to avoid triggering it in the first place?

    @vadmium vadmium changed the title Flood of “ImportWarning: sys.meta_path is empty” after exception with socket subclass Warning at interpreter exit triggers flood of “ImportWarning: sys.meta_path is empty” Sep 18, 2014
    @pquentin
    Copy link
    Mannequin

    pquentin mannequin commented Sep 24, 2014

    I've also been affected by this when testing integration with a third-party library (NLTK). NLTK does need to be fixed, but the ResourceWarning already say so.

    The new one-liner doesn't seem contrived to me.

    @vadmium
    Copy link
    Member Author

    vadmium commented Oct 9, 2014

    Quentin, do you think this should be reopened?

    Brett Cannon, I wonder if the only reason you closed this bug is because you thought the scenario to trigger it is very unlikely. Considering it affected someone else, and that there are other real-world triggers in addition to Py Socks, would it be okay to reopen it? I could try to make a patch or some concrete suggestions when I have a chance, if that helps change your mind :)

    Perhaps a regression test could be based on this experiment:

    >>> import sys, warnings
    >>> sys.meta_path = None
    >>> sys.modules.pop("linecache", None)
    <module 'linecache' from '/usr/lib/python3.4/linecache.py'>
    >>> warnings.warn("boom")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib/python3.4/warnings.py", line 15, in showwarning
        file.write(formatwarning(message, category, filename, lineno, line))
      File "/usr/lib/python3.4/warnings.py", line 21, in formatwarning
        import linecache
      File "/home/proj/python/lib/misc.py", line 41, in __call__
        return self.__wrapped__(name, globals, locals, fromlist, level)
      File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
      File "<frozen importlib._bootstrap>", line 2222, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 2150, in _find_spec
      File "/usr/lib/python3.4/warnings.py", line 15, in showwarning
        file.write(formatwarning(message, category, filename, lineno, line))
    . . .
      File "<frozen importlib._bootstrap>", line 2236, in _find_and_load
    RuntimeError: maximum recursion depth exceeded while calling a Python object

    @pquentin
    Copy link
    Mannequin

    pquentin mannequin commented Oct 9, 2014

    Martin, yes, I'd be glad to see a fix if it's not too complicated.

    @brettcannon
    Copy link
    Member

    I'm already planning to look into this problem in issue bpo-21052 so feel free to follow over there.

    @brettcannon
    Copy link
    Member

    This has now been fixed in https://hg.python.org/cpython/rev/d9f71bc6d897 . Thanks to everyone who helped with the bug report!

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants