Skip to content

Commit 4850991

Browse files
committed
Finish migration to ResourceUri and fix lint_files_dispatch handler (handle partial results correctly)
1 parent 3b867b9 commit 4850991

File tree

9 files changed

+57
-47
lines changed

9 files changed

+57
-47
lines changed

docs/wm-protocol.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ connect to it.
99
- TCP on `127.0.0.1`, random free port
1010
- Content-Length framing (same as LSP): `Content-Length: N\r\n\r\n{json_body}`
1111
- Discovery: port written to `.venvs/dev_workspace/cache/finecode/wm_port`
12-
- Auto-stops when the last client disconnects (after a 5s grace period) or if no client connects 30 seconds after start of WM Server
12+
- Auto-stops when the last client disconnects (after a 30s grace period by default, configurable via `--disconnect-timeout`) or if no client connects within 30 seconds after WM Server startup
1313

1414
## JSON-RPC 2.0
1515

@@ -715,11 +715,13 @@ Clients can log or display this path so the user can open the file directly when
715715

716716
#### `server/shutdown`
717717

718-
Explicitly shut down the WM Server.
718+
Explicitly shut down the WM Server. Clients can use this when they intentionally
719+
want the WM to stop or restart, rather than waiting for disconnect-timeout
720+
auto-shutdown.
719721

720722
- **Type:** request
721723
- **Clients:** any
722-
- **Status:** stub
724+
- **Status:** implemented
723725

724726
**Params:** `{}`
725727

extensions/fine_python_package_info/fine_python_package_info/is_artifact_published_to_registry_py_handler.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from finecode_extension_api import code_action
44
from finecode_extension_api.actions.artifact import get_src_artifact_registries_action
55
from finecode_extension_api.actions.publishing import is_artifact_published_to_registry_action
6+
from finecode_extension_api.resource_uri import resource_uri_to_path
67
from finecode_extension_api.interfaces import (
78
iactionrunner,
89
ihttpclient,
@@ -132,7 +133,7 @@ async def run(
132133
except KeyError as exception:
133134
raise code_action.ActionFailedException("File object has no 'filename' key") from exception
134135

135-
is_published_by_dist_path = {dist_path: dist_path.name in published_file_names for dist_path in dist_artifact_paths}
136+
is_published_by_dist_path = {dist_path: resource_uri_to_path(dist_path).name in published_file_names for dist_path in dist_artifact_paths}
136137
else:
137138
is_published_by_dist_path = {dist_path: False for dist_path in dist_artifact_paths}
138139

finecode_builtin_handlers/src/finecode_builtin_handlers/create_envs_discover_envs.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
ilogger,
88
iprojectinfoprovider,
99
)
10+
from finecode_extension_api.resource_uri import path_to_resource_uri
1011

1112

1213
@dataclasses.dataclass
@@ -52,10 +53,10 @@ async def run(
5253
envs = [
5354
create_envs_action.EnvInfo(
5455
name=env_name,
55-
venv_dir_path=self.runner_info_provider.get_venv_dir_path_of_env(
56-
env_name
56+
venv_dir_path=path_to_resource_uri(
57+
self.runner_info_provider.get_venv_dir_path_of_env(env_name)
5758
),
58-
project_def_path=project_def_path,
59+
project_def_path=path_to_resource_uri(project_def_path),
5960
)
6061
for env_name in deps_groups
6162
]

finecode_builtin_handlers/src/finecode_builtin_handlers/install_env_install_deps.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
InstallEnvsRunResult,
1010
)
1111
from finecode_extension_api.interfaces import iactionrunner, ilogger
12+
from finecode_extension_api.resource_uri import path_to_resource_uri, resource_uri_to_path
1213
from finecode_builtin_handlers.dependency_config_utils import process_raw_deps
1314

1415

@@ -53,19 +54,20 @@ async def run(
5354
.get(env.name, {})
5455
.get("dependencies", {})
5556
)
57+
project_def_path = resource_uri_to_path(env.project_def_path)
5658
dependencies: list[dict] = []
5759
process_raw_deps(
5860
env_raw_deps,
5961
env_deps_config,
6062
dependencies,
6163
deps_groups,
62-
project_def_path=env.project_def_path,
64+
project_def_path=project_def_path,
6365
)
6466

6567
install_deps_payload = install_deps_in_env_action.InstallDepsInEnvRunPayload(
6668
env_name=env.name,
6769
venv_dir_path=env.venv_dir_path,
68-
project_dir_path=env.project_def_path.parent,
70+
project_dir_path=path_to_resource_uri(project_def_path.parent),
6971
dependencies=[
7072
install_deps_in_env_action.Dependency(
7173
name=dep["name"],

finecode_builtin_handlers/src/finecode_builtin_handlers/install_env_read_config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
InstallEnvsRunResult,
77
)
88
from finecode_extension_api.interfaces import ilogger, iprojectinfoprovider
9+
from finecode_extension_api.resource_uri import resource_uri_to_path
910
from finecode_builtin_handlers import dependency_config_utils
1011

1112

@@ -32,11 +33,12 @@ async def run(
3233
payload: install_env_action.InstallEnvRunPayload,
3334
run_context: install_env_action.InstallEnvRunContext,
3435
) -> InstallEnvsRunResult:
36+
project_def_path = resource_uri_to_path(payload.env.project_def_path)
3537
project_raw_config = await self.project_info_provider.get_project_raw_config(
36-
payload.env.project_def_path
38+
project_def_path
3739
)
3840
dependency_config_utils.make_project_config_pip_compatible(
39-
project_raw_config, payload.env.project_def_path
41+
project_raw_config, project_def_path
4042
)
4143
run_context.project_def = project_raw_config
4244
return InstallEnvsRunResult(errors=[])

finecode_builtin_handlers/src/finecode_builtin_handlers/install_envs_discover_envs.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
ilogger,
99
iprojectinfoprovider,
1010
)
11+
from finecode_extension_api.resource_uri import path_to_resource_uri
1112

1213

1314
@dataclasses.dataclass
@@ -55,10 +56,10 @@ async def run(
5556
envs = [
5657
EnvInfo(
5758
name=env_name,
58-
venv_dir_path=self.runner_info_provider.get_venv_dir_path_of_env(
59-
env_name
59+
venv_dir_path=path_to_resource_uri(
60+
self.runner_info_provider.get_venv_dir_path_of_env(env_name)
6061
),
61-
project_def_path=project_def_path,
62+
project_def_path=path_to_resource_uri(project_def_path),
6263
)
6364
for env_name in deps_groups
6465
]
Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import asyncio
21
import dataclasses
32

43
from finecode_extension_api import code_action
54
from finecode_extension_api.actions.artifact import group_src_artifact_files_by_lang_action
65
from finecode_extension_api.actions.code_quality import lint_files_action
76
from finecode_extension_api.interfaces import iactionrunner, ilogger
7+
from finecode_extension_api.resource_uri import ResourceUri
88

99

1010
@dataclasses.dataclass
@@ -17,7 +17,7 @@ class LintFilesDispatchHandler(
1717
LintFilesDispatchHandlerConfig,
1818
]
1919
):
20-
"""Group files by language once and dispatch to lint_{lang}_files subactions concurrently.
20+
"""Group files by language once and dispatch to lint_{lang}_files subactions.
2121
2222
Subaction names follow the convention: language "python" maps to "lint_python_files",
2323
"javascript" maps to "lint_javascript_files", etc. Each subaction must be registered
@@ -32,18 +32,30 @@ def __init__(
3232
self.action_runner = action_runner
3333
self.logger = logger
3434

35+
async def _lint_file(
36+
self,
37+
subaction: iactionrunner.ActionDeclaration[lint_files_action.LintFilesAction],
38+
file_uri: ResourceUri,
39+
meta: code_action.RunActionMeta,
40+
) -> lint_files_action.LintFilesRunResult:
41+
return await self.action_runner.run_action(
42+
action=subaction,
43+
payload=lint_files_action.LintFilesRunPayload(file_paths=[file_uri]),
44+
meta=meta,
45+
)
46+
3547
async def run(
3648
self,
3749
payload: lint_files_action.LintFilesRunPayload,
3850
run_context: lint_files_action.LintFilesRunContext,
39-
) -> lint_files_action.LintFilesRunResult:
51+
) -> None:
4052
subactions_by_lang = self.action_runner.get_actions_for_parent(
4153
lint_files_action.LintFilesAction
4254
)
4355

4456
if not subactions_by_lang:
4557
self.logger.debug("LintFilesDispatchHandler: no language subactions registered")
46-
return lint_files_action.LintFilesRunResult(messages={})
58+
return
4759

4860
# Group files by language — single pass, O(files).
4961
group_action = self.action_runner.get_action_by_source(
@@ -59,27 +71,17 @@ async def run(
5971
)
6072
files_by_lang = files_by_lang_result.files_by_lang
6173

62-
# Dispatch concurrently — each subaction receives only its language's files.
63-
lint_tasks: list[asyncio.Task[lint_files_action.LintFilesRunResult]] = []
64-
try:
65-
async with asyncio.TaskGroup() as tg:
66-
for lang, files in files_by_lang.items():
67-
if not files:
68-
continue
69-
lint_tasks.append(
70-
tg.create_task(
71-
self.action_runner.run_action(
72-
action=subactions_by_lang[lang],
73-
payload=lint_files_action.LintFilesRunPayload(file_paths=files),
74-
meta=run_context.meta,
75-
)
76-
)
77-
)
78-
except ExceptionGroup as eg:
79-
error_str = ". ".join([str(e) for e in eg.exceptions])
80-
raise code_action.ActionFailedException(error_str) from eg
74+
# Build reverse mapping: file → language subaction.
75+
file_to_subaction: dict[ResourceUri, iactionrunner.ActionDeclaration[lint_files_action.LintFilesAction]] = {}
76+
for lang, files in files_by_lang.items():
77+
for file_uri in files:
78+
file_to_subaction[file_uri] = subactions_by_lang[lang]
8179

82-
result = lint_files_action.LintFilesRunResult(messages={})
83-
for task in lint_tasks:
84-
result.update(task.result())
85-
return result
80+
# Schedule per-file coroutines via partial_result_scheduler so that
81+
# run_action can execute them concurrently and send partial results.
82+
for file_uri in payload.file_paths:
83+
if file_uri in file_to_subaction:
84+
run_context.partial_result_scheduler.schedule(
85+
file_uri,
86+
self._lint_file(file_to_subaction[file_uri], file_uri, run_context.meta),
87+
)

finecode_dev_extensions/src/finecode_dev_extensions/publish_and_verify_artifact_action.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import dataclasses
2-
import pathlib
32

43
from finecode_extension_api import code_action, textstyler
4+
from finecode_extension_api.resource_uri import ResourceUri
55

66

77
@dataclasses.dataclass
88
class PublishAndVerifyArtifactRunPayload(code_action.RunActionPayload):
9-
src_artifact_def_path: pathlib.Path
10-
dist_artifact_paths: list[pathlib.Path]
9+
src_artifact_def_path: ResourceUri
10+
dist_artifact_paths: list[ResourceUri]
1111
force: bool = False
1212

1313

finecode_dev_extensions/src/finecode_dev_extensions/publish_and_verify_artifact_handler.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import dataclasses
2-
import pathlib
32

43
from finecode_extension_api import code_action
54
from finecode_extension_api.actions.publishing import (
@@ -45,8 +44,8 @@ async def run(
4544
) -> PublishAndVerifyArtifactRunResult:
4645
run_meta = run_context.meta
4746

48-
src_artifact_def_path: pathlib.Path = payload.src_artifact_def_path
49-
dist_artifact_paths: list[pathlib.Path] = payload.dist_artifact_paths
47+
src_artifact_def_path = payload.src_artifact_def_path
48+
dist_artifact_paths = payload.dist_artifact_paths
5049

5150
# Publish the artifact
5251
publish_action = self.action_runner.get_action_by_source(

0 commit comments

Comments
 (0)