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

Test teardown fails with ERROR .hypothesis/tmp - FileNotFoundError: [Errno 2] #4200

Closed
enitrat opened this issue Dec 11, 2024 · 4 comments · Fixed by #4212
Closed

Test teardown fails with ERROR .hypothesis/tmp - FileNotFoundError: [Errno 2] #4200

enitrat opened this issue Dec 11, 2024 · 4 comments · Fixed by #4212

Comments

@enitrat
Copy link

enitrat commented Dec 11, 2024

In our CI Job in which we use pytest and hypothesis, we run our tests with uv run pytest -n logical --junitxml=junit.xml -o junit_family=legacy

After 100% of tests are run, the process fails with error:

ERROR .hypothesis/tmp - FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/keth/keth/cairo/.hypothesis/tmp'

I'm not sure exactly where this could come from, as it isn't always systematic.

@Zac-HD
Copy link
Member

Zac-HD commented Dec 11, 2024

Can you provide a minimal reproducing example? GitHub code spaces can be good for multi-file setups.

@enitrat
Copy link
Author

enitrat commented Dec 11, 2024

I'm not really sure how to produce a MRE - my first hypothesis (no pun intended) is that this happens when the GHA Caches are reaching the 10GB limit, and are saturated - perhaps the runner is not having enough space to keep the tmp files?

@ClementWalter
Copy link

The error message

============================= test session starts ==============================
platform linux -- Python 3.10.12, pytest-8.3.4, pluggy-1.5.0
rootdir: /home/runner/work/keth/keth/cairo
configfile: pyproject.toml
plugins: asyncio-0.24.0, typeguard-2.13.3, hypothesis-6.122.3, xdist-3.6.1, profiling-1.8.1
asyncio: mode=strict, default_loop_scope=session
created: 64/64 workers
64 workers [525 items]

........................................................................ [ 13%]
........................................................................ [ 27%]
........................................................................ [ 41%]
........................................................................ [ 54%]
........................................................................ [ 68%]
........................................................................ [ 82%]
........................................................................ [ 96%]
.....................                                                    [100%]
==================================== ERRORS ====================================
_______________________ ERROR collecting .hypothesis/tmp _______________________
../.venv/lib/python3.10/site-packages/_pytest/runner.py:341: in from_call
    result: TResult | None = func()
../.venv/lib/python3.10/site-packages/_pytest/runner.py:389: in collect
    return list(collector.collect())
../.venv/lib/python3.10/site-packages/_pytest/main.py:523: in collect
    for direntry in scandir(self.path):
../.venv/lib/python3.10/site-packages/_pytest/pathlib.py:950: in scandir
    with os.scandir(path) as s:
E   FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/keth/keth/cairo/.hypothesis/tmp'

suggests that the error is in pytest_make_collect_report and eventually in this classe's collect

@final
class Dir(nodes.Directory):
    """Collector of files in a file system directory.

    .. versionadded:: 8.0

    .. note::

        Python directories with an `__init__.py` file are instead collected by
        :class:`~pytest.Package` by default. Both are :class:`~pytest.Directory`
        collectors.
    """

    @classmethod
    def from_parent(  # type: ignore[override]
        cls,
        parent: nodes.Collector,
        *,
        path: Path,
    ) -> Self:
        """The public constructor.

        :param parent: The parent collector of this Dir.
        :param path: The directory's path.
        :type path: pathlib.Path
        """
        return super().from_parent(parent=parent, path=path)

    def collect(self) -> Iterable[nodes.Item | nodes.Collector]:
        config = self.config
        col: nodes.Collector | None
        cols: Sequence[nodes.Collector]
        ihook = self.ihook
        for direntry in scandir(self.path):
            if direntry.is_dir():
                path = Path(direntry.path)
                if not self.session.isinitpath(path, with_parents=True):
                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
                        continue
                col = ihook.pytest_collect_directory(path=path, parent=self)
                if col is not None:
                    yield col

            elif direntry.is_file():
                path = Path(direntry.path)
                if not self.session.isinitpath(path):
                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
                        continue
                cols = ihook.pytest_collect_file(file_path=path, parent=self)
                yield from cols

what is this .hypothesis/tmp file actually?

@Zac-HD
Copy link
Member

Zac-HD commented Dec 24, 2024

As the name suggests, it's a temporary directory; probably this one as we're writing the unicode cache at startup. We might be able to work around that, though there are tricky race conditions on various platforms - I don't think it's worth changing.

I'd actually describe this as a pytest bug; the scandir() function could return an empty list if the path to scan does not exist.

Furthermore, to hit this you must be (attempting to) collect tests under the .hypothesis/ directory, which is going to cost you startup time for no benefit. Because the norecursedirs config option excludes .* by default, your pytest configuration must be overriding this setting - check that and try adding the defaults back in. I'm planning to put a check for this into Hypothesis' pytest plugin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants