pytest-dev/pytest · error · UsageError
Plugins may be specified as a sequence or a ','-separated st
Error message
Plugins may be specified as a sequence or a ','-separated string of plugin names. Got: {specs!r} What it means
The _get_plugin_specs_as_list function parses plugin specifications from PYTEST_PLUGINS or pytest_plugins in conftest. It accepts None, a module object (treated as empty), a comma-separated string, or a Sequence of strings. If the value is any other type (e.g., a dict, int, or set), pytest raises UsageError. This guards against misconfigured plugin declarations.
Source
Thrown at src/_pytest/config/__init__.py:953
def _get_plugin_specs_as_list(
specs: types.ModuleType | str | Sequence[str] | None,
) -> list[str]:
"""Parse a plugins specification into a list of plugin names."""
# None means empty.
if specs is None:
return []
# Workaround for #3899 - a submodule which happens to be called "pytest_plugins".
if isinstance(specs, types.ModuleType):
return []
# Comma-separated list.
if isinstance(specs, str):
return specs.split(",") if specs else []
# Direct specification.
if isinstance(specs, collections.abc.Sequence):
return list(specs)
raise UsageError(
f"Plugins may be specified as a sequence or a ','-separated string of plugin names. Got: {specs!r}"
)
def _iter_rewritable_modules(package_files: Iterable[str]) -> Iterator[str]:
"""Given an iterable of file names in a source distribution, return the "names" that should
be marked for assertion rewrite.
For example the package "pytest_mock/__init__.py" should be added as "pytest_mock" in
the assertion rewrite mechanism.
This function has to deal with dist-info based distributions and egg based distributions
(which are still very much in use for "editable" installs).
Here are the file names as seen in a dist-info based distribution:
pytest_mock/__init__.py
pytest_mock/_version.pyView on GitHub (pinned to 98b357f69e)
Solutions
- Ensure pytest_plugins is a list, tuple, or comma-separated string of plugin names.
- If using a set, convert to a list: pytest_plugins = list(my_set).
- If setting PYTEST_PLUGINS in env, use a comma-separated string: PYTEST_PLUGINS='a,b'.
Example fix
# before (conftest.py)
pytest_plugins = {'plugin_a', 'plugin_b'} # set, not allowed
# after (conftest.py)
pytest_plugins = ['plugin_a', 'plugin_b'] Defensive patterns
Strategy: type-guard
Validate before calling
from collections.abc import Sequence
import types
def validate_plugin_specs(specs) -> list[str]:
if specs is None:
return []
if isinstance(specs, types.ModuleType):
return []
if isinstance(specs, str):
return specs.split(',') if specs else []
if isinstance(specs, Sequence):
return [str(s) for s in specs]
raise TypeError(f'Invalid plugin specs type: {type(specs).__name__}. Use a list, tuple, or comma-separated string.') Type guard
from collections.abc import Sequence
import types
def is_valid_plugin_specs(specs) -> bool:
return specs is None or isinstance(specs, (types.ModuleType, str, Sequence)) Prevention
- Always declare pytest_plugins as a list or tuple of strings in conftest.py.
- When setting PYTEST_PLUGINS in env, use comma-separated string format.
- Avoid dynamically constructing pytest_plugins with set/dict comprehensions.
When it happens
Trigger: Setting pytest_plugins = {'a', 'b'} (a set/dict) in conftest.py, or setting PYTEST_PLUGINS to a non-string env value. The isinstance checks for None, ModuleType, str, and Sequence all fail, triggering the UsageError.
Common situations: Writing pytest_plugins = ('plugin1', 'plugin2') as a tuple works (Sequence), but using a set or dict does not. Also, dynamically computing pytest_plugins with a buggy expression that yields an unexpected type.
Related errors
- plugin {name} cannot be disabled
- Blocking conftest files using -p is not supported: -p no:{na
- Missing required plugins: {}
- {cat} is not a Warning subclass
- {filepath}: {exc}
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/31d2059140956d23.json.
Report an issue: GitHub.