Debug advice on intermittent FileNotFound error when collecting distributed coverage data in Jenkins
Los mantenedores suelen responder en 15 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 28/100
- Tipo de issue
- Error
- Claridad
- Necesita aclaración
- Estado de actividad
- Estancado
- Stack tecnológico
- python
- Área
- ci-cd, testing-qa
Línea de trabajo
Begin by reproducing the Jenkins failure with the listed Python, pytest, pytest-cov, pytest-xdist, and coverage versions, then inspect the stack-trace path through pytest_cov/plugin.py:297, pytest_cov/engine.py:338, and coverage/control.py:790. The issue provides no repository file, test, or requested code change, so completion would first require identifying a reproducible cause and agreeing on the expected fix or diagnostic output.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
We have some random Jenkins build failures. Some pytest runs fail (after all actual tests succeed) with an INTERNALERROR, when coverage data is collected from the pytest-xdist workers. I don't know how to proceed, or what I can do to get more debug output. Thanks in advance!
Expected vs actual result
Some times the result is as expected (coverage data is collected just fine), some times it is not.
Reproducer
Versions
We use Python 3.9.10 on GNU/Linux. Excerpt from our setup.cfg:
[options.extras_require]
test =
coverage >= 7.1, < 7.2
pytest >= 7.2, < 7.3
pytest-metadata != 2.0.0
pytest-cov >= 4.0, < 4.1
pytest-html >= 3.2, < 3.3
pytest-sugar >= 0.9, < 0.10
pytest-xdist >= 3.1, < 3.2
Config
Excerpt from our (anonymized) pyproject.toml
[tool.pytest.ini_options]
addopts = "-q --self-contained-html --css=tests/fixtures/report.css"
markers = [
"unit: marks tests as unit tests. Will be added automatically if not integration, verification or validation test.",
"integration: marks tests as integration test.",
"verification: marks tests as verification test.",
"validation: marks tests as validation test.",
"slow: marks tests as slow (runtime > 5min).",
"external: marks tests that require external inputs.",
]
testpaths = [
"tests",
]
[tool.coverage.run]
omit = [
"src/proj/__init__.py",
"src/proj/_version.py",
]
source = [
"src/proj/",
]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"def __str__",
]
Code
Unfortunately, I can't provide code. But here's the (anonymized) stack trace from the error:
INTERNALERROR> config = <_pytest.config.Config object at 0x7fb707e12340>
INTERNALERROR> doit = <function _main at 0x7fb708b32dc0>
INTERNALERROR>
INTERNALERROR> def wrap_session(
INTERNALERROR> config: Config, doit: Callable[[Config, "Session"], Optional[Union[int, ExitCode]]]
INTERNALERROR> ) -> Union[int, ExitCode]:
INTERNALERROR> """Skeleton command line program."""
INTERNALERROR> session = Session.from_config(config)
INTERNALERROR> session.exitstatus = ExitCode.OK
INTERNALERROR> initstate = 0
INTERNALERROR> try:
INTERNALERROR> try:
INTERNALERROR> config._do_configure()
INTERNALERROR> initstate = 1
INTERNALERROR> config.hook.pytest_sessionstart(session=session)
INTERNALERROR> initstate = 2
INTERNALERROR> > session.exitstatus = doit(config, session) or 0
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/_pytest/main.py:270:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> config = <_pytest.config.Config object at 0x7fb707e12340>
INTERNALERROR> session = <Session job exitstatus=<ExitCode.INTERNAL_ERROR: 3> testsfailed=0 testscollected=949>
INTERNALERROR>
INTERNALERROR> def _main(config: Config, session: "Session") -> Optional[Union[int, ExitCode]]:
INTERNALERROR> """Default command line protocol for initialization, session,
INTERNALERROR> running tests and reporting."""
INTERNALERROR> config.hook.pytest_collection(session=session)
INTERNALERROR> > config.hook.pytest_runtestloop(session=session)
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/_pytest/main.py:324:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <_HookCaller 'pytest_runtestloop'>, args = ()
INTERNALERROR> kwargs = {'session': <Session job exitstatus=<ExitCode.INTERNAL_ERROR: 3> testsfailed=0 testscollected=949>}
INTERNALERROR> argname = 'session', firstresult = True
INTERNALERROR>
INTERNALERROR> def __call__(self, *args, **kwargs):
INTERNALERROR> if args:
INTERNALERROR> raise TypeError("hook calling supports only keyword arguments")
INTERNALERROR> assert not self.is_historic()
INTERNALERROR>
INTERNALERROR> # This is written to avoid expensive operations when not needed.
INTERNALERROR> if self.spec:
INTERNALERROR> for argname in self.spec.argnames:
INTERNALERROR> if argname not in kwargs:
INTERNALERROR> notincall = tuple(set(self.spec.argnames) - kwargs.keys())
INTERNALERROR> warnings.warn(
INTERNALERROR> "Argument(s) {} which are declared in the hookspec "
INTERNALERROR> "can not be found in this hook call".format(notincall),
INTERNALERROR> stacklevel=2,
INTERNALERROR> )
INTERNALERROR> break
INTERNALERROR>
INTERNALERROR> firstresult = self.spec.opts.get("firstresult")
INTERNALERROR> else:
INTERNALERROR> firstresult = False
INTERNALERROR>
INTERNALERROR> > return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/pluggy/_hooks.py:265:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <_pytest.config.PytestPluginManager object at 0x7fb712d80730>
INTERNALERROR> hook_name = 'pytest_runtestloop'
INTERNALERROR> methods = [<HookImpl plugin_name='main', plugin=<module '_pytest.main' from '/opt/data/jenkins/project/workspace/job...b7078ea6d0>>, <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7fb6a435c700>>]
INTERNALERROR> kwargs = {'session': <Session job exitstatus=<ExitCode.INTERNAL_ERROR: 3> testsfailed=0 testscollected=949>}
INTERNALERROR> firstresult = True
INTERNALERROR>
INTERNALERROR> def _hookexec(self, hook_name, methods, kwargs, firstresult):
INTERNALERROR> # called from all hookcaller instances.
INTERNALERROR> # enable_tracing will set its own wrapping function at self._inner_hookexec
INTERNALERROR> > return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/pluggy/_manager.py:80:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <pytest_cov.plugin.CovPlugin object at 0x7fb7078ea6d0>
INTERNALERROR> session = <Session job exitstatus=<ExitCode.INTERNAL_ERROR: 3> testsfailed=0 testscollected=949>
INTERNALERROR>
INTERNALERROR> @pytest.hookimpl(hookwrapper=True)
INTERNALERROR> def pytest_runtestloop(self, session):
INTERNALERROR> yield
INTERNALERROR>
INTERNALERROR> if self._disabled:
INTERNALERROR> return
INTERNALERROR>
INTERNALERROR> compat_session = compat.SessionWrapper(session)
INTERNALERROR>
INTERNALERROR> self.failed = bool(compat_session.testsfailed)
INTERNALERROR> if self.cov_controller is not None:
INTERNALERROR> > self.cov_controller.finish()
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/pytest_cov/plugin.py:297:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <pytest_cov.engine.DistMaster object at 0x7fb7078b8160>, args = ()
INTERNALERROR> kwargs = {}
INTERNALERROR> original_cwd = '/opt/data/jenkins/project/workspace/job'
INTERNALERROR>
INTERNALERROR> @functools.wraps(meth)
INTERNALERROR> def ensure_topdir_wrapper(self, *args, **kwargs):
INTERNALERROR> try:
INTERNALERROR> original_cwd = os.getcwd()
INTERNALERROR> except OSError:
INTERNALERROR> # Looks like it's gone, this is non-ideal because a side-effect will
INTERNALERROR> # be introduced in the tests here but we can't do anything about it.
INTERNALERROR> original_cwd = None
INTERNALERROR> os.chdir(self.topdir)
INTERNALERROR> try:
INTERNALERROR> > return meth(self, *args, **kwargs)
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/pytest_cov/engine.py:44:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <pytest_cov.engine.DistMaster object at 0x7fb7078b8160>
INTERNALERROR>
INTERNALERROR> @_ensure_topdir
INTERNALERROR> def finish(self):
INTERNALERROR> """Combines coverage data and sets the list of coverage objects to report on."""
INTERNALERROR>
INTERNALERROR> # Combine all the suffix files into the data file.
INTERNALERROR> > self.cov.stop()
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/pytest_cov/engine.py:338:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> self = <coverage.control.Coverage object at 0x7fb7078b8220>, data_paths = None
INTERNALERROR> strict = False, keep = False
INTERNALERROR>
INTERNALERROR> def combine(
INTERNALERROR> self,
INTERNALERROR> data_paths: Optional[Iterable[str]] = None,
INTERNALERROR> strict: bool = False,
INTERNALERROR> keep: bool = False
INTERNALERROR> ) -> None:
INTERNALERROR> """Combine together a number of similarly-named coverage data files.
INTERNALERROR>
INTERNALERROR> All coverage data files whose name starts with `data_file` (from the
INTERNALERROR> coverage() constructor) will be read, and combined together into the
INTERNALERROR> current measurements.
INTERNALERROR>
INTERNALERROR> `data_paths` is a list of files or directories from which data should
INTERNALERROR> be combined. If no list is passed, then the data files from the
INTERNALERROR> directory indicated by the current data file (probably the current
INTERNALERROR> directory) will be combined.
INTERNALERROR>
INTERNALERROR> If `strict` is true, then it is an error to attempt to combine when
INTERNALERROR> there are no data files to combine.
INTERNALERROR>
INTERNALERROR> If `keep` is true, then original input data files won't be deleted.
INTERNALERROR>
INTERNALERROR> .. versionadded:: 4.0
INTERNALERROR> The `data_paths` parameter.
INTERNALERROR>
INTERNALERROR> .. versionadded:: 4.3
INTERNALERROR> The `strict` parameter.
INTERNALERROR>
INTERNALERROR> .. versionadded: 5.5
INTERNALERROR> The `keep` parameter.
INTERNALERROR> """
INTERNALERROR> self._init()
INTERNALERROR> self._init_data(suffix=None)
INTERNALERROR> self._post_init()
INTERNALERROR> self.get_data()
INTERNALERROR>
INTERNALERROR> > combine_parallel_data(
INTERNALERROR> self._data,
INTERNALERROR> aliases=self._make_aliases(),
INTERNALERROR> data_paths=data_paths,
INTERNALERROR> strict=strict,
INTERNALERROR> keep=keep,
INTERNALERROR> message=self._message,
INTERNALERROR> )
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/coverage/control.py:790:
INTERNALERROR> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
INTERNALERROR>
INTERNALERROR> data = <CoverageData @0x7fb6f419b970 _no_disk=False _basename='/opt/data/jenkins/project/workspace/job..._have_used=True _has_lines=False _has_arcs=True _current_context=None _current_context_id=None _query_context_ids=None>
INTERNALERROR> aliases = <coverage.files.PathAliases object at 0x7fb6f419b3d0>
INTERNALERROR> data_paths = None, strict = False, keep = False
INTERNALERROR> message = <bound method Coverage._message of <coverage.control.Coverage object at 0x7fb7078b8220>>
INTERNALERROR>
INTERNALERROR> def combine_parallel_data(
INTERNALERROR> data: CoverageData,
INTERNALERROR> aliases: Optional[PathAliases] = None,
INTERNALERROR> data_paths: Optional[Iterable[str]] = None,
INTERNALERROR> strict: bool = False,
INTERNALERROR> keep: bool = False,
INTERNALERROR> message: Optional[Callable[[str], None]] = None,
INTERNALERROR> ) -> None:
INTERNALERROR> """Combine a number of data files together.
INTERNALERROR>
INTERNALERROR> `data` is a CoverageData.
INTERNALERROR>
INTERNALERROR> Treat `data.filename` as a file prefix, and combine the data from all
INTERNALERROR> of the data files starting with that prefix plus a dot.
INTERNALERROR>
INTERNALERROR> If `aliases` is provided, it's a `PathAliases` object that is used to
INTERNALERROR> re-map paths to match the local machine's.
INTERNALERROR>
INTERNALERROR> If `data_paths` is provided, it is a list of directories or files to
INTERNALERROR> combine. Directories are searched for files that start with
INTERNALERROR> `data.filename` plus dot as a prefix, and those files are combined.
INTERNALERROR>
INTERNALERROR> If `data_paths` is not provided, then the directory portion of
INTERNALERROR> `data.filename` is used as the directory to search for data files.
INTERNALERROR>
INTERNALERROR> Unless `keep` is True every data file found and combined is then deleted
INTERNALERROR> from disk. If a file cannot be read, a warning will be issued, and the
INTERNALERROR> file will not be deleted.
INTERNALERROR>
INTERNALERROR> If `strict` is true, and no files are found to combine, an error is
INTERNALERROR> raised.
INTERNALERROR>
INTERNALERROR> `message` is a function to use for printing messages to the user.
INTERNALERROR>
INTERNALERROR> """
INTERNALERROR> files_to_combine = combinable_files(data.base_filename(), data_paths)
INTERNALERROR>
INTERNALERROR> if strict and not files_to_combine:
INTERNALERROR> raise NoDataError("No data to combine")
INTERNALERROR>
INTERNALERROR> file_hashes = set()
INTERNALERROR> combined_any = False
INTERNALERROR>
INTERNALERROR> for f in files_to_combine:
INTERNALERROR> if f == data.data_filename():
INTERNALERROR> # Sometimes we are combining into a file which is one of the
INTERNALERROR> # parallel files. Skip that file.
INTERNALERROR> if data._debug.should('dataio'):
INTERNALERROR> data._debug.write(f"Skipping combining ourself: {f!r}")
INTERNALERROR> continue
INTERNALERROR>
INTERNALERROR> try:
INTERNALERROR> rel_file_name = os.path.relpath(f)
INTERNALERROR> except ValueError:
INTERNALERROR> # ValueError can be raised under Windows when os.getcwd() returns a
INTERNALERROR> # folder from a different drive than the drive of f, in which case
INTERNALERROR> # we print the original value of f instead of its relative path
INTERNALERROR> rel_file_name = f
INTERNALERROR>
INTERNALERROR> > with open(f, "rb") as fobj:
INTERNALERROR> E FileNotFoundError: [Errno 2] No such file or directory: '/opt/data/jenkins/project/workspace/job/.coverage.myhost.25783.340214'
INTERNALERROR>
INTERNALERROR> .env/lib/python3.9/site-packages/coverage/data.py:148: FileNotFoundError
What has been tried to solve the problem
Adding --full-trace option to pytest in our Jenkinsfile.
- Lenguaje dominante
- Python
- Estrellas
- 2.1k
- Forks
- 253
- Merge medio
- 12 d 18 h
- PR fusionados (30 d)
- 6
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de pytest-dev/pytest-cov
-
Celery tests require package; test blows up if Celery not installed instead of skipping the tests gracefullyPosiblemente ocupada @dchaudhari7177 la tomó hace 90 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
pytest-dev/pytest-cov#750 ·
Los mantenedores suelen responder en 15 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
pytest-dev/pytest-cov#617 · 1 comentario ·
Los mantenedores suelen responder en 15 días
-
Only set dynamic context on coveragepy cores supporting it, perhaps?Posiblemente ocupada @terminalchai la tomó hace 5 días. Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
pytest-dev/pytest-cov#755 · 3 comentarios ·
Los mantenedores suelen responder en 15 días
-
INTERNALERROR when generating html report using pytest-cov 7.1.0 with jinjaPosiblemente ocupada @daleselaji-dev la tomó hace 77 días. Abierto
Dificultad 3/5 1-2 días Aptitud para principiantes 58/100
pytest-dev/pytest-cov#748 ·
Los mantenedores suelen responder en 15 días
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 28/100
pytest-dev/pytest-cov#747 · 1 reacción ·
Los mantenedores suelen responder en 15 días
Todos los issues de pytest-dev/pytest-cov
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
google-agentic-commerce/AP2#388 ·
-
area:codegen backend:cuda backend:hip bug direction:input
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
CrossGL/crosstl#3061 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
rlaope/oh-my-hermes#2304 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
mochan-tk/agentic-dev-kit-for-codex#64 ·
Los mantenedores suelen responder en 1 día
-
Windows ARM memory-leakAbiertobug docs performance
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
Los mantenedores suelen responder en 3 días