Skip to content

Commit 1437e73

Browse files
authored
Fix relative-beyond-top-level false positive (#1186)
* Fix ``relative-beyond-top-level`` false positive
1 parent 1419ac5 commit 1437e73

File tree

7 files changed

+34
-2
lines changed

7 files changed

+34
-2
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ Release date: TBA
3636

3737
* Improve brain for ``typing.Callable`` and ``typing.Type``.
3838

39+
* Fix bug with importing namespace packages with relative imports
40+
41+
Closes PyCQA/pylint#5059
42+
3943

4044
What's New in astroid 2.8.0?
4145
============================

astroid/nodes/scoped_nodes.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import builtins
4444
import io
4545
import itertools
46+
import os
4647
import typing
4748
from typing import List, Optional, TypeVar
4849

@@ -732,10 +733,17 @@ def relative_to_absolute_name(self, modname, level):
732733
if level:
733734
if self.package:
734735
level = level - 1
736+
package_name = self.name.rsplit(".", level)[0]
737+
elif not os.path.exists("__init__.py") and os.path.exists(
738+
modname.split(".")[0]
739+
):
740+
level = level - 1
741+
package_name = ""
742+
else:
743+
package_name = self.name.rsplit(".", level)[0]
735744
if level and self.name.count(".") < level:
736745
raise TooManyLevelsError(level=level, name=self.name)
737746

738-
package_name = self.name.rsplit(".", level)[0]
739747
elif self.package:
740748
package_name = self.name
741749
else:
@@ -744,7 +752,7 @@ def relative_to_absolute_name(self, modname, level):
744752
if package_name:
745753
if not modname:
746754
return package_name
747-
return f"{package_name}.{modname}"
755+
return f"{package_name}.{modname.split('.')[0]}"
748756
return modname
749757

750758
def wildcard_import_names(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from namespace_package import top_level_function
2+
3+
top_level_function.do_something()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from ..plugin_api import top_message
2+
3+
4+
def plugin_message(msg):
5+
return "plugin_message: %s" % top_message(msg)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def top_message(msg):
2+
return "top_message: %s" % msg
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .lower_level.helper_function import plugin_message
2+
3+
4+
def do_something():
5+
return plugin_message("called by do_something")

tests/unittest_inference.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6535,5 +6535,10 @@ def play():
65356535
assert next(node.infer()).pytype() == ".B"
65366536

65376537

6538+
def test_namespace_package() -> None:
6539+
"""check that a file using namespace packages and relative imports is parseable"""
6540+
resources.build_file("data/beyond_top_level/import_package.py")
6541+
6542+
65386543
if __name__ == "__main__":
65396544
unittest.main()

0 commit comments

Comments
 (0)