[issue45833] NamedTemporaryFile deleted before enclosing context manager exit
New submission from Brian McCutchon : Consider the following code: # Copyright 2021 Google LLC. # SPDX-License-Identifier: Apache-2.0 import contextlib import os @contextlib.contextmanager def my_tmp_file(): with tempfile.NamedTemporaryFile('w') as f: yield f os.stat(my_tmp_file().__enter__().name) # File not found os.stat(contextlib.ExitStack().enter_context(my_tmp_file()).name) # Same I would expect the file to still exist, as __exit__ has not been called and I can't see why the file would have been closed. Also, it performs as expected when using NamedTemporaryFile directly, but not when it is nested in another context manager. It also performs as expected when my_tmp_file() or contextlib.ExitStack() is used in a "with" statement. -- components: Library (Lib) messages: 406494 nosy: Brian McCutchon priority: normal severity: normal status: open title: NamedTemporaryFile deleted before enclosing context manager exit type: behavior versions: Python 3.9 ___ Python tracker <https://bugs.python.org/issue45833> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36395] Add deferred single-threaded/fake executor to concurrent.futures
New submission from Brian McCutchon : Currently, it is possible to make a basic single-threaded executor for unit testing: class FakeExecutor(futures.Executor): def submit(self, f, *args, **kwargs): future = futures.Future() future.set_result(f(*args, **kwargs)) return future def shutdown(self, wait=True): pass However, this evaluates the provided function eagerly, which may be undesirable for tests. It prevents the tests from catching a whole class of errors (those where the caller forgot to call .result() on a future that is only desirable for its side-effects). It would be great to have an Executor implementation where the function is only called when .result() is called so tests can catch those errors. I might add that, while future.set_result is documented as being supported for unit tests, a comment in the CPython source says that Future.__init__() "Should not be called by clients" (https://github.com/python/cpython/blob/master/Lib/concurrent/futures/_base.py#L317), suggesting that even the above code is unsupported and leaving me wondering how I should test future-heavy code without using mock.patch on everything. -- Alternatives that don't work -- One might think it possible to create a FakeFuture to do this: class FakeFuture(object): def __init__(self, to_invoke): self._to_invoke = to_invoke def result(self, timeout=None): return self._to_invoke() However, futures.wait is not happy with this: futures.wait([FakeFuture(lambda x: 1)]) # AttributeError: 'FakeFuture' object has no attribute '_condition' If FakeFuture is made to extend futures.Future, the above line instead hangs: class FakeFuture(futures.Future): def __init__(self, to_invoke): super(FakeFuture, self).__init__() self._to_invoke = to_invoke def result(self, timeout=None): return self._to_invoke() I feel like I shouldn't have to patch out wait() in order to get good unit tests. -- messages: 338576 nosy: Brian McCutchon priority: normal severity: normal status: open title: Add deferred single-threaded/fake executor to concurrent.futures type: enhancement versions: Python 3.7 ___ Python tracker <https://bugs.python.org/issue36395> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36395] Add deferred single-threaded/fake executor to concurrent.futures
Brian McCutchon added the comment: Mostly nondeterminism. It seems like creating a ThreadPoolExecutor with one worker could still be nondeterministic, as there are two threads: the main thread and the worker thread. It gets worse if multiple executors are needed. Another option would be to design and document futures.Executor to be extended so that I can make my own fake executor. -- ___ Python tracker <https://bugs.python.org/issue36395> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36395] Add deferred single-threaded/fake executor to concurrent.futures
Brian McCutchon added the comment: I understand your hesitation to add a fake. Would it be better to make it possible to subclass Executor so that a third party implementation of this can be developed? As for an example, here is an example of nondeterminism when using a ThreadPoolExecutor with a single worker. It sometimes prints "False" and sometimes "True" on my machine. from concurrent import futures import time complete = False def complete_eventually(): global complete for _ in range(15): pass complete = True with futures.ThreadPoolExecutor(max_workers=1) as pool: pool.submit(complete_eventually) print(complete) -- ___ Python tracker <https://bugs.python.org/issue36395> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36395] Add deferred single-threaded/fake executor to concurrent.futures
Brian McCutchon added the comment: No, I do not have such an example, as most of my tests try to fake the executors. -- ___ Python tracker <https://bugs.python.org/issue36395> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com