Bug 2466672
| Summary: | python-futurist fails to build with Python 3.15: 3 tests failures with FileNotFoundError: [Errno 2] No such file or directory | ||
|---|---|---|---|
| Product: | [Fedora] Fedora | Reporter: | Karolina Surma <ksurma> |
| Component: | python-futurist | Assignee: | Javier Peña <jpena> |
| Status: | CLOSED ERRATA | QA Contact: | Fedora Extras Quality Assurance <extras-qa> |
| Severity: | unspecified | Docs Contact: | |
| Priority: | unspecified | ||
| Version: | rawhide | CC: | apevec, jpena, jruzicka.pkg, ksurma, mhroncok, openstack-sig, steve.traylen |
| Target Milestone: | --- | ||
| Target Release: | --- | ||
| Hardware: | Unspecified | ||
| OS: | Unspecified | ||
| Whiteboard: | |||
| Fixed In Version: | python-futurist-3.3.0-3.fc45 | Doc Type: | --- |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2026-05-18 19:35:14 UTC | Type: | Bug |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
| Bug Depends On: | |||
| Bug Blocks: | 2412434 | ||
https://src.fedoraproject.org/rpms/python-futurist/pull-request/2 Really not sure about this... These tests have broken also 3.14.4 -> 3.15.5 as well. https://github.com/python/cpython/issues/140734 feels related. (In reply to Steve Traylen from comment #2) > These tests have broken also 3.14.4 -> 3.15.5 as well. > That should have read. These tests have broken also 3.14.4 -> 3.14.5 as well. > https://github.com/python/cpython/issues/140734 > > feels related. Test case, this now fails with 3.14.5 as well as the new 3.15.
Certainly it does run okay for F44 python 3.14 version.
#!/usr/bin/env python3
import concurrent.futures
def returns_one():
return 1
if __name__ == '__main__':
for i in range(10):
print(f"Run {i}...")
with concurrent.futures.ProcessPoolExecutor() as executor:
fut = executor.submit(returns_one)
assert fut.result() == 1
print(f"Run {i} ok")
print("All done")
This is better.
#!/usr/bin/env python3
"""
Test case for CPython forkserver race condition.
Each iteration shuts down the executor, killing the forkserver,
forcing ensure_running() to restart it for the next iteration.
"""
import concurrent.futures
def returns_one():
return 1
for i in range(10):
print(f"Run {i}...")
with concurrent.futures.ProcessPoolExecutor() as executor:
fut = executor.submit(returns_one)
assert fut.result() == 1
print(f"Run {i} ok")
print("All done")
This script:
* F45 script fails.
* F44 script runs.
#!/usr/bin/env python3
"""
Test case for CPython forkserver race condition.
Each iteration shuts down the executor, killing the forkserver,
forcing ensure_running() to restart it for the next iteration.
"""
import concurrent.futures
def returns_one():
return 1
for i in range(10):
print(f"Run {i}...")
with concurrent.futures.ProcessPoolExecutor() as executor:
fut = executor.submit(returns_one)
assert fut.result() == 1
print(f"Run {i} ok")
print("All done")
Python 3.15.0a8 and 3.15.0b1:
File "/usr/lib64/python3.15/multiprocessing/spawn.py", line 140, in _check_not_importing_main
raise RuntimeError('''
...<16 lines>...
''')
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
To fix this issue, refer to the "Safe importing of main module"
section in https://docs.python.org/3/library/multiprocessing.html
concurrent.futures.process._RemoteTraceback:
'''
Process 1203351 terminated abruptly with exit code 1'''
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/churchyard/tmp/script-concurrent.py", line 15, in <module>
assert fut.result() == 1
~~~~~~~~~~^^
File "/usr/lib64/python3.15/concurrent/futures/_base.py", line 450, in result
return self.__get_result()
~~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.15/concurrent/futures/_base.py", line 395, in __get_result
raise self._exception
concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending.
Python 3.14.4 and 3.14.5:
File "/usr/lib64/python3.14/multiprocessing/spawn.py", line 140, in _check_not_importing_main
raise RuntimeError('''
...<16 lines>...
''')
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
To fix this issue, refer to the "Safe importing of main module"
section in https://docs.python.org/3/library/multiprocessing.html
Traceback (most recent call last):
File "/home/churchyard/tmp/script-concurrent.py", line 14, in <module>
fut = executor.submit(returns_one)
File "/usr/lib64/python3.14/concurrent/futures/process.py", line 816, in submit
self._adjust_process_count()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.14/concurrent/futures/process.py", line 775, in _adjust_process_count
self._spawn_process()
~~~~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.14/concurrent/futures/process.py", line 793, in _spawn_process
p.start()
~~~~~~~^^
File "/usr/lib64/python3.14/multiprocessing/process.py", line 121, in start
self._popen = self._Popen(self)
~~~~~~~~~~~^^^^^^
File "/usr/lib64/python3.14/multiprocessing/context.py", line 306, in _Popen
return Popen(process_obj)
File "/usr/lib64/python3.14/multiprocessing/popen_forkserver.py", line 35, in __init__
super().__init__(process_obj)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/usr/lib64/python3.14/multiprocessing/popen_fork.py", line 20, in __init__
self._launch(process_obj)
~~~~~~~~~~~~^^^^^^^^^^^^^
File "/usr/lib64/python3.14/multiprocessing/popen_forkserver.py", line 51, in _launch
self.sentinel, w = forkserver.connect_to_new_process(self._fds)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
File "/usr/lib64/python3.14/multiprocessing/forkserver.py", line 106, in connect_to_new_process
connection.answer_challenge(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
wrapped_client, self._forkserver_authkey)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.14/multiprocessing/connection.py", line 992, in answer_challenge
message = connection.recv_bytes(256) # reject large message
File "/usr/lib64/python3.14/multiprocessing/connection.py", line 223, in recv_bytes
buf = self._recv_bytes(maxlength)
File "/usr/lib64/python3.14/multiprocessing/connection.py", line 448, in _recv_bytes
buf = self._recv(4)
File "/usr/lib64/python3.14/multiprocessing/connection.py", line 413, in _recv
chunk = read(handle, to_read)
ConnectionResetError: [Errno 104] Connection reset by peer
Python 3.13.13: all ok.
Adjustment to the script:
import concurrent.futures
def returns_one():
return 1
if __name__ == '__main__':
for i in range(10):
print(f"Run {i}...")
with concurrent.futures.ProcessPoolExecutor() as executor:
fut = executor.submit(returns_one)
assert fut.result() == 1
print(f"Run {i} ok")
Makes it run on all 3.13, 3.14, 3.15.
https://src.fedoraproject.org/rpms/python-futurist/pull-request/3 is another fix which is probably not correct still, at least its easy to understand. Too much I don't understand here. So there's something in https://github.com/testing-cabal/fixtures/blob/master/fixtures/_fixtures/tempdir.py which is messing up TMPDIR As for the following script it does produce exactly the same error message but I'm not sure if I have just constructed something obscure that produces the same error. It certainly seems like something to avoid in the first place. good on 3.12 and 3.13 fails on 3.14 and 3.15 , """ Reproducer for forkserver stale address bug. When a forkserver is started in a subprocess and that subprocess exits, the forkserver dies but its socket address can be inherited by another process. If that other process then tries to use ProcessPoolExecutor with the default forkserver start method, it fails with FileNotFoundError because it tries to connect to the stale socket address rather than starting a new forkserver. """ import multiprocessing import multiprocessing.forkserver from concurrent.futures import ProcessPoolExecutor def returns_one(): return 1 def start_forkserver_and_exit(): """Start a forkserver in this process then exit, leaving address in /tmp/fs_addr.""" ctx = multiprocessing.get_context('forkserver') p = ctx.Process(target=returns_one) p.start() p.join() with open('/tmp/fs_addr', 'w') as f: f.write(multiprocessing.forkserver._forkserver._forkserver_address) if __name__ == '__main__': # Start forkserver in a child process, then let that process exit p = multiprocessing.Process(target=start_forkserver_and_exit) p.start() p.join() # Simulate inheriting the stale forkserver address (as stestr workers do) with open('/tmp/fs_addr') as f: addr = f.read() print(f"Injecting stale forkserver address: {addr}") multiprocessing.forkserver._forkserver._forkserver_address = addr # Fails with FileNotFoundError - should restart forkserver instead with ProcessPoolExecutor() as e: print(e.submit(returns_one).result()) # Is a closer match to what's going on.
import multiprocessing
import multiprocessing.forkserver
import tempfile
import shutil
from concurrent.futures import ProcessPoolExecutor
def returns_one():
return 1
if __name__ == '__main__':
# Simulate what NestedTempfile does - redirect tempfile to a temp dir
tmpdir = tempfile.mkdtemp()
tempfile.tempdir = tmpdir
# Start the forkserver - it creates its socket inside tmpdir
with ProcessPoolExecutor() as e:
assert e.submit(returns_one).result() == 1
# Simulate NestedTempfile teardown - delete the temp dir
tempfile.tempdir = None
shutil.rmtree(tmpdir)
# Now try to use ProcessPoolExecutor again - forkserver address is stale
with ProcessPoolExecutor() as e:
print(e.submit(returns_one).result())
FEDORA-2026-2fa7e69931 (python-futurist-3.3.0-3.fc45) has been submitted as an update to Fedora 45. https://bodhi.fedoraproject.org/updates/FEDORA-2026-2fa7e69931 FEDORA-2026-2fa7e69931 (python-futurist-3.3.0-3.fc45) has been pushed to the Fedora 45 stable repository. If problem still persists, please make note of it in this bug report. |
python-futurist fails to build with Python 3.15.0a8. 3 tests fail: {3} futurist.tests.test_executors.TestExecutors.test_run_one(process) [0.002874s] ... FAILED Captured traceback: ~~~~~~~~~~~~~~~~~~~ Traceback (most recent call last): File "/builddir/build/BUILD/python-futurist-3.3.0-build/futurist-3.3.0/futurist/tests/test_executors.py", line 111, in test_run_one fut = self.executor.submit(returns_one) File "/builddir/build/BUILD/python-futurist-3.3.0-build/futurist-3.3.0/futurist/_futures.py", line 494, in submit return self._gatherer.submit(fn, *args, **kwargs) ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^ File "/builddir/build/BUILD/python-futurist-3.3.0-build/futurist-3.3.0/futurist/_futures.py", line 119, in submit fut = self._submit_func(fn, *args, **kwargs) File "/usr/lib64/python3.15/concurrent/futures/process.py", line 830, in submit self._adjust_process_count() ~~~~~~~~~~~~~~~~~~~~~~~~~~^^ File "/usr/lib64/python3.15/concurrent/futures/process.py", line 789, in _adjust_process_count self._spawn_process() ~~~~~~~~~~~~~~~~~~~^^ File "/usr/lib64/python3.15/concurrent/futures/process.py", line 807, in _spawn_process p.start() ~~~~~~~^^ File "/usr/lib64/python3.15/multiprocessing/process.py", line 121, in start self._popen = self._Popen(self) ~~~~~~~~~~~^^^^^^ File "/usr/lib64/python3.15/multiprocessing/context.py", line 309, in _Popen return Popen(process_obj) File "/usr/lib64/python3.15/multiprocessing/popen_forkserver.py", line 35, in __init__ super().__init__(process_obj) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ File "/usr/lib64/python3.15/multiprocessing/popen_fork.py", line 20, in __init__ self._launch(process_obj) ~~~~~~~~~~~~^^^^^^^^^^^^^ File "/usr/lib64/python3.15/multiprocessing/popen_forkserver.py", line 51, in _launch self.sentinel, w = forkserver.connect_to_new_process(self._fds) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ File "/usr/lib64/python3.15/multiprocessing/forkserver.py", line 106, in connect_to_new_process client.connect(self._forkserver_address) ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory https://docs.python.org/3.15/whatsnew/3.15.html For the build logs, see: https://copr-be.cloud.fedoraproject.org/results/@python/python3.15/fedora-rawhide-x86_64/10398246-python-futurist/ For all our attempts to build python-futurist with Python 3.15, see: https://copr.fedorainfracloud.org/coprs/g/python/python3.15/package/python-futurist/ Testing and mass rebuild of packages is happening in copr. You can follow these instructions to test locally in mock if your package builds with Python 3.15: https://copr.fedorainfracloud.org/coprs/g/python/python3.15/ Let us know here if you have any questions. Python 3.15 is planned to be included in Fedora 45. To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.15. A build failure prevents us from testing all dependent packages (transitive [Build]Requires), so if this package is required a lot, it's important for us to get it fixed soon. We'd appreciate help from the people who know this package best, but if you don't want to work on this now, let us know so we can try to work around it on our side.