Skip to content

fix: pytest config ignored when python_functions / python_classes / describe_prefixes are customised #115

@sruiz-savia

Description

@sruiz-savia

pytest config ignored when python_functions / python_classes / describe_prefixes are customised

Problem

When using custom pytest naming conventions (e.g. should_*, it_* for functions or A_*, Describe* for classes), neotest-python silently ignores the project configuration and falls back to defaults. Tests with non-default prefixes are never discovered.

A secondary symptom is that on large projects the plugin hangs Neovim during test discovery.

Environment

  • neotest-python (latest)
  • pytest with custom [tool.pytest.ini_options] in pyproject.toml
  • optionally: pytest-describe plugin

Reproduction

pyproject.toml:

[tool.pytest.ini_options]
python_functions = "should_* it_* test_*"
python_classes   = "Describe*  A_* Test*"
describe_prefixes = ["describe", "context"]
def describe_math():
    def it_adds():
        assert 1 + 1 == 2          # not discovered

class DescribeMath:
    def should_multiply(self):
        assert 2 * 3 == 6          # not discovered

def test_fallback():
    assert True                    # discovered (default prefix)

Only test_fallback is discovered. Functions with it_, should_ prefixes and
classes with Describe* prefix are invisible to the plugin.

Root causes

1. Subprocess runs without cwd — reads the wrong pyproject.toml

scan_pytest_config in base.lua launches the config-extraction subprocess via
lib.process.run with no working directory. The process inherits Neovim's cwd
(which may differ from the project root), so pytest finds the wrong — or no —
pyproject.toml and returns defaults.

2. Hang on large projects

The fix attempted by passing the project root as a pytest collection path
(pytest.main(["-k", "neotest_none", root])) causes pytest to walk the entire
testpaths tree before printing the config JSON, blocking Neovim indefinitely on
large projects.

3. config.getini("describe_prefixes") crashes silently

In pytest.py, TestNameTemplateExtractor.pytest_collection_modifyitems calls
config.getini("describe_prefixes") without a try/except. When pytest-describe
is not installed this raises ValueError, crashing the subprocess before any JSON
is printed. Lua receives no output and uses hardcoded defaults.

4. Wrong fallback default for test_function_pattern

The hardcoded Lua fallback is "^test", which matches unintended names like
testing_helper or testutils and misses the it_* prefix entirely. It should
be "^test_|^it_".

5. Missing treesitter query for decorated namespace functions

Decorated test functions (@decorator\ndef test_foo()) and decorated classes are
handled, but decorated namespace/container functions are not:

@some_decorator
def describe_math():       # ← not captured as a namespace
    def it_adds(): ...

Proposed fix

neotest_python/pytest.py — replace the pytest.main() call in
extract_test_name_template with direct parsing of the config files
(pyproject.toml via tomllib/tomli, pytest.ini / setup.cfg / tox.ini
via configparser). This is instantaneous, requires no pytest collection, and
correctly reads the project config regardless of the process working directory.
Also wrap getini("describe_prefixes") in try/except ValueError.

lua/neotest-python/base.lua — pass root (already computed in
discover_positions) through treesitter_queriesscan_pytest_config → the
subprocess argument list, so the Python script receives the project root explicitly.
Fix the fallback default from "^test" to "^test_|^it_". Add a sixth treesitter
query to capture decorated namespace/container functions.

lua/neotest-python/adapter.lua — pass root to base.treesitter_queries.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions