Skip to content

Commit cc9de46

Browse files
stroxlermeta-codesync[bot]
authored andcommitted
Exclude companion declarations of the requesting fixture
Summary: A fixture's implementation and stub describe the same provider. Use retained module-owned fixture metadata to recognize a same-name parent request and exclude that provider's companion declaration before climbing to an ancestor. Preserve class-to-module parents and ordinary consumers' implementation/stub preference without resolving unrelated imports. ___ landed-with-radar-review Differential Revision: D129132931 fbshipit-source-id: fb3076c3ce74c4b5708d3c6b09dce29a518a747d
1 parent f792579 commit cc9de46

2 files changed

Lines changed: 32 additions & 10 deletions

File tree

‎pyrefly/lib/state/lsp/pytest.rs‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,16 @@ impl<'a> Transaction<'a> {
132132
})
133133
.collect();
134134
if definitions.is_empty() && preference.follow_pytest_conftest {
135+
let requesting_fixture_name = self
136+
.get_exports_data(handle)
137+
.pytest_fixtures()
138+
.iter()
139+
.find(|fixture| {
140+
fixture.range == enclosing_function_range
141+
&& fixture.fixture_name.as_ref().unwrap_or(&fixture.name) == identifier.id()
142+
})
143+
.map(|fixture| fixture.name.clone());
144+
let current_path = handle.path().as_path();
135145
// Module fixtures take precedence; discover conftests only after a local miss.
136146
let candidates = once(handle.clone())
137147
.chain(once_with(|| pytest_conftest_handles(self, handle, preference)).flatten());
@@ -143,9 +153,16 @@ impl<'a> Transaction<'a> {
143153
while seen.insert((target_handle.clone(), target_name.clone())) {
144154
let exports = self.get_exports_data(&target_handle);
145155
if let Some(fixture) = exports.pytest_fixtures().iter().find(|fixture| {
146-
if fixture.range == enclosing_function_range
147-
&& target_handle.path().as_path() == handle.path().as_path()
148-
{
156+
let target_path = target_handle.path().as_path();
157+
let is_same_definition = fixture.range == enclosing_function_range
158+
&& target_path == current_path;
159+
// The implementation and its stub denote the same module-level provider.
160+
let is_paired_definition = requesting_fixture_name.as_ref()
161+
== Some(&fixture.name)
162+
&& target_handle.path().style() != handle.path().style()
163+
&& target_path.parent() == current_path.parent()
164+
&& target_path.file_stem() == current_path.file_stem();
165+
if is_same_definition || is_paired_definition {
149166
return false;
150167
}
151168
if imported {

‎pyrefly/lib/test/lsp/definition.rs‎

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,18 +1064,23 @@ fn pytest_conftest_override_requests_parent_with_companion_stub() {
10641064
TextSize::try_from(code.find("local_answer(answer)").unwrap() + "local_answer(".len())
10651065
.unwrap();
10661066
let transaction = state.transaction();
1067-
for definitions in [
1068-
transaction.goto_definition(&handle, position).unwrap(),
1069-
transaction.goto_declaration(&handle, position).unwrap(),
1067+
for (definitions, expected) in [
1068+
(
1069+
transaction.goto_definition(&handle, position).unwrap(),
1070+
"conftest.py",
1071+
),
1072+
(
1073+
transaction.goto_declaration(&handle, position).unwrap(),
1074+
"conftest.pyi",
1075+
),
10701076
] {
1071-
// BUG: the requesting fixture's companion is still selected instead of its parent.
10721077
assert_eq!(
1073-
definitions[0].module.path().as_path().parent().unwrap(),
1074-
root.path().join("tests"),
1078+
definitions[0].module.path().as_path(),
1079+
root.path().join(expected),
10751080
);
10761081
assert_eq!(
10771082
definitions[0].module.code_at(definitions[0].range),
1078-
"local_answer",
1083+
"answer"
10791084
);
10801085
}
10811086
let consumer_position = TextSize::try_from(test_code.find("answer").unwrap()).unwrap();

0 commit comments

Comments
 (0)