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.py

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Ensure pytest_plugins is a list, tuple, or comma-separated string of plugin names.
  2. If using a set, convert to a list: pytest_plugins = list(my_set).
  3. 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

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


AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04). Data as JSON: /data/errors/31d2059140956d23.json. Report an issue: GitHub.