diff --git a/changelog/3899.bugfix.rst b/changelog/3899.bugfix.rst new file mode 100644 index 000000000..8f117779e --- /dev/null +++ b/changelog/3899.bugfix.rst @@ -0,0 +1 @@ +Do not raise ``UsageError`` when an imported package has a ``pytest_plugins.py`` child module. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 23e09ff40..26999e125 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -559,8 +559,8 @@ def _get_plugin_specs_as_list(specs): which case it is returned as a list. Specs can also be `None` in which case an empty list is returned. """ - if specs is not None: - if isinstance(specs, str): + if specs is not None and not isinstance(specs, types.ModuleType): + if isinstance(specs, six.string_types): specs = specs.split(",") if specs else [] if not isinstance(specs, (list, tuple)): raise UsageError( diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index c8a391b78..95c419599 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -969,6 +969,20 @@ def test_import_plugin_unicode_name(testdir): assert r.ret == 0 +def test_pytest_plugins_as_module(testdir): + """Do not raise an error if pytest_plugins attribute is a module (#3899)""" + testdir.makepyfile( + **{ + "__init__.py": "", + "pytest_plugins.py": "", + "conftest.py": "from . import pytest_plugins", + "test_foo.py": "def test(): pass", + } + ) + result = testdir.runpytest() + result.stdout.fnmatch_lines("* 1 passed in *") + + def test_deferred_hook_checking(testdir): """ Check hooks as late as possible (#1821).