Skip to content

Commit e6422f9

Browse files
authored
Allow to configure import style from extension (#29)
1 parent 8d0dd85 commit e6422f9

File tree

6 files changed

+77
-33
lines changed

6 files changed

+77
-33
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ uv.lock
99
.pytest_cache
1010
.ruff_cache
1111
testing/*.py
12+
testing/.vscode

auto_typing_final/lsp.py

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import uuid
12
from collections.abc import Iterable
23
from importlib.metadata import version
3-
from typing import cast
4+
from typing import cast, get_args
45

56
import attr
67
import cattrs
@@ -9,10 +10,17 @@
910
from pygls import server
1011
from pygls.workspace import TextDocument
1112

12-
from auto_typing_final.transform import IMPORT_MODES_TO_IMPORT_CONFIGS, AddFinal, Edit, ImportMode, make_replacements
13+
from auto_typing_final.transform import (
14+
IMPORT_STYLES_TO_IMPORT_CONFIGS,
15+
AddFinal,
16+
Edit,
17+
ImportConfig,
18+
ImportStyle,
19+
make_replacements,
20+
)
1321

1422
LSP_SERVER = server.LanguageServer(name="auto-typing-final", version=version("auto-typing-final"), max_workers=5)
15-
IMPORT_CONFIG = IMPORT_MODES_TO_IMPORT_CONFIGS[ImportMode.typing_final]
23+
IMPORT_CONFIG: ImportConfig | None = None
1624

1725

1826
@attr.define
@@ -45,15 +53,17 @@ def make_text_edit(edit: Edit) -> lsp.TextEdit:
4553

4654

4755
def make_diagnostics(source: str) -> Iterable[lsp.Diagnostic]:
56+
if not IMPORT_CONFIG:
57+
return
4858
result = make_replacements(root=SgRoot(source, "python").root(), import_config=IMPORT_CONFIG)
4959

5060
for replacement in result.replacements:
5161
if replacement.operation_type == AddFinal:
52-
fix_message = f"{LSP_SERVER.name}: Add typing.Final"
53-
diagnostic_message = "Missing typing.Final"
62+
fix_message = f"{LSP_SERVER.name}: Add {IMPORT_CONFIG.value}"
63+
diagnostic_message = f"Missing {IMPORT_CONFIG.value}"
5464
else:
55-
fix_message = f"{LSP_SERVER.name}: Remove typing.Final"
56-
diagnostic_message = "Unexpected typing.Final"
65+
fix_message = f"{LSP_SERVER.name}: Remove {IMPORT_CONFIG.value}"
66+
diagnostic_message = f"Unexpected {IMPORT_CONFIG.value}"
5767

5868
fix = Fix(message=fix_message, text_edits=[make_text_edit(edit) for edit in replacement.edits])
5969
if result.import_text:
@@ -74,6 +84,8 @@ def make_diagnostics(source: str) -> Iterable[lsp.Diagnostic]:
7484

7585

7686
def make_fixall_text_edits(source: str) -> Iterable[lsp.TextEdit]:
87+
if not IMPORT_CONFIG:
88+
return
7789
result = make_replacements(root=SgRoot(source, "python").root(), import_config=IMPORT_CONFIG)
7890

7991
for replacement in result.replacements:
@@ -98,7 +110,35 @@ def make_workspace_edit(text_document: TextDocument, text_edits: list[lsp.TextEd
98110

99111

100112
@LSP_SERVER.feature(lsp.INITIALIZE)
101-
def initialize(params: lsp.InitializeParams) -> None: ... # noqa: ARG001
113+
async def initialize(_: lsp.InitializeParams) -> None: ...
114+
115+
116+
@LSP_SERVER.feature(lsp.INITIALIZED)
117+
async def initialized(_: lsp.InitializedParams) -> None:
118+
await LSP_SERVER.register_capability_async(
119+
params=lsp.RegistrationParams(
120+
registrations=[
121+
lsp.Registration(
122+
id=str(uuid.uuid4()),
123+
method=lsp.WORKSPACE_DID_CHANGE_CONFIGURATION,
124+
register_options=lsp.DidChangeConfigurationRegistrationOptions(section=LSP_SERVER.name),
125+
)
126+
]
127+
)
128+
)
129+
130+
131+
@LSP_SERVER.feature(lsp.WORKSPACE_DID_CHANGE_CONFIGURATION)
132+
def workspace_did_change_configuration(params: lsp.DidChangeConfigurationParams) -> None:
133+
if (
134+
isinstance(params.settings, dict)
135+
and (settings := params.settings.get(LSP_SERVER.name))
136+
and isinstance(settings, dict)
137+
and (import_style := settings.get("import-style"))
138+
and (import_style in get_args(ImportStyle))
139+
):
140+
global IMPORT_CONFIG # noqa: PLW0603
141+
IMPORT_CONFIG = IMPORT_STYLES_TO_IMPORT_CONFIGS[import_style]
102142

103143

104144
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_OPEN)

auto_typing_final/main.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,11 @@
33
from collections.abc import Iterable
44
from difflib import unified_diff
55
from pathlib import Path
6+
from typing import get_args
67

78
from ast_grep_py import SgRoot
89

9-
from auto_typing_final.transform import (
10-
IMPORT_MODES_TO_IMPORT_CONFIGS,
11-
ImportConfig,
12-
ImportMode,
13-
make_replacements,
14-
)
10+
from auto_typing_final.transform import IMPORT_STYLES_TO_IMPORT_CONFIGS, ImportConfig, ImportStyle, make_replacements
1511

1612

1713
def transform_file_content(source: str, import_config: ImportConfig) -> str:
@@ -49,10 +45,10 @@ def main() -> int:
4945
parser = argparse.ArgumentParser()
5046
parser.add_argument("files", type=Path, nargs="*")
5147
parser.add_argument("--check", action="store_true")
52-
parser.add_argument("--import-mode", type=ImportMode, default=ImportMode.typing_final)
48+
parser.add_argument("--import-style", type=str, choices=get_args(ImportStyle), default="typing-final")
5349

5450
args = parser.parse_args()
55-
import_config = IMPORT_MODES_TO_IMPORT_CONFIGS[args.import_mode]
51+
import_config = IMPORT_STYLES_TO_IMPORT_CONFIGS[args.import_style]
5652

5753
has_changes = False
5854

auto_typing_final/transform.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import re
22
from collections.abc import Iterable
33
from dataclasses import dataclass
4-
from enum import Enum
4+
from typing import Literal
55

66
from ast_grep_py import SgNode
77

88
from auto_typing_final.finder import find_all_definitions_in_functions, has_global_identifier_with_name
99

10-
11-
class ImportMode(Enum):
12-
typing_final = "typing-final"
13-
final = "final"
10+
ImportStyle = Literal["typing-final", "final"]
1411

1512

1613
@dataclass
@@ -21,14 +18,14 @@ class ImportConfig:
2118
import_identifier: str
2219

2320

24-
IMPORT_MODES_TO_IMPORT_CONFIGS = {
25-
ImportMode.typing_final: ImportConfig(
21+
IMPORT_STYLES_TO_IMPORT_CONFIGS: dict[ImportStyle, ImportConfig] = {
22+
"typing-final": ImportConfig(
2623
value="typing.Final",
2724
outer_regex=re.compile(r"typing\.Final\[(.*)\]{1}"),
2825
import_text="import typing",
2926
import_identifier="typing",
3027
),
31-
ImportMode.final: ImportConfig(
28+
"final": ImportConfig(
3229
value="Final",
3330
outer_regex=re.compile(r"Final\[(.*)\]{1}"),
3431
import_text="from typing import Final",

package.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,21 @@
2424
"category": "auto-typing-final",
2525
"command": "auto-typing-final.restart"
2626
}
27-
]
27+
],
28+
"configuration": {
29+
"properties": {
30+
"auto-typing-final.import-style": {
31+
"default": "typing-final",
32+
"enum": ["typing-final", "final"],
33+
"enumDescriptions": [
34+
"Use `import typing` and `typing.Final`",
35+
"Use `from typing import Final` and `Final`"
36+
],
37+
"description": "Import style",
38+
"scope": "resource"
39+
}
40+
}
41+
}
2842
},
2943
"scripts": {
3044
"lint": "biome format --write .",

tests/test_main.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import pytest
22

33
from auto_typing_final.main import transform_file_content
4-
from auto_typing_final.transform import (
5-
IMPORT_MODES_TO_IMPORT_CONFIGS,
6-
ImportConfig,
7-
ImportMode,
8-
)
4+
from auto_typing_final.transform import IMPORT_STYLES_TO_IMPORT_CONFIGS, ImportConfig
95

106

11-
@pytest.mark.parametrize("import_config", IMPORT_MODES_TO_IMPORT_CONFIGS.values())
7+
@pytest.mark.parametrize("import_config", IMPORT_STYLES_TO_IMPORT_CONFIGS.values())
128
@pytest.mark.parametrize(
139
("before", "after"),
1410
[
@@ -591,7 +587,7 @@ def foo(self):
591587
],
592588
)
593589
def test_transform_file_content(case: str) -> None:
594-
import_config = IMPORT_MODES_TO_IMPORT_CONFIGS[ImportMode.typing_final]
590+
import_config = IMPORT_STYLES_TO_IMPORT_CONFIGS["typing-final"]
595591
before, _, after = case.partition("---")
596592
assert (
597593
transform_file_content(f"{import_config.import_text}\n" + before.strip(), import_config=import_config)
@@ -656,5 +652,5 @@ def f():
656652
)
657653
def test_add_import(case: str) -> None:
658654
before, _, after = case.partition("---")
659-
import_config = IMPORT_MODES_TO_IMPORT_CONFIGS[ImportMode.typing_final]
655+
import_config = IMPORT_STYLES_TO_IMPORT_CONFIGS["typing-final"]
660656
assert transform_file_content(before.strip(), import_config=import_config) == after.strip()

0 commit comments

Comments
 (0)