pylint icon indicating copy to clipboard operation
pylint copied to clipboard

Relative imports broken in pylint 2.5.2

Open bsiem opened this issue 4 years ago • 6 comments

Pylint fails with relative imports within a package. Having a package b in directory a with three files:

a/b/__init__.py

from .one import ONE
from .two import TWO

a/b/one.py

ONE = 1

a/b/two.py

from .one import ONE
TWO = ONE + ONE

pylint 2.4.4 + astroid 2.3.3 do not generate any warning or error, which is as expected.

pylint 2.5.2 + astroid 2.4.1 generates an import-error:

$ export PYTHONPATH=/full/path/to/a
$ cd /full/path/to
$ pylint a
************* Module a.b
a/b/__init__.py:2:0: E0401: Unable to import 'a.b.two' (import-error)

Versions:

$ pylint --version pylint 2.5.2 astroid 2.4.1 Python 3.8.3 (default, May 17 2020, 18:15:42) [GCC 10.1.0]

bsiem avatar May 28 '20 08:05 bsiem

I also run into this. But I get "E402 : Attempted relative import beyond top-level package (relative-beyond-top-level)" instead of E401. Also the error depends on what $(pwd) is when pylint is launched. A reproducer that you can copy-paste:

cd /tmp
mkdir -p a/ 
touch a/__init__.py 
echo -e "s = 1\nprint(s)" > a/b.py 
echo -e "from .b import s\nprint(s)" > a/c.py 
cd /tmp/a/
pylint /tmp/a/c.py # error E402
cd /tmp/
pylint /tmp/a/c.py # ok
cd /
pylint /tmp/a/c.py # ok

cnliao avatar May 28 '20 11:05 cnliao

I also run into this. But I get "E402 : Attempted relative import beyond top-level package (relative-beyond-top-level)" instead of E401. Also the error depends on what $(pwd) is when pylint is launched. A reproducer that you can copy-paste:

Thank you! That issue is already reported, but it is a different case. If you want to test the case that is described in this issue:

mkdir -p /tmp/a/b
echo -e "ONE = 1" > /tmp/a/b/one.py
echo -e "from .one import ONE\nTWO = ONE + ONE" > /tmp/a/b/two.py
echo -e "from .one import ONE\nfrom .two import TWO" > /tmp/a/b/__init__.py
echo -e "import b\nprint(b.TWO)" > /tmp/a/main.py
cd /tmp
pylint a

Setting PYTHONPATH (to /tmp/a) does not make a difference.

bsiem avatar May 28 '20 11:05 bsiem

I noticed that this issues is very sensitive to the environment - i.e. it triggered on the dev machine but not the CI. The discrepancy appears even with tox inside the identical docker image.

Apparently the reason is that it is sensitive to the order in which files are iterated (os.walk) by asroid.

tilsche avatar Oct 07 '20 21:10 tilsche

I'm seeing this was fixed in PyCQA/astroid@2ee20ccdf62450db611acc4a1a7e42f407ce8a14 (2.9.1). A test would be a good idea, though, since it looks a little orthogonal to what was described there.

jacobtylerwalls avatar Jul 03 '22 05:07 jacobtylerwalls

See a report in https://github.com/PyCQA/pylint/issues/5319#issuecomment-1192998978 that this isn't fixed yet on astroid 2.11.7.

jacobtylerwalls avatar Jul 22 '22 23:07 jacobtylerwalls

See an attempt at a regression test in #7117

jacobtylerwalls avatar Jul 31 '22 19:07 jacobtylerwalls

In the original example, a is not a package. In more modern versions of pylint/astroid --recursive=y is the solution for iterating directories to find packages, e.g. b. #7117 adds a test to ensure a/b can be linted.

jacobtylerwalls avatar Aug 21 '22 14:08 jacobtylerwalls