Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions