Skip to content

Modules of files specified on the command line can be cached with the wrong name #7339

Open
@gcbirzan-plutoflume

Description

@gcbirzan-plutoflume

Bug description

When specifying on the command line files to check where the name of namespace package shares the name with a regular package in another namespace, the latter is cached in astroid with the name of the first package. This will cause any usage of the first one to break.

This happens because in two places sys.path is modified (once in place, once when calling astroid) to include the namespace package that contains the second namespace (I know it's confusing, see the example). But, the correct behaviour is to rely on sys.path and if the file is importable, not modify sys.path. This might cache the module with the wrong name (if sys.path contains, for example, foo and foo/bar, the stuff in foo/bar now is accessible by two names), but this only matters if it's imported, at which point it will be re-imported, with the correct name.

Setup

mkdir -p ns1/ ns2/ns1; touch ns1/m2.py ns2/ns1/__init__.py; echo 'import ns1.m2' > ns1/m1.py

ls -R (for visualising structure)

$ ls -R
ns1     ns2

./ns1:
m1.py   m2.py

./ns2:
ns1

./ns2/ns1:
__init__.py

Configuration

[MESSAGES CONTROL]

disable=C0114,W0611

Command used

pylint ns1/m1.py ns2/ns1/__init__.py

Pylint output

************* Module m1
ns1/m1.py:1:0: E0401: Unable to import 'ns1.m2' (import-error)
ns1/m1.py:1:0: E0611: No name 'm2' in module 'ns1' (no-name-in-module)

Expected behavior

This is perfectly valid code, which can be ran from the command line.

My suggested solution, as explained in the description is to check whether the file is importable normally and skip modifying sys.path. I don't think this would break anything, and it might fix other bugs I cannot imagine right now.

What I did was create a is_importable function that just calls astroid.modutils.modpath_from_file and returns False when it gets an import error, True otherwise. Then I skipped adding to sys.path when the file was directly importable.

I did this in here and here. This broke some tests, but still trying to figure exactly why and whether the tests are wrong or my code breaks some edge case. I'll update the issue once I have an answer on that.

Pylint version

pylint 2.15.0-a0
astroid 2.12.2
Python 3.7.4 (default, Oct 26 2021, 12:29:57) 
[Clang 12.0.0 (clang-1200.0.32.29)]

OS / Environment

No response

Additional dependencies

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bug 🪲Import systemNeeds PRThis issue is accepted, sufficiently specified and now needs an implementation

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions