Skip to content

loadscope bug: :: in test parameters breaks scope detection #1335

@Mno-hime

Description

@Mno-hime

Summary

LoadScopeScheduling._split_scope() uses nodeid.rsplit("::", 1) to
determine the test scope (file). When a parametrized test value contains
:: (e.g. IPv6 addresses), the split lands inside the parameter instead
of at the .py:: boundary. Tests from the same file get assigned to
different workers, each paying the full fixture setup/teardown cost.

Affected code

xdist/scheduler/loadscope.py, _split_scope():

def _split_scope(self, nodeid: str) -> str:
    return nodeid.rsplit("::", 1)[0]

Example

nodeid: synthrecord/tests_synthrecord.py::test_forward[cafe:cafe::cafe-AAAA]
                                                             ^^
                                                      rsplit lands here

expected scope: synthrecord/tests_synthrecord.py
actual scope:   synthrecord/tests_synthrecord.py::test_forward[cafe:cafe

Impact observed in BIND 9 CI

Six synthrecord tests have IPv6 addresses (::1, cafe:cafe::cafe,
cafe::) in their parameters. These get misclassified into separate
scopes and routed to different workers. Each triggers a full named
startup/shutdown cycle (~30 s). In a real CI run (job 7468217), the
synthrecord scope spanned 1001 s instead of ~8 s because the orphaned
tests were interleaved with unrelated scopes on other workers.

Suggested fix

Split on .py:: instead of the last :::

def _split_scope(self, nodeid: str) -> str:
    if ".py::" in nodeid:
        return nodeid.split(".py::")[0] + ".py"
    return nodeid.rsplit("::", 1)[0]

This is unambiguous: .py:: only appears at the module boundary.

Reproduction

from xdist.scheduler.loadscope import LoadScopeScheduling

s = LoadScopeScheduling.__new__(LoadScopeScheduling)

# Normal test — correct scope
print(s._split_scope("foo/bar.py::test_one"))
# -> foo/bar.py

# IPv6 in parameter — wrong scope
print(s._split_scope("foo/bar.py::test_ip[::1-expected]"))
# -> foo/bar.py::test_ip[

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