I recently modified the GitHub actions testing workflow to use pytest-xdist to run the unit tests in parallel. This resulted in a nice speedup, but also occasionally causes a test failure with the exception EOFError: Ran out of input. This is apparently related to multiple parallel workers trying to read or write (not sure which) to the same file at the same time.
It's unclear to me which test(s) trigger this. My non-scientific observation is that the error is always triggered by test_activity.py (although I could be wrong about that) and it seems to have something to do with accessing the pint cache. See full stacktrace from an example failed CI test run below.
Manually re-running the tests usually result in success, so this is a non-deterministic failure. We need to either find the offending unit test and modify it, or (less preferred) go back to running unit tests in serial.
Run pytest -n auto --cov=src/pyEQL --cov-report=xml
============================= test session starts ==============================
platform linux -- Python 3.10.14, pytest-8.3.2, pluggy-1.5.0 -- /opt/hostedtoolcache/Python/3.10.14/x64/bin/python
cachedir: .pytest_cache
rootdir: /home/runner/work/pyEQL/pyEQL
configfile: pyproject.toml
testpaths: tests
plugins: cov-5.0.0, xdist-3.6.1
created: 4/4 workers
4 workers [134 items]
scheduling tests via LoadScheduling
==================================== ERRORS ====================================
___________________ ERROR collecting tests/test_activity.py ____________________
tests/test_activity.py:18: in <module>
from pyEQL.activity_correction import _debye_parameter_activity, _debye_parameter_B
__builtins__ = <builtins>
__cached__ = '/home/runner/work/pyEQL/pyEQL/tests/__pycache__/test_activity.cpython-310.pyc'
__doc__ = '\npyEQL activity correction methods test suite\n============================================\n\nThis file contains te...ve functions. In some\ncases, the output is also tested against a well-established model published\nby USGS(PHREEQC)\n'
__file__ = '/home/runner/work/pyEQL/pyEQL/tests/test_activity.py'
__loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7ff017d74af0>
__name__ = 'tests.test_activity'
__package__ = 'tests'
__spec__ = ModuleSpec(name='tests.test_activity', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7ff017d74af0>, origin='/home/runner/work/pyEQL/pyEQL/tests/test_activity.py')
np = <module 'numpy' from '/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/numpy/__init__.py'>
platform = <module 'platform' from '/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/platform.py'>
pytest = <module 'pytest' from '/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pytest/__init__.py'>
src/pyEQL/__init__.py:36: in <module>
ureg = UnitRegistry(cache_folder=":auto:")
JSONStore = <class 'maggma.stores.mongolike.JSONStore'>
UnitRegistry = <class 'pint.registry.UnitRegistry'>
__builtins__ = <builtins>
__cached__ = '/home/runner/work/pyEQL/pyEQL/src/pyEQL/__pycache__/__init__.cpython-310.pyc'
__doc__ = '\npyEQL is a python package for calculating the properties of aqueous solutions\nand performing chemical thermodynamics computations.\n\n:copyright: 2013-2024 by Ryan S. Kingsbury\n:license: LGPL, see LICENSE for more details.\n'
__file__ = '/home/runner/work/pyEQL/pyEQL/src/pyEQL/__init__.py'
__loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7ff00b4de980>
__name__ = 'pyEQL'
__package__ = 'pyEQL'
__path__ = ['/home/runner/work/pyEQL/pyEQL/src/pyEQL']
__spec__ = ModuleSpec(name='pyEQL', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7ff00b4de980>, origin='/home/runner/work/pyEQL/pyEQL/src/pyEQL/__init__.py', submodule_search_locations=['/home/runner/work/pyEQL/pyEQL/src/pyEQL'])
__version__ = '0.0.post1.dev1+g893cdb8'
dist_name = 'pyEQL'
files = <function files at 0x7ff00b170b80>
logger = <Logger pyEQL (WARNING)>
logging = <module 'logging' from '/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/logging/__init__.py'>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/plain/registry.py:153: in __call__
obj._after_init()
__class__ = <class 'pint.facets.plain.registry.RegistryMeta'>
args = ()
kwargs = {'cache_folder': ':auto:'}
obj = <pint.registry.UnitRegistry object at 0x7ff007dce440>
self = <class 'pint.registry.UnitRegistry'>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/system/registry.py:76: in _after_init
super()._after_init()
__class__ = <class 'pint.facets.system.registry.GenericSystemRegistry'>
self = <pint.registry.UnitRegistry object at 0x7ff007dce440>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/group/registry.py:64: in _after_init
super()._after_init()
__class__ = <class 'pint.facets.group.registry.GenericGroupRegistry'>
self = <pint.registry.UnitRegistry object at 0x7ff007dce440>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/plain/registry.py:329: in _after_init
loaded_files = self.load_definitions(path, True)
path = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
self = <pint.registry.UnitRegistry object at 0x7ff007dce440>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/plain/registry.py:594: in load_definitions
parsed_project = self._def_parser.parse_file(file)
file = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
is_resource = True
self = <pint.registry.UnitRegistry object at 0x7ff007dce440>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/delegates/txt_defparser/defparser.py:124: in parse_file
return fp.parse(
cfg = None
filename = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
self = <pint.delegates.txt_defparser.defparser.DefParser object at 0x7ff007dce500>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/flexparser/flexparser.py:1644: in parse
pp[(source_location, target)] = parsed = parser.parse(
CustomParser = <class 'pint.delegates.txt_defparser.defparser._PintParser'>
config = ParserConfig(non_int_type=<class 'float'>)
delimiters = {'\n': (<DelimiterInclude.SPLIT: 1>, <DelimiterAction.CONTINUE: 1>), '\r': (<DelimiterInclude.SPLIT: 1>, <DelimiterAct..., <DelimiterAction.CONTINUE: 1>), '#': (<DelimiterInclude.SPLIT_BEFORE: 3>, <DelimiterAction.CAPTURE_NEXT_TIL_EOL: 2>)}
entry_point = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
extra_parser_kwargs = {'diskcache': <pint.delegates.base_defparser.build_disk_cache_class.<locals>.PintDiskCache object at 0x7ff007dce410>}
locator = <function default_locator at 0x7ff0080e9000>
parsed = ParsedSource(parsed_source=PintRootBlock(opening=BOF(start_line=0, start_col=0, end_line=0, end_col=0, raw=None, conte...99, start_col=0, end_line=899, end_col=0, raw=None), delimiters={}), config=ParserConfig(non_int_type=<class 'float'>))
parser = <pint.delegates.txt_defparser.defparser._PintParser object at 0x7ff007dfe410>
pending = []
pp = {None: ParsedSource(parsed_source=PintRootBlock(opening=BOF(start_line=0, start_col=0, end_line=0, end_col=0, raw=None...9, start_col=0, end_line=899, end_col=0, raw=None), delimiters={}), config=ParserConfig(non_int_type=<class 'float'>))}
prefer_resource_as_file = True
source_location = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
spec = <class 'pint.delegates.txt_defparser.defparser._PintParser'>
strip_spaces = True
target = 'constants_en.txt'
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/flexparser/flexparser.py:1182: in parse
return self.parse_file(source_location)
self = <pint.delegates.txt_defparser.defparser._PintParser object at 0x7ff007dfe410>
source_location = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/constants_en.txt')
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/delegates/txt_defparser/defparser.py:58: in parse_file
content, _basename = self._diskcache.load(path, super().parse_file)
__class__ = <class 'pint.delegates.txt_defparser.defparser._PintParser'>
path = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/constants_en.txt')
self = <pint.delegates.txt_defparser.defparser._PintParser object at 0x7ff007dfe410>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/flexcache/flexcache.py:379: in load
converted_object = self.rawload(header, cache_path)
cache_path = PosixPath('/home/runner/.cache/pint/f5162aaf3660e5d66c2f8d5e987428b18449d72e.pickle')
converter = <bound method Parser.parse_file of <pint.delegates.txt_defparser.defparser._PintParser object at 0x7ff007dfe410>>
converter_id = 'parse_file'
header = build_disk_cache_class.<locals>.PathHeader(source=PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/si...system='Linux', python_implementation='CPython', python_version='3.10.14', pint_version='0.24.3', non_int_type='float')
header_class = <class 'pint.delegates.base_defparser.build_disk_cache_class.<locals>.PathHeader'>
pass_hash = False
self = <pint.delegates.base_defparser.build_disk_cache_class.<locals>.PintDiskCache object at 0x7ff007dce410>
source_object = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/constants_en.txt')
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/flexcache/flexcache.py:421: in rawload
return pickle.load(fi)
E EOFError: Ran out of input
cache_path = PosixPath('/home/runner/.cache/pint/f5162aaf3660e5d66c2f8d5e987428b18449d72e.pickle')
fi = <_io.BufferedReader name='/home/runner/.cache/pint/f5162aaf3660e5d66c2f8d5e987428b18449d72e.pickle'>
header = build_disk_cache_class.<locals>.PathHeader(source=PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/si...system='Linux', python_implementation='CPython', python_version='3.10.14', pint_version='0.24.3', non_int_type='float')
self = <pint.delegates.base_defparser.build_disk_cache_class.<locals>.PintDiskCache object at 0x7ff007dce410>
___________________ ERROR collecting tests/test_activity.py ____________________
tests/test_activity.py:18: in <module>
from pyEQL.activity_correction import _debye_parameter_activity, _debye_parameter_B
__builtins__ = <builtins>
__cached__ = '/home/runner/work/pyEQL/pyEQL/tests/__pycache__/test_activity.cpython-310.pyc'
__doc__ = '\npyEQL activity correction methods test suite\n============================================\n\nThis file contains te...ve functions. In some\ncases, the output is also tested against a well-established model published\nby USGS(PHREEQC)\n'
__file__ = '/home/runner/work/pyEQL/pyEQL/tests/test_activity.py'
__loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7fb968790af0>
__name__ = 'tests.test_activity'
__package__ = 'tests'
__spec__ = ModuleSpec(name='tests.test_activity', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7fb968790af0>, origin='/home/runner/work/pyEQL/pyEQL/tests/test_activity.py')
np = <module 'numpy' from '/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/numpy/__init__.py'>
platform = <module 'platform' from '/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/platform.py'>
pytest = <module 'pytest' from '/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pytest/__init__.py'>
src/pyEQL/__init__.py:36: in <module>
ureg = UnitRegistry(cache_folder=":auto:")
JSONStore = <class 'maggma.stores.mongolike.JSONStore'>
UnitRegistry = <class 'pint.registry.UnitRegistry'>
__builtins__ = <builtins>
__cached__ = '/home/runner/work/pyEQL/pyEQL/src/pyEQL/__pycache__/__init__.cpython-310.pyc'
__doc__ = '\npyEQL is a python package for calculating the properties of aqueous solutions\nand performing chemical thermodynamics computations.\n\n:copyright: 2013-2024 by Ryan S. Kingsbury\n:license: LGPL, see LICENSE for more details.\n'
__file__ = '/home/runner/work/pyEQL/pyEQL/src/pyEQL/__init__.py'
__loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7fb9615da9e0>
__name__ = 'pyEQL'
__package__ = 'pyEQL'
__path__ = ['/home/runner/work/pyEQL/pyEQL/src/pyEQL']
__spec__ = ModuleSpec(name='pyEQL', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7fb9615da9e0>, origin='/home/runner/work/pyEQL/pyEQL/src/pyEQL/__init__.py', submodule_search_locations=['/home/runner/work/pyEQL/pyEQL/src/pyEQL'])
__version__ = '0.0.post1.dev1+g893cdb8'
dist_name = 'pyEQL'
files = <function files at 0x7fb9615fcb80>
logger = <Logger pyEQL (WARNING)>
logging = <module 'logging' from '/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/logging/__init__.py'>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/plain/registry.py:153: in __call__
obj._after_init()
__class__ = <class 'pint.facets.plain.registry.RegistryMeta'>
args = ()
kwargs = {'cache_folder': ':auto:'}
obj = <pint.registry.UnitRegistry object at 0x7fb9547c6470>
self = <class 'pint.registry.UnitRegistry'>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/system/registry.py:76: in _after_init
super()._after_init()
__class__ = <class 'pint.facets.system.registry.GenericSystemRegistry'>
self = <pint.registry.UnitRegistry object at 0x7fb9547c6470>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/group/registry.py:64: in _after_init
super()._after_init()
__class__ = <class 'pint.facets.group.registry.GenericGroupRegistry'>
self = <pint.registry.UnitRegistry object at 0x7fb9547c6470>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/plain/registry.py:329: in _after_init
loaded_files = self.load_definitions(path, True)
path = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
self = <pint.registry.UnitRegistry object at 0x7fb9547c6470>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/facets/plain/registry.py:594: in load_definitions
parsed_project = self._def_parser.parse_file(file)
file = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
is_resource = True
self = <pint.registry.UnitRegistry object at 0x7fb9547c6470>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/delegates/txt_defparser/defparser.py:124: in parse_file
return fp.parse(
cfg = None
filename = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
self = <pint.delegates.txt_defparser.defparser.DefParser object at 0x7fb9547c6530>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/flexparser/flexparser.py:1644: in parse
pp[(source_location, target)] = parsed = parser.parse(
CustomParser = <class 'pint.delegates.txt_defparser.defparser._PintParser'>
config = ParserConfig(non_int_type=<class 'float'>)
delimiters = {'\n': (<DelimiterInclude.SPLIT: 1>, <DelimiterAction.CONTINUE: 1>), '\r': (<DelimiterInclude.SPLIT: 1>, <DelimiterAct..., <DelimiterAction.CONTINUE: 1>), '#': (<DelimiterInclude.SPLIT_BEFORE: 3>, <DelimiterAction.CAPTURE_NEXT_TIL_EOL: 2>)}
entry_point = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
extra_parser_kwargs = {'diskcache': <pint.delegates.base_defparser.build_disk_cache_class.<locals>.PintDiskCache object at 0x7fb9547c6440>}
locator = <function default_locator at 0x7fb954ae5000>
parsed = ParsedSource(parsed_source=PintRootBlock(opening=BOF(start_line=0, start_col=0, end_line=0, end_col=0, raw=None, conte...99, start_col=0, end_line=899, end_col=0, raw=None), delimiters={}), config=ParserConfig(non_int_type=<class 'float'>))
parser = <pint.delegates.txt_defparser.defparser._PintParser object at 0x7fb9547fa410>
pending = []
pp = {None: ParsedSource(parsed_source=PintRootBlock(opening=BOF(start_line=0, start_col=0, end_line=0, end_col=0, raw=None...9, start_col=0, end_line=899, end_col=0, raw=None), delimiters={}), config=ParserConfig(non_int_type=<class 'float'>))}
prefer_resource_as_file = True
source_location = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/default_en.txt')
spec = <class 'pint.delegates.txt_defparser.defparser._PintParser'>
strip_spaces = True
target = 'constants_en.txt'
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/flexparser/flexparser.py:1182: in parse
return self.parse_file(source_location)
self = <pint.delegates.txt_defparser.defparser._PintParser object at 0x7fb9547fa410>
source_location = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/constants_en.txt')
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/delegates/txt_defparser/defparser.py:58: in parse_file
content, _basename = self._diskcache.load(path, super().parse_file)
__class__ = <class 'pint.delegates.txt_defparser.defparser._PintParser'>
path = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/constants_en.txt')
self = <pint.delegates.txt_defparser.defparser._PintParser object at 0x7fb9547fa410>
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/flexcache/flexcache.py:379: in load
converted_object = self.rawload(header, cache_path)
cache_path = PosixPath('/home/runner/.cache/pint/f5162aaf3660e5d66c2f8d5e987428b18449d72e.pickle')
converter = <bound method Parser.parse_file of <pint.delegates.txt_defparser.defparser._PintParser object at 0x7fb9547fa410>>
converter_id = 'parse_file'
header = build_disk_cache_class.<locals>.PathHeader(source=PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/si...system='Linux', python_implementation='CPython', python_version='3.10.14', pint_version='0.24.3', non_int_type='float')
header_class = <class 'pint.delegates.base_defparser.build_disk_cache_class.<locals>.PathHeader'>
pass_hash = False
self = <pint.delegates.base_defparser.build_disk_cache_class.<locals>.PintDiskCache object at 0x7fb9547c6440>
source_object = PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/pint/constants_en.txt')
/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/flexcache/flexcache.py:421: in rawload
return pickle.load(fi)
E EOFError: Ran out of input
cache_path = PosixPath('/home/runner/.cache/pint/f5162aaf3660e5d66c2f8d5e987428b18449d72e.pickle')
fi = <_io.BufferedReader name='/home/runner/.cache/pint/f5162aaf3660e5d66c2f8d5e987428b18449d72e.pickle'>
header = build_disk_cache_class.<locals>.PathHeader(source=PosixPath('/opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/si...system='Linux', python_implementation='CPython', python_version='3.10.14', pint_version='0.24.3', non_int_type='float')
self = <pint.delegates.base_defparser.build_disk_cache_class.<locals>.PintDiskCache object at 0x7fb9547c6440>
_____________________________ ERROR collecting gw1 _____________________________
Different tests were collected between gw3 and gw1. The difference is:
--- gw3
+++ gw1
@@ -1,3 +1,17 @@
+tests/test_activity.py::test_units_and_equality
+tests/test_activity.py::test_debye_params
+tests/test_activity.py::test_activity_crc_HCl
+tests/test_activity.py::test_activity_crc_CsI
+tests/test_activity.py::test_activity_crc_bacl2
+tests/test_activity.py::test_activity_crc_licl
+tests/test_activity.py::test_activity_crc_rbcl
+tests/test_activity.py::test_activity_crc_MgCl2
+tests/test_activity.py::test_activity_crc_KBr
+tests/test_activity.py::test_activity_crc_k2so4
+tests/test_activity.py::test_activity_pitzer_nacl_1
+tests/test_activity.py::test_water_activity_pitzer_nacl_1
+tests/test_activity.py::test_activity_pitzer_phreeqc_nacl_2
+tests/test_activity.py::test_water_activity_phreeqc_pitzer_nacl_2
tests/test_bulk_properties.py::test_empty_solution
tests/test_bulk_properties.py::test_hardness_1
tests/test_bulk_properties.py::test_hardness_2
To see why this happens see Known limitations in documentation
_____________________________ ERROR collecting gw0 _____________________________
Different tests were collected between gw3 and gw0. The difference is:
--- gw3
+++ gw0
@@ -1,3 +1,17 @@
+tests/test_activity.py::test_units_and_equality
+tests/test_activity.py::test_debye_params
+tests/test_activity.py::test_activity_crc_HCl
+tests/test_activity.py::test_activity_crc_CsI
+tests/test_activity.py::test_activity_crc_bacl2
+tests/test_activity.py::test_activity_crc_licl
+tests/test_activity.py::test_activity_crc_rbcl
+tests/test_activity.py::test_activity_crc_MgCl2
+tests/test_activity.py::test_activity_crc_KBr
+tests/test_activity.py::test_activity_crc_k2so4
+tests/test_activity.py::test_activity_pitzer_nacl_1
+tests/test_activity.py::test_water_activity_pitzer_nacl_1
+tests/test_activity.py::test_activity_pitzer_phreeqc_nacl_2
+tests/test_activity.py::test_water_activity_phreeqc_pitzer_nacl_2
tests/test_bulk_properties.py::test_empty_solution
tests/test_bulk_properties.py::test_hardness_1
tests/test_bulk_properties.py::test_hardness_2
To see why this happens see Known limitations in documentation
---------- coverage: platform linux, python 3.10.14-final-0 ----------
Coverage XML written to file coverage.xml
=========================== short test summary info ============================
ERROR tests/test_activity.py - EOFError: Ran out of input
ERROR tests/test_activity.py - EOFError: Ran out of input
ERROR gw1
ERROR gw0
I recently modified the GitHub actions
testing
workflow to usepytest-xdist
to run the unit tests in parallel. This resulted in a nice speedup, but also occasionally causes a test failure with the exceptionEOFError: Ran out of input
. This is apparently related to multiple parallel workers trying to read or write (not sure which) to the same file at the same time.It's unclear to me which test(s) trigger this. My non-scientific observation is that the error is always triggered by
test_activity.py
(although I could be wrong about that) and it seems to have something to do with accessing thepint
cache. See full stacktrace from an example failed CI test run below.Manually re-running the tests usually result in success, so this is a non-deterministic failure. We need to either find the offending unit test and modify it, or (less preferred) go back to running unit tests in serial.