Skip to content

Forbid lazy imports - #3758

Open
Khabib73 wants to merge 3 commits into
wemake-services:masterfrom
Khabib73:feat/lazy
Open

Forbid lazy imports#3758
Khabib73 wants to merge 3 commits into
wemake-services:masterfrom
Khabib73:feat/lazy

Conversation

@Khabib73

Copy link
Copy Markdown
Contributor

I have made things!

Refs #3639

We need to wait 3.15

@Khabib73

Copy link
Copy Markdown
Contributor Author

CI falling precisely because of code coverage :)

@sobolevn sobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please test lazy from, add a changelog entry.

)


def test_lazy_import():

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need these tests?


lazy import json

def some():

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, remove the function.


def some():
import json
...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
...

Is only emitted on ``python3.15+``.

Reasoning:
...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is an overly complicated feature that is needed for just a couple use-cases. Retuning an object from a function does exactly the same thing: it imports something and returns it, when needed.

self._check_lazy_import(node)

def _check_lazy_import(self, node: ast.Import | ast.ImportFrom) -> None:
if PY315 and imports.is_lazy_import(node):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if PY315 should be a part of the logic, not visitor.

class _ImportLazy(_BaseImportValidator):
"""Validator of ``ast.Import`` and ``ast.ImportFrom`` nodes."""

def validate(self, node: ast.Import | ast.ImportFrom) -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have an alias for this? AnyImport?

@Khabib73
Khabib73 requested a review from sobolevn August 13, 2026 15:41

@sobolevn sobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, add 3.15rc1 into the test matrix and fix the CI :)

def validate(self, node: AnyImport) -> None:
self._check_lazy_import(node)

def _check_lazy_import(self, node: AnyImport) -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can squash these two methods into one

return blacklisted or with_from_or_to or too_short


def is_lazy_import(node: AnyImport) -> bool:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, add conditional coverage everywhere.

Comment on lines +59 to +64
>>> is_lazy_import(ast.Import(names=[ast.alias(name='a')]))
False

>>> is_lazy_import(ast.Import(names=[ast.alias(name='a')], is_lazy=1))
True

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
>>> is_lazy_import(ast.Import(names=[ast.alias(name='a')]))
False
>>> is_lazy_import(ast.Import(names=[ast.alias(name='a')], is_lazy=1))
True

function is simple enough, we can remove this example / test.

Comment on lines +66 to +68
if not PY315:
return False
return bool(getattr(node, 'is_lazy', False))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not PY315:
return False
return bool(getattr(node, 'is_lazy', False))
return bool(getattr(node, 'is_lazy', False))

It would return False on other python versions by default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, but I thought that it would be useful for docs :)

from wemake_python_styleguide.visitors.ast.imports import WrongImportVisitor

if not PY315: # pragma: >=3.15 no cover
pytest.skip( # pragma: no cover

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use skipif with module-level?

"""

error_template = (
'Found a lazy import, use a regular import inside a function instead'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'Found a lazy import, use a regular import inside a function instead'
'Found a lazy import'

Comment thread CHANGELOG.md
### Features

- Adds `WPS482`: forbid lazy imports, #3639

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please test lazy from, add a changelog entry.

🤔

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use 2 empty lines between versions :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants