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

NamedTemporaryFile does not generate a ResourceWarning for unclosed files (unlike TemporaryFile) #73053

Open
jdufresne mannequin opened this issue Dec 4, 2016 · 12 comments
Labels
3.7 (EOL) end of life stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@jdufresne
Copy link
Mannequin

jdufresne mannequin commented Dec 4, 2016

BPO 28867
Nosy @vstinner, @bitdancer, @jdufresne
PRs
  • bpo-28867: Warn when NamedTemporaryFile is not explicitly closed #1936
  • Files
  • namedtemporaryfile-resourcewarning.patch: Patch to add ResourceWarning to NamedTemporaryFile
  • namedtemporaryfile-resourcewarning-2.patch: Updated patch
  • namedtemporaryfile-resourcewarning-3.patch: Patch take 3
  • namedtemporaryfile-resourcewarning-4.patch: Patch take 4
  • 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 = None
    created_at = <Date 2016-12-04.17:47:27.371>
    labels = ['3.7', 'type-bug', 'library']
    title = 'NamedTemporaryFile does not generate a ResourceWarning for unclosed files (unlike TemporaryFile)'
    updated_at = <Date 2017-06-04.03:13:36.750>
    user = 'https://github.com/jdufresne'

    bugs.python.org fields:

    activity = <Date 2017-06-04.03:13:36.750>
    actor = 'jdufresne'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2016-12-04.17:47:27.371>
    creator = 'jdufresne'
    dependencies = []
    files = ['45783', '45789', '45851', '45852']
    hgrepos = []
    issue_num = 28867
    keywords = ['patch']
    message_count = 11.0
    messages = ['282352', '282355', '282360', '282366', '282372', '282599', '282629', '282630', '282631', '282933', '282955']
    nosy_count = 4.0
    nosy_names = ['vstinner', 'r.david.murray', 'SilentGhost', 'jdufresne']
    pr_nums = ['1936']
    priority = 'normal'
    resolution = None
    stage = 'needs patch'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue28867'
    versions = ['Python 3.6', 'Python 3.7']

    @jdufresne
    Copy link
    Mannequin Author

    jdufresne mannequin commented Dec 4, 2016

    When using unittest, I'll frequently enable -Wall to help catch code smells and potential bugs.

    One feature of this, I'm told when files aren't explicitly closed with an error like: "ResourceWarning: unclosed file <...>". I've noticed this warning is generated for an unclosed tempfile.TemporaryFile (good), but not for an unclosed tempfile.NamedTemporaryFile (possible bug).

    I've verified this on Python 3.5 and 3.6.

    Example test:

    import tempfile
    import unittest
    
    
    class MyTest(unittest.TestCase):
        def test_temporary_file(self):
            tempfile.TemporaryFile()
    
        def test_named_temporary_file(self):
            tempfile.NamedTemporaryFile()
    

    Actual output:

    $ Python-3.6.0b4/python --version
    Python 3.6.0b4
    $ Python-3.6.0b4/python -Wall -m unittest -v test
    test_named_temporary_file (test.MyTest) ... ok
    test_temporary_file (test.MyTest) ... /home/jon/test.py:7: ResourceWarning: unclosed file <_io.BufferedRandom name=3>
      tempfile.TemporaryFile()
    ok
    
    ----------------------------------------------------------------------
    Ran 2 tests in 0.004s
    
    OK
    
    

    Expected:

    I expect both tests to generate a ResourceWarning, as neither test explicitly closes the file.

    @jdufresne jdufresne mannequin added stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error labels Dec 4, 2016
    @SilentGhost
    Copy link
    Mannequin

    SilentGhost mannequin commented Dec 4, 2016

    Looking at the code it seems NamedTemporaryFile is closed on destruction of the object, so there is no need for ResourceWarning, because the file descriptor is not leaking.

    You also don't need to involve unittest here. Just running python with -Wall would generate a warning if there is a need for one.

    @bitdancer
    Copy link
    Member

    The point of ResourceWarning it tell you when you are depending on destructors for cleanup, so this does look like a bug.

    @SilentGhost
    Copy link
    Mannequin

    SilentGhost mannequin commented Dec 4, 2016

    The point of ResourceWarning it tell you when you are depending on destructors for cleanup
    But there is an explicit call in __del__ to .close(), it's looks like intended behaviour and is ultimately the difference that Jon was seeing between NamedTemporaryFile and TemporaryFile.

    @bitdancer
    Copy link
    Member

    __del__ is a destructor. If the file is open when it is called, it should emit a ResourceWarning.

    @SilentGhost
    Copy link
    Mannequin

    SilentGhost mannequin commented Dec 7, 2016

    The ResourceWarning that you've introduced need to be "fixed" in a few place in test_urllib2

    @SilentGhost SilentGhost mannequin added the 3.7 (EOL) end of life label Dec 7, 2016
    @jdufresne
    Copy link
    Mannequin Author

    jdufresne mannequin commented Dec 7, 2016

    Thanks for the review. I have updated the patch. Now all warnings during tests handled. Please let me know if there are any other concerns with the changes.

    @bitdancer
    Copy link
    Member

    Hmm. That e.close() looks like there may be a deeper problem here. I don't have time to investigate myself, unfortunately.

    @jdufresne
    Copy link
    Mannequin Author

    jdufresne mannequin commented Dec 7, 2016

    Just for some context, the e.close() is handling this bit of code:

    # loop detection
    # .redirect_dict has a key url if url was previously visited.
    if hasattr(req, 'redirect_dict'):
    visited = new.redirect_dict = req.redirect_dict
    if (visited.get(newurl, 0) >= self.max_repeats or
    len(visited) >= self.max_redirections):
    raise HTTPError(req.full_url, code,
    self.inf_msg + msg, headers, fp)
    else:
    visited = new.redirect_dict = req.redirect_dict = {}
    visited[newurl] = visited.get(newurl, 0) + 1
    # Don't close the fp until we are sure that we won't use it
    # with HTTPError.
    fp.read()
    fp.close()

    When there is no error, http_error_302() will close the passed fp, on error, it will not. The following comment indicates this is intentional:

    # Don't close the fp until we are sure that we won't use it
    # with HTTPError.

    But I agree, this may pose a problem when enforcing deterministic resource handling.

    @jdufresne
    Copy link
    Mannequin Author

    jdufresne mannequin commented Dec 11, 2016

    I've taken a new approach to resolve the urllib issues.

    I believe HTTPError _should not_ warn when __del__ is called as HTTPError wraps an existing resource instead of generating its own. IIUC, in this case, I believe it falls to the responsibility of code generating the resource to properly close and manage the resource (or pass that responsibility along). If I misunderstood, please let me know.

    All feedback on the patch is welcome, thanks.

    @jdufresne
    Copy link
    Mannequin Author

    jdufresne mannequin commented Dec 12, 2016

    I decided to try a new direction.

    Instead of modifying _TemporaryFileCloser to handle urllib, I've changed urllib classes to not inherit from _TemporaryFileCloser. The urllib classes are not temporary files as built by tempfile, so I believe this makes more sense. There is a small amount of code copied to the existing class, but I believe this cleans up the inheritance in a way that makes more sense for the given objects and requires fewer workarounds.

    All feedback on this alternative approach is welcome. Thanks.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    @mmerickel
    Copy link

    mmerickel commented Mar 28, 2023

    Just to bump this because it's been inactive for 7 years ... similar to #103070, NamedTemporaryFile really should be emitting a proper ResourceWarning as this ticket notes, and it should point at user code to help folks track down the call sites. The changes in #1936 seemed to be generally correct, but were lost because the PR was focused on urllib instead of tempfile.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    Status: No status
    Development

    No branches or pull requests

    2 participants