diff --git a/changelog/4344.bugfix.rst b/changelog/4344.bugfix.rst new file mode 100644 index 00000000000..644a6f03058 --- /dev/null +++ b/changelog/4344.bugfix.rst @@ -0,0 +1 @@ +Fix RuntimeError/StopIteration when trying to collect package with "__init__.py" only. diff --git a/src/_pytest/main.py b/src/_pytest/main.py index fa4d8d3d509..a9d310cb62d 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -621,7 +621,13 @@ def _collect(self, arg): # Module itself, so just use that. If this special case isn't taken, then all # the files in the package will be yielded. if argpath.basename == "__init__.py": - yield next(m[0].collect()) + try: + yield next(m[0].collect()) + except StopIteration: + # The package collects nothing with only an __init__.py + # file in it, which gets ignored by the default + # "python_files" option. + pass return for y in m: yield y diff --git a/testing/test_collection.py b/testing/test_collection.py index 1cc8938666f..52c6aa9995b 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -1211,6 +1211,18 @@ def test_collect_pkg_init_and_file_in_args(testdir): ) +def test_collect_pkg_init_only(testdir): + subdir = testdir.mkdir("sub") + init = subdir.ensure("__init__.py") + init.write("def test_init(): pass") + + result = testdir.runpytest(str(init)) + result.stdout.fnmatch_lines(["*no tests ran in*"]) + + result = testdir.runpytest("-v", "-o", "python_files=*.py", str(init)) + result.stdout.fnmatch_lines(["sub/__init__.py::test_init PASSED*", "*1 passed in*"]) + + @pytest.mark.skipif( not hasattr(py.path.local, "mksymlinkto"), reason="symlink not available on this platform",