Skip to content

Commit 9f146b3

Browse files
authored
Merge pull request #787 from python-rope/lieryan-typing-import-info
Add type hints to importinfo.py and add repr to ImportInfo
2 parents 14d6fd2 + 3f89161 commit 9f146b3

File tree

4 files changed

+58
-14
lines changed

4 files changed

+58
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# **Upcoming release**
22

3+
- #787 Add type hints to importinfo.py and add repr to ImportInfo (@lieryan)
34
- #786 Upgrade Actions used in Github Workflows (@lieryan)
45
- #785 Refactoring movetest.py (@lieryan)
56

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ force-exclude = 'ropetest|rope/base/prefs.py'
8787
[tool.coverage.report]
8888
exclude_also = [
8989
"if TYPE_CHECKING:",
90+
"raise NotImplementedError()",
9091
]
9192

9293
[tool.isort]

rope/refactor/importutils/importinfo.py

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from typing import List, Tuple
1+
from abc import abstractmethod, ABC
2+
from typing import List, Tuple, Optional, Protocol
23

34

45
class ImportStatement:
@@ -64,17 +65,22 @@ def accept(self, visitor):
6465
return visitor.dispatch(self)
6566

6667

67-
class ImportInfo:
68-
def get_imported_primaries(self, context):
69-
pass
68+
class ImportInfo(ABC):
69+
names_and_aliases: List[Tuple[str, Optional[str]]]
70+
71+
@abstractmethod
72+
def get_imported_primaries(self, context) -> List[str]: ...
7073

7174
def get_imported_names(self, context):
7275
return [
7376
primary.split(".")[0] for primary in self.get_imported_primaries(context)
7477
]
7578

76-
def get_import_statement(self):
77-
pass
79+
def __repr__(self):
80+
return f'<{self.__class__.__name__} "{self.get_import_statement()}">'
81+
82+
@abstractmethod
83+
def get_import_statement(self) -> str: ...
7884

7985
def is_empty(self):
8086
pass
@@ -105,10 +111,13 @@ def get_empty_import():
105111

106112

107113
class NormalImport(ImportInfo):
108-
def __init__(self, names_and_aliases):
114+
def __init__(
115+
self,
116+
names_and_aliases: List[Tuple[str, Optional[str]]],
117+
) -> None:
109118
self.names_and_aliases = names_and_aliases
110119

111-
def get_imported_primaries(self, context):
120+
def get_imported_primaries(self, context) -> List[str]:
112121
result = []
113122
for name, alias in self.names_and_aliases:
114123
if alias:
@@ -117,7 +126,7 @@ def get_imported_primaries(self, context):
117126
result.append(name)
118127
return result
119128

120-
def get_import_statement(self):
129+
def get_import_statement(self) -> str:
121130
result = "import "
122131
for name, alias in self.names_and_aliases:
123132
result += name
@@ -131,12 +140,20 @@ def is_empty(self):
131140

132141

133142
class FromImport(ImportInfo):
134-
def __init__(self, module_name, level, names_and_aliases):
143+
module_name: str
144+
level: int
145+
146+
def __init__(
147+
self,
148+
module_name: str,
149+
level: int,
150+
names_and_aliases: List[Tuple[str, Optional[str]]],
151+
):
135152
self.module_name = module_name
136153
self.level = level
137154
self.names_and_aliases = names_and_aliases
138155

139-
def get_imported_primaries(self, context):
156+
def get_imported_primaries(self, context) -> List[str]:
140157
if self.names_and_aliases[0][0] == "*":
141158
module = self.get_imported_module(context)
142159
return [name for name in module if not name.startswith("_")]
@@ -173,7 +190,7 @@ def get_imported_module(self, context):
173190
self.module_name, context.folder, self.level
174191
)
175192

176-
def get_import_statement(self):
193+
def get_import_statement(self) -> str:
177194
result = "from " + "." * self.level + self.module_name + " import "
178195
for name, alias in self.names_and_aliases:
179196
result += name
@@ -190,14 +207,17 @@ def is_star_import(self):
190207

191208

192209
class EmptyImport(ImportInfo):
193-
names_and_aliases: List[Tuple[str, str]] = []
210+
names_and_aliases = []
194211

195212
def is_empty(self):
196213
return True
197214

198-
def get_imported_primaries(self, context):
215+
def get_imported_primaries(self, context) -> List[str]:
199216
return []
200217

218+
def get_import_statement(self) -> str:
219+
raise NotImplementedError()
220+
201221

202222
class ImportContext:
203223
def __init__(self, project, folder):

ropetest/reprtest.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from rope.contrib import findit
1111
from rope.contrib.autoimport import models
1212
from rope.refactor import occurrences
13+
from rope.refactor.importutils import importinfo
1314
from ropetest import testutils
1415

1516

@@ -165,3 +166,24 @@ def test_autoimport_models_finalquery(project, mod1):
165166
obj = models.Package.delete_by_package_name
166167
assert isinstance(obj, models.FinalQuery)
167168
assert repr(obj) == expected_repr
169+
170+
171+
def test_repr_normal_import(project):
172+
obj = importinfo.NormalImport([("abc", None), ("ghi", "jkl")])
173+
expected_repr = '<NormalImport "import abc, ghi as jkl">'
174+
assert isinstance(obj, importinfo.NormalImport)
175+
assert repr(obj) == expected_repr
176+
177+
178+
def test_repr_from_import(project):
179+
obj = importinfo.FromImport("pkg1.pkg2", 0, [("abc", None), ("ghi", "jkl")])
180+
expected_repr = '<FromImport "from pkg1.pkg2 import abc, ghi as jkl">'
181+
assert isinstance(obj, importinfo.FromImport)
182+
assert repr(obj) == expected_repr
183+
184+
185+
def test_repr_from_import_with_level(project):
186+
obj = importinfo.FromImport("pkg1.pkg2", 3, [("abc", None), ("ghi", "jkl")])
187+
expected_repr = '<FromImport "from ...pkg1.pkg2 import abc, ghi as jkl">'
188+
assert isinstance(obj, importinfo.FromImport)
189+
assert repr(obj) == expected_repr

0 commit comments

Comments
 (0)