Skip to content

multiple python_functions patterns in pyproject.toml causes only first pattern to be recognized #110

Description

@sruizr

Bug: multiple python_functions patterns in pyproject.toml causes only first pattern to be recognized

Description

When python_functions is configured with multiple space-separated patterns in pyproject.toml, neotest-python only recognizes test functions matching the first pattern. Functions matching subsequent patterns are silently ignored in the neotest UI, even though pytest itself collects them correctly.

Environment

  • neotest-python version: e6df4f1 (origin/master, origin/HEAD)
  • Neovim version: v0.12.1
  • pytest version: 9.0.3

Configuration

pyproject.toml:

[tool.pytest.ini_options]
python_functions = "should_* scenario_* test_*"

neotest setup:

require("neotest-python")({
  runner = "pytest",
  pytest_discover_instances = true,
})

Steps to reproduce

  1. Configure python_functions with multiple patterns in pyproject.toml as above
  2. Enable pytest_discover_instances = true in neotest-python config
  3. Open a test file containing functions with different prefixes, e.g. should_foo, scenario_bar, test_baz
  4. Observe that only should_* functions appear in neotest — scenario_* and test_* are not discovered

Expected behaviour

All functions matching any of the configured patterns should be discovered and displayed by neotest.

Actual behaviour

Only functions matching the first pattern (should_*) is discovered.

Running the extraction script manually confirms the problem:

cd /your/project && python ~/.local/share/nvim/lazy/neotest-python/neotest.py --pytest-extract-test-name-template
# returns: {"python_functions": "should_*"}
# expected: {"python_functions": "should_* scenario_* test_*"}

Root cause (two layers)

Layer 1 — Python script (neotest_python/pytest.py line 243):

config.getini("python_functions") returns a list of all configured patterns, but only the first element is taken:

# bug
config = {"python_functions": config.getini("python_functions")[0]}

This means the JSON output sent to the Lua layer already loses all patterns after the first.

Layer 2 — Lua (lua/neotest-python/base.lua line ~120):

Even if the Python script were fixed to return all patterns as a space-separated string, the Lua layer assigns the raw string directly into a treesitter #match? predicate:

-- bug
test_function_pattern = pytest_option.python_functions
-- result: "should_* scenario_* test_*" passed as a single regex

The treesitter #match? predicate expects a single regex pattern. A space-separated glob string is not valid regex alternation.

Fix (both files required)

neotest_python/pytest.py line 243:

# before
config = {"python_functions": config.getini("python_functions")[0]}
# after
config = {"python_functions": " ".join(config.getini("python_functions"))}

lua/neotest-python/base.lua line ~120:

-- before
test_function_pattern = pytest_option.python_functions
-- after
local patterns = vim.split(pytest_option.python_functions, " ", { trimempty = true })
local regex_parts = vim.tbl_map(function(p)
  return "^" .. p:gsub("%*", "")
end, patterns)
test_function_pattern = table.concat(regex_parts, "|")
-- result: "^should_|^scenario_|^test_"

This produces a valid treesitter regex alternation that correctly matches all configured prefixes.

Verification

After applying both fixes, all should_*, scenario_* and test_* functions are correctly discovered by neotest. Running pytest --collect-only was always collecting them correctly, confirming the issue was entirely within neotest-python's pattern handling.

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