Skip to content

Commit 4bba655

Browse files
committed
Implement config setting imports.preferred_import_style
1 parent 9d7f2ef commit 4bba655

3 files changed

Lines changed: 107 additions & 7 deletions

File tree

docs/default_config.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,13 @@ def set_prefs(prefs):
107107
#
108108
# prefs["ignore_bad_imports"] = False
109109

110-
# If `True`, rope will insert new module imports as
111-
# `from <package> import <module>` by default.
110+
# Controls how rope inserts new import statements. Must be one of:
111+
#
112+
# - "normal-import" will insert `import <package>`
113+
# - "from-module" will insert `from <package> import <module>`
114+
# - "from-global" insert insert `from <package>.<module> import <object>`
112115
#
113-
# prefs["prefer_module_from_imports"] = False
116+
# prefs.imports.preferred_import_style = "normal-import"
114117

115118
# If `True`, rope will transform a comma list of imports into
116119
# multiple separate import statements when organizing

rope/base/prefs.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Rope preferences."""
2+
from enum import Enum
23
from dataclasses import asdict, dataclass
34
from textwrap import dedent
45
from typing import Any, Callable, Dict, List, Optional, Tuple
@@ -34,6 +35,20 @@ class AutoimportPrefs:
3435
)
3536

3637

38+
@dataclass
39+
class ImportPrefs:
40+
preferred_import_style: str = field(
41+
default="default",
42+
description=dedent("""
43+
Controls how rope inserts new import statements. If set to
44+
``"normal-import"`` (default) will insert ``import <package>``; if
45+
set to ``"from-module"`` will insert ``from <package> import
46+
<module>``; if set to ``"from-global"`` rope will insert ``from
47+
<package>.<module> import <object>``.
48+
"""),
49+
)
50+
51+
3752
@dataclass
3853
class Prefs:
3954
"""Class to store rope preferences."""
@@ -149,7 +164,7 @@ class Prefs:
149164
default=False,
150165
description=dedent("""
151166
If ``True`` modules with syntax errors are considered to be empty.
152-
The default value is ``False``; When ``False`` syntax errors raise
167+
The default value is ``False``; when ``False`` syntax errors raise
153168
``rope.base.exceptions.ModuleSyntaxError`` exception.
154169
"""),
155170
)
@@ -164,8 +179,8 @@ class Prefs:
164179
prefer_module_from_imports: bool = field(
165180
default=False,
166181
description=dedent("""
167-
If ``True``, rope will insert new module imports as ``from
168-
<package> import <module>`` by default.
182+
**Deprecated**. ``imports.preferred_import_style`` takes
183+
precedence over ``prefer_module_from_imports``.
169184
"""),
170185
)
171186

@@ -232,7 +247,13 @@ class Prefs:
232247
"""),
233248
)
234249
autoimport: AutoimportPrefs = field(
235-
default_factory=AutoimportPrefs, description="Preferences for Autoimport")
250+
default_factory=AutoimportPrefs,
251+
description="Preferences for Autoimport",
252+
)
253+
imports: ImportPrefs = field(
254+
default_factory=ImportPrefs,
255+
description="Preferences for Import Organiser",
256+
)
236257

237258
def set(self, key: str, value: Any):
238259
"""Set the value of `key` preference to `value`."""
@@ -320,3 +341,21 @@ def get_config(root: Folder, ropefolder: Folder) -> PyToolConfig:
320341
global_config=True,
321342
)
322343
return config
344+
345+
346+
class ImportStyle(Enum): # FIXME: Use StrEnum once we're on minimum Python 3.11
347+
normal_import = "normal-import"
348+
from_module = "from-module"
349+
from_global = "from-global"
350+
351+
352+
DEFAULT_IMPORT_STYLE = ImportStyle.normal_import
353+
354+
355+
def get_preferred_import_style(prefs: Prefs) -> ImportStyle:
356+
try:
357+
return ImportStyle(prefs.imports.preferred_import_style)
358+
except ValueError:
359+
if prefs.imports.preferred_import_style == "default" and prefs.prefer_module_from_imports:
360+
return ImportStyle.from_module
361+
return DEFAULT_IMPORT_STYLE

ropetest/refactor/importutilstest.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,68 @@
11
import unittest
22
from textwrap import dedent
33

4+
from rope.base.prefs import get_preferred_import_style, ImportStyle, Prefs, ImportPrefs
5+
from rope.base.prefs import DEFAULT_IMPORT_STYLE
46
from rope.refactor.importutils import ImportTools, add_import, importinfo
57
from ropetest import testutils
68

79

10+
class TestImportPrefs:
11+
def test_preferred_import_style_is_normal_import(self, project):
12+
pref = Prefs(imports=ImportPrefs(preferred_import_style="normal-import"))
13+
assert pref.imports.preferred_import_style == "normal-import"
14+
assert get_preferred_import_style(pref) == ImportStyle.normal_import
15+
16+
def test_preferred_import_style_is_from_module(self, project):
17+
pref = Prefs(imports=ImportPrefs(preferred_import_style="from-module"))
18+
assert pref.imports.preferred_import_style == "from-module"
19+
assert get_preferred_import_style(pref) == ImportStyle.from_module
20+
21+
def test_preferred_import_style_is_from_global(self, project):
22+
pref = Prefs(imports=ImportPrefs(preferred_import_style="from-global"))
23+
assert pref.imports.preferred_import_style == "from-global"
24+
assert get_preferred_import_style(pref) == ImportStyle.from_global
25+
26+
def test_invalid_preferred_import_style_is_default(self, project):
27+
pref = Prefs(imports=ImportPrefs(preferred_import_style="invalid-value"))
28+
assert pref.imports.preferred_import_style == "invalid-value"
29+
assert get_preferred_import_style(pref) == DEFAULT_IMPORT_STYLE
30+
assert get_preferred_import_style(pref) == ImportStyle.normal_import
31+
32+
def test_default_preferred_import_style_default_is_normal_imports(self, project):
33+
pref = Prefs()
34+
assert pref.imports.preferred_import_style == "default"
35+
assert get_preferred_import_style(pref) == ImportStyle.normal_import
36+
37+
def test_default_preferred_import_style_default_and_prefer_module_from_imports(self, project):
38+
pref = Prefs(
39+
prefer_module_from_imports=True,
40+
imports=ImportPrefs(preferred_import_style="default"),
41+
)
42+
assert get_preferred_import_style(pref) == ImportStyle.from_module
43+
44+
def test_preferred_import_style_is_normal_import_takes_precedence_over_prefer_module_from_imports(self, project):
45+
pref = Prefs(
46+
prefer_module_from_imports=True,
47+
imports=ImportPrefs(preferred_import_style="normal_import"),
48+
)
49+
assert get_preferred_import_style(pref) == ImportStyle.normal_import
50+
51+
def test_preferred_import_style_is_from_module_takes_precedence_over_prefer_module_from_imports(self, project):
52+
pref = Prefs(
53+
prefer_module_from_imports=True,
54+
imports=ImportPrefs(preferred_import_style="from-module"),
55+
)
56+
assert get_preferred_import_style(pref) == ImportStyle.from_module
57+
58+
def test_preferred_import_style_is_from_global_takes_precedence_over_prefer_module_from_imports(self, project):
59+
pref = Prefs(
60+
prefer_module_from_imports=True,
61+
imports=ImportPrefs(preferred_import_style="from-global"),
62+
)
63+
assert get_preferred_import_style(pref) == ImportStyle.from_global
64+
65+
866
class ImportUtilsTest(unittest.TestCase):
967
def setUp(self):
1068
super().setUp()

0 commit comments

Comments
 (0)