Skip to content

Commit 5e38fab

Browse files
committed
Modified import resolution logic to handle namespace stub packages. This case isn't explicitly covered by PEP 561, but there is a proposal to amend the PEP to clarify how to handle this case.
1 parent cdbe961 commit 5e38fab

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

packages/pyright-internal/src/analyzer/importResolver.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,11 @@ export class ImportResolver {
793793

794794
// We found fully typed stub packages.
795795
if (importResult.packageDirectory) {
796-
return importResult;
796+
// If this is a namespace package that wasn't resolved, assume that
797+
// it's a partial stub package and continue looking for a real package.
798+
if (!importResult.isNamespacePackage || importResult.isImportFound) {
799+
return importResult;
800+
}
797801
}
798802
}
799803

packages/pyright-internal/src/tests/importResolver.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ test('stub package', () => {
137137
path: combinePaths(libraryRoot, 'myLib-stubs', 'stub.pyi'),
138138
content: '# empty',
139139
},
140+
{
141+
path: combinePaths(libraryRoot, 'myLib-stubs', '__init__.pyi'),
142+
content: '# empty',
143+
},
140144
{
141145
path: combinePaths(libraryRoot, 'myLib', 'partialStub.py'),
142146
content: 'def test(): pass',
@@ -148,6 +152,28 @@ test('stub package', () => {
148152
assert(!importResult.isImportFound);
149153
});
150154

155+
test('stub namespace package', () => {
156+
const files = [
157+
{
158+
path: combinePaths(libraryRoot, 'myLib-stubs', 'stub.pyi'),
159+
content: '# empty',
160+
},
161+
{
162+
path: combinePaths(libraryRoot, 'myLib', 'partialStub.py'),
163+
content: 'def test(): pass',
164+
},
165+
];
166+
167+
// If fully typed stub package exists, that wins over the real package.
168+
const importResult = getImportResult(files, ['myLib', 'partialStub']);
169+
assert(importResult.isImportFound);
170+
assert(!importResult.isStubFile);
171+
assert.strictEqual(
172+
1,
173+
importResult.resolvedPaths.filter((f) => f === combinePaths(libraryRoot, 'myLib', 'partialStub.py')).length
174+
);
175+
});
176+
151177
test('stub in typing folder over partial stub package', () => {
152178
const typingFolder = combinePaths(normalizeSlashes('/'), 'typing');
153179
const files = [

0 commit comments

Comments
 (0)