Skip to content

Cycle when resolving an imported module with __all__ #261

@dhruvmanila

Description

@dhruvmanila

Summary

play.py:

from foo import bar

# revealed on main: Never
# revealed before `__all__` support: <module 'foo.bar'>
reveal_type(bar)

foo/__init__.pyi:

from foo import bar

__all__ = ["bar"]

foo/bar/__init__.pyi (empty file):

Running this with:

cargo run --bin ty -- check --project=/path/to/project

This is reproduced with or without the custom typeshed that I've provided below.

Trace logs that are interesting and reveals a cycle on symbol query:

Resolving import statement from module `foo` into file `/Users/dhruv/playground/ty/isolated3/play.py`
(query) resolve_module{name=foo}
Resolved module `foo` to `/Users/dhruv/playground/ty/isolated3/foo/__init__.pyi`
(query) infer_definition_types{range=48..51, file=File(System("/Users/dhruv/playground/ty/isolated3/play.py"))}
(query) member_lookup_with_policy: <module 'foo'>.bar
imported_symbol: "bar" in /Users/dhruv/playground/ty/isolated3/foo/__init__.pyi
(query) symbol{name="bar", file=/Users/dhruv/playground/ty/isolated3/foo/__init__.pyi}
(query) dunder_all_names{file=System("/Users/dhruv/playground/ty/isolated3/foo/__init__.pyi")}
(query) infer_definition_types{range=16..19, file=File(System("/Users/dhruv/playground/ty/isolated3/foo/__init__.pyi"))}
(query) member_lookup_with_policy: <module 'foo'>.bar
imported_symbol: "bar" in /Users/dhruv/playground/ty/isolated3/foo/__init__.pyi
(query) (CYCLE) symbol{name="bar", file=/Users/dhruv/playground/ty/isolated3/foo/__init__.pyi}

This might be related to #113.

The reason this isn't occurring before __all__ support is that the bar module is not being re-exported in foo/__init__.pyi via "redundant alias" but is via __all__. So, before __all__ support, it wouldn't trigger the infer_definition_types query and fallback to using Type::ModuleType.to_instance(db).member(db, name) instead which would avoid the cycle.

Custom typeshed with only the following files:

stdlib/builtins.pyi:

class object: ...
class type: ...
class int: ...
class str: ...
class list: ...

stdlib/types.pyi:

__all__ = ["ModuleType"]

class ModuleType: ...

stdlib/typing.pyi:

__all__ = ["reveal_type"]

def reveal_type[T](obj: T, /) -> T: ...

stdlib/VERSIONS:

builtins: 3.0-
types: 3.0-
typing: 3.5-

Version

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingimportsModule resolution, site-packages discovery, import-related diagnostics

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions