Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circular import detected when module exported in __init__.py imports another module from the same package #1864

Closed
ravindUwU opened this issue Sep 23, 2021 · 4 comments

Comments

@ravindUwU
Copy link

In a VSCode workspace with "python.analysis.typeCheckingMode": "strict" and the following project structure,

# pack/secondary.py
	class Foo:
		pass

# pack/primary.py
	from . import secondary

	class Foo:
		def __init__(self, sec: secondary.Foo) -> None:
			pass

# pack/__init__.py
	__all__ = [
		'Foo',
	]

	from .primary import Foo

Pylance detects a circular import because primary.Foo imports secondary.Foo from the same package via the from . import ... statement. Is this expected? 🤔

Importing secondary.Foo via a from .secondary import Foo as SecondaryFoo works.

Expected behaviour

(No errors)

Actual behaviour

Error at pack/__init__.py:1.

Cycle detected in import chain
  pack\__init__.py
  pack\primary.py

Environment data

  • Language Server version: v2021.9.3
  • OS and version: Windows 10 Home 19043.1237
  • Python version: 3.9.7

Logs

Python Language Server
[Info  - 1:59:48 pm] Pylance language server 2021.9.3 (pyright d2771b18) starting
[Info  - 1:59:48 pm] Server root directory: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist
[Info  - 1:59:48 pm] No configuration file found.
[Info  - 1:59:48 pm] No pyproject.toml file found.
[Info  - 1:59:48 pm] Setting pythonPath for service "project": "~\project\.venv\Scripts\python.exe"
[Warn  - 1:59:48 pm] stubPath ~\project\typings is not a valid directory.
[Info  - 1:59:48 pm] Assuming Python version 3.9
[Info  - 1:59:48 pm] Assuming Python platform Windows
Search paths for ~\project
  ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib
  ~\project
  ~\project\typings
  ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stubs\...
  ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\bundled\stubs
  ~\AppData\Local\Programs\Python\Python39\DLLs
  ~\AppData\Local\Programs\Python\Python39\Lib
  ~\AppData\Local\Programs\Python\Python39
  ~\project\.venv
  ~\project\.venv\Lib\site-packages
[Info  - 1:59:49 pm] Searching for source files
[Info  - 1:59:49 pm] Auto-excluding ~\project\.venv
[Info  - 1:59:49 pm] Found 3 source files
[Info  - 1:59:49 pm] Background analysis(1) root directory: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist
[Info  - 1:59:49 pm] Background analysis(1) started
Background analysis message: setConfigOptions
Background analysis message: setImportResolver
Background analysis message: ensurePartialStubPackages
Background analysis message: setTrackedFiles
Background analysis message: markAllFilesDirty
Background analysis message: setFileOpened
Background analysis message: getSemanticTokens full
[BG(1)] getSemanticTokens full at ~\project\pack\__init__.py ...
[BG(1)]   parsing: ~\project\pack\__init__.py (12ms)
[BG(1)]   parsing: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\builtins.pyi [fs read 2ms] (96ms)
[BG(1)]   binding: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\builtins.pyi (37ms)
[BG(1)]   binding: ~\project\pack\__init__.py (0ms)
[BG(1)]   parsing: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\typing.pyi [fs read 3ms] (66ms)
[BG(1)]   binding: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\typing.pyi (20ms)
[BG(1)]   parsing: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\_typeshed\__init__.pyi [fs read 1ms] (8ms)
[BG(1)]   binding: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\_typeshed\__init__.pyi (2ms)
[BG(1)]   parsing: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\typing_extensions.pyi [fs read 0ms] (2ms)
[BG(1)]   binding: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\typing_extensions.pyi (1ms)
[BG(1)]   parsing: ~\project\pack\primary.py [fs read 1ms] (3ms)
[BG(1)]   binding: ~\project\pack\primary.py (1ms)
[BG(1)] getSemanticTokens full at ~\project\pack\__init__.py (283ms)
Background analysis message: getSemanticTokens range
[BG(1)] getSemanticTokens range 0:0 - 5:0 at ~\project\pack\__init__.py (1ms)
Background analysis message: analyze
[BG(1)] analyzing: ~\project\pack\__init__.py ...
[BG(1)]   checking: ~\project\pack\__init__.py (4ms)
[BG(1)] analyzing: ~\project\pack\__init__.py (5ms)
Background analysis message: resumeAnalysis
Background analysis message: getDiagnosticsForRange
Background analysis message: getDiagnosticsForRange
[FG] parsing: ~\project\pack\__init__.py (12ms)
[FG] parsing: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\builtins.pyi [fs read 2ms] (87ms)
[FG] binding: ~\.vscode\extensions\ms-python.vscode-pylance-2021.9.3\dist\typeshed-fallback\stdlib\builtins.pyi (35ms)
[FG] binding: ~\project\pack\__init__.py (0ms)
@erictraut
Copy link
Contributor

The from . import secondary statement in primary.py is referencing __init__.py, but __init__.py is importing the primary submodule.

You've already discovered the approach I would recommend — to change the import statement in primary.py to from .secondary import Foo as _Foo or something similar.

The cycle detection logic in pylance is an advanced (strict-mode) feature that is off by default. Some cycles that it detects may not cause problems at runtime, but they can result in code fragility that will result in a runtime error when code is modified. If you prefer, you can leave it disabled.

@ravindUwU
Copy link
Author

ravindUwU commented Sep 23, 2021

Yeah; from .secondary import ... as ... does get kinda clunky when one has to import many members from secondary 😅.
import .secondary as secondary doesn't work either.

@erictraut thanks; is this a non-issue?

@gilbsgilbs
Copy link

gilbsgilbs commented Oct 21, 2021

I'm hitting the exact same issue. I ended up disabling this rule because importing lots of objects directly from the module instead of importing the module itself tends to pollute the namespace, which makes code harder to read and write. Yet, as @ravindUwU noted, it still feels wrong to disable this rule just because import .secondary is a syntax error in Python.

I completely understand the rationale behind the rule so closing this as wontfix may be acceptable, but maybe adding an option to skip the __init__.py file when importing a bound name would be a way to address our issue without loosing all the benefit from cycles detection?

@judej
Copy link
Contributor

judej commented Apr 20, 2022

Closing old issue. If this is still a problem, please reopen with the information requested. thanks

@judej judej closed this as completed Apr 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants